2012年6月17日

MECEと「7±2」と「その他禁止!」の話

世の中、分析を行う上で使う価値のある「考え方のツール」というのはいくつもあります。MECEもそのひとつ。網羅性を尽くしたい時によく使われますね。あまりにも広まっているので、珍しくもなんともないのですが…

珍しくない割には、ちゃんと使いこなしている人が余りいません。
いや、言い過ぎですね。今の会社で、私の周りには、あまりいません。

で、何故なのかなぁ、と調べていくと…うむ。これは酷い。お前ら何考えてるんだ、という事が浮かび上がりました。それが「7±2」と「その他禁止!」のルールを知らない、と言う事。

いや、「7±2」は聞いたことがある、と言う人も多いんですよ? 多いんですが…覚えているだけという感じ。意味無いじゃん。

というわけで、今回は私が知っている「MECEを使う上での注意事項」を2つ紹介しようと思います。



まずは MECE についてのおさらいから。

MECEは「Mutually Exclusive and Collectively Exhaustive」の略です。見ての通り実際には2つの条件「Mutually Exclusive」と「Collectively Exhaustive」を両方満たせ、と言っています。


Mutually Exclusive というのは「相互に排他的な項目」…もっと簡単に「ダブリ無し」とか「無駄なし」と言い換えられています。
「Aが成り立つ場合と、Bが成り立つ場合と、Cが成り立つ場合と…」
と列挙していった時に、それぞれが互いに重なり合っていると場合分けが大変になるので、なるべく
「Aが成り立つなら、BやCは成り立たない」
ように条件を決めてやろう、というわけです。


Collectively Exhaustive は「完全な全体集合」ということです。「漏れなし」と言い換えられています。
後から「考慮対象外」が出てきて困ったことになってしまうことがないように、最初から「これで全部」であることを考慮する。特に分類項目なんかを考える時に重要なルールです。


MECEはどういうときに使うかというと…まぁ、「条件分け」と「各条件に当てはまる事象として何が言えるか/既知の情報として何があるか」を分類して、考慮漏れ・配慮漏れを見つけたり、まだ誰も攻略していないブルーオーシャンを見つけたりするのに使います。


例えば客に何かレポートを送らなくちゃいけない場合、「言わなくちゃいけないことは何か?」を考える時に、最初に MECE で条件分けをして、それぞれの箱のなかに何が入るかを並べていき、穴がないことを確認する、なんていう風に使う事が多いです、最近は。


「それで全部考え尽くしたよね?」
と議論とか考察の最後に確認しなくちゃいけない場合は、最初から MECE を考慮しておくと非常に便利です。

MECE …ちゃんと使いこなすと便利だというのは、誰でも直感的に判ると思うんですが…実はこいつには制約事項があります。

その一つ目が「7±2」。

もっと簡単に言いましょう。
書け!!

えぇ、この単純な条件をロクに実施しない奴がほとんどなんですよ。


MECEは「ME」の条件が「分類数を減らす」事に寄与し、「CE」の条件が「網羅性」に寄与します。別の言い方をすると、MECEを使った場合の真の価値は「CE」の方にある。CE の条件を満たす時に ME の条件を満たしていないと無限地獄に陥るから、MEの条件が付与されているのに過ぎません。


一方で。7±2」の条件は「人間が一度に把握できる概念数の上限」を示しています。チャンク、と呼ばれていますが、ようするに「一塊にできる」概念を持ってきた時に、人間は 5~9個しか「塊」を覚えていられないのです。

更に言うなら。

MEの条件だけなら、9個に近い所まで人間は覚えられます。これは、「互いに排他である」事を理解するには、一度に2つの「塊」だけを比較すれば良いため、記憶にあまり大きな負荷がかからないから。

しかし、CEの条件の場合、人間が覚えられる塊は5個に近い処にまで落ちていきます。「全体網羅性」は「全部の塊を一気に把握しないと判らない」ため、CEの確認は記憶に非常に大きな負荷がかかる作業になります。

