天泣記

2006-02-01 (Wed)

#1 php_escape_shell_cmd (2) [CODE blog]

php_escape_shell_cmd を使っているところを少したどってみる。

とりあえず検索。

https://www.codeblog.org/gonzui/search?q=php_escape_shell_cmd&fm=all

いくつか見ていくと、PHP の popen で使っている例が見つかった。

php-5.1.0/ext/standard/file.c:880,923-924

880: PHP_FUNCTION(popen)

...

923:                 tmp = php_escape_shell_cmd(buf);
924:                 fp = VCWD_POPEN(tmp, p);

ふむ。VCWD_POPENというのはこのまえの virtual_popen である。とすると文字列が PHPレベルから php_escape_shell_cmd 経由で shell にたどり着くルートがあることになる。

#2 strncpy, strlcpy [CODE blog]

そういえばまず使わないせいか、strncpy の仕様をよく覚えていないことに気がついた。

2次元的になイメージで表示してみれば忘れにくいかも、というわけで表示させてみる。

% cat t.c
#include <stdio.h>
#include <string.h>
int main()
{
  char buf[10];
  int i, n;
  for (n = 0; n < 10; n++) {
    memset(buf, 1, 10);
    strncpy(buf, "abcde", n);
    printf("%d:", n);
    for (i = 0; i < 10; i++) printf(" %02x", (unsigned char)buf[i]);
    printf("\n");
  }
  return 0;
}
% gcc t.c
% ./a.out
0: 01 01 01 01 01 01 01 01 01 01
1: 61 01 01 01 01 01 01 01 01 01
2: 61 62 01 01 01 01 01 01 01 01
3: 61 62 63 01 01 01 01 01 01 01
4: 61 62 63 64 01 01 01 01 01 01
5: 61 62 63 64 65 01 01 01 01 01
6: 61 62 63 64 65 00 01 01 01 01
7: 61 62 63 64 65 00 00 01 01 01
8: 61 62 63 64 65 00 00 00 01 01
9: 61 62 63 64 65 00 00 00 00 01

ふむ。null terminate されないとか、null padding がおこるといった、今まで耳にしていた話が確認できる。

ついでに、strlcpy も同様に試してみる。

% cat t.c
#include <stdio.h>
#include <string.h>
int main()
{
  char buf[10];
  int i, n;
  for (n = 0; n < 10; n++) {
    memset(buf, 1, 10);
    strlcpy(buf, "abcde", n);
    printf("%d:", n);
    for (i = 0; i < 10; i++)
      printf(" %02x", (unsigned char)buf[i]);
    printf("\n");
  }
  return 0;
}
% gcc t.c
% ./a.out
0: 01 01 01 01 01 01 01 01 01 01
1: 00 01 01 01 01 01 01 01 01 01
2: 61 00 01 01 01 01 01 01 01 01
3: 61 62 00 01 01 01 01 01 01 01
4: 61 62 63 00 01 01 01 01 01 01
5: 61 62 63 64 00 01 01 01 01 01
6: 61 62 63 64 65 00 01 01 01 01
7: 61 62 63 64 65 00 01 01 01 01
8: 61 62 63 64 65 00 01 01 01 01
9: 61 62 63 64 65 00 01 01 01 01

null padding な行われず、(0<n であれば) null terminate が起こることが見てとれる。

2006-02-02 (Thu)

#1 stpcpy [CODE blog]

strlcpy といえば、最近 austin-group-l で、ちょっと話が出ていたのを思いだし、読み返してみる。

http://www.opengroup.org/austin/mailarchives/ag/msg08955.html

読み返してみると、提案の中に stpcpy, stpncpy があるのだが、なんで strlcpy, strlcat にしないのか、という話である。

strlcpy, strlcat についてはそれはそれとして、stpcpy, stpncpy とはなんだろう?

調べてみると、これは glibc にあるもので、strcpy, strncpy に似ているが、コピーした文字列の最後を指すポインタを返値とするものらしい。 (マニュアルには stpcpy の由来はたぶん MS-DOS、とある。)

たしかに、strcpy は内部的に文字列の長さを計測するのにその情報を呼出側で得られない。それで悲しい思いをしたことは何度かある。strpcpy が標準化されるとしたらそういう思いをする必要がなくなるわけで、めでたいことだ。

#2 strlcpy and strlcat - consistent, safe, string copy and concatenation. [CODE blog]

http://www.gratisoft.us/todd/papers/strlcpy.html

そういえば読んだことがない。

#3 SSLv2, TRACE [CODE blog]

ふと思い立って https://www.codeblog.org で SSLv2 と TRACE メソッドを disable する。

SSLProtocol All -SSLv2
TraceEnable off

2006-02-03 (Fri)

#1 strncat [CODE blog]

strncat についても2次元にしてみる。

% cat t.c
#include <stdio.h>
#include <string.h>
int main()
{
  char orig[10];
  char buf[sizeof(orig)];
  int i, n;
  memset(orig, '\x01', sizeof(buf));
  strcpy(orig, "ABC");
  for (n = 0; n < 10; n++) {
    memcpy(buf, orig, sizeof(orig));
    strncat(buf, "abcde", n);
    printf("%d:", n);
    for (i = 0; i < 10; i++) printf(" %02x", (unsigned char)buf[i]);
    printf("\n");
  }
  return 0;
}
% gcc t.c
% ./a.out
0: 41 42 43 00 01 01 01 01 01 01
1: 41 42 43 61 00 01 01 01 01 01
2: 41 42 43 61 62 00 01 01 01 01
3: 41 42 43 61 62 63 00 01 01 01
4: 41 42 43 61 62 63 64 00 01 01
5: 41 42 43 61 62 63 64 65 00 01
6: 41 42 43 61 62 63 64 65 00 01
7: 41 42 43 61 62 63 64 65 00 01
8: 41 42 43 61 62 63 64 65 00 01
9: 41 42 43 61 62 63 64 65 00 01

ちょっとわかりにくいので文字に変えて情報を付加してみる。

strncat(dest, src, n)
        src: a  b  c  d  e \0
dest: A  B  C \0 \1 \1 \1 \1 \1 \1
  n
  0:  A  B  C \0 \1 \1 \1 \1 \1 \1
  1:  A  B  C  a \0 \1 \1 \1 \1 \1
  2:  A  B  C  a  b \0 \1 \1 \1 \1
  3:  A  B  C  a  b  c \0 \1 \1 \1
  4:  A  B  C  a  b  c  d \0 \1 \1
  5:  A  B  C  a  b  c  d  e \0 \1
  6:  A  B  C  a  b  c  d  e \0 \1
  7:  A  B  C  a  b  c  d  e \0 \1
  8:  A  B  C  a  b  c  d  e \0 \1
  9:  A  B  C  a  b  c  d  e \0 \1

src から min(strlen(src), n) だけコピーされ、必ず null terminate されることがわかる。

#2 strlcat [CODE blog]

最後に strlcat である。

