セキュリティキャンプ2024 WebAssemblyゼミの備忘録
WebAssemblyゼミの講師を@saza_kuとさせてもらいました
新設のゼミでして、Wasm楽しいよという独り言と、受講生の方々が優秀すぎましたという備忘録です

WebAssemblyゼミとは?
WebAssembly(Wasm)は仮想命令セットです。RustやGoをはじめ様々な言語で記述されたアプリケーションをWasmターゲットにコンパイルできます。
Wasmは仮想命令セットですので、x86などのCPUで実行できるようWasmの命令を解釈するソフトウェアが必要になります。これをWasmランタイムと呼んでいまして、本ゼミはWasmランタイムを実装するゼミです。
Wasmの仕様を読み解きながら、基本的なWasmランタイムを実装し、ちょっとしたアプリケーションを動かす、というのがゼミの当初のゴールでした(このゴールはすぐに良い意味で破られます)

応募課題
応募課題ではWasmバイナリのparseやWasmランタイムの最初の一歩を作ってもらいました。応募段階でフィボナッチが動いていたりメモリ操作ができていたりとかなりの完成度の方がちらほらいて、選考には苦戦した記憶があります。応募していただいた方に為になるような課題になっていたら良いのですがこれは難しいですね...
事前準備
6月-当日にかけては事前準備期間です。負担にならない程度に、当日は実質3日間しかないので開発を進めておこうというという時間です。
本ゼミではWasmの基本的な仕様に沿ったランタイムの実装を進めてもらいました。週1でsyncをして様子を聞いたり、講師の方からWASIやWasm I/Oの話をしたりとゆるゆると進めました。
ゆるゆる進めていたつもりでしたが、気づいたらDoomが動いていました。
自作WebAssemblyランタイムでDoomが動いた!
— ふぁ (@faa0311) 2024年8月8日
Python + Numpy なのでフレームレートはカス pic.twitter.com/OUyqEF7kbo
Doomを動かすには、Wasmの基本的な命令に加え、WASI(WebAssembly System Interface)と呼ばれる、Wasmがシステムのリソース(ファイル、ネットワークなど)にアクセスするときに発行するAPIの処理を実装する必要があります。
実装スピードが早すぎることを認識します
当日
キャンプ期間は、主に各々のWasmランタイムに好きな拡張を入れていく時間となりました。スライドの掲載許可ももらったので簡単に紹介します。
1人目:Wasmライブマイグレーション + InfiniBandを使って送る

実行途中のWasmバイナリを、別マシンにその実行途中のステータスを送ることで処理を移譲する仕組みを実装してくれました。InfiniBandを使いたいとのことで、彼のWasmランタイムのステータスはなんと400Gの帯域を通って転送されています。Wasmバイナリを転送することで処理を委譲する、というこの仕組みを使ったユースケースもたくさん考えていました
2人目:Wasm GC対応 + セルフホスト


github.comWasm GCを自作Wasmランタイムに実装してくれました。Wasm GCは仕様が大きく、自分も追えてなかった仕様なのですが、仕様読み解き力の高さを発揮し、3日間でちゃんと動くサブセットを実装していました。
セルフホストしたWasmランタイム上で、Wasmアプリケーションが動いている様子

3人目:WASIモリモリ実装
WASIを脅威のスピード感でモリモリ実装してくれました。
HTTP serverが動いている様子

Wasm化されたファイル配信HTTP serverを自作Wasmランタイムで動かし、Wasm化されたDoomを配信し、V8がDoomを実行している様子(ややこしい)

さいごに
Wasmはいろんなことができて楽しいなあとは以前から思っていましたが、今回は新しい楽しみ方を受講生の方から教えてもらった気がします。
Wasmは応用先が広い形態であると同時に、仕組みを理解するにあたって仕様があること、コアの仕様がそこまで大きくないこと、テストがあること、あたりの環境が良くて、今回のような2, 3ヶ月で入門して好きに応用するのに良いのかもしれないな...
他のゼミはじめキャンプ全体のことも書きたいことあるけれど、一旦このあたりで。
パワフルな受講生に元気をもらった一週間でした
日吉で好きな飲食店10選
この記事は慶應理工 Advent Calendar 2022 - Adventarの9日目の記事です。
昨日の記事はこちら↓
こんにちは!J科4年の者です。
何書こうかなと当日まで迷っていたのですが、日吉で好きな飲食店10選を紹介したいと思います。お付き合いください。
第1位 アジアンビストロ Dai 日吉店
立地: 駅から3分程度
昼の提供時間: 10分くらい
ひとこと: 堂々の第一位。どの料理を食べても美味しいです。酸味だったり辛さだったりの味付けが他の料理にはない美味しさで、「お店を出してくれてありがとうございます」と毎回感謝しながら食べています。アジアな味が好きな人は是非行ってほしいです。好きすぎて日吉店以外にも通ってます。
第2位 中華そば どんぐり
立地: 矢上キャンパスの坂を降りて1分程度
昼の提供時間: 10-15分くらい
ひとこと: 煮干し出汁の中華そば。ラーメンほどこってりせず、でもチャーシュー始めまろやかさもあり、とても美味しい。冬でも食後にアイスキャンディーをくれます。
第3位 ぎょしん
立地: 駅から2分程度
昼の提供時間: 1分くらい
ひとこと: 早い。安い。おいしい。丼ぶりを頼んで30秒くらいで出来上がるスピード感。困ったときのぎょしん。季節の握りもたまに無性に食べたくなる。17:00までランチタイムなのも有り難い。
第4位 学食
ひとこと: 学食入れるのはセンスないか?って思ったけれど、健康・早さ・席の多さ・安さ...やっぱり学食は素晴らしい!
以下は順序なしです。
やながわ精肉店
ローストビーフ丼がおいしいです。ローストビーフの盛られ方が綺麗で見た目も映えていますし、ちょっと洋風な味付けが美味しいです。おしゃれ。ハンバーグのお店らしいので多分ハンバーグも美味しいです。
ピッチェリアレジスタ
夜のコースが1500円とコスパの良さが推しです。ザイタリアンな美味しさ。もちもち系ピザが好きです。気軽に行けて美味しくて最高。
ぷくぷく亭
食べログ百名店。生姜焼きとかハンバーグとかの王道な洋食。内観も料理も古き良きな雰囲気が醸し出る。珍しく学生ではないお客さんの割合が多いイメージです。
ドマーレ
スパゲッティの種類が多いですし、どれも美味しいですし、入りやすいのに落ち着いてる雰囲気も良い。大盛りも特盛も無料。ナスとトマトとモッツァレラチーズみたいなメニューが推しです。困ったときのドマーレ。
濱星
煮干し系のラーメンって美味しいですよね。昔は唐揚げ食べ放題とかもやっていたと聞いたことがある。
グラッチェ
矢上を出て元住吉の方向に5分ほど歩くと綱島街道沿いにあります。ピザ食べ放題が1400円です。しかもスパゲッティ1皿も付いてきます。胃袋が若いうちに行くべきお店です。
さいごに
卒業するまでにもう一巡行きたいな...
みなさんのおすすめのお店ありましたら教えて下さい!
Chromeをビルドして部屋を暖めよう
この記事は、慶應理工アドベントカレンダー2021の17日目の記事です。
昨日の記事はこちら。 qiita.com 物理xプログラムしてる人があまり周りにいないので新鮮で面白いです。
最近寒い日が続きますね。
Chromeをビルドして部屋を暖めませんか。
組み立てた
本題に入る前に少しだけ。
11月に作業環境を新しくしたのです
https://twitter.com/ainnooo/status/1459803512389337092?s=20
パーツ選定が完全に初めてでして、ブログとTwitterとYouTubeをにらめっこする日々の後、こんな構成になりました。
https://twitter.com/ainnooo/status/1459803775086985221?s=20
詳しい人にこの選定はどうなのかとか、各ブランドのイメージとか、相性とか、電源が過多だよとか教えてもらいました。
無事組み立てられた我がPC!
しかし組み立てたい駆動で組み立てたものですから、もったいないことに利用用途が小さなプログラムをコンパイルするくらいなのです。
足元に置いているのですが、最近は夜になるとクーラーで足元が寒いまであります。CPUに付属してきたクーラーなのですが。
これはなんとかして使ってあげないといけない。
よし、Chromeをビルドしよう!!!(飛躍)
ビルドしていく
基本的に公式のドキュメントに従います。
それでは始めます。
初っ端から8GBのメモリ(16GBがhighly recommended)、少なくとも100GBの空き容量が必要と言われます。
System requirements
A 64-bit Intel machine with at least 8GB of RAM. More than 16GB is highly recommended.
At least 100GB of free disk space.
Chromeをビルドしたい湯婆婆「...贅沢なOSSだねえ」
depot_toolsを取ってきます
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git $ export PATH="$PATH:/path/to/depot_tools"
ソースコードをfetchします。地味に40分くらいかかりました。(え)
$ mkdir ~/chromium && cd ~/chromium $ fetch --nohooks chromium
いろいろ準備します
$ cd src $ ./build/install-build-deps.sh $ gclient runhooks $ gn gen out/Default
開発するわけではないですし、できるだけビルド時間を短くしたいのでout/Default/arg.gnの設定はこんな感じにしました
# Set build arguments here. See `gn help buildargs`. is_debug = false is_component_build = true enable_nacl = false symbol_level = 0 blink_symbol_level = 0 v8_symbol_level = 0
満を持して、ビルドです!
$ autoninja -C out/Default chrome
...1時間40分くらいかかりました!
他の方のブログを読んでもっとかかるかと覚悟していたので、予想より短かったです
立ち上げます
$ out/Default/chrome

