Since we can create temp file by using O_TMPFILE flag and filesystem driver also has this api, we should also check this operation whether strip S_ISGID. Signed-off-by: Yang Xu <xuyang2018.jy@xxxxxxxxxxx> --- src/idmapped-mounts/idmapped-mounts.c | 155 +++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 1 deletion(-) diff --git a/src/idmapped-mounts/idmapped-mounts.c b/src/idmapped-mounts/idmapped-mounts.c index 8f292228..362b8820 100644 --- a/src/idmapped-mounts/idmapped-mounts.c +++ b/src/idmapped-mounts/idmapped-mounts.c @@ -337,6 +337,24 @@ out: return fret; } +static bool openat_tmpfile_supported(int dirfd) +{ + int fd = -1; + + fd = openat(dirfd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID); + if (fd == -1) { + if (errno == ENOTSUP) + return false; + else + return log_errno(false, "failure: create"); + } + + if (close(fd)) + log_stderr("failure: close"); + + return true; +} + /* __expected_uid_gid - check whether file is owned by the provided uid and gid */ static bool __expected_uid_gid(int dfd, const char *path, int flags, uid_t expected_uid, gid_t expected_gid, bool log) @@ -7841,7 +7859,10 @@ static int setgid_create(void) { int fret = -1; int file1_fd = -EBADF; + int tmpfile_fd = -EBADF; pid_t pid; + bool supported = false; + char path[PATH_MAX]; if (!caps_supported()) return 0; @@ -7866,6 +7887,8 @@ static int setgid_create(void) goto out; } + supported = openat_tmpfile_supported(t_dir1_fd); + pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -7883,9 +7906,24 @@ static int setgid_create(void) if (!is_setgid(t_dir1_fd, FILE1, 0)) die("failure: is_setgid"); + /* create tmpfile via filesystem tmpfile api */ + if (supported) { + tmpfile_fd = openat(t_dir1_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID); + if (tmpfile_fd < 0) + die("failure: create"); + /* link the temporary file into the filesystem, making it permanent */ + snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd); + if (linkat(AT_FDCWD, path, t_dir1_fd, FILE2, AT_SYMLINK_FOLLOW)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (!is_setgid(t_dir1_fd, FILE2, 0)) + die("failure: is_setgid"); + } + /* create directory */ if (mkdirat(t_dir1_fd, DIR1, 0000)) - die("failure: create"); + die("failure: mkdirat"); /* Directories always inherit the setgid bit. */ if (!is_setgid(t_dir1_fd, DIR1, 0)) @@ -7908,6 +7946,9 @@ static int setgid_create(void) if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) die("failure: check ownership"); + if (supported && !expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) + die("failure: check ownership"); + if (!expected_uid_gid(t_dir1_fd, DIR1 "/" FILE1, 0, 0, 0)) die("failure: check ownership"); @@ -7920,6 +7961,9 @@ static int setgid_create(void) if (unlinkat(t_dir1_fd, FILE1, 0)) die("failure: delete"); + if (supported && unlinkat(t_dir1_fd, FILE2, 0)) + die("failure: delete"); + if (unlinkat(t_dir1_fd, DIR1 "/" FILE1, 0)) die("failure: delete"); @@ -7957,6 +8001,21 @@ static int setgid_create(void) if (is_setgid(t_dir1_fd, FILE1, 0)) die("failure: is_setgid"); + /* create tmpfile via filesystem tmpfile api */ + if (supported) { + tmpfile_fd = openat(t_dir1_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID); + if (tmpfile_fd < 0) + die("failure: create"); + /* link the temporary file into the filesystem, making it permanent */ + snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd); + if (linkat(AT_FDCWD, path, t_dir1_fd, FILE2, AT_SYMLINK_FOLLOW)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (is_setgid(t_dir1_fd, FILE2, 0)) + die("failure: is_setgid"); + } + /* create directory */ if (mkdirat(t_dir1_fd, DIR1, 0000)) die("failure: create"); @@ -7992,6 +8051,9 @@ static int setgid_create(void) if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) die("failure: check ownership"); + if (supported && !expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) + die("failure: check ownership"); + /* * In setgid directories newly created directories always * inherit the gid from the parent directory. Verify that the @@ -8009,6 +8071,9 @@ static int setgid_create(void) if (unlinkat(t_dir1_fd, FILE1, 0)) die("failure: delete"); + if (supported && unlinkat(t_dir1_fd, FILE2, 0)) + die("failure: delete"); + if (unlinkat(t_dir1_fd, DIR1 "/" FILE1, 0)) die("failure: delete"); @@ -8083,7 +8148,10 @@ static int setgid_create_idmapped(void) struct mount_attr attr = { .attr_set = MOUNT_ATTR_IDMAP, }; + int tmpfile_fd = -EBADF; pid_t pid; + bool supported = false; + char path[PATH_MAX]; if (!caps_supported()) return 0; @@ -8131,6 +8199,7 @@ static int setgid_create_idmapped(void) goto out; } + supported = openat_tmpfile_supported(open_tree_fd); pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -8151,6 +8220,21 @@ static int setgid_create_idmapped(void) if (is_setgid(open_tree_fd, FILE1, 0)) die("failure: is_setgid"); + /* create tmpfile via filesystem tmpfile api */ + if (supported) { + tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID); + if (tmpfile_fd < 0) + die("failure: create"); + /* link the temporary file into the filesystem, making it permanent */ + snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd); + if (linkat(AT_FDCWD, path, open_tree_fd, FILE2, AT_SYMLINK_FOLLOW)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (is_setgid(open_tree_fd, FILE2, 0)) + die("failure: is_setgid"); + } + /* create directory */ if (mkdirat(open_tree_fd, DIR1, 0000)) die("failure: create"); @@ -8173,6 +8257,9 @@ static int setgid_create_idmapped(void) if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000)) die("failure: check ownership"); + if (supported && !expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000)) + die("failure: check ownership"); + /* * In setgid directories newly created directories always * inherit the gid from the parent directory. Verify that the @@ -8254,7 +8341,10 @@ static int setgid_create_idmapped_in_userns(void) struct mount_attr attr = { .attr_set = MOUNT_ATTR_IDMAP, }; + int tmpfile_fd = -EBADF; pid_t pid; + bool supported = false; + char path[PATH_MAX]; if (!caps_supported()) return 0; @@ -8302,6 +8392,7 @@ static int setgid_create_idmapped_in_userns(void) goto out; } + supported = openat_tmpfile_supported(open_tree_fd); pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -8322,6 +8413,21 @@ static int setgid_create_idmapped_in_userns(void) if (!is_setgid(open_tree_fd, FILE1, 0)) die("failure: is_setgid"); + /* create tmpfile via filesystem tmpfile api */ + if (supported) { + tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID); + if (tmpfile_fd < 0) + die("failure: create"); + /* link the temporary file into the filesystem, making it permanent */ + snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd); + if (linkat(AT_FDCWD, path, open_tree_fd, FILE2, AT_SYMLINK_FOLLOW)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (!is_setgid(open_tree_fd, FILE2, 0)) + die("failure: is_setgid"); + } + /* create directory */ if (mkdirat(open_tree_fd, DIR1, 0000)) die("failure: create"); @@ -8346,6 +8452,9 @@ static int setgid_create_idmapped_in_userns(void) if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) die("failure: check ownership"); + if (supported && !expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0)) + die("failure: check ownership"); + if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0)) die("failure: check ownership"); @@ -8357,6 +8466,8 @@ static int setgid_create_idmapped_in_userns(void) if (unlinkat(open_tree_fd, FILE1, 0)) die("failure: delete"); + if (supported && unlinkat(open_tree_fd, FILE2, 0)) + die("failure: delete"); if (unlinkat(open_tree_fd, DIR1 "/" FILE1, 0)) die("failure: delete"); if (unlinkat(open_tree_fd, CHRDEV1, 0)) @@ -8410,6 +8521,21 @@ static int setgid_create_idmapped_in_userns(void) if (is_setgid(open_tree_fd, FILE1, 0)) die("failure: is_setgid"); + /* create tmpfile via filesystem tmpfile api */ + if (supported) { + tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID); + if (tmpfile_fd < 0) + die("failure: create"); + /* link the temporary file into the filesystem, making it permanent */ + snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd); + if (linkat(AT_FDCWD, path, open_tree_fd, FILE2, AT_SYMLINK_FOLLOW)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (is_setgid(open_tree_fd, FILE2, 0)) + die("failure: is_setgid"); + } + /* create directory */ if (mkdirat(open_tree_fd, DIR1, 0000)) die("failure: create"); @@ -8446,6 +8572,9 @@ static int setgid_create_idmapped_in_userns(void) if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000)) die("failure: check ownership"); + if (supported && !expected_uid_gid(open_tree_fd, FILE2, 0, 0, 1000)) + die("failure: check ownership"); + /* * In setgid directories newly created directories always * inherit the gid from the parent directory. Verify that the @@ -8463,6 +8592,9 @@ static int setgid_create_idmapped_in_userns(void) if (unlinkat(open_tree_fd, FILE1, 0)) die("failure: delete"); + if (supported && unlinkat(open_tree_fd, FILE2, 0)) + die("failure: delete"); + if (unlinkat(open_tree_fd, DIR1 "/" FILE1, 0)) die("failure: delete"); @@ -8515,6 +8647,21 @@ static int setgid_create_idmapped_in_userns(void) if (is_setgid(open_tree_fd, FILE1, 0)) die("failure: is_setgid"); + /* create tmpfile via filesystem tmpfile api */ + if (supported) { + tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID); + if (tmpfile_fd < 0) + die("failure: create"); + /* link the temporary file into the filesystem, making it permanent */ + snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd); + if (linkat(AT_FDCWD, path, open_tree_fd, FILE2, AT_SYMLINK_FOLLOW)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (is_setgid(open_tree_fd, FILE2, 0)) + die("failure: is_setgid"); + } + /* create directory */ if (mkdirat(open_tree_fd, DIR1, 0000)) die("failure: create"); @@ -8546,6 +8693,9 @@ static int setgid_create_idmapped_in_userns(void) if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) die("failure: check ownership"); + if (supported && !expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0)) + die("failure: check ownership"); + if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0)) die("failure: check ownership"); @@ -8558,6 +8708,9 @@ static int setgid_create_idmapped_in_userns(void) if (unlinkat(open_tree_fd, FILE1, 0)) die("failure: delete"); + if (supported && unlinkat(open_tree_fd, FILE2, 0)) + die("failure: delete"); + if (unlinkat(open_tree_fd, DIR1 "/" FILE1, 0)) die("failure: delete"); -- 2.27.0