以下の内容はhttps://tenforward.hatenablog.com/entry/2019/03/24/140946より取得しました。


Linux 4.14 で導入された Namespaced file capabilities(2)

User Namespace 外から Namespaced file capability を設定する

前回、

tenforward.hatenablog.com

では、非特権ユーザで起動したコンテナ内の root ユーザーで File capability を設定しました。

ここで、自作コンテナ派の皆様が気になるのは、この capability をコンテナ外から設定するのはどうしたらいいのだろう? というところではないかと思います。コンテナランタイム側からコンテナ内の capability を設定する必要があるかもしれません。

もちろん、これも簡単にできます。先に getcap コマンドに -n オプションを付与しましたが、これと同じオプションが setcap にも存在します。

setcap -n 200000 cap_net_raw+ep ./ping

と言ったように、User Namespace 内の root の uid を指定して capability を指定します。

まず、コンテナ内からアクセスできるように、ホスト環境上で ping コマンドをコンテナの rootfs 内にコピーします。LXC の非特権コンテナは次のようなディレクトリ以下に rootfs が置かれますので、ここにコピーします。ping2 という名前でコピーしました。

$ sudo cp /bin/ping ~/.local/share/lxc/c3/rootfs/home/karma/ping2

次にコピーした ping2 バイナリに対して setcap します。

$ sudo setcap -n 200000 cap_net_raw+ep ~/.local/share/lxc/c3/rootfs/home/karma/ping2 (-nオプションでroot uidを指定)
$ sudo getcap -n ~/.local/share/lxc/c3/rootfs/home/karma/ping2
/home/karma/.local/share/lxc/c3/rootfs/home/karma/ping2 = cap_net_raw+ep [rootid=200000]
$ sudo getfattr -d -m "security" ~/.local/share/lxc/c3/rootfs/home/karma/ping2
getfattr: Removing leading '/' from absolute path names
# file: home/karma/.local/share/lxc/c3/rootfs/home/karma/ping2
security.capability=0sAQAAAwAgAAAAAAAAAAAAAAAAAABADQMA

設定されましたね。

再度コンテナ内に入ってみましょう。

$ lxc-attach c3
# su - karma
$ ls -l ./ping*
-rwxr-xr-x 1 karma  users   56,920  2月 21日  16:30 ./ping*
-rwxr-xr-x 1 nobody nogroup 56,920  2月 21日  16:39 ./ping2*

ホスト側の権限でコピーしていますので、ファイルの所有権が nobody:nogroup になっていますね。

$ sudo getcap -n ./ping2
./ping2 = cap_net_raw+ep [rootid=200000]

capability を確認すると、設定されているのがわかります。では、実行してみましょう。

$ ./ping2 -c 1 www.google.com
PING www.google.com (216.58.196.228) 56(84) bytes of data.
64 bytes from kix06s01-in-f228.1e100.net (216.58.196.228): icmp_seq=1 ttl=49 time=1.22 ms

--- www.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.226/1.226/1.226/0.000 ms

実行できました。

Namespace 外からでも問題なく設定できますね。

kernel のデータ構造の変更

ここからは素人なので間違ってる可能性あります。詳しくはご自分でどうぞ。

4.13 までは include/uapi/linux/capability.h を見ると、以下のような構造体がありました。

#define VFS_CAP_FLAGS_EFFECTIVE 0x000001

  : (snip)

#define VFS_CAP_REVISION_2 0x02000000

struct vfs_cap_data {
    __le32 magic_etc;            /* Little endian */
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
};

https://elixir.bootlin.com/linux/v4.13/source/include/uapi/linux/capability.h#L53 付近)

この permittedinheritable に必要な capability を設定するわけですね。effective セットは file capability の場合はオンオフだったと思いますので、magic_etc に設定します。

effective セットを設定する場合、これ(4.13)までは、

struct vfs_cap_data xattr;

xattr.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;

のように設定したようです。

4.14 以降で Namespaced file capability が導入されたあとは、

#define VFS_CAP_REVISION_2  0x02000000
#define VFS_CAP_U32_2           2
#define XATTR_CAPS_SZ_2         (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))

#define VFS_CAP_REVISION_3 0x03000000
#define VFS_CAP_U32_3           2
#define XATTR_CAPS_SZ_3         (sizeof(__le32)*(2 + 2*VFS_CAP_U32_3))

#define XATTR_CAPS_SZ           XATTR_CAPS_SZ_3
#define VFS_CAP_U32             VFS_CAP_U32_3
#define VFS_CAP_REVISION   VFS_CAP_REVISION_3

struct vfs_cap_data {
    __le32 magic_etc;            /* Little endian */
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
};

/*
 * same as vfs_cap_data but with a rootid at the end
 */
struct vfs_ns_cap_data {
    __le32 magic_etc;
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
    __le32 rootid;
};

https://elixir.bootlin.com/linux/v4.14/source/include/uapi/linux/capability.h#L64 付近)

というように struct vfs_ns_cap_data という、vfs_cap_data の最後に rootid が追加された構造体が追加されています。そう、これが setcapgetcap で追加された -n オプションの正体ですね(たぶん)。

それと同時に、従来の Namespaced されていない file capability なのか、Namespaced な file capability なのかは、magic_etc に指定する file capability の Revision で指定します。

先のコードと対応する例だと、

struct vfs_ns_cap_data xattr;

xattr.magic_etc = VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;

となるわけですね(たぶん)。

(つづく)

tenforward.hatenablog.com




以上の内容はhttps://tenforward.hatenablog.com/entry/2019/03/24/140946より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14