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 <behlendorf1@llnl.gov>
Signed-off-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
Closes #14098
This commit is contained in:
Richard Yao 2022-10-27 11:03:48 -04:00 committed by Brian Behlendorf
parent 82ad2a06ac
commit 4170ae4ea6
4 changed files with 34 additions and 31 deletions

View File

@ -90,21 +90,32 @@ smb_retrieve_shares(void)
/* Go through the directory, looking for shares */ /* Go through the directory, looking for shares */
while ((directory = readdir(shares_dir))) { while ((directory = readdir(shares_dir))) {
int fd;
if (directory->d_name[0] == '.') if (directory->d_name[0] == '.')
continue; continue;
snprintf(file_path, sizeof (file_path), snprintf(file_path, sizeof (file_path),
"%s/%s", SHARE_DIR, directory->d_name); "%s/%s", SHARE_DIR, directory->d_name);
if (stat(file_path, &eStat) == -1) { if ((fd = open(file_path, O_RDONLY | O_CLOEXEC)) == -1) {
rc = SA_SYSTEM_ERR; rc = SA_SYSTEM_ERR;
goto out; goto out;
} }
if (!S_ISREG(eStat.st_mode)) if (stat(file_path, &eStat) == -1) {
continue; close(fd);
rc = SA_SYSTEM_ERR;
goto out;
}
if ((share_file_fp = fopen(file_path, "re")) == NULL) { if (!S_ISREG(eStat.st_mode)) {
close(fd);
continue;
}
if ((share_file_fp = fdopen(fd, "r")) == NULL) {
close(fd);
rc = SA_SYSTEM_ERR; rc = SA_SYSTEM_ERR;
goto out; goto out;
} }

View File

@ -88,29 +88,21 @@ map_writer(void *filename)
int ret = 0; int ret = 0;
char *buf = NULL; char *buf = NULL;
int page_size = getpagesize(); int page_size = getpagesize();
int op_errno = 0;
char *file_path = filename; char *file_path = filename;
while (1) { while (1) {
ret = access(file_path, F_OK); fd = open(file_path, O_RDWR);
if (ret) { if (fd == -1) {
op_errno = errno; if (errno == ENOENT) {
if (op_errno == ENOENT) {
fd = open(file_path, O_RDWR | O_CREAT, 0777); fd = open(file_path, O_RDWR | O_CREAT, 0777);
if (fd == -1) { if (fd == -1) {
err(1, "open file failed"); err(1, "open file failed");
} }
ret = ftruncate(fd, page_size); ret = ftruncate(fd, page_size);
if (ret == -1) { if (ret == -1) {
err(1, "truncate file failed"); err(1, "truncate file failed");
} }
} else { } else {
err(1, "access file failed!");
}
} else {
fd = open(file_path, O_RDWR, 0777);
if (fd == -1) {
err(1, "open file failed"); err(1, "open file failed");
} }
} }

View File

@ -46,7 +46,6 @@ main(void)
int i, fd; int i, fd;
char spath[1024], dpath[1024]; char spath[1024], dpath[1024];
const char *penv[] = {"TESTDIR", "TESTFILE0"}; const char *penv[] = {"TESTDIR", "TESTFILE0"};
struct stat sbuf;
(void) fprintf(stdout, "Verify O_TMPFILE file can be linked.\n"); (void) fprintf(stdout, "Verify O_TMPFILE file can be linked.\n");
@ -73,12 +72,10 @@ main(void)
run("export"); run("export");
run("import"); run("import");
if (stat(dpath, &sbuf) < 0) { if (unlink(dpath) == -1) {
perror("stat"); perror("unlink");
unlink(dpath);
exit(5); exit(5);
} }
unlink(dpath);
return (0); return (0);
} }

View File

@ -48,7 +48,7 @@
static void static void
test_stat_mode(mode_t mask) test_stat_mode(mode_t mask)
{ {
struct stat st, fst; struct stat fst;
int i, fd; int i, fd;
char spath[1024], dpath[1024]; char spath[1024], dpath[1024];
const char *penv[] = {"TESTDIR", "TESTFILE0"}; const char *penv[] = {"TESTDIR", "TESTFILE0"};
@ -68,7 +68,7 @@ test_stat_mode(mode_t mask)
err(2, "open(%s)", penv[0]); err(2, "open(%s)", penv[0]);
if (fstat(fd, &fst) == -1) if (fstat(fd, &fst) == -1)
err(3, "open"); err(3, "fstat(%s)", penv[0]);
snprintf(spath, sizeof (spath), "/proc/self/fd/%d", fd); snprintf(spath, sizeof (spath), "/proc/self/fd/%d", fd);
snprintf(dpath, sizeof (dpath), "%s/%s", penv[0], penv[1]); snprintf(dpath, sizeof (dpath), "%s/%s", penv[0], penv[1]);
@ -78,19 +78,22 @@ test_stat_mode(mode_t mask)
err(4, "linkat"); err(4, "linkat");
close(fd); close(fd);
if (stat(dpath, &st) == -1) /* Verify fstat(2) result at old path */
err(5, "stat");
unlink(dpath);
/* Verify fstat(2) result */
mode = fst.st_mode & 0777; mode = fst.st_mode & 0777;
if (mode != masked) if (mode != masked)
errx(6, "fstat(2) %o != %o\n", mode, masked); errx(5, "fstat(2) %o != %o\n", mode, masked);
/* Verify stat(2) result */ fd = open(dpath, O_RDWR);
mode = st.st_mode & 0777; if (fd == -1)
err(6, "open(%s)", dpath);
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) if (mode != masked)
errx(7, "stat(2) %o != %o\n", mode, masked); errx(8, "fstat(2) %o != %o\n", mode, masked);
} }
int int