samples/landlock: Add support for file reparenting
authorMickaël Salaün <mic@digikod.net>
Fri, 6 May 2022 16:10:59 +0000 (18:10 +0200)
committerMickaël Salaün <mic@digikod.net>
Mon, 23 May 2022 11:28:00 +0000 (13:28 +0200)
Add LANDLOCK_ACCESS_FS_REFER to the "roughly write" access rights and
leverage the Landlock ABI version to only try to enforce it if it is
supported by the running kernel.

Reviewed-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Link: https://lore.kernel.org/r/20220506161102.525323-10-mic@digikod.net
samples/landlock/sandboxer.c

index c089e9c..3e404e5 100644 (file)
@@ -159,7 +159,11 @@ out_free_name:
        LANDLOCK_ACCESS_FS_MAKE_SOCK | \
        LANDLOCK_ACCESS_FS_MAKE_FIFO | \
        LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
-       LANDLOCK_ACCESS_FS_MAKE_SYM)
+       LANDLOCK_ACCESS_FS_MAKE_SYM | \
+       LANDLOCK_ACCESS_FS_REFER)
+
+#define ACCESS_ABI_2 ( \
+       LANDLOCK_ACCESS_FS_REFER)
 
 /* clang-format on */
 
@@ -167,10 +171,11 @@ int main(const int argc, char *const argv[], char *const *const envp)
 {
        const char *cmd_path;
        char *const *cmd_argv;
-       int ruleset_fd;
+       int ruleset_fd, abi;
+       __u64 access_fs_ro = ACCESS_FS_ROUGHLY_READ,
+             access_fs_rw = ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_WRITE;
        struct landlock_ruleset_attr ruleset_attr = {
-               .handled_access_fs = ACCESS_FS_ROUGHLY_READ |
-                                    ACCESS_FS_ROUGHLY_WRITE,
+               .handled_access_fs = access_fs_rw,
        };
 
        if (argc < 2) {
@@ -196,12 +201,11 @@ int main(const int argc, char *const argv[], char *const *const envp)
                return 1;
        }
 
-       ruleset_fd =
-               landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
-       if (ruleset_fd < 0) {
+       abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
+       if (abi < 0) {
                const int err = errno;
 
-               perror("Failed to create a ruleset");
+               perror("Failed to check Landlock compatibility");
                switch (err) {
                case ENOSYS:
                        fprintf(stderr,
@@ -221,13 +225,23 @@ int main(const int argc, char *const argv[], char *const *const envp)
                }
                return 1;
        }
-       if (populate_ruleset(ENV_FS_RO_NAME, ruleset_fd,
-                            ACCESS_FS_ROUGHLY_READ)) {
+       /* Best-effort security. */
+       if (abi < 2) {
+               ruleset_attr.handled_access_fs &= ~ACCESS_ABI_2;
+               access_fs_ro &= ~ACCESS_ABI_2;
+               access_fs_rw &= ~ACCESS_ABI_2;
+       }
+
+       ruleset_fd =
+               landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+       if (ruleset_fd < 0) {
+               perror("Failed to create a ruleset");
+               return 1;
+       }
+       if (populate_ruleset(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) {
                goto err_close_ruleset;
        }
-       if (populate_ruleset(ENV_FS_RW_NAME, ruleset_fd,
-                            ACCESS_FS_ROUGHLY_READ |
-                                    ACCESS_FS_ROUGHLY_WRITE)) {
+       if (populate_ruleset(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) {
                goto err_close_ruleset;
        }
        if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {