2019/10/16


Linux の sudo に root 権限を奪取できるバグが見つかった。

Linuxの「sudo」コマンドにroot権限奪取の脆弱性。ユーザーID処理のバグで制限無効化 - Engadget 日本版

この脆弱性は、sudoコマンドのユーザーIDに-1もしくは4294967295を指定すると、誤って0(ゼロ)と認識して処理してしまうというもの。0(ゼロ)はrootのユーザーIDであるため、攻撃者は完全なrootとしてコマンドを実行できることになります。

https://japanese.engadget.com/2019/10/14/linux-sudo-root-id/

既に Ubuntu 等にはパッチが配布され始めているらしいですが、この記事ではこのバグが如何にして起こったのかを調査し今後の為に共有したい。

sudo のコードは以下からダウンロードできる。取得には mercurial が必要。

Sudo Source Repo
https://www.sudo.ws/hg.html

修正差分は以下。

sudo: 83db8dba09e7
https://www.sudo.ws/repos/sudo/rev/83db8dba09e7

差分だと分かりづらいので、この現象が起きうるソースを調べていく。sudo は実行されると plugins/sudoers/sudoers.cinit_vars が呼ばれ、続いて set_runaspwrunas_user ありで呼ばれる。set_runaspw では与えられたユーザID文字列(#-1 の # 以降)を解析する為に sudo_strtoid_v1 が呼ばれる。この sudo_strtoid_v1 が今回バグを生んだ関数。

id_t
sudo_strtoid_v1(const char *p, const char *sep, char **endp, const char **errstr)
{
    char *ep;
    id_t ret = 0;
    long long llval;
    bool valid = false;
    debug_decl(sudo_strtoid, SUDO_DEBUG_UTIL)

    /* skip leading space so we can pick up the sign, if any */
    while (isspace((unsigned char)*p))
        p++;
    if (sep == NULL)
        sep = "";
    errno = 0;
    llval = strtoll(p, &ep, 10);
    if (ep != p) {
        /* check for valid separator (including '\0') */
        do {
            if (*ep == *sep)
                valid = true;
        } while (*sep++ != '\0');
    }
    if (!valid) {
        if (errstr != NULL)
            *errstr = N_("invalid value");
        errno = EINVAL;
        goto done;
    }
    if (errno == ERANGE) {
        if (errstr != NULL) {
            if (llval == LLONG_MAX)
                *errstr = N_("value too large");
            else
                *errstr = N_("value too small");
        }
        goto done;
    }
    ret = (id_t)llval;
    if (errstr != NULL)
        *errstr = NULL;
    if (endp != NULL)
        *endp = ep;
done:
    debug_return_id_t(ret);
}

勘のいい方であれば、これを見ただけで「アーーーッ!」と思うかもしれない。

    llval = strtoll(p, &ep, 10);
    if (ep != p) {
        /* check for valid separator (including '\0') */
        do {
            if (*ep == *sep)
                valid = true;
        } while (*sep++ != '\0');
    }

strtoll は文字列のポインタを基数と共に渡すと、long long 型整数値に変換し戻り値で返却します。数値として解釈された後は数値として解釈できなかった文字まで第二引数で指定されたポインタがシフトします。つまりこのコードでもし -1 が指定されると、正常な数値として扱われます。errno も設定されません。llval の範囲チェックもされていません。epp は異るアドレスとなり、今回呼び出されるケースでは sep が NULL なので -1 という単語のみをチェックする為に呼ばれたこの関数は、valid = true と認識してしまいます。後は時の流れに身を任せ、あなたの色に染められるだけになります。怖いですね。修正内容では strtoll 呼び出し直後に errno の確認が行われ、値の範囲も確認されています。正直なぜこれ strtoul を使わないんだろうなと思ったりもしますがソースの場所からするとユーティリティ関数なのでしょう。wandbox でお試しできる様にしてあるので遊びたい人は遊んで下さい。数字の横が (null) ならパスしたという事になります。

なお -1 が通ってしまうと何がまずいかについてはココを参照下さい。

教訓

境界値チェックを行わないと、死ぬ

Posted at by



2019/10/10


8月に Google Developers Expert となり、新米の様にオロオロとしています。過去の GDE ミーティングの議事録を見せて頂いているのですが Google Document に保存されており、Go だけでなく他のカテゴリの GDE に関する物も含めると全てに目を通すのはなかなか骨が折れます。技術者なので問題は技術で解決すべく、これらの資料を grep 検索できる様にしました。

Google Document はエクスポートすると Microsoft Word の形式となるので、Microsoft Word から Markdown に変換するプログラムを書けばテキスト検索もできるし、なんならそのまま GitHub に貼り付けてしまう事もできます。

GitHub - mattn/docx2md

docx2md Convert Microsoft Word Document to Markdown Usage -1 docx2md NewDocument.docx Installation -1 ...

https://github.com/mattn/docx2md

出力は UTF-8 のテキストファイルなので、grep コマンドを使って検索できます。Windows から日本語を使って検索するのであれば jvgrep を使って頂く事もできます。

docx2md

ぜひ御活用ください。また、まだ未対応の書式が幾つかあるのでプルリクエストをお待ちしています。

そうそう、GitHub Sponsors を開設したのでよろしくお願いします!

Sponsor @mattn on GitHub Sponsors
https://github.com/users/mattn/sponsorship
改訂2版 みんなのGo言語 改訂2版 みんなのGo言語
松木 雅幸, mattn, 藤原 俊一郎, 中島 大一, 上田 拓也, 牧 大輔, 鈴木 健太
技術評論社 Kindle版 / ¥2,350 (2019年08月01日)
 
発送可能時間:

Posted at by



2019/08/31


以前から自宅で動かしている物体認識ウェブサーバを汎用的な作りにして GitHub に公開しました。

GitHub - mattn/mongoose-tflite: Object Detect API server using TensorFlow Lite

mongoose-tflite Object Detect API server using TensorFlow Lite. Usage -1 ./mongoose-tflite Requiremen...

https://github.com/mattn/mongoose-tflite

TensorFlow は Raspberry Pi で動かす事も出来るけど、CPU 使用率やメモリ使用量がとてつもなく多く、特に Raspberry Pi 3 でもヒーヒー言ってしまいます。実際 TensorFlow と mackerel-agent を使ったお部屋監視システムがそうでした。

Mackerel と Raspberry Pi で作るお部屋監視システム - Qiita
https://qiita.com/mattn/items/e045875ad32b46b018f3

そこでもっと軽い物を作ろうと、以前 TensorFlow から TensorFlow Lite に移植しました。なかなか軽くて良い出来だったので、もしかしてこれはウェブ API にしてしまえば色々な人が使えるんじゃないかと思い、go-tflite を使ってウェブサーバにしてみました。これは結構ご機嫌よく動いていました。

その後、突然 C++ を書きたい病を患ってしまい、Go から C++ に書き直されました。

Big Sky :: C++ な WebServer 実装 crow と TensorFlow Lite を使って Object Detection の API サーバを書いた。

自宅で動かしている物体認識サーバは TensorFlow を使って Go で書かれていたのだけど、CPU 負荷が高いので以前 go-tflite で書き換えた。その後 Raspberry Pi Zer...

https://mattn.kaoriya.net/software/lang/c/20190630225105.htm

一応C言語版も書いておくかという事で今回は mongoose というC言語のウェブサーバ上に TensorFlow Lite の物体認識処理を乗せる事にしました。

TensorFlow のルートディレクトリを探す為だけに go コマンドが使われていますが、Go は使ってません。気にしないで下さい。make コマンドでビルド出来ます。実行して curl 等で画像をアップロードすると以下のレスポンスが返ります。

[
  {
    "label": "Egyptian cat",
    "probability": 0.8392156958580017
  }
]

※ jq でフォーマットしています。確率 0.2 より下はカットしています。

Posted at by