私はRustでtun / tapプログラムを書こうとしています。 rootとして実行したくないので、バイナリ機能にCAP_NET_ADMINを追加しました。
$sudo setcap cap_net_admin=eip target/release/tunnel
$getcap target/release/tunnel
target/release/tunnel = cap_net_admin+eip
しかし、これはうまくいきません。私が読んだすべての内容は、これがtunを生成するために必要な唯一の機能であることを示唆していますが、プログラムはioctlからEPERMを取得します。 strace に次のエラーが表示されます。
openat(AT_FDCWD, "/dev/net/tun", O_RDWR|O_CLOEXEC) = 3
fcntl(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
ioctl(3, TUNSETIFF, 0x7ffcdac7c7c0) = -1 EPERM (Operation not permitted)
完全なroot権限でバイナリが正常に実行できることを確認しましたが、sudoの実行を要求したくありません。ここでCAP_NET_ADMINだけでは十分ではないのはなぜですか?
参考までに、Linux version 4.15.0-45
このioctlにはカーネルからEPERMを返す方法がいくつかあることがわかりました(https://elixir.bootlin.com/linux/v4.15/source/drivers/net/tun.c#L2194) そして、そのうちの少なくとも1人は満足しているようです。他の人を調べる方法がわからない。
if (!capable(CAP_NET_ADMIN))
return -EPERM;
...
if (tun_not_capable(tun))
return -EPERM;
...
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
ベストアンサー1
target/release/tunnel
私はあなたのバイナリを持つファイルシステムがnosuid
このオプションでマウントされていると思います。これは setuid ビットだけでなくファイル機能にも影響します。
また、可能な限り set-capability または setuid バイナリを追跡することはできません。カーネルは、dプロセスexecve()
で呼び出されたときにファイル機能を無視します。ptrace
$ getcap tapy
tapy = cap_net_admin+eip
$ ./tapy
tapy: {tap1}
^C
$ strace -e trace=ioctl ./tapy
ioctl(3, TUNSETIFF, 0x7ffdc5b2fef0) = -1 EPERM (Operation not permitted)
tapy: ioctl TUNSETIFF: Operation not permitted
+++ exited with 1 +++