このため、全てを記憶だけに頼っていると(すでに何度も使っていて慣れている分類パターンならばともかく、新規の分類パターンの場合)、MEの条件は満たしているがCEの条件を満たしていない分類法を使ってしまったり、全条件パターンについて網羅的に調べきれずに失念してしまう物が出てきたりと、ミスが続発します。

えぇ、
MECEは書いてなんぼ
なんでございますよ、奥様。

MECEは記憶力だけで
使うもんじゃない
んでございますよ、お嬢様。


なのに、ノートに書かない、そこらへんの紙にすらろくに書かない、ホワイトボードも何も使わない奴らがゴロゴロゴロゴロ…挙句に、穴だらけの考察を持ってきて
「これでどうですかねぇ」
とか、寝言は寝て言えと。


そもそもお前ら、俺がノートを6冊以上消費しているのに、まだ半分使ってないとか、なにやっとんのかと(ただし、私はノートの紙の片面しか基本的に使わないようにしているので、私が6冊使う間に3冊しか使ってなくてもそれはOK。2冊しか使ってない、とか言うのはありえなくはない状態)。
そんなに「何も書いてない」状態自体、MECEを使いこなせていない証拠だろうが。


えぇ、実際。私はほとんどの考察をノートに書いていまして。というか書かないとダメで。覚えていられませんで。というか私の記憶力は 5±2ぐらいしかないんじゃないかという嫌な予感が、特に英語を叩きこまれた辺りからずーっとしているんですが(多分、無茶な環境変化を食らったせいで記憶制御ユニットが一部壊れたんじゃないかと…)。



閑話休題。


とにかく。MECEを使いこなしたければ「書け」。これがポイント。そして殆どの人が「実行に移していない」ポイントの1つ目でもあり、その度に穴だらけの考察が出来上がる理由でもあります。


具体的に「どう」書くか、は人それぞれです。
私は表を作って埋めていくタイプが好きです。人によってはマインドマップで書くのが好きだという人もいます(これでMEの条件を満たしていると判る理由が私にはわからない)。何がどこにあるんだかよく判らない具合に列挙するだけ、と言う人も居ます(これでもちゃんとMECEの条件を満たす辺りがすごい)。
まぁ、やり方はいろいろです。そこをとやかくいうつもりは全くありません。重要なのは「覚えきれないに決まってるんだから、記憶力に頼るな」と言う事。



さて、MECE を使いこなす上での2つ目の制約条件。それが「その他禁止!」です。


例えば…人間を次のように分類する場合を考えてみましょう。

  1. 女性
  2. オカマ
  3. その他

女性とオカマは排他です。オカマの性別は(一応)男性ですから。オカマは男性全体ではありませんが、男性の部分集合です。また、「その他」は「女性でもオカマでもない」ものを表すので、この3つは Mutually Exclusive なのは間違いありません。


「その他」は「それまで列挙してきた条件を満たさないもの全て」という意味なので、Collectively Exhaustive でもあります。女性でもオカマでもない人間は全て「その他」に分類できます。どこにも属さない人間は発生しません。


つまり「女性」「オカマ」「その他」と言う分類は、確かに MECE を満たしているのです。しかし…この分類、役に立つでしょうか??


実は殆どの場合、役に立ちません。それは分類の精度がバラバラだから…ではなく、「CE」の条件を満たしているのが『その他』という単語に起因しているからです。実はこの分類、「その他」に何が当てはまるのか、理解できている保証がありません。そのような保証がなくてもMECEの条件を満たしてしまう、それが『その他』という単語の恐ろしいところなのです。


実際、この条件から「その他」にはどのような人が割り当てられるか、想像できるでしょうか? ノーマルな男性? あぁ、それは確かに「一部」そうでしょうね。その他には? 「フタナリ」…んー、女性とオカマの定義によっては若干ブレますが、それもアリでしょう。他には?…


