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 にたどり着くルートがあることになる。
そういえばまず使わないせいか、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 が起こることが見てとれる。
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 が標準化されるとしたらそういう思いをする必要がなくなるわけで、めでたいことだ。
http://www.gratisoft.us/todd/papers/strlcpy.html
そういえば読んだことがない。
ふと思い立って https://www.codeblog.org で SSLv2 と TRACE メソッドを disable する。
SSLProtocol All -SSLv2 TraceEnable off
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 されることがわかる。
最後に 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 がコピー元のバッファの長さだからである。
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 を提供していた場合に) バッファオーバーフローを防ぐために使っていて、文字列の先頭部分を得るという機能は使っていないのであろう。
つぎのようなつっこみがあった。 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
strcpy, strcat のかわりに strncpy, strncat (もしくは strlcpy, strlcat) のような引数に長さを付加した関数を使うと安全になるという話がある。最近、この話についてすこし議論したのでちょっと書いてみよう。
まずこの話に違和感を感じるのは、長さを付加してバッファオーバーフローを防いだとしても、それはおそらく正しい修正ではないということである。 strcpy, strcat を使っていたのであれば、文字列全体がコピーないし追加されることを意図していたはずであり、長さを制限して文字列全体が扱われなくなってしまうというのは、端的にいってしまえばバグである。
ここで正しい修正はむろん適切なサイズだけメモリを確保することであり、正しく修正すれば長さを制限するまでもなくバッファオーバーフローは起きないわけである。それなのになぜその正しい修正ではなく長さを制限するという話が語られるのだろうか。
おそらく、人間は誰しも間違うものであり、間違いにもレベルがあると考えると、長さを付加する利点を理解することができる。
バッファオーバーフローよりも文字列全体が扱われないほうがましだという考えに立てば、長さを付加する意味はある。扱うデータと指定した長さのどちらかが正しければバッファオーバーフローは起きないので、バッファオーバーフローの可能性をかなり引き下げることができる。
しかし、本当に正しく動作するためには両方を正しく指定しなければならない。つまりどちらかでも失敗すると正しく動かないわけで、全体としては間違う可能性は上がっているのも確かである。この点は気持が悪い。
ただ、assert のようなものだと考えて、バッファオーバーフローよりはデバッグが簡単になると思えばその点は許容できるかも知れない。ただ、その効果を考えるなら、長さをオーバーしたときに abort するという選択肢があってほしいかも。
FreeBSD の getcontext/setcontext の carry flag の話は直ったようなので、FreeBSD 7 以降では workaround を disable する。
MFC されるらしいので、6.1 以降にしたほうがいいかもしれない。
ただ、minor version は predefined macro からは参照しにくい感じ。
__FreeBSD_cc_version というのがあることにはあるが、これは gcc 本体にはなくて、FreeBSD 側で追加しているもののようだ。
まぁ、そもそも version じゃなくて configure でチェックするという案もあるが、ちゃんと検査できるかというとちょっと怪しい。
マックスとマスクは似ている?
<URL:http://www.zojirushi.co.jp/corp/gaiyo/gaiyo.html>
「象印マホービン株式会社」という名前だったとは知らなかった。
「マホービン」の部分が。
もうすこし書いてみよう。
まず、バッファオーバーフローに対して文字列全体が扱われないのは本当にましか、という点である。
この話を安全性の関係で取り上げるときはセキュリティ的に安全になることが期待されているわけだが、それは直接的には微妙な所だと感じる。バッファオーバーフローが起きてもセキュリティ問題になるとは限らないし、文字列全体が扱われないことがセキュリティ問題になることも考えられないわけではない。それでもバッファオーバーフローの方がセキュリティ問題になりやすいのだと主張されれば反論できるわけではないのだが、納得はできないので根拠を示してほしくはある。
しかし、デバッグしやすくなることは確信できる。バッファオーバーフローによるメモリ破壊はどこで問題が発生するのかわからなくて厄介なのに対し、文字列が途中で切れているのは原因をたどるのがかなり楽だと思う。
したがって、デバッグしやすくすることによって、バグ修正が進んで、その結果としてプログラムが正しく (文字列全体をバッファオーバーフローを起こさずに扱えるように) なり、安全性が向上する、というストーリーならば納得できる。
もうひとつの点は、修正の容易さである。
文字列の扱いを改善する根本的な方法は、文字列を実現するデータ構造をつくって操作を隠蔽してしまうことである。実際、C++ はそういうものを提供しているわけで、それが不可能というわけではない。
しかし、そういうものを使っていないコードを使うように書き換えるのはおそらく大規模な修正になる。少なくとも他人のコードを監査する (OpenBSD のような) 立場では、そういう修正は困難であろう。そもそもプログラムのデータ構造がそういうものを使いやすいようになっているかという問題があるし、仮に修正をしてしまったとするとバージョンアップのたびの merge 作業にかかる手間が大きくなるという問題もある。
つまりたとえ根本的な方法があろうと実際に行われなければ改善されないわけで、可能な所からやるには長さを制限するというのはひとつの方法であるとは思う。
そういうことを考えると、strlcpy, strlcat が OpenBSD から出てきたというのはわかる気がする。
ただ、安全性が向上するための (私が) 納得できるストーリーとしては、長さを制限するだけではなく、その後にバグ修正を進める必要があるわけであるが、そこを強調する必要が無いだろうか。それとも、そうやってバグが見つかればそれは明らかなので強調する必要は無いのだろうか。
日毎、月毎のページにアクセスする 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 プラグインを加えるのは面倒臭い。
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 なんかいじらなくてもそのまま動いた。
<URL:http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=351633>
tDiary への認証で、TypeKey の need_email=0 に変えてみた。
これで、使っていない e-mail address を要求しなくなり、それについて尋ねられることがなくなった。
(qwik は別で、e-mail address は実際に使っているので尋ねられる)
wikipedia に strlcpy の項目があることに気がつく。
strlcpy はバッファオーバーフローしないから安全という簡単な記述だなぁ。
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
というようになる。ちゃんとうごいた。
pr というのは problem report のことであるが、あまり一般的な言葉ではないように感じる。
感じるが、その感覚が一般的ではないという可能性もあるので google で数えてみよう。
% google-count pr bug 657000000 pr 528000000 bug
なんと、bug よりも pr のほうが多いという結果になった。
fixme を検索すると、とりあえず32個見つかる。
https://www.codeblog.org/gonzui/search?q=fixme&fm=all
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.
うぅむ。そういう環境をいま作るとしたらどうしたらいいだろう。
コメントとして HTML 内に残すようにしてみた。
benzen
でも、コメントの中には -- が書けないので、むりやり空白を挿入したのだが、矢印じゃない線につかうのでコメントという形は余り良くないかも。
・ 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
Database Management Systems というところの講義資料を読んでみる。
なかなか面白い。
最近、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 にしたところが短くする努力である。
ふと思ったのだが、世の中に存在する https サーバの証明書の中身を探せる検索エンジンというのはどうだろうか。
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]
end return part
end
るびまの巻頭言の「リファレンスマニュアル整備について」という話を読んで、ふと去年のプロジェクトがどうなったのか調べてみた。
ここで今年とのいくつかの類似点が見られる。
今後の状況が類似の展開をたどるか、あるいは別の展開を見せるかは不明であるが、とりあえず ML ができるまでの期間を比較してみたいところではある。(去年は 2004-12-30提案、2005-01-23作成だった)
あと、去年は結局マイナーチェンジから始めるような方向性に思い直した感じだが、今年もそう変わるかどうかという点も興味深い。
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 がわかりにくくなってしまっているが、これをエスケープするのは本当に必要だろうか?
というわけで、ひさしぶりに 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 全てをエスケープする関数の用途は、使われる文脈が不明でもともかくその文字自身の意味として扱わせるというものになる。しかし、使われる文脈が不明という状況はどのくらいあるのだろうか。あまりないような気がするので、そういう関数は使いにくく (長く) しておいてもいいかもしれない。危険ではないのでそれほど使いにくい必要はないが。
さて、では、エスケープ関数はどういう API がいいだろうか。
まず、現在のエスケープ関数はたいてい文字列を受け取って文字列を返す関数であり、どうも使い分けが難しい。実際、space を表現する + を使えないところで使ってしまうケースを何回か見たことがある。
これをどうにかしたいと以前から思っているのだが、form を扱っているという文脈をもっと利用するといいのではないだろうか。
つまり、form が生成するのと同様な URL を生成するときに form 用のエスケープ関数が必要になるわけで、そのエスケープ関数が呼ばれるときには、多くの場合、呼出元では (name, value) 対の並びをもっていて、順にエスケープして & ないし ; でつなぐという処理をしているわけである。とすると、(name,value)対の並び自体を受け取って、全部エスケープしてつないで返すというのがいいのではなかろうか。
こうすることによる利点はいくつも考えられる。
・ いままでよりも多くの処理をライブラリにまかせられ、簡単になる。 ・ 受け取る引数の型が違うので、単純な文字列のエスケープと間違いようがない。
まぁ、間違いを防ぐという意味ではどこでも使える確実なのをひとつ使いやすいところにおいておく (reserved 全てを percent encoding するのを短い名前で用意する) という方法も考えられるのだが、そうすると percent encoding が余計に行われるので、URL が汚くなる。
URL はユーザインターフェースの一部であり、そこを不要に汚すのはよろしくない。
なぜ 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 とかの定義された集合の和でエスケープすべき文字を定義しているから、余計なのまで含めてしまう、というわけかな。
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 を扱うライブラリのデザインによってそういうのを支援することも可能かもしれない。
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 の定義をたどってコピーして修正しないといけない。
そういう記法を使っていることが問題の根本かも。
小林さんに教えてもらったのだが、以前の 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つ?
文字の種類をちょっとまとめてみる。
・ 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
うぅむ。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 を気にする観点が中途半端に入り込んだのではないかと思わせる。
関係する RFC はもうひとつある。
・ RFC:2732 Format for Literal IPv6 Addresses in URL's
これは、http://[3ffe:2a00:100:7031::1] などという記法を定義していて、RFC:2396 から、"[", "]" を unwise から reserved に移している。
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 に使われることは許されていない。まぁ、将来的になんかの用途に使われはじめることもあるかもしれないが。
ふと思ったのだが、本を適当に開くと、その本でもっともページをとっている部分、おそらくはもっとも充実したコンテンツの部分が、もっとも高い確率で開かれる。
とくに、辞書やリファレンスマニュアルマニュアルなどの場合、個々の項目のどれかを含むページが開かれることになる。まえがきなどが開かれる可能性はかなり低い。
では、Web で、読者があるサイトの「もっとも充実したコンテンツ」を見つけるにはどうしたらいいだろう?
あるいは、サイトの製作者が「もっとも充実したコンテンツ」に自然に誘導するにはどうしたらいいだろう?
ふと、最近の 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)
探してみると見つかった。
http://x42.com/rss/rfc.rss
こっちも見つかった。 http://interglacial.com/rss/internet-drafts/internet_drafts___groups.rss
RFC:3986 の Reference Resolution の項をざっと読む。
うぅむ。remove_dot_segments って、空の segment に関する記述がないけど、いいんかな。
Athlon X2 では、HLT命令で TSC が止まって、RDTSC で読み取れるのが Core 間でずれるらしい。
<URL:http://www.atmarkit.co.jp/flinux/rensai/watch2006/watch02b.html>
SMP とかででずれるという話は聞いたことがあったが、具体的に原因を読んだのははじめてだな。
渕先生を見た。
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]