% cat t.c
#include <stdio.h>
#include <string.h>
int main()
{
  char orig[10];
  char buf[sizeof(orig)];
  int i, n;
  memset(orig, '\x01', sizeof(buf));
  strcpy(orig, "ABC");
  for (n = 0; n < 12; n++) {
    memcpy(buf, orig, sizeof(orig));
    strlcat(buf, "abcde", n);
    printf("%d:", n);
    for (i = 0; i < 10; i++) printf(" %02x", (unsigned char)buf[i]);
    printf("\n");
  }
  return 0;
}
% gcc t.c
/tmp//ccl19707.o(.text+0x38): In function `main':
: warning: strcpy() is almost always misused, please use strlcpy()
Z:akr@openbsd38.vmw% ./a.out
0: 41 42 43 00 01 01 01 01 01 01
1: 41 42 43 00 01 01 01 01 01 01
2: 41 42 43 00 01 01 01 01 01 01
3: 41 42 43 00 01 01 01 01 01 01
4: 41 42 43 00 01 01 01 01 01 01
5: 41 42 43 61 00 01 01 01 01 01
6: 41 42 43 61 62 00 01 01 01 01
7: 41 42 43 61 62 63 00 01 01 01
8: 41 42 43 61 62 63 64 00 01 01
9: 41 42 43 61 62 63 64 65 00 01
10: 41 42 43 61 62 63 64 65 00 01
11: 41 42 43 61 62 63 64 65 00 01

これも文字に変えてみる。

strlcat(dest, src, n)
        src: a  b  c  d  e \0
dest: A  B  C \0 \1 \1 \1 \1 \1 \1
  n
  0:  A  B  C \0 \1 \1 \1 \1 \1 \1
  1:  A  B  C \0 \1 \1 \1 \1 \1 \1
  2:  A  B  C \0 \1 \1 \1 \1 \1 \1
  3:  A  B  C \0 \1 \1 \1 \1 \1 \1
  4:  A  B  C \0 \1 \1 \1 \1 \1 \1
  5:  A  B  C  a \0 \1 \1 \1 \1 \1
  6:  A  B  C  a  b \0 \1 \1 \1 \1
  7:  A  B  C  a  b  c \0 \1 \1 \1
  8:  A  B  C  a  b  c  d \0 \1 \1
  9:  A  B  C  a  b  c  d  e \0 \1
 10:  A  B  C  a  b  c  d  e \0 \1
 11:  A  B  C  a  b  c  d  e \0 \1

こう図示すると、strlcat は strncat とはあからさまに形が違う。これは、strncat の n がコピーする長さの最大値であるのに対し、 strlcat の n がコピー元のバッファの長さだからである。

2006-02-04 (Sat)

#1 vsnprintf [CODE blog]

vsnprintf は ISO C にもある標準な関数であるが、歴史が浅いためかいろんなアプリケーションで代替関数が定義されている。

ただ、この関数は全部自前で書くのは面倒臭いため、奇妙な実装が使われることもあるようである。

・ X (の Mesa) では vsprintf をつかって実装している。はみ出てしまう部分は、mprotect でアクセス不能なメモリ領域を作り、SEGV を trap している。
・ Apache では、vfprintf で /dev/null に書き込んで返値から長さを得た後、vsprintf を使っている。しかし、setvbuf を使っているところはなんか設定したバッファから結果の文字列を取り出すことを意図していた名残のような気もする。あと、/dev/null を open した後 close してない。
・ dpkg では、vfprintf でテンポラリファイルに書き出したものを読み出している。
・ Berkeley DB では単純にバッファ長を無視して vsprintf を使う。
・ dhcp でも単純に無視して vsprintf を使う。
・ nvi でも単純に無視して vsprintf を使う。

まぁ、システムに vsnprintf が存在すれば使われないだろうから、最近のシステムでは使われないのだろう。

それはそれとして、バッファ長を無視するアプリケーションがあるのは興味深い。そのようなアプリケーションでは、バッファ長を越えるような vsprintf 呼び出しはしない (はず) という意図が見える。つまり、バッファ長は純粋に (システムがまともな vsnprintf を提供していた場合に) バッファオーバーフローを防ぐために使っていて、文字列の先頭部分を得るという機能は使っていないのであろう。

#2 SSLCipherSuite [CODE blog]

つぎのようなつっこみがあった。 https://www.codeblog.org/blog/akr/?date=20060202#c01

SSLProtocolでSSLv2を抑制したので、ついでに暗号スペックの方も40bit系を抑制したらいかがでしょうか? こんな感じ。

 SSLCipherSuite RSA:!EXP:!NULL:+HIGH:+MEDIUM:-LOW

この辺もどうぞ。 http://www.modssl.org/docs/2.8/ssl_reference.html#ToC9

40bit を抑制するのは正しい気がする。

現在の SSLCipherSuite は次のようになっている。

SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL

まぁ、+SSLv2 とか入っていて怪しいのだが、それはそれとして例示してもらったのと比較してみる。

% diff -u =(openssl ciphers -v 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL'|sort) =(openssl ciphers -v 'RSA:!EXP:!NULL:+HIGH:+MEDIUM:-LOW'|sort)
--- /tmp/zshjmARou      2006-02-04 02:01:34.000000000 +0900
+++ /tmp/zsh3XUcjY      2006-02-04 02:01:34.000000000 +0900
@@ -1,27 +1,8 @@
 AES128-SHA              SSLv3 Kx=RSA      Au=RSA  Enc=AES(128)  Mac=SHA1
 AES256-SHA              SSLv3 Kx=RSA      Au=RSA  Enc=AES(256)  Mac=SHA1
-DES-CBC-MD5             SSLv2 Kx=RSA      Au=RSA  Enc=DES(56)   Mac=MD5
-DES-CBC-SHA             SSLv3 Kx=RSA      Au=RSA  Enc=DES(56)   Mac=SHA1
 DES-CBC3-MD5            SSLv2 Kx=RSA      Au=RSA  Enc=3DES(168) Mac=MD5
 DES-CBC3-SHA            SSLv3 Kx=RSA      Au=RSA  Enc=3DES(168) Mac=SHA1
-DHE-DSS-AES128-SHA      SSLv3 Kx=DH       Au=DSS  Enc=AES(128)  Mac=SHA1
-DHE-DSS-AES256-SHA      SSLv3 Kx=DH       Au=DSS  Enc=AES(256)  Mac=SHA1
-DHE-DSS-RC4-SHA         SSLv3 Kx=DH       Au=DSS  Enc=RC4(128)  Mac=SHA1
-DHE-RSA-AES128-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA1
-DHE-RSA-AES256-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA1
-EDH-DSS-DES-CBC-SHA     SSLv3 Kx=DH       Au=DSS  Enc=DES(56)   Mac=SHA1
-EDH-DSS-DES-CBC3-SHA    SSLv3 Kx=DH       Au=DSS  Enc=3DES(168) Mac=SHA1
-EDH-RSA-DES-CBC-SHA     SSLv3 Kx=DH       Au=RSA  Enc=DES(56)   Mac=SHA1
-EDH-RSA-DES-CBC3-SHA    SSLv3 Kx=DH       Au=RSA  Enc=3DES(168) Mac=SHA1
-EXP-DES-CBC-SHA         SSLv3 Kx=RSA(512) Au=RSA  Enc=DES(40)   Mac=SHA1 export
-EXP-EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH(512)  Au=DSS  Enc=DES(40)   Mac=SHA1 export
-EXP-EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH(512)  Au=RSA  Enc=DES(40)   Mac=SHA1 export
-EXP-RC2-CBC-MD5         SSLv2 Kx=RSA(512) Au=RSA  Enc=RC2(40)   Mac=MD5  export
-EXP-RC2-CBC-MD5         SSLv3 Kx=RSA(512) Au=RSA  Enc=RC2(40)   Mac=MD5  export
-EXP-RC4-MD5             SSLv2 Kx=RSA(512) Au=RSA  Enc=RC4(40)   Mac=MD5  export
-EXP-RC4-MD5             SSLv3 Kx=RSA(512) Au=RSA  Enc=RC4(40)   Mac=MD5  export
 RC2-CBC-MD5             SSLv2 Kx=RSA      Au=RSA  Enc=RC2(128)  Mac=MD5
-RC4-64-MD5              SSLv2 Kx=RSA      Au=RSA  Enc=RC4(64)   Mac=MD5
 RC4-MD5                 SSLv2 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=MD5
 RC4-MD5                 SSLv3 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=MD5
 RC4-SHA                 SSLv3 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=SHA1

んー、これだとちょっと削りすぎか。ログを見ても削れている部分を使っている通信は多い。

40bit のを削るだけなら -EXP にするだけで済むようではある。

% diff -u =(openssl ciphers -v 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL') =(openssl ciphers -v 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:-EXP:+eNULL')
--- /tmp/zshBN9P03      2006-02-04 02:03:32.000000000 +0900
+++ /tmp/zshpoAmJ9      2006-02-04 02:03:32.000000000 +0900
@@ -18,10 +18,3 @@
 RC4-MD5                 SSLv2 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=MD5
 RC4-64-MD5              SSLv2 Kx=RSA      Au=RSA  Enc=RC4(64)   Mac=MD5
 DES-CBC-MD5             SSLv2 Kx=RSA      Au=RSA  Enc=DES(56)   Mac=MD5
-EXP-EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH(512)  Au=RSA  Enc=DES(40)   Mac=SHA1 export
-EXP-EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH(512)  Au=DSS  Enc=DES(40)   Mac=SHA1 export
-EXP-DES-CBC-SHA         SSLv3 Kx=RSA(512) Au=RSA  Enc=DES(40)   Mac=SHA1 export
-EXP-RC2-CBC-MD5         SSLv3 Kx=RSA(512) Au=RSA  Enc=RC2(40)   Mac=MD5  export
-EXP-RC4-MD5             SSLv3 Kx=RSA(512) Au=RSA  Enc=RC4(40)   Mac=MD5  export
-EXP-RC2-CBC-MD5         SSLv2 Kx=RSA(512) Au=RSA  Enc=RC2(40)   Mac=MD5  export
-EXP-RC4-MD5             SSLv2 Kx=RSA(512) Au=RSA  Enc=RC4(40)   Mac=MD5  export
% openssl ciphers -v 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:-EXP:+eNULL'|grep 40
zsh: done       openssl ciphers -v  |
zsh: exit 1     grep 40

さらに、-SSLv2 とすると次のように変わる。

% diff -u =(openssl ciphers -v 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:-EXP:+eNULL') =(openssl ciphers -v 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:-SSLv2:-EXP:+eNULL')
--- /tmp/zshknwPKc      2006-02-04 02:10:48.000000000 +0900
+++ /tmp/zshprSrXe      2006-02-04 02:10:48.000000000 +0900
@@ -13,8 +13,3 @@
 EDH-RSA-DES-CBC-SHA     SSLv3 Kx=DH       Au=RSA  Enc=DES(56)   Mac=SHA1
 EDH-DSS-DES-CBC-SHA     SSLv3 Kx=DH       Au=DSS  Enc=DES(56)   Mac=SHA1
 DES-CBC-SHA             SSLv3 Kx=RSA      Au=RSA  Enc=DES(56)   Mac=SHA1
-DES-CBC3-MD5            SSLv2 Kx=RSA      Au=RSA  Enc=3DES(168) Mac=MD5
-RC2-CBC-MD5             SSLv2 Kx=RSA      Au=RSA  Enc=RC2(128)  Mac=MD5
-RC4-MD5                 SSLv2 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=MD5
-RC4-64-MD5              SSLv2 Kx=RSA      Au=RSA  Enc=RC4(64)   Mac=MD5
-DES-CBC-MD5             SSLv2 Kx=RSA      Au=RSA  Enc=DES(56)   Mac=MD5

さらに、-LOW とすると次のように変わる。

% diff -u =(openssl ciphers -v 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:-SSLv2:-EXP:+eNULL') =(openssl ciphers -v 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP:+eNULL')
--- /tmp/zshrzD1KL      2006-02-04 02:34:24.000000000 +0900
+++ /tmp/zshL0QdtV      2006-02-04 02:34:24.000000000 +0900
@@ -10,6 +10,3 @@
 DHE-DSS-RC4-SHA         SSLv3 Kx=DH       Au=DSS  Enc=RC4(128)  Mac=SHA1
 RC4-SHA                 SSLv3 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=SHA1
 RC4-MD5                 SSLv3 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=MD5
-EDH-RSA-DES-CBC-SHA     SSLv3 Kx=DH       Au=RSA  Enc=DES(56)   Mac=SHA1
-EDH-DSS-DES-CBC-SHA     SSLv3 Kx=DH       Au=DSS  Enc=DES(56)   Mac=SHA1
-DES-CBC-SHA             SSLv3 Kx=RSA      Au=RSA  Enc=DES(56)   Mac=SHA1

ログを見ても 56bit のこの3つを使っている人はいないようである。

というわけで、とりあえずはこうである。

SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP:+eNULL
#3 strcpy, strcat に対する長さ指定 [CODE blog]

strcpy, strcat のかわりに strncpy, strncat (もしくは strlcpy, strlcat) のような引数に長さを付加した関数を使うと安全になるという話がある。最近、この話についてすこし議論したのでちょっと書いてみよう。

まずこの話に違和感を感じるのは、長さを付加してバッファオーバーフローを防いだとしても、それはおそらく正しい修正ではないということである。 strcpy, strcat を使っていたのであれば、文字列全体がコピーないし追加されることを意図していたはずであり、長さを制限して文字列全体が扱われなくなってしまうというのは、端的にいってしまえばバグである。

ここで正しい修正はむろん適切なサイズだけメモリを確保することであり、正しく修正すれば長さを制限するまでもなくバッファオーバーフローは起きないわけである。それなのになぜその正しい修正ではなく長さを制限するという話が語られるのだろうか。

おそらく、人間は誰しも間違うものであり、間違いにもレベルがあると考えると、長さを付加する利点を理解することができる。

バッファオーバーフローよりも文字列全体が扱われないほうがましだという考えに立てば、長さを付加する意味はある。扱うデータと指定した長さのどちらかが正しければバッファオーバーフローは起きないので、バッファオーバーフローの可能性をかなり引き下げることができる。

しかし、本当に正しく動作するためには両方を正しく指定しなければならない。つまりどちらかでも失敗すると正しく動かないわけで、全体としては間違う可能性は上がっているのも確かである。この点は気持が悪い。

ただ、assert のようなものだと考えて、バッファオーバーフローよりはデバッグが簡単になると思えばその点は許容できるかも知れない。ただ、その効果を考えるなら、長さをオーバーしたときに abort するという選択肢があってほしいかも。

2006-02-05 (Sun)

#1

FreeBSD の getcontext/setcontext の carry flag の話は直ったようなので、FreeBSD 7 以降では workaround を disable する。

MFC されるらしいので、6.1 以降にしたほうがいいかもしれない。

ただ、minor version は predefined macro からは参照しにくい感じ。

__FreeBSD_cc_version というのがあることにはあるが、これは gcc 本体にはなくて、FreeBSD 側で追加しているもののようだ。

まぁ、そもそも version じゃなくて configure でチェックするという案もあるが、ちゃんと検査できるかというとちょっと怪しい。

#2

マックスとマスクは似ている?

#3

<URL:http://www.zojirushi.co.jp/corp/gaiyo/gaiyo.html>

「象印マホービン株式会社」という名前だったとは知らなかった。

「マホービン」の部分が。

#4 strcpy, strcat に対する長さ指定 (2) [CODE blog]

もうすこし書いてみよう。

まず、バッファオーバーフローに対して文字列全体が扱われないのは本当にましか、という点である。

この話を安全性の関係で取り上げるときはセキュリティ的に安全になることが期待されているわけだが、それは直接的には微妙な所だと感じる。バッファオーバーフローが起きてもセキュリティ問題になるとは限らないし、文字列全体が扱われないことがセキュリティ問題になることも考えられないわけではない。それでもバッファオーバーフローの方がセキュリティ問題になりやすいのだと主張されれば反論できるわけではないのだが、納得はできないので根拠を示してほしくはある。

しかし、デバッグしやすくなることは確信できる。バッファオーバーフローによるメモリ破壊はどこで問題が発生するのかわからなくて厄介なのに対し、文字列が途中で切れているのは原因をたどるのがかなり楽だと思う。

したがって、デバッグしやすくすることによって、バグ修正が進んで、その結果としてプログラムが正しく (文字列全体をバッファオーバーフローを起こさずに扱えるように) なり、安全性が向上する、というストーリーならば納得できる。

もうひとつの点は、修正の容易さである。

文字列の扱いを改善する根本的な方法は、文字列を実現するデータ構造をつくって操作を隠蔽してしまうことである。実際、C++ はそういうものを提供しているわけで、それが不可能というわけではない。

しかし、そういうものを使っていないコードを使うように書き換えるのはおそらく大規模な修正になる。少なくとも他人のコードを監査する (OpenBSD のような) 立場では、そういう修正は困難であろう。そもそもプログラムのデータ構造がそういうものを使いやすいようになっているかという問題があるし、仮に修正をしてしまったとするとバージョンアップのたびの merge 作業にかかる手間が大きくなるという問題もある。

つまりたとえ根本的な方法があろうと実際に行われなければ改善されないわけで、可能な所からやるには長さを制限するというのはひとつの方法であるとは思う。

そういうことを考えると、strlcpy, strlcat が OpenBSD から出てきたというのはわかる気がする。

ただ、安全性が向上するための (私が) 納得できるストーリーとしては、長さを制限するだけではなく、その後にバグ修正を進める必要があるわけであるが、そこを強調する必要が無いだろうか。それとも、そうやってバグが見つかればそれは明らかなので強調する必要は無いのだろうか。

#5 tDiary の URL [CODE blog]

日毎、月毎のページにアクセスする URL を ? がつかない形にしてみる。

http://tdiary-users.sourceforge.jp/cgi-bin/wiki.cgi?html%A4%C7%A5%A2%A5%AF%A5%BB%A5%B9%A4%B7%A4%BF%A4%A4

を読むと、いくつか方法があるようだが、mod_rewrite の方法を使ってみた。

しかし、全員に html_anchor プラグインを加えるのは面倒臭い。

2006-02-06 (Mon)

#1

jocky に挑戦。

gdb が shell を経由してコマンドを起動するため、shell に jockey.so が効いてうまく動かなくて困ったが、結局、次のようなスクリプトを SHELL 環境変数で指定することによって gdb から date を動かすことに成功。

#!/bin/sh

LD_PRELOAD=libjockey.so
LD_LIBRARY_PATH=/usr/local/lib/fakethread:/usr/local/lib
JOCKEY='replay=1;excludedprogram=-'
export LD_PRELOAD LD_LIBRARY_PATH JOCKEY

exec date

あと、jockey --verbose で設定すべき環境変数が得られることもわかった。

... あー、そっか、date だからか。/bin/date だから、excludedprogram=- を設定するはめになって、excludedprogram=- になっていると、/bin/sh にも効いてしまうのか。

/bin/date を別なところにコピーして試すと、SHELL なんかいじらなくてもそのまま動いた。

#2

<URL:http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=351633>

#3 TypeKey の need_email [CODE blog]

tDiary への認証で、TypeKey の need_email=0 に変えてみた。

これで、使っていない e-mail address を要求しなくなり、それについて尋ねられることがなくなった。

(qwik は別で、e-mail address は実際に使っているので尋ねられる)

#4 wikipedia, strlcpy [CODE blog]

wikipedia に strlcpy の項目があることに気がつく。

strlcpy はバッファオーバーフローしないから安全という簡単な記述だなぁ。

2006-02-07 (Tue)

#1 kw プラグイン [CODE blog]

tDiary で RFC とかを参照する方法を調べていると、kw プラグインというのがちょうどよく使えそう。

グローバルな設定ファイルに

@options['kw.dic'] = [
  ['RFC', 'http://www.ietf.org/rfc/rfc$1.txt', 'nil'],
  ['CVE', 'http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-$1', 'nil'],
  ['debian-bug', 'http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=$1', 'nil'],
  ['netbsd-bug', 'http://www.NetBSD.org/cgi-bin/query-pr-single.pl?number=$1', 'nil'],
  ['freebsd-bug', 'http://www.freebsd.org/cgi/query-pr.cgi?pr=$1', 'nil'],
  ['openbsd-bug', 'http://cvs.openbsd.org/cgi-bin/query-pr-wrapper?full=yes&numbers=$1', 'nil'],
  ['gcc-bug', 'http://gcc.gnu.org/bugzilla/show_bug.cgi?id=$1', 'nil'],
  ['apache-bug', 'http://issues.apache.org/bugzilla/show_bug.cgi?id=$1', 'nil'],
  ['php-bug', 'http://bugs.php.net/bug.php?id=$1', 'nil'],
  ['linux-bug', 'http://bugzilla.kernel.org/show_bug.cgi?id=$1', 'nil'],
  ['ruby-list', 'http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/$1', 'nil'],
  ['ruby-dev', 'http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/$1', 'nil'],
  ['ruby-ext', 'http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-ext/$1', 'nil'],
  ['ruby-math', 'http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-math/$1', 'nil'],
  ['ruby-talk', 'http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/$1', 'nil'],
  ['ruby-core', 'http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/$1', 'nil'],
]

というように書いて、kw プラグインを有効にし、

と書くと

・ RFC:2822
・ CVE:2005-2337
・ debian-bug:351633
・ netbsd-bug:32609
・ freebsd-bug:91421
・ openbsd-bug:1533
・ gcc-bug:22127
・ apache-bug:38084
・ php-bug:22367
・ linux-bug:5573
・ ruby-dev:28286

というようになる。ちゃんとうごいた。

#2 pr と bug [CODE blog]

pr というのは problem report のことであるが、あまり一般的な言葉ではないように感じる。

感じるが、その感覚が一般的ではないという可能性もあるので google で数えてみよう。

% google-count pr bug
657000000       pr
528000000       bug

なんと、bug よりも pr のほうが多いという結果になった。

2006-02-09 (Thu)

#1 fixme [CODE blog]

fixme を検索すると、とりあえず32個見つかる。

https://www.codeblog.org/gonzui/search?q=fixme&fm=all

#2 crypt [CODE blog]

crypt の仕様としては NULL を返すことがあるらしい。

が、普通は返り値を検査しない感じである。

https://www.codeblog.org/gonzui/search?f=10&q=funcall%3Acrypt

マニュアルを見ると、法的な問題で実装されていないときに ENOSYS になるという話らしい。

manpages-2.17/man3/crypt.3:91-94

91: .B ENOSYS
92: The
93: .BR crypt ()
94: function was not implemented, probably because of U.S.A. export restrictions.

うぅむ。そういう環境をいま作るとしたらどうしたらいいだろう。

#3 graphviz での図のソース [CODE blog]

コメントとして HTML 内に残すようにしてみた。

benzen

7053fea257ed20708dfc86113941c630ce4f9ec6096baddf88c478931e3169b4.png

でも、コメントの中には -- が書けないので、むりやり空白を挿入したのだが、矢印じゃない線につかうのでコメントという形は余り良くないかも。

2006-02-16 (Thu)

#1 POSIX で -1 を grep してみる [CODE blog]
・ clock で (clock_t)-1
・ mktime で (time_t)-1
・ lseek で (off_t)-1
・ wcrtomb で (size_t)-1
・ ftok で (key_t)-1
・ mq_open で (mqd_t)-1
・ chown で (uid_t)-1
・ wait で (pid_t)-1
・ mmap で (void *)-1
・ iconv で (size_t)-1
・ iconv_open で (iconv_t)-1

2006-02-19 (Sun)

#1

Database Management Systems というところの講義資料を読んでみる。

なかなか面白い。

2006-02-20 (Mon)

#1 Ruby の open-uri での SSL [CODE blog]

最近、open-uri では SSL を扱える。

つまり、次のようなことができる。

require 'open-uri'
open('https://www.codeblog.org') {|f| ... }

ここで、CA 証明書は openssl がデフォルトで提供するものが使われる。

ruby-1.8.4/lib/open-uri.rb:235-238

235:       http.verify_mode = OpenSSL::SSL::VERIFY_PEER
236:       store = OpenSSL::X509::Store.new
237:       store.set_default_paths
238:       http.cert_store = store

ruby-1.8.4/ext/openssl/ossl_x509store.c:242-253,590

242: static VALUE
243: ossl_x509store_set_default_paths(VALUE self)
244: {
245:     X509_STORE *store;
246:
247:     GetX509Store(self, store);
248:     if (X509_STORE_set_default_paths(store) != 1){
249:         ossl_raise(eX509StoreError, NULL);
250:     }
251:
252:     return Qnil;
253: }

...

590:     rb_define_method(cX509Store, "set_default_paths", ossl_x509store_set_default_paths, 0);

さて、これはこれで (証明書はユーザが信用できると選んだものだけを使えという立場でなければ) いいわけであるが、まぁ、いつか誰かが検証しない挙動を要求することは予想していた。

その「いつか」というのが先週末おとずれたのだが、要求したひとの提案は、次のようにできるようにしてはどうかというものであった。

require 'open-uri'
require 'openssl'
open("https://...", :verify_mode=>OpenSSL::SSL::VERIFY_NONE) {|f| ... }

わるくはない。ここでの API の設計方針は「セキュリティ的によろしくないことは書きにくくあるべき」というものである。さらに「書きにくい」ということのひとつの側面は「長い」ということである。

その方針からして、検証しない挙動は書きにくくあるべきで、OpenSSL::SSL::VERIFY_NONE というそれなりに長い定数名が必要なのはよいことである。さらに、その定数を参照するために require 'openssl' が必要になるのもよい。

ただ、ひとつ改良できるところを見つけたので、そこを改良する。

require 'open-uri'
require 'openssl'
open("https://...", :ssl_verify_mode=>OpenSSL::SSL::VERIFY_NONE) {|f| ... }

オプションの先頭に ssl_ をつけることにより、4文字もよくなった。

さて、そのへんの調整はそれとして、もうすこし考えると、証明書をユーザが指定して検証するほうが検証しない挙動よりもお薦めであるということに気がついた。現時点で open-uri にはその方法がないので、もし :ssl_verify_mode だけ追加すると、よりお薦めな証明書を指定する方法がないのに、お薦めできない検証しない方法だけが用意されることになる。これはよろしくない。方針に反する。

というわけで、証明書を指定するオプションも同時に実装することにした。ここでのポイントは、そのオプションは :ssl_verify_mode よりも短く、使いやすくすることである。まぁ、証明書を用意するのは手間がかかるのでプログラマの手間を全体として少なくするのは難しいがやらないよりはましである。というわけで :ssl_ca_cert という名前にした。certificate じゃなくて cert にしたところが短くする努力である。

#2 証明書検索 [CODE blog]

ふと思ったのだが、世の中に存在する https サーバの証明書の中身を探せる検索エンジンというのはどうだろうか。

#3 gonzui で識別子全部をリンクしてみる [CODE blog]

Index: gonzui/webapp/markup.rb =================================================================== RCS file: /cvsroot/gonzui/gonzui/gonzui/webapp/markup.rb,v retrieving revision 1.21 diff -u -p -r1.21 markup.rb

gonzui/webapp/markup.rb 20 Feb 2006 06:49:53 -0000 1.21

+++ gonzui/webapp/markup.rb 20 Feb 2006 06:50:09 -0000 @@ -81,6 +81,10 @@ module Gonzui

query_string =  sprintf("%s:%s", tt, text)
uri = @search_uri + HTTPUtils.escape_form(query_string)
part = [:a, {:href => uri}, part]
elsif @info.type == :ident
query_string = text
uri = @search_uri + HTTPUtils.escape_form(query_string)
part = [:a, {:href => uri}, part]
end
return part
end

2006-02-21 (Tue)

#1

るびまの巻頭言の「リファレンスマニュアル整備について」という話を読んで、ふと去年のプロジェクトがどうなったのか調べてみた。

ここで今年とのいくつかの類似点が見られる。

今後の状況が類似の展開をたどるか、あるいは別の展開を見せるかは不明であるが、とりあえず ML ができるまでの期間を比較してみたいところではある。(去年は 2004-12-30提案、2005-01-23作成だった)

あと、去年は結局マイナーチェンジから始めるような方向性に思い直した感じだが、今年もそう変わるかどうかという点も興味深い。

2006-02-22 (Wed)

#1 [gonzui] gonzui と f+ [CODE blog]

gonzui で、識別子を全て検索のリンクにしたときに、URL のエスケープの問題を見つけた。

gonzui-1.2/gonzui/webapp/markup.rb:81-83

81:         query_string =  sprintf("%s:%s", tt, text)
82:         uri = @search_uri + query_string
83:         part = [:a, {:href => uri}, part]

ここで text はソースコード内の関数名であり、@search_uri は ...?q= という URL の前部である。また、tt は fundef や funcall といった検索の種類を表している。

問題は、ここで URL の中に関数名をそのまま入れることである。ただ、これは C のような関数に使える名前が十分に制限された言語では問題にならない。しかし、Lisp のように名前の自由度が大きな言語では問題になる。

具体的に問題の起こる関数名を探したところ、Emacs の float.el というものの中に、f+ という関数が見付かった。

emacs-21.4/lisp/emacs-lisp/float.el:167,181

167: (defun f+ (a1 a2)

...

181:       (f+ a1 (f- a2))

へー、Emacs って昔は浮動小数点演算を elisp で実装してたんだ、という話はさておき、 f+ の関数呼び出しをクリックして検索すると、f+ の関数定義を探すべきところが f の関数定義を探すようになっていた。

これは、URL が ...?q=fundef:f+ となって、この query を受け取った側が HTML form としてデコードすると + が space になってしまうからである。

そのため、ここは修正して query_string に form 用のエスケープ関数 (WEBrick::HTTPUtils.escape_form) を適用し、...?q=fundef%3Af%2B という URL を生成するようにした。

さて、ここで疑問に思ったのが、+ だけでなく : もエスケープされてしまうというところである。エスケープされて URL がわかりにくくなってしまっているが、これをエスケープするのは本当に必要だろうか?

#2 [spec] URL escape [CODE blog]

というわけで、ひさしぶりに RFC:3986 と HTML4.01 を眺めて考えてみる。

考えた結果、: はエスケープしないでよいという結論に達した。

というか、一般に form の値でエスケープしないといけないのは &, ;, =, +, #, %, [, ], space, 非ASCII printable 文字だけでいいんじゃないだろうか。(= は微妙なところだが)

RFC:3986 の仕様は、文字列の上に URI という構文を定義している。そして、その構文に対して意味も定義している。もちろん全ての意味を定義しているわけではなく、ごく基礎的な部分だけである。

その基礎の上に、HTML4.01 は form への入力を URI の query として表現する方法を定義している。

そして、各 web application は各 application で扱う意味を URI や form の上に表現する方法を決めるわけである。

ここで、RFC:3986 自身が query に定義している構文と意味は次の通りである。

・ 構文: *( unreserved / pct-encoded / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" / ":" / "@" / "/" / "?" )
・ 意味: unreserved な文字は percent encoding してもしなくても意味が変わらない

ここで、unreserved は ALPHA / DIGIT / "-" / "." / "_" / "~" であり、また、"!" から "?" は reserved の部分集合になっている。

そして、HTML4.01 は query の中身を [&;] で区切った name=value の並びとし、また + は space を意味すると定義している。つまり、RFC:3986 が用意してくれた reserved の中で query に使える文字 (percent encoding するかどうかで意味が変わっても良い文字) のうち、&, ;, = , + を使って (name, value) という対の並びを表現するということである。

ここでデリミタに reserved 内の文字を使っているのはそれらの文字をデリミタとしてでなく表現するのに percent encoding を使えるようにするためである。もし、unreserved 内の文字をデリミタにしたとすると、percent encoding してもしなくても意味が変わらないという定義により、デリミタでない意味を表現する方法を何か他に考えなければならなくなる。

さて、やっと本題の : であるが、これは RFC:3986 の定義からすると query 内に使ってよい文字で、percent encoding するかどうかで意味が変わって「も」よい文字である。

しかし、HTML4.01 form では、: はデリミタとしては使っていない。そして RFC:3986 では、デリミタとして使っていない文字はその文字自身を意味するとして扱うと定義されている。従って、form の場合は percent encoding するかどうかでは意味は変わらない。つまり、form に使うときには : をエスケープする理由はない。 (むろん、エスケープしてはいけない理由もない - URL の美しさを除けば)

というわけで、form 用のエスケープ関数は form で使用しているデリミタ以外は reserved であってもエスケープしないでもよさそうである。

逆に、reserved 全てをエスケープする関数の用途は、使われる文脈が不明でもともかくその文字自身の意味として扱わせるというものになる。しかし、使われる文脈が不明という状況はどのくらいあるのだろうか。あまりないような気がするので、そういう関数は使いにくく (長く) しておいてもいいかもしれない。危険ではないのでそれほど使いにくい必要はないが。

#3 [spec] エスケープ関数の API [CODE blog]

さて、では、エスケープ関数はどういう API がいいだろうか。

まず、現在のエスケープ関数はたいてい文字列を受け取って文字列を返す関数であり、どうも使い分けが難しい。実際、space を表現する + を使えないところで使ってしまうケースを何回か見たことがある。

これをどうにかしたいと以前から思っているのだが、form を扱っているという文脈をもっと利用するといいのではないだろうか。

つまり、form が生成するのと同様な URL を生成するときに form 用のエスケープ関数が必要になるわけで、そのエスケープ関数が呼ばれるときには、多くの場合、呼出元では (name, value) 対の並びをもっていて、順にエスケープして & ないし ; でつなぐという処理をしているわけである。とすると、(name,value)対の並び自体を受け取って、全部エスケープしてつないで返すというのがいいのではなかろうか。

こうすることによる利点はいくつも考えられる。

・ いままでよりも多くの処理をライブラリにまかせられ、簡単になる。
・ 受け取る引数の型が違うので、単純な文字列のエスケープと間違いようがない。

まぁ、間違いを防ぐという意味ではどこでも使える確実なのをひとつ使いやすいところにおいておく (reserved 全てを percent encoding するのを短い名前で用意する) という方法も考えられるのだが、そうすると percent encoding が余計に行われるので、URL が汚くなる。

URL はユーザインターフェースの一部であり、そこを不要に汚すのはよろしくない。

#4 [spec] WEBrick::HTTPUtils#escape_form [CODE blog]

なぜ WEBrick::HTTPUtils#escape_form は (私の視点からすると) 余計にエスケープするのだろう? コードを読んでみよう。

ruby-1.8.4/lib/webrick/httputils.rb:344,350,352-354,364,377-381

344:     reserved = ';/?:@&=+$,'

...

350:     control  = (0x0..0x1f).collect{|c| c.chr }.join + "\x7f"

...

352:     delims   = '<>#%"'
353:     unwise   = '{}|\\^[]`'
354:     nonascii = (0x80..0xff).collect{|c| c.chr }.join

...

364:     UNESCAPED_FORM = _make_regex(reserved+control+delims+unwise+nonascii)

...

377:     def escape_form(str)
378:       ret = _escape(str, UNESCAPED_FORM)
379:       ret.gsub!(/ /, "+")
380:       ret
381:     end

ふむ。unwise ってことはRFC:3986じゃないな。RFC:2396か。

こっちの視点からすると、&;=+#%[] だけでいいわけだが、それらを含むのは、reserved, delims, unwise にわかれていて、ちょうどそれだけという集合がない。もちろん、それだけの集合を決定するためには HTML form の知識を使わないといけないので、URI の RFC に載っていたら逆に変なわけだけど。にもかかわらず、reserved とかの定義された集合の和でエスケープすべき文字を定義しているから、余計なのまで含めてしまう、というわけかな。

2006-02-23 (Thu)

#1 [spec] web application 固有のデリミタ [CODE blog]

reserved のうち、デリミタとして使われているものをデータとして扱うにはエスケープしなければならない。

HTML form では、;&=+ をデリミタとして使っているが、reserved はまだまだ残っている。

ところで、fundef:strcpy の : は gonzui 固有のデリミタではないだろうか。

現在、gonzui は、ここで : としても %3A としてもとくに区別せずに動作する。これはつまり、fundef のような検索の種類を示す文字列として、: が含まれているものは使えないということである。もし、これを区別するようにして、: としたときはデリミタ、%3A としたときはデータの一部とすれば、: を含む種類も扱えるようになりそうである。

現在、: と %3A が区別しないのは、application/x-www-form-urlencoded な query を分割して各要素を切り出した時点で %XX をデコードするからである。このデコードを遅延して、gonzui の検索条件の構文にしたがって分割した後にすれば、検索の種類などの要素に : を入れられるだろう。

しかし、こうすることの欠点はいくつか思い付く。

・ ブラウザから form を submit したときに : がそのままになるか %3A になるかは怪しい。少なくとも個々の文字についてどちらになるか制御することはできない。
・ 既存の application/x-www-form-urlencoded デコーダを利用できなくなる。

後者は自前で書けばいいが、前者は致命的である。ブラウザから submit することを想定する限り、デリミタを増やすことは考えない方がよさそうである。

しかし、逆にいえば、ブラウザから submit しなければ、そういう URL を設計しても特に問題なさそうだともいえる。

そもそもそういうのを encourage すべきかどうかは微妙なところだが、 application/x-www-form-urlencoded を扱うライブラリのデザインによってそういうのを支援することも可能かもしれない。

#2 [spec] ABNF [CODE blog]

URL を parse するとき、デリミタでどんどん切り出していく。まず : より前を scheme として取り出し、? までを hier-part として取り出し、hier-part 内を / で分割すしていく、という感じである。かなり省略してあるが。

ここで、先に行われる分割で使用されるデリミタは要素に表れない。もうちょっと正確にいえば、要素の右のデリミタは要素内には表れない。たとえば、: は scheme には表れないし、? は hier-part には表れないし、# は query には表れない。

これは当り前で、もし表れ得るとしたら分割のしかたが曖昧になってしまうからである。

そして、query が form からだったとすると、個々の key/value 要素は ;&= は含まない。

こうやって分割が繰り返されていく処理過程を見ると、個々の要素に使える文字の定義は引き算で定義するのが適当に思える。

つまり、たとえば、query に使える文字集合は URI で使える文字集合から分割の邪魔になるものを除いたものとし、 form 用の分割に邪魔になるものをさらに除いたものを key/value 要素に直接使える文字集合とする、という感じである。

しかし、RFC では ABNF で定義し、ABNF には残念なことに引き算がない。なので、ぜんぶ足し算で定義されている。

もし URI の query から ;&=+ を除いたもの、といった定義しようと思うと、query の定義をたどってコピーして修正しないといけない。

そういう記法を使っていることが問題の根本かも。

#3 [spec] URL と URI の reserved [CODE blog]

小林さんに教えてもらったのだが、以前の RFC では URL と URI の reserved が 2文字違っていたのだそうな。

確認してみよう。

URL は RFC:1738 で、URI は RFC:2396 である。

RFC1738 URL:

reserved in a scheme, the octet must be encoded.  The characters ";",
"/", "?", ":", "@", "=" and "&" are the characters which may be

RFC:2396 URI:

reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
              "$" | ","

うぅむ、たしかに。"$" と "," がない。

追記: む。"+" もないではないか。3つ?

2006-02-24 (Fri)

#1 [spec] URI の文字 [CODE blog]

文字の種類をちょっとまとめてみる。

・ RFC:3986 Uniform Resource Identifier (URI): Generic Syntax
・ RFC:2396 Uniform Resource Identifiers (URI): Generic Syntax
・ RFC:1808 Relative Uniform Resource Locators
・ RFC:1738 Uniform Resource Locators (URL)

                        URI             URI             URL
oct   dec   hex   chr   RFC3986         RFC2396         RFC1738,1808
041   33    21    !     sub-delims      mark            extra
042   34    22    "                     delims          punctuation
043   35    23    #     gen-delims      delims          punctuation
044   36    24    $     sub-delims      reserved        safe
045   37    25    %                     delims          punctuation
046   38    26    &     sub-delims      reserved        reserved
047   39    27    '     sub-delims      mark            extra
050   40    28    (     sub-delims      mark            extra
051   41    29    )     sub-delims      mark            extra
052   42    2A    *     sub-delims      mark            extra
053   43    2B    +     sub-delims      reserved        safe
054   44    2C    ,     sub-delims      reserved        extra
055   45    2D    -     unreserved      mark            safe
056   46    2E    .     unreserved      mark            safe
057   47    2F    /     gen-delims      reserved        reserved
072   58    3A    :     gen-delims      reserved        reserved
073   59    3B    ;     sub-delims      reserved        reserved
074   60    3C    <                     delims          punctuation
075   61    3D    =     sub-delims      reserved        reserved
076   62    3E    >                     delims          punctuation
077   63    3F    ?     gen-delims      reserved        reserved
100   64    40    @     gen-delims      reserved        reserved
133   91    5B    [     gen-delims      unwise          national
134   92    5C    \                     unwise          national
135   93    5D    ]     gen-delims      unwise          national
136   94    5E    ^                     unwise          national
137   95    5F    _     unreserved      mark            safe
140   96    60    `                     unwise          national
173   123   7B    {                     unwise          national
174   124   7C    |                     unwise          national
175   125   7D    }                     unwise          national
176   126   7E    ~     unreserved      mark            national

RFC3986
  reserved    = gen-delims / sub-delims

RFC2396
  alpha    = lowalpha | upalpha
  alphanum = alpha | digit
  unreserved  = alphanum | mark

RFC1738,1808
  unreserved     = alpha | digit | safe | extra
#2 [spec] national [CODE blog]

うぅむ。RFC:1738, RFC:1808 には national なんてのがあったのか。

national に割り当てられた文字は他で使われていない。 national という非終端記号を参照しているところはないし、 national という名前が何かという説明もない。それらの文字が使われない理由は次のように説明されている。

Other characters are unsafe because
gateways and other transport agents are known to sometimes modify
such characters. These characters are "{", "}", "|", "\", "^", "~",
"[", "]", and "`".

うぅむ、gateways and other transport agents ねぇ。まぁ、説明はないが、national という名前と、実際の集合が ISO 646 の可変部分から @ を除いたものであることを考えると、これはおそらく ISO 646 から来ているのであろう。

ただ、ISO 646 を考慮するなら,@ を使っているのは甘いといわざるを得ない。

RFC を決めるときに、ISO 646 を気にする観点が中途半端に入り込んだのではないかと思わせる。

#3 [spec] RFC 2732 [CODE blog]

関係する RFC はもうひとつある。

・ RFC:2732 Format for Literal IPv6 Addresses in URL's

これは、http://[3ffe:2a00:100:7031::1] などという記法を定義していて、RFC:2396 から、"[", "]" を unwise から reserved に移している。

#4 [spec] national, unwise [CODE blog]

RFC:2396 の unwise は RFC:1738 の national から "~" を除いたものである。これにより、RFC:2396 では、~ がふつうに URL の中に使えるようになった。

現実には、それ以前から URL 内に ~ は使われていたわけで、その現状を追認したということであろう。 (RFC:1738 では使えないから %7E にすべきだという話が流布したという昔話もある)

というわけで、 ISO 646 の可変部分の 10文字のうち、"@" ははじめから URL で使用でき、 "~" は RFC:2396 で使用できるようになり、 "[", "]" は RFC:2732 で使えるようになった。

残りの 6文字は RFC:3986 では言及されておらず、それらを示す非終端記号もない。つまり、現時点で URI に使われることは許されていない。まぁ、将来的になんかの用途に使われはじめることもあるかもしれないが。

2006-02-25 (Sat)

#1

ふと思ったのだが、本を適当に開くと、その本でもっともページをとっている部分、おそらくはもっとも充実したコンテンツの部分が、もっとも高い確率で開かれる。

とくに、辞書やリファレンスマニュアルマニュアルなどの場合、個々の項目のどれかを含むページが開かれることになる。まえがきなどが開かれる可能性はかなり低い。

では、Web で、読者があるサイトの「もっとも充実したコンテンツ」を見つけるにはどうしたらいいだろう?

あるいは、サイトの製作者が「もっとも充実したコンテンツ」に自然に誘導するにはどうしたらいいだろう?

#2 [spec] RFC [CODE blog]

ふと、最近の RFC を (タイトルだけ) 眺めてみる。

http://www.rfc-editor.org/rfc-index2.html

・ RFC:4350 A Uniform Resource Name (URN) Formal Namespace for the New Zealand Government
・ RFC:4324 Calendar Access Protocol (CAP)
・ RFC:4289 Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures
・ RFC:4287 The Atom Syndication Format
・ RFC:4270 Attacks on Cryptographic Hashes in Internet Protocols
・ RFC:4266 The gopher URI Scheme
・ RFC:4263 Media Subtype Registration for Media Type text/troff
・ RFC:4249 Implementer-Friendly Specification of Message and MIME-Part Header Fields and Field Components
・ RFC:4248 The telnet URI Scheme
・ RFC:4234 Augmented BNF for Syntax Specifications: ABNF
・ RFC:4229 HTTP Header Field Registrations
・ RFC:4198 A Uniform Resource Name (URN) Namespace for Federated Content
・ RFC:4194 The S Hexdump Format
・ RFC:4169 Hypertext Transfer Protocol (HTTP) Digest Authentication Using Authentication and Key Agreement (AKA) Version-2
・ RFC:4157 The prospero URI Scheme
・ RFC:4156 The wais URI Scheme
・ RFC:4155 The application/mbox Media Type
・ RFC:4151 The 'tag' URI Scheme
・ RFC:4122 A Universally Unique IDentifier (UUID) URN Namespace
・ RFC:4088 Uniform Resource Identifier (URI) Scheme for the Simple Network Management Protocol (SNMP)
・ RFC:4049 BinaryTime: An Alternate Format for Representing Date and Time in ASN.1
・ RFC:4047 MIME Sub-type Registrations for Flexible Image Transport System (FITS)
#3 [spec] RFC の RSS [CODE blog]

探してみると見つかった。

http://x42.com/rss/rfc.rss

#4 [spec] internet-draft の RSS [CODE blog]

こっちも見つかった。 http://interglacial.com/rss/internet-drafts/internet_drafts___groups.rss

2006-02-27 (Mon)

#1 [spec] RFC:3986 [CODE blog]

RFC:3986 の Reference Resolution の項をざっと読む。

うぅむ。remove_dot_segments って、空の segment に関する記述がないけど、いいんかな。

2006-02-28 (Tue)

#1

Athlon X2 では、HLT命令で TSC が止まって、RDTSC で読み取れるのが Core 間でずれるらしい。

<URL:http://www.atmarkit.co.jp/flinux/rensai/watch2006/watch02b.html>

SMP とかででずれるという話は聞いたことがあったが、具体的に原因を読んだのははじめてだな。

#2

渕先生を見た。

#3

stack limit の違いにより、mmap が返す値が違うことを知ったわけだが、試しに、次のようにして Ruby のオブジェクトがどのあたりのアドレスになるかを調べてみる。

% ./ruby -e '                   
8192.downto(1) {|s|
  Process.setrlimit(Process::RLIMIT_STACK, s * 1024 * 1024)
  r = IO.popen(["./ruby", "-e", "p Object.new"]) {|f| f.read }
  puts "#{s} #{Integer(r[/0x[0-9a-f]+/])}"
}' > z

で、gnuplot でプロットすると... え、なにこの折れ線?

Linux 2.6.15 で。


[latest]


田中哲