そう。これ、いつまででも「他には?」って聞いていられるんです。そういう曖昧模糊としたラベリングでは、「そこに対応するものを思いつけ」と言われてもいつまでも終わらない。逆に「これはどこに分類されるんだ?」となった時に「その他」がどれぐらいの大きさになるのかも予測がつかない。もし、大半が「その他」に入ってしまったら、多分その分類は意味を成さないでしょう。




ところが、この「その他」もこれがまた、失敗した考察にはよく出てくる。そして「その他」が実は重要な要素を持っているはずなのに、完全に失念されていたりする。


なので「その他禁止!」となるわけです。意味もわかってないものを使うな、と。でないと、何のために MECE を使って考えているのか、わからなくなりますからね。

というわけで、MECEを使う上での条件「7±2」と「その他禁止!」というお話でした。

どっと払い(なんでや)

2012年4月9日

I just couldn't stand it....

いやー、アメリカに出張になった時からず――っと我慢してたんだけど。Easterで大半のお店が閉まってる中、ToysRusで見つけちゃったら…我慢できなかった。
Kindle Fire I got .. photo

まぁ、なんか後ろから全力で背中を突き飛ばしてくれた人もいたみたいだけれど…$200だったので買ってしまいましたよ、あぁ…

とりあえず、日本語の Web Page も読めたし、なかなか面白い。
同時に、「お急ぎ配送サービス」とかが1ヶ月無料…とかのサービスも付いてきていて、あぁ、こりゃアメリカ合衆国だけにするわけだわさ、と納得。つーか、本の虫な人とか、Amazonのヘビーユーザーなら、これは安い買い物だろう。

2012年2月10日

Sudo format string vulnerability

前置き

Sudo format string vulnerability ( CVE-2012-0809 )  というバグが、sudo コマンドには存在する。CVEが出ていることからも判るように、結構深刻なバグで、セキュリティ・ホールとしての性質を伴う。sudoのページによれば
運が良くても sudo はクラッシュし、
運が悪いと攻撃者に root 権限を掌握される問題が含まれているかもしれない
との事だ。

で、このバグ、何がどうなっているのかについては、『てきとうなメモ: [Linux][Security] sudo-1.8のバグ』が詳しい。とても詳しいので、そちらだけ見ておけばいいやと思っていたのだが、何箇所かから、
お前も書け
という圧力を食らったので、書くことにする。ただし、新しい情報がなにかあるって言うわけじゃない。

影響範囲

このバグは sudo の 1.8.0 で導入され 1.8.3-p2 で修正されました。なので、影響は 1.8.0 - 1.8.3-p1 と言うことになります。

で、商用 Linux distribution の中で、影響があるのはなさそうです。
Free distribution の中も含めると、Fedora16, OpenSuSE 12.1, Rawhide の3つが影響を受けているようです。
(http://rpm.pbone.net/index.php3 でどのdistributionがどのrpmを使っているのか、分かります)

ただし、それ以外のOSでも sudo は使っているはずです。それらが安全かどうかは判りません。一応、sudo のページには対応している各種OS用の置き換えバイナリは用意されているようです。

という訳で、ほぼ影響はない、と言うことなので、以下は笑い話として。他人の失敗は蜜の味 (^w^)。

攻撃方法

攻撃方法は次のとおりです。
  1.  ln -s /sbin/sudo /tmp/%s
    のようにして、sudu コマンドを「%s」というファイル名にすり替える
  2. /tmp/%s を実行する

%s は printf() 系処理が format 文として利用しているものであれば、大抵のもので問題が生じるようです。どれでどのような症状が出るのかは、CPUなどにある程度依存します。


こうすると、argv[0] 文字列の中に %s という文字列が含まれるようになります。


技術的概略

このバグは、すごく簡単に言うと printf() 系関数を2段階かけた事に起因したバグです。printf() 系関数を多段に使うことは、セキュリティを考慮したコーディングとしては非常にまずいもので、
絶対やるな
と言っても構わないぐらい、危険な行為です。

修正後も2度使っていますが、まぁ、これならしょうがないかな、という所にまで治っています。

実はもう一つ、例外処理が足りていない、と言う問題もあります。sudoだから発生する確率はあまり高くありませんが…仮想メモリシステムを使い切った状態だと危険ですね。

詳細

sudo-1.8.3-p1 の ./src/sudo.c の最後に次のような関数があります。デバッグログを出力するためのコードですが、ここに悪さの元が含まれています:

void
sudo_debug(int level, const char *fmt, ...)
{
    va_list ap;
    char *fmt2;

    if (level > debug_level)
 return;

    /* Backet fmt with program name and a newline to make it a single write */
    easprintf(&fmt2, "%s: %s\n", getprogname(), fmt);
    va_start(ap, fmt);
    vfprintf(stderr, fmt2, ap);
    va_end(ap);
    efree(fmt2);
}

通常、argv[0] は "sudo" という文字列へのポインタです。で、getprogname() は argv[0]を返すようになっています。
そこで、
     fmt = "%s"
   fmtの次の引数 = "hello"
のような場合について考えてみましょう。


    easprintf(&fmt2, "%s: %s\n", getprogname(), fmt);


この行を通った段階で fmt2 は


    fmt2 = "sudo: %s\n";



になります。で、その後:


    vfprintf(stderr, fmt2, ap);


という行を通ると、stderr には


    "sudo: hello\n";


という文字列が送りつけられることになります。
何も問題はありませんよね??

では、攻撃方法にあるように sudo コマンドに対してリンクを貼って './%s' という名前で起動したらどうなるでしょう?

argv[0] = "./%s"

になります。



    easprintf(&fmt2, "%s: %s\n", getprogname(), fmt);


この行を通った段階で fmt2 は


    fmt2 = "./%s: %s\n";



になります。で、その後:


    vfprintf(stderr, fmt2, ap);


という行を通ると、stderr にはまず、第1引数である "hello" が出るので:


    "./hello: 



…おや、困りました。後半の %s のための文字列へのポインタが引数として渡されていません。しかも vfprintf() はそんな事を知りません。しょうがないので、stack 上にある値をポインタと解釈してしまいます。

運がよいと、「Segmentation Violation」が発生します。で sudo はクラッシュします。あぁ、core を吐かないように設定しているといいんですが…。運が悪いと、coreファイルを持っていかれますが、そこには /etc/shadow の値が書いてあるかもしれません。
まぁ、意図的にやっている奴らは
確実に core 取得できるように
設定してから実行するよね。
はっはっはっ

まぁ、運良く大した情報が保存されていない core ファイルが出来上がることを祈るしかありませんな。


ちなみに。"%s" は上記のとおりですが、"%n" という楽しい引数がございましてな…これ、引数で渡したアドレスにそこまで書いた文字数を「書きこむ」んですわ… はっはっは …

判ったと思いますが、万が一これらのバージョンを使っていたら
血の涙を流してでも upgrade しろ!!

対策

1.8.3-p2 はこう変更されました。
void
sudo_debug(int level, const char *fmt, ...)
{
    va_list ap;
    char *buf;

    if (level > debug_level)
 return;

    /* Bracket fmt with program name and a newline to make it a single write */
    va_start(ap, fmt);
    evasprintf(&buf, fmt, ap);
    va_end(ap);
    fprintf(stderr, "%s: %s\n", getprogname(), buf);
    efree(buf);
}

えぇ、見ての通り printf は相変わらず2度使われています。

ただ、1度目は与えられたフォーマットと引数から、とりあえず buf という文字列を作るために、2度目はargv[0] と buf を fprintf() で出力するために使われます。

fmt は sudo のプログラム内で指定するフォーマット文ですし、fprintf() で使われるフォーマット文もプログラム内で指定するフォーマット文ですので、取り敢えず引数に %s などの危険な記号が含まれていても安全、とは言えるでしょう。


ただね。このコード、 buf == NULL だった場合を考慮していないんですわ。一応、glibc の場合 NULL を渡されると "(null)" という文字列を出しますけどね、これは必須ではない。たとえばSolarisは core dump するそうです。

環境によっては fprintf() の例外処理の定義が甘い所につけ込んだコードになる危険性は残されています。