羽村堰〜奥多摩 🚴‍♂️

4/13 (土) 羽村堰に立ち寄って、奥多摩までのぼってきた

f:id:hiboma:20190417234818p:plain

都内では桜の満開を過ぎてしまい、西部の山中の桜がこれから満開を迎えるという頃合いだった。奥多摩湖の桜を見るつもりで出かけたが帰りが遅くなりそうだったので途中で下山して終わり. 128km で finish

続きを読む

荒川〜吉見さくら堤公園〜川越 🚴‍♂️

4/5(金) 吉見の桜を見にいった

f:id:hiboma:20190408144733p:plain

去年、一昨年も似たようなコースを走っている

hiboma.hatenadiary.jp

hiboma.hatenadiary.jp

シーズン到来に備えて、車体のオーバーホールとパーツ交換 ( クランクの52-36 化、 9000系と8000系の mixed 構成 にした ) も済ませたし、暖かく走りやすい季節にもなったので日記も再開

続きを読む

Linux Kernel CVE-2019-9857 の PoC を書いて検証・観察した

表題の通り CVE-2019-9857 が出ており、その PoC を書いてどのような影響があるのを検証・観察した.

CVE-2019-9857 の概要

nvd.nist.gov

In the Linux kernel through 5.0.2, the function inotify_update_existing_watch() in fs/notify/inotify/inotify_user.c neglects to call fsnotify_put_mark() with IN_MASK_CREATE after fsnotify_find_mark(), which will cause a memory leak (aka refcount leak). Finally, this will cause a denial of service.

ローカルの攻撃者により inotify でDoS を引き起こせる 脆弱性です.

続きを読む

さよなら和敬塾南寮

技術の話はない、プライベートな日記です

寮をみてきた

私が大学生の時に住んでいた和敬塾南寮 <わけいじゅく みなみりょう> が今期を持って学生の入塾をやめるとのことで、友人と連れ添って見学にいってきた。

結局取り壊しするんだっけ? 大事な点を確認し忘れた

和敬塾とは

公益財団法人和敬塾は、東京都文京区目白台にある男子大学生・大学院生向けの学生寮。1955年、前川製作所の創業者である前川喜作によって創設された。

文京区 目白台に位置する学生寮で、ホテル椿山荘や東京カテドラル、日本女子大が立ち並ぶ目白通り沿に広大な敷地を確保して建っている.

続きを読む

Linux 版の Sysinternals ProcDump を試す (2)

前回の続きです

hiboma.hatenadiary.jp

実装の話

本エントリでは ProcDump が コアダンプをどのように採取するかを調べていく.

(現状の) Linux ProcDump は gcore を薄くラップして扱うバイナリと理解した

ダンプの採取方法を調べる 🔍

github.com

ソースコードの量は大したことないので git clone してざっと斜め読みするといい. スレッドを積極的に使う設計は Windows な流儀なのかな?

CoreDumpWriter.c が肝 📖

ファイルの量も少ないの順番に眺めていって、CoreDumpWriter.c がコアダンプ採取の責務を負っているソースだと判別をつけた.

詳細はすっ飛ばして、以下の行を見れば gcorepopen2() で呼び出しているのが確認できる

