From 4170ae4ea600fea6ac9daa8b145960c9de3915fc Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 27 Oct 2022 11:03:48 -0400 Subject: [PATCH] Fix TOCTOU race conditions reported by CodeQL and Coverity CodeQL and Coverity both complained about: * lib/libshare/os/linux/smb.c * tests/zfs-tests/cmd/mmapwrite.c * twice * tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c * tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c * coverity had a second complaint that CodeQL did not have * tests/zfs-tests/cmd/suid_write_to_file.c * Coverity had two complaints and CodeQL had one complaint, both differed. The CodeQL complaint is about the main point of the test, so it is not fixable without a hack involving `fork()`. The issues reported by CodeQL are fixed, with the exception of the last one, which is deemed to be a false positive that is too much trouble to wrokaround. The issues reported by Coverity were only fixed if CodeQL complained about them. There were issues reported by Coverity in a number of other files that were not reported by CodeQL, but fixing the CodeQL complaints is considered a priority since we want to integrate it into a github workflow, so the remaining Coverity complaints are left for future work. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14098 --- lib/libshare/os/linux/smb.c | 15 +++++++++-- tests/zfs-tests/cmd/mmapwrite.c | 14 +++-------- .../functional/tmpfile/tmpfile_002_pos.c | 7 ++---- .../functional/tmpfile/tmpfile_stat_mode.c | 25 +++++++++++-------- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/lib/libshare/os/linux/smb.c b/lib/libshare/os/linux/smb.c index 157b19aa85f4..8eb1894de531 100644 --- a/lib/libshare/os/linux/smb.c +++ b/lib/libshare/os/linux/smb.c @@ -90,21 +90,32 @@ smb_retrieve_shares(void) /* Go through the directory, looking for shares */ while ((directory = readdir(shares_dir))) { + int fd; + if (directory->d_name[0] == '.') continue; snprintf(file_path, sizeof (file_path), "%s/%s", SHARE_DIR, directory->d_name); + if ((fd = open(file_path, O_RDONLY | O_CLOEXEC)) == -1) { + rc = SA_SYSTEM_ERR; + goto out; + } + if (stat(file_path, &eStat) == -1) { + close(fd); rc = SA_SYSTEM_ERR; goto out; } - if (!S_ISREG(eStat.st_mode)) + if (!S_ISREG(eStat.st_mode)) { + close(fd); continue; + } - if ((share_file_fp = fopen(file_path, "re")) == NULL) { + if ((share_file_fp = fdopen(fd, "r")) == NULL) { + close(fd); rc = SA_SYSTEM_ERR; goto out; } diff --git a/tests/zfs-tests/cmd/mmapwrite.c b/tests/zfs-tests/cmd/mmapwrite.c index ca55d730fd34..a18609898485 100644 --- a/tests/zfs-tests/cmd/mmapwrite.c +++ b/tests/zfs-tests/cmd/mmapwrite.c @@ -88,29 +88,21 @@ map_writer(void *filename) int ret = 0; char *buf = NULL; int page_size = getpagesize(); - int op_errno = 0; char *file_path = filename; while (1) { - ret = access(file_path, F_OK); - if (ret) { - op_errno = errno; - if (op_errno == ENOENT) { + fd = open(file_path, O_RDWR); + if (fd == -1) { + if (errno == ENOENT) { fd = open(file_path, O_RDWR | O_CREAT, 0777); if (fd == -1) { err(1, "open file failed"); } - ret = ftruncate(fd, page_size); if (ret == -1) { err(1, "truncate file failed"); } } else { - err(1, "access file failed!"); - } - } else { - fd = open(file_path, O_RDWR, 0777); - if (fd == -1) { err(1, "open file failed"); } } diff --git a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c index 424231d112b2..906b81b4d9b3 100644 --- a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c +++ b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c @@ -46,7 +46,6 @@ main(void) int i, fd; char spath[1024], dpath[1024]; const char *penv[] = {"TESTDIR", "TESTFILE0"}; - struct stat sbuf; (void) fprintf(stdout, "Verify O_TMPFILE file can be linked.\n"); @@ -73,12 +72,10 @@ main(void) run("export"); run("import"); - if (stat(dpath, &sbuf) < 0) { - perror("stat"); - unlink(dpath); + if (unlink(dpath) == -1) { + perror("unlink"); exit(5); } - unlink(dpath); return (0); } diff --git a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c index 4c34aec8bdb4..1a934a8b1852 100644 --- a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c +++ b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c @@ -48,7 +48,7 @@ static void test_stat_mode(mode_t mask) { - struct stat st, fst; + struct stat fst; int i, fd; char spath[1024], dpath[1024]; const char *penv[] = {"TESTDIR", "TESTFILE0"}; @@ -68,7 +68,7 @@ test_stat_mode(mode_t mask) err(2, "open(%s)", penv[0]); if (fstat(fd, &fst) == -1) - err(3, "open"); + err(3, "fstat(%s)", penv[0]); snprintf(spath, sizeof (spath), "/proc/self/fd/%d", fd); snprintf(dpath, sizeof (dpath), "%s/%s", penv[0], penv[1]); @@ -78,19 +78,22 @@ test_stat_mode(mode_t mask) err(4, "linkat"); close(fd); - if (stat(dpath, &st) == -1) - err(5, "stat"); - unlink(dpath); - - /* Verify fstat(2) result */ + /* Verify fstat(2) result at old path */ mode = fst.st_mode & 0777; if (mode != masked) - errx(6, "fstat(2) %o != %o\n", mode, masked); + errx(5, "fstat(2) %o != %o\n", mode, masked); + + fd = open(dpath, O_RDWR); + if (fd == -1) + err(6, "open(%s)", dpath); - /* Verify stat(2) result */ - mode = st.st_mode & 0777; + if (fstat(fd, &fst) == -1) + err(7, "fstat(%s)", dpath); + + /* Verify fstat(2) result at new path */ + mode = fst.st_mode & 0777; if (mode != masked) - errx(7, "stat(2) %o != %o\n", mode, masked); + errx(8, "fstat(2) %o != %o\n", mode, masked); } int