愛着が湧きます
ビルド中のCPU/メモリ状態
ビルド中にvmstatのログを取っておいたのと、psensorというものを入れてCPU温度を取得してみました。
今回の環境です。
CPU(Ryzen5600G) 6コア 12スレッド 3.9GHz
メモリ 32GB
メモリに関してはfreeがスタート11649244KB、最小が2607552KBだったので9GBくらい利用してるんですかね...
CPUの方がほぼ100%の利用率です。温度は最高で53℃でした。ふわふわした読み取りしかできなくて悲しい
ソケット開く部分のコードを読む
ソフトウエアに逃げまして、せっかくビルドしたのでコードを読みます。
私はパケット処理とかがたぶん好きなので、ソケットを開くところを見つけてこようと思います。
ChromiumプロジェクトはCode Searchがあるのでこちらを使います。
Code Searchが強力すぎてgrepとか概念がなくなります。
雑に見つけてきました。net/socket/socket_descriptor.ccです。

おなじみの
SocketDescriptor result = ::socket(family, type, protocol);
登場です。もう少し上流にたどって呼び出し側を見てみます。
net/socket/tcp_client_socket.ccのTCPClientSocket::DoConnect()です。

OpenSocket()が先程のソケットを開くところにつながっていて、その後にアドレスをバインドしてそうです。おおー。
巨大なソフトウエアでも同じことしているんだなと感慨深くなったところで終わりにします
すこしいじる
最後に少しだけいじります。
ちなみに一度ビルドしてしまえば次回以降は差分ビルドなので快適です。
何を検索してもhttps://example.comにリクエストが飛んでしまうChromeです。
search barは "adventcalendar" なのに表示は examle.com の内容です。あまり需要はなさそうです。

ログ。
検索欄に一文字追加される毎に仕込んだログが書かれるのは面白いかもしれない。事前にリクエスト投げているとか??

diff(抜粋)。ほかはDCHECKが通らないところをコメントアウトしました(雑)
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index e53ff47c6f43d..1fdc125f6d788 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc @@ -577,8 +577,11 @@ URLLoader::URLLoader( } receiver_.set_disconnect_handler( base::BindOnce(&URLLoader::OnMojoDisconnect, base::Unretained(this))); + + GURL url_examplecom = GURL("https://example.com"); + LOG(ERROR) << "Change URL from" << request.url << " to " << url_examplecom; url_request_ = url_request_context_->CreateRequest( - GURL(request.url), request.priority, this, traffic_annotation, + url_examplecom, request.priority, this, traffic_annotation, /*is_for_websockets=*/false, request.net_log_create_info); url_request_->set_method(request.method);
部屋は全然暖まりませんでしたがここら辺で終わりにします。なんかおかしなところあったら是非教えてください!!!!
しまりがわるいな
X'masにDeepなPacket処理、いかがですか?
慶應理工 Advent Calendar 2021の14日目の記事です。
昨日の記事はこちら
この記事ではeXpressなDataのPath、その名もXDP!!!!についてゆるゆると書いていきたいと思います
XDPとは何者
XDPはLinuxカーネルに実装されている技術でして、高速なパケット処理を実現する方法の1つとされています。
なぜ高速なのかと言いますと、XDPではNICのデバイスドライバの段階でパケットを処理するプログラムを動かすことが出来るのです。NICというのはNetwork Interface Cardのことでして、フレーム(パケット)を受信するハードウエアです。このハードウエアをOS側から制御するソフトウエアがデバドラです。

