Rustでtun/tapプログラムを記述しようとしています。ルートとして実行したくないので、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;
あなたの_target/release/tunnel
_バイナリが存在するファイルシステムは、nosuid
オプションでマウントされていると思います。これは、setuidビットだけでなく、ファイル機能にも影響します。
また、set-capabilitiesまたはsetuidバイナリをトレースすることはできません-カーネルは、ptrace
dプロセスからexecve()
を呼び出すときにファイル機能を無視します。
_$ 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 +++
_