ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

cgroup v2の、BPFによるデバイスアクセス制御を試す

RubyKaigiも近付いたしeBPFの機運を高めようとしている。

タイトルですが、そういうことができます。

www.kernel.org

このドキュメントにも「どうすればできる」と言うところが書いておらず、最終的にカーネルのサンプルを眺めることになる。

elixir.bootlin.com

elixir.bootlin.com

続きを読む

GWなのでRustでLuaを実装し(ようとし)た話

GWは、ゲートウェイじゃなくゴールデンウィークです。

タイトルの通り、連休の多くの空き時間を言語実装に費やしてしまった...。

github.com

とにかく、スターがついて承認されたいという気持ちが強いです(結論ファースト)。


今のところ、この辺りの機能はできている。

  • 四則演算
  • Rustでの/Luaでのグローバル関数定義
  • 関数内ローカル変数
  • if/then/else文
  • 配列ベースの繰り返し(ただ、配列操作ができない)

フィボナッチ数を求めるとこんな感じ。 2.4 GHz / 8コア Intel Core i9Macで実行した。といってもシングルコアしか使わないのだが。

function dofib(n)
   if n < 2 then
      return 1
   else
      return dofib(n-1) + dofib(n-2)
   end
   print("Unreachable!\n")
end

print(dofib(25))
print("\n")
$ time ./target/release/purua lua_examples/fib2.lua
121393
./target/release/purua lua_examples/fib2.lua  2.12s user 0.01s system 99% cpu 2.132 total

## 比較用 ruby 2.7.1
$ time ruby /tmp/rubyfib.rb
121393
ruby /tmp/rubyfib.rb  0.07s user 0.07s system 56% cpu 0.259 total
続きを読む

Rubyのptyライブラリで標準入力を渡す

すごく昔こういう記事を書いたんだけれど。

udzura.hatenablog.jp

フィヨルド方面より、まさかのこの記事に関する質問が来て、さらに「入力を渡すにはどうすればいいか」という追加質問がきたのであった。

試した感じ、なんとも素直に動かなかったので、どうすればいいかを書き残しておこうと思う。

続きを読む

eBPF的な意味で使えるcgroup idを取る方法

メモ程度に。


追記 @ 2021/04/20 12:41

inode番号と同じになるようになっているらしい。なので、

cgpath = ARGV[0]
puts File::Stat.new(cgpath).ino

これだけでいいです... 以下は、構造体キャストの例として残す。


github.com

この実装によると

struct cgid_file_handle
{
  unsigned int handle_bytes;
  int handle_type;
  uint64_t cgid;
};
  • そうすると handle->cgid に入ってる

という感じっぽい。なので言語を選ばず実装できる。Rubyのようなスクリプト言語ならffi(fiddle)を使ってこういう感じ:

require 'fiddle/import'

module Glibc
  extend Fiddle::Importer
  dlload 'libc.so.6'
  extern 'int name_to_handle_at(int dirfd, const char *pathname, vod *handle, int *mount_id, int flags)'
end

AT_FDCWD = -100 # この値らしい。そうなの...
cgpath = ARGV[0]
handle = Fiddle::Pointer.malloc(16)
handle[0, 16] = [8, 0, 0].pack("I I Q")
mount_id = Fiddle::Pointer.malloc(4)

if Glibc.name_to_handle_at(-100, cgpath, handle, mount_id, 0) < 0
  raise SystemCallError.new Fiddle.last_error
end

cgid = handle[0, 16].unpack("I I Q").last
puts "cgid of #{cgpath}: #{cgid}"

取れてそう。

$ sudo ruby /tmp/getcgid.rb /sys/fs/cgroup/unified/system.slice/docker-af6e1e860a07152351fc3b549479b08f45d0e484564dbbb3330a43d8c7686e94.scope
cgid of /sys/fs/cgroup/unified/system.slice/docker-af6e1e860a07152351fc3b549479b08f45d0e484564dbbb3330a43d8c7686e94.scope: 4863

実際このIDで絞り込んだら、ちゃんとそのコンテナのイベントだけ取れてるみたい。

$ sudo bpftrace -e \
    'tracepoint:syscalls:sys_enter_clone / cgroup == 4863 / { printf("Hola!\n"); } '
Attaching 1 probe...
Hola!
Hola!
...

Rustでもunshare(というか、Linux Namespaceの分離)したい!

あらかじめ宣言しますが、タイトルでunshare(2)と言いながらclone(2)を使います。

コンテナを自作する のが趣味だったので、Rustでもコンテナの基本的な機能であるLinux Namespace周りのコーディングをしてみた。

続きを読む