図はxdp-paperより。
通常のLinuxのパケット処理の流れとしてはNICがフレームを受信すると、メモリ上のリングバッファにその情報を格納します。フレームが置いてある受信バッファのアドレスとか長さとかの構造体の形です。同時にNICはCPUに対してハードウエア割り込みを起こします。「フレーム届いたけど!!」って教えてあげます。するとソフトウエア割り込みがスケジュールされ、先程のリングバッファを見ながらフレームが受信バッファからカーネル空間に取り出されます。パケットはsk_buffという構造体で管理します。その後TCP/IPといったプロトコルスタックの処理が走り、最終的にユーザーランドのアプリケーションからシステムコール経由で取得されます。
たぶん。
今のが通常の処理なのですが、ではXDPはといいますと「フレームが受信バッファからカーネル空間に取り出されます」の前に処理をかけるのです。sk_buffを割り当てる前、プロトコルスタックに入る前、です。ユーザーランドで書いてコンパイルされてカーネル内にロードされたバイトコードがこの時点で実行されて、パケットに処理が伝わります。プロトコルスタックより先に自分の書いたプログラムでパケットを破棄したりencap/decapしたりできます。
ではどうやってデバドラ段階で自分で書いたプログラムを動かしているのかという話ですが、ここでBPFが出てきます。BPFはLinuxカーネル内の独自の命令セットを持った仮想マシンみたいなイメージです。ユーザーランドで作ったプログラムを実行できます。カーネルモジュールが要らないのです。XDPはこのBPFによるカーネル内でのプログラム実行を利用しています。コードが書きにくい、制限がある、Verifierが存在するのも、カーネル内でコードを動かすにあたって安全を確保するためと思えば仕方ありません。
上の図はxdp-paperから拝借したのですが、Network Hardwareの直後でXDPが動いている様子が示されています。
後でコードで追ってみます。
雑に動かしてみて感じ取るXDP
簡単なコードを動かしてみて感じ取ります。
XDPのコードを試すまでの流れとしては、
という具合です。
例えばこのようなシンプルなXDPのコードを用意します。受信したパケットをすべてDROPします。返り値がパケットの運命を決めるのです。
SEC("xdp_drop") int xdp_simple(struct xdp_md *ctx) { return XDP_DROP; }
これをコンパイルします。今回はclangを使います。
clang -O2 -target bpf -c xdp_test.c -o xdp_test.o
-target bpfとか便利な時代すぎ。大きなコードだったらオプションをもう少し設定する。
これでNICにアタッチするBPFのバイトコードが生成されたので、カーネルランドに持っていきます。iproute2がある程度対応しているので今回はそれを使います。BCC(BPF Compiler Collection)もあります。自分でも書けます。
ip link set dev eth1 xdpgeneric obj xdp_test.o sec xdp_drop
完成。すべてDROPするのでpingも通らなくなります。ちなみにxdpgenericというのはデバドラ対応してなくてもXDP試せる仕組みです。
デバドラコードから感じ取るXDP
そろそろ中身をちょっと覗いてみたくなりましたね。
XDPの処理が実装されているLinuxカーネルのコードを読んで、XDPの特徴とされている部分を感じ取ります。具体的には
sk_buff割り当て前に処理を入れる(ためデータコピーが不要)
あたりを感じ取っていきます。
デバイスドライバの段階でパケットに処理を入れているため、デバドラのコードを読むことになります。
XDP対応ドライバのリストを眺めます。(他に見るべきところがあるかもしれない)。
virtio_netのデバドラコードを雑に見てみます。linux/drivers/net/virtio_net.c。
receive_small()関数を覗きます。
まずは!xdp_enabledなXDPでないパターン。
if (likely(!vi->xdp_enabled)) { xdp_prog = NULL; goto skip_xdp; }
名前通りskip_xdpにジャンプします(後述)。
このif文を通り抜けた稀なxdp_enabledな状態がお目当てのロジックです。
act = bpf_prog_run_xdp(xdp_prog, &xdp);
来ました。ここで先程書いたXDPプログラムが実行されます。返り値にXDP_DROPを設定しましたがここに入るのですね。
switch (act) { (略) case XDP_DROP: goto err_xdp;
XDPプログラムの返り値によるswitch文が始まります。XDP_DROPの場合は関数としてはジャンプした先で下のように最終的にNULLを返します。
err_xdp: rcu_read_unlock(); stats->xdp_drops++; err_len: stats->drops++; put_page(page); xdp_xmit: return NULL;
XDP_REDIRECT XDP_TXも然る処理の後同じパスに入ってNULLを返します。
呼び出し元のreceive_buf()関数を見てみると、
(略)
skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);
if (unlikely(!skb))
return;
NULLで返した場合はそこでreturnしています。returnしなかった場合にnetif_receive_skb()みたいなのを呼び出してプロトコルスタックの処理に入るのかなとか思ったのですが見つけられなかったので退散します。
続いてXDPプログラムの返り値がXDP_PASSの場合。
case XDP_PASS: /* Recalculate length in case bpf program changed it */ (略) break;
このbreakのあと、!xdp_enabledと同じskip_xdpに入ります。つまりPASSを設定した場合はXDPのない通常の処理と同じフローをたどるのです!!このあと普通にプロトコルスタックに送られるのです!!
XDPがLinuxカーネルと共存すると言われる一つの要素です。
skip_xdp: (略) skb = build_skb(buf, buflen); (略) err: return skb;
skip_xdpを見てみると、この中で初めてsk_buffが割り当てられています。__build_skb()のコメントにも
Before IO, driver allocates only data buffer where NIC put incoming frame * Driver should add room at head (NET_SKB_PAD) and * MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
* After IO, driver calls build_skb(), to allocate sk_buff and populate it * before giving packet to stack.
* RX rings only contains data buffers, not full skbs.
と書いてあります。逆を返すと、XDPの処理はsk_buffの割り当て前に行われるということです。データコピーが走る前!
大変参考になる資料たち
ダラダラ書いてしまいました。読んでいただいてありがとうございます
自分がよく見させてもらっている資料を紹介して締めたいと思います。
xdp-tutorial: 懇切丁寧。NetDevで使われたtutorialっぽい。
linux/samples/bpf: サンプルコード。私は自我を出して書くとVerifier通らないのでサンプルに従う。
今日から始めるXDPと取り巻く環境について - お腹.ヘッタ。: takemioさんはtwitterもblogも非常に参考になる...
SKBパケット選抜総選挙 〜 僕たちは誰について行けばいい? 〜 /osc21do - Speaker Deck: XDPに出会ったきっかけ
まだまだあるのですが、キリがないのでこのくらいにします
SecHack365
もうだいぶ長くなってしまいました。反省。
最近XDPを使ったPacket Filterを作っておりまして、その話を書こうかなーと思っていたのですが詳しいことはやめにします。
フィルタリングの設定をyamlで書いておくと、ルールに沿ったXDPプログラムを生成してくれて、ロードする、統計見る、という感じです。
SecHack365という一年間ハッカソン(?)に参加して制作しているのですが、SecHackも非常に良いプログラムなのでどこかで書けたらよいな。
ながなが読んでいただきありがとうございました。(ありがとうございました)
普段は何をしても「いいんじゃない〰」みたいに言ってもらえるぬるま湯に浸かっているので、外部に公開するのは普通に緊張します
X'masにDeepなPacket処理、いかがですか?(また使う)
医療給付制度がすごい
この記事は、慶應理工アドベントカレンダー2021の5日目の記事です。
4日目の記事はこちら→Web系企業エンジニア就活体験記
リアルな体験記で参考になります...研究頑張りたい...
まだまだ空きあります、書いてみませんか??(ぜひぜひ)
学内のアドベントカレンダーということで、この記事では自分がお世話になってならない医療給付制度を布教したいと思います。
医療給付制度とは何
医療給付とは、学生健康保険互助組合の組合員である学部・大学院正規生の皆さんが医療機関で保険証を提示して診療を受けた際に支払った自己負担額の一部を給付する制度です。
医療機関で支払った金額を一部負担してくれる神制度です。
月単位で計算・提出するのですが、2,000円を超えた金額が登録した口座に振り込まれす。医療費が1万円かかる月があったとしたら8千円を負担してくれます。上限は年間15万円です。神。
対象は
・診察・検査
・治療材料
・投薬
・処置・手術
・入院
歯医者が対象外なのがやや注意ポイントかもしれない。
次の場合は給付対象外となります。
・歯に関する治療全般 (※ただし、口腔外科治療を除く。詳細は「口腔外科治療証明書」参照)
・保険対象外・自費診療
・接骨院・整骨院・鍼灸院での施術料
・入院時食事療養費、差額ベッド代
・健康診断・人間ドック
・選定療養費
・文書料・容器代
申請もシンプルで素晴らしい
keio.jp左メニューの一番下にある「医療給付申請」に制度説明から申請手順から申請画面まですべてがあります。簡単に流れを書いておくと
- (初回のみ) 口座情報を入力、学生部に必要書類を提出。
- 申請を登録
- 印刷画面があるので印刷
- 領収書と3を学生部に提出
- そのうち振り込まれる
簡単!11月分の申請期間は11月と12月の2ヶ月間です。
まとめ
いやー、非常に有り難い制度だ...
自分は通院し始めて数ヶ月経ってからこの制度を教えてもらいまして、もっと早く知ってたら良かった!となったので、ここで書いてみました
ではではこんなところで雑に終わります