int WriteCoreDumpInternal(struct CoreDumpWriter *self)
{

// ...

    // assemble the command
    if(sprintf(command, "gcore -o %s_%s_%s %d 2>&1", name, desc, date, pid) < 0){
        Log(error, INTERNAL_ERROR);
        Trace("WriteCoreDumpInternal: failed sprintf gcore command");        
        exit(-1);
    }


    // generate core dump for given process
    commandPipe = popen2(command, "r", &gcorePid);
    self->Config->gcorePid = gcorePid;

popen2 はシェルを fork(2) して pipe(2) で結果を受け取る関数である. PythonRuby のインタフェースを真似た感じかな? (この関数の実装も同ファイルに載っているが、冗長なので省略する)

gcore とは何ですか?

gcore の中身はシェルスクリプトで、 gdb をラップしたコマンドである. gdb をインストールすると付属してくるコマンド

🔗 gcore のソースを載せた gist

gcore を呼び出すと、結局は gdb を呼びだすことになる. ProcDump 独自の実装でコアダンプを採取しているのかと思ったが、そんなことなかった 🙃 すでに gdb で出来ることを作り直すのは、大車輪の再実装になるもんね

プロセスをどのように見張っているのか?

前回のエントリでは CPU 使用率やメモリ(RSS) を閾値にしてコアダンプをとってみたが、どういった仕組みなのだろうか?

f:id:hiboma:20190217121748g:plain

ProcDump プロセスを strace すると /proc/$pid/stats を 1秒ごとに open(2), read(2) しているスレッドがトレースできる

# 💤  1秒ブロックすることを示す

[pid  3073] futex(0x60b5bc, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 25, {1550324077, 477259191}, ffffffff) = -1 ETIMEDOUT (Connection timed out) 💤
[pid  3073] futex(0x60b590, FUTEX_WAKE_PRIVATE, 1) = 0
[pid  3073] kill(3060, SIG_0)           = 0
[pid  3073] open("/proc/3060/stat", O_RDONLY) = 3 👈
[pid  3073] fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
[pid  3073] read(3, "3060 (a.out) S 2854 3060 2854 34"..., 1024) = 301
[pid  3073] close(3)                    = 0
[pid  3073] kill(3060, SIG_0)           = 0
[pid  3073] futex(0x60b5bc, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 27, {1550324078, 479654480}, ffffffff) = -1 ETIMEDOUT (Connection timed out) 💤
[pid  3073] futex(0x60b590, FUTEX_WAKE_PRIVATE, 1) = 0
[pid  3073] kill(3060, SIG_0)           = 0
[pid  3073] open("/proc/3060/stat", O_RDONLY) = 3 👈
[pid  3073] fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
[pid  3073] read(3, "3060 (a.out) S 2854 3060 2854 34"..., 1024) = 301
[pid  3073] close(3)                    = 0
[pid  3073] kill(3060, SIG_0)           = 0
[pid  3073] futex(0x60b5bc, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 29, {1550324079, 503662811}, ffffffff) = -1 ETIMEDOUT (Connection timed out) 💤
[pid  3073] futex(0x60b590, FUTEX_WAKE_PRIVATE, 1) = 0
[pid  3073] kill(3060, SIG_0)           = 0
[pid  3073] open("/proc/3060/stat", O_RDONLY) = 3 👈
[pid  3073] fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
[pid  3073] read(3, "3060 (a.out) S 2854 3060 2854 34"..., 1024) = 301
[pid  3073] close(3)                    = 0
[pid  3073] kill(3060, SIG_0)           = 0

ここらの実装は TriggerThreadProcs.c に書いてある

github.com

初見で「phtread を抽象化して扱ってるし、難しいのかな ...? 」と身構えてしまったが、詳細を読んでいくと思ったよりも素朴な実装 + 設計である.

感想

/proc/$pid/stat や cgroup の値を閾値 最新のメトリクスだと PSI なんかを見張ったりすると、より精緻なトリガーを作れたりするのかなと思った

udzura.hatenablog.jp

コアダンプ採取のコードは gcore だった

  • バックトレースだけ獲れりゃ十分なケースもあると思うので gstack に置き換えられるといいかなぁ
  • プロセスのメトリクスをとってコマンドをトリガーするコードと、コアダンプを採取するコードとを分離すると汎用的なツールに消化できそうだが ( それ、monit じゃね??? とか ... )

Linux 版の Sysinternals ProcDump を試す (1)

先のエントリで書いたように最近は Windows も触っていて 主に Sysinternals ツールを使って Windows 探検をしている

hiboma.hatenadiary.jp

その流れで ProcDump の使い方を調べていた.

f:id:hiboma:20190217165143p:plain

Sysinternals の ProcDump

technet.microsoft.com

Windows 版の詳細は上記のリンクを辿って自分でご覧になって欲しい。その中で、CPU 使用率やメモリ使用量(コミットチャージ) をコアダンプ生成のトリガーにできるのが目に留まった

-c 
    CPU しきい値を指定します。このしきい値に達すると、プロセスのダンプが作成されます。

-m 
    メモリ コミットのしきい値を MB 単位で指定します。このしきい値に達すると、プロセスのダンプが作成されます。

gdb もこんな風に扱えたら便利かな〜??? と思っていたところ、ふと Linux 版の存在があるのを思い出したのだった!

Linux 版 🐧

下記のリポジトリで ProcDump の Linux 版が公開されている

github.com

ディストリビューション向けのパッケージが配布されており、インストールの手順はREADME.md に書かれている

CLI インタフェースを調べる

手順通りに Ubuntu Xenial にインストールして、man を読み何ができるのかをざっと調べる

man(8)                                                                                     procdump manpage                                                                                     man(8)

NAME
       procdump - generate coredumps based off performance triggers.

SYNOPSIS
       procdump [OPTIONS...] TARGET
             -C   CPU threshold at which to create a coredump of the process from 0 to 100 * nCPU
             -c   CPU threshold below which to create a coredump of the process from 0 to 100 * nCPU
             -M   Memory commit threshold in MB at which to create a coredump
             -m   Trigger when memory commit drops below specified MB value
             -n   Number of dumps to write before exiting
             -s   Consecutive seconds before dump is written (default is 10)
         TARGET must be exactly one of these:
             -p   pid of the process

DESCRIPTION
       procdump  is  a  Linux reimagining of the class ProcDump tool from the Sysinternals suite of tools for Windows. Procdump provides a convenient way for Linux developers to create core dumps of
       their application based on performance triggers.

1.0.1                                                                                         12/18/2017                                                                                        man(8)

Linux 版でも CPU使用率 やメモリ使用量をトリガーにしてコアダンプできる。コアダンプを採取する回数を指定できたり、採取の間隔を指定できる

アーキテクチャに依存しないエッセンスとなるオプションだけを実装した感じで、Windows 版よりだいぶ簡素かな?

検証(1): メモリの使用量を閾値にしてコアダンプを採取流 🔍

以下のようなテストプロセスを起動して、ProcDump でコアダンプを採取する

  1. 100MB の仮想メモリmalloc(3) するa
  2. 1 の仮想メモリでマイナーページフォルトを起こす
  3. 1 の仮想メモリを free(3) する
  4. 3秒スリープする
  5. 1-4 を3回繰り返す

さて、上記のプロセスを ProcDump したのを GIF 動画でにした

f:id:hiboma:20190217121748g:plain

コアダンプが合計3回採取されているのがわかるだろうか?

ソース 📖

上記のデモで使ったソースは下記の通り

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void malloc_and_free() { 
    size_t size = 100 * 1024 * 1024;

    char *p = malloc(size);
    if (p == NULL) { 
        perror("failed to malloc");
        exit(1);
    }

    // memset でもええねん
    for (size_t i = 0; i < size; i++)  { 
        p[i] = '@';
    }
   
    sleep(3);
    free(p);
}

int main() { 
    sleep(5);
    malloc_and_free();
    malloc_and_free();
    malloc_and_free();
}

注意: ProcDump の動作を確認するためのコードなので、コアダンプを採取しても面白いことはなにもない

使ってみよう(2): CPU 使用率を閾値にする 🔍

CPU 使用率を監視してダンプを採取する GIF 動画が ProcDump のリポジトリにのっているので、引用として掲載する

f:id:hiboma:20190217121836g:plain

Source: GitHub - Microsoft/ProcDump-for-Linux: A Linux version of the ProcDump Sysinternals tool

採取したコアダンプを調査することで CPU 使用率が高い時のバックトレースを調べていくことができるだろう

ユースケース

網を張って気長に待つようなデバッグに向いてるだろう

長時間実行した際に特定の負荷のパターンでうごくプロセスがいるとして、そのようなケースで作業を半自動化できて便利だろう. ( 例: たまーに CPU時間が10数秒スパイクするプロセスがいて調査したいが、再現するタイミングがよくわからない )

Windows Sysinternals徹底解説 改訂新版』でもそのようなトラブルシューティングの例を出している

まとめ

  • ProcDump を使うと CPU使用率やメモリ使用量をトリガーにしてコアダンプをとれる
  • プロセスのリソースを見張ってトリガーにする単体のコマンドがあれば、コアダンプの採取以外にも使えて便利な気がする
  • コアダンプのサイズは大きくなりがちなので、バックトレースだけ取れたら十分かなという気もする

次回のエントリでは Procump の実装を見ていく

インサイド Windows 第七版、Windows Sysinternals 徹底解説 📚 、その他エッセイ

会社 で Windows Surface Go を支給してもらったので Windows 筋トレをしている

私の Windows レベル

腰を据えて Windows を触るのは WIndows XP を扱って以来で 10数年ぶり (2011年位に会社から 1-2ヶ月間だけ貸与してもらったことはあるけど).

f:id:hiboma:20190214235203p:plain

Surface Go を手に入れるまではコントロールパネルを開く方法も分からないくらいに退化していた

鈍器で筋トレだ 📘

ということで『インサイド Windows 第七版』と『Windows Sysinternals 徹底解説』を買った

インサイドWindows 第7版 上 システムアーキテクチャ、プロセス、スレッド、メモリ管理、他 (マイクロソフト公式解説書)

インサイドWindows 第7版 上 システムアーキテクチャ、プロセス、スレッド、メモリ管理、他 (マイクロソフト公式解説書)

Windows Sysinternals徹底解説 改訂新版 (マイクロソフト公式解説書)

Windows Sysinternals徹底解説 改訂新版 (マイクロソフト公式解説書)

低レイヤーの話が高密度で書き記されているが、Linux カーネルの問題に取り組んできた際に身につけた知識や経験も手伝って「Windows っておもろい OS 」なんだなと、たくさんの発見をしながら読みすすめられている.

Linux と同じように捉えていいモデルや概念や設計があれば、全く異種や未知のものもあり、Windows のことをほんと表層的にしか理解できてなかったのだと痛感している.

共通点を知る 🔍

VMMap でプロセスのメモリレイアウトを見るとこんなんになる

f:id:hiboma:20190215011716p:plain

VMMap を使うと Linux の pmap と 似た出力 を得られる.

似た と書いたが、プロセスのメモリレイアウトは CPU (x86アーキテクチャ) を反映している / 密結合するポイントのせいか、WindowsLinux とで大きくは変わらないようだ. フィールド名の差異はあれど pmap の出力を理解してれば VMMap も難なく理解できる (その逆も然りだろう).

違いを知る 🔎

Process Explorer でプロセス一覧をみる

f:id:hiboma:20190215012754p:plain

プロセスモデルは抽象化のアプローチが Linux とは全然違うもんなんだな〜 と素朴な感想を持っている. ハードから離れたレイヤでの抽象化は OS の個性が輝くところなのだろう

📕📘

このように Windows の本を読みながら Linux と比較しながら進めている.

known-unknown と技術書の話

ここからは全く別の話題

技術の勉強に励む際に 入門書を手にしてボトムアップで固めて攻めていくのは一つの勉強手段だ. 別の手段として、いろいろレベル感をすっ飛ばした書籍にチャレンジしてトップダウンで進める方法あるだろう. unknown-unknown の森に飛び込み known-unknown の中で迷子になりながら鍛えていく方法.

pyama.fun

その中でknown unknownという概念が紹介されている。それは、システムチューニングの局面においてknown-known,known-unknown,unknown-unknownという分類で説明されている。

さらに引用

known-knownは知っていることを知っていること、例えばtopコマンドでプロセスごとのCPUの使用率を見れることを知っているし、見たことがある。 known-unknownは知らないことを知っていること。topコマンドを知っているけど、使ったことはない(観測してない) unknown-unknownは知らないことを知らないこと。これはtopコマンドを知らないこと。

もう一個引用

これを少しでもknown-unknownにするためにはひたすら本を読むとか、識者に教えてもらうとか、インターネットで調べるとかそういう手段になると思うのだけど (...)

私の話: Linux カーネル本の話

自分の過去を振り返るならば、『詳細 Linux カーネル』を手にしたのは 10年も前のことだが、書籍を買った当初はどこを読んでもまったくもって何も理解ができずに圧倒されてしまった.

詳解 Linuxカーネル 第3版

詳解 Linuxカーネル 第3版

known-unknown の山 (鈍器) がそこに (物理的に) 存在することは確実に理解はした. ( なんで買ったんだこの本??? )

樹海で迷子になる

そもそも C言語を全く書けないのにカーネル本を手にしたのがすっ飛ばし過ぎてるようにも思い、ゆっくりと時間をかけて、C言語の入門書を読んだり、『詳解 UNIX プログラミング』にチャレンジしたり、途中で全く興味を失ったり、何かの機会に興味が再発したり、また飽きたり ... と紆余曲折を経ながらも少しずつ known-unknownknown-known に変えることができた.

現在では 会社のお仕事の場面でも知識 + 経験 + スキルとして生かせるレベルまで書籍の内容を吸収したと思う ( 未だコードは全然かけないけど 🙃 )

過去のお話の注意点

このように過去の話をふりかえるとバイアスが強烈にかかり、美化して話がちだ.

失敗している例もあって、技術的に理解が及ばないまま背伸びして買った書籍で内容を全然モノにしないまま挫折したのもたくさんある. 私はグラフィカルなレイヤを扱うのはどうも苦手で、そういったレイヤの技術書はどれもこれも途中で放り投げてしまった ( 懐かしの ActionScript3 や Processing や iOSアプリや ... )

何の技術がどうやって自分の強み・興味・自信のコアとして定着するかは、短い時間の中では推し量れないもんだね