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. Reviewed-by: Christian Brauner (Microsoft) <brauner@xxxxxxxxxx> Signed-off-by: Yang Xu <xuyang2018.jy@xxxxxxxxxxx> --- v3->v4: use linkat with AT_EMPTY_PATH to make the temporary file permanent instead of snprint and link with AT_SYMLINK_FOLLOW src/idmapped-mounts/idmapped-mounts.c | 139 ++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/src/idmapped-mounts/idmapped-mounts.c b/src/idmapped-mounts/idmapped-mounts.c index a1c22da2..8fe06408 100644 --- a/src/idmapped-mounts/idmapped-mounts.c +++ b/src/idmapped-mounts/idmapped-mounts.c @@ -51,6 +51,7 @@ #define FILE1_RENAME "file1_rename" #define FILE2 "file2" #define FILE2_RENAME "file2_rename" +#define FILE3 "file3" #define DIR1 "dir1" #define DIR2 "dir2" #define DIR3 "dir3" @@ -340,6 +341,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) @@ -7844,7 +7863,9 @@ static int setgid_create(void) { int fret = -1; int file1_fd = -EBADF; + int tmpfile_fd = -EBADF; pid_t pid; + bool supported = false; if (!caps_supported()) return 0; @@ -7869,6 +7890,8 @@ static int setgid_create(void) goto out; } + supported = openat_tmpfile_supported(t_dir1_fd); + pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -7932,6 +7955,24 @@ static int setgid_create(void) if (unlinkat(t_dir1_fd, CHRDEV1, 0)) die("failure: delete"); + /* 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 */ + if (linkat(tmpfile_fd, "", t_dir1_fd, FILE3, AT_EMPTY_PATH)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (!is_setgid(t_dir1_fd, FILE3, 0)) + die("failure: is_setgid"); + if (!expected_uid_gid(t_dir1_fd, FILE3, 0, 0, 0)) + die("failure: check ownership"); + if (unlinkat(t_dir1_fd, FILE3, 0)) + die("failure: delete"); + } + exit(EXIT_SUCCESS); } if (wait_for_pid(pid)) @@ -8021,6 +8062,24 @@ static int setgid_create(void) if (unlinkat(t_dir1_fd, CHRDEV1, 0)) die("failure: delete"); + /* 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 */ + if (linkat(tmpfile_fd, "", t_dir1_fd, FILE3, AT_EMPTY_PATH)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (is_setgid(t_dir1_fd, FILE3, 0)) + die("failure: is_setgid"); + if (!expected_uid_gid(t_dir1_fd, FILE3, 0, 0, 0)) + die("failure: check ownership"); + if (unlinkat(t_dir1_fd, FILE3, 0)) + die("failure: delete"); + } + exit(EXIT_SUCCESS); } if (wait_for_pid(pid)) @@ -8042,6 +8101,8 @@ static int setgid_create_idmapped(void) .attr_set = MOUNT_ATTR_IDMAP, }; pid_t pid; + int tmpfile_fd = -EBADF; + bool supported = false; if (!caps_supported()) return 0; @@ -8089,6 +8150,8 @@ static int setgid_create_idmapped(void) goto out; } + supported = openat_tmpfile_supported(open_tree_fd); + pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -8171,6 +8234,24 @@ static int setgid_create_idmapped(void) if (unlinkat(open_tree_fd, CHRDEV1, 0)) die("failure: delete"); + /* 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 */ + if (linkat(tmpfile_fd, "", t_dir1_fd, FILE3, AT_EMPTY_PATH)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (is_setgid(open_tree_fd, FILE3, 0)) + die("failure: is_setgid"); + if (!expected_uid_gid(open_tree_fd, FILE3, 0, 10000, 10000)) + die("failure: check ownership"); + if (unlinkat(open_tree_fd, FILE3, 0)) + die("failure: delete"); + } + exit(EXIT_SUCCESS); } if (wait_for_pid(pid)) @@ -8194,6 +8275,8 @@ static int setgid_create_idmapped_in_userns(void) .attr_set = MOUNT_ATTR_IDMAP, }; pid_t pid; + int tmpfile_fd = -EBADF; + bool supported = false; if (!caps_supported()) return 0; @@ -8241,6 +8324,8 @@ 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"); @@ -8307,6 +8392,24 @@ static int setgid_create_idmapped_in_userns(void) if (unlinkat(open_tree_fd, CHRDEV1, 0)) die("failure: delete"); + /* 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 */ + if (linkat(tmpfile_fd, "", t_dir1_fd, FILE3, AT_EMPTY_PATH)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (!is_setgid(open_tree_fd, FILE3, 0)) + die("failure: is_setgid"); + if (!expected_uid_gid(open_tree_fd, FILE3, 0, 0, 0)) + die("failure: check ownership"); + if (unlinkat(open_tree_fd, FILE3, 0)) + die("failure: delete"); + } + exit(EXIT_SUCCESS); } if (wait_for_pid(pid)) @@ -8415,6 +8518,24 @@ static int setgid_create_idmapped_in_userns(void) if (unlinkat(open_tree_fd, CHRDEV1, 0)) die("failure: delete"); + /* 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 */ + if (linkat(tmpfile_fd, "", t_dir1_fd, FILE3, AT_EMPTY_PATH)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (is_setgid(open_tree_fd, FILE3, 0)) + die("failure: is_setgid"); + if (!expected_uid_gid(open_tree_fd, FILE3, 0, 0, 1000)) + die("failure: check ownership"); + if (unlinkat(open_tree_fd, FILE3, 0)) + die("failure: delete"); + } + exit(EXIT_SUCCESS); } if (wait_for_pid(pid)) @@ -8511,6 +8632,24 @@ static int setgid_create_idmapped_in_userns(void) if (unlinkat(open_tree_fd, CHRDEV1, 0)) die("failure: delete"); + /* 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 */ + if (linkat(tmpfile_fd, "", t_dir1_fd, FILE3, AT_EMPTY_PATH)) + die("failure: linkat"); + if (close(tmpfile_fd)) + die("failure: close"); + if (is_setgid(open_tree_fd, FILE3, 0)) + die("failure: is_setgid"); + if (!expected_uid_gid(open_tree_fd, FILE3, 0, 0, 0)) + die("failure: check ownership"); + if (unlinkat(open_tree_fd, FILE3, 0)) + die("failure: delete"); + } + exit(EXIT_SUCCESS); } if (wait_for_pid(pid)) -- 2.31.1