[njs] Fixed TOCTOU in fs.mkdir() introduced in cb2ff67e595d.
Dmitry Volyntsev
xeioex at nginx.com
Mon Jul 27 14:36:20 UTC 2020
details: https://hg.nginx.org/njs/rev/6078d0c735b4
branches:
changeset: 1481:6078d0c735b4
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Mon Jul 27 14:18:15 2020 +0000
description:
Fixed TOCTOU in fs.mkdir() introduced in cb2ff67e595d.
Found by Coverity (CID 1465508).
diffstat:
src/njs_fs.c | 75 +++++++++++++++++++++++++++++------------------------------
1 files changed, 37 insertions(+), 38 deletions(-)
diffs (137 lines):
diff -r cb2ff67e595d -r 6078d0c735b4 src/njs_fs.c
--- a/src/njs_fs.c Wed Jul 15 15:51:06 2020 +0300
+++ b/src/njs_fs.c Mon Jul 27 14:18:15 2020 +0000
@@ -1135,96 +1135,95 @@ static njs_int_t
njs_fs_make_path(njs_vm_t *vm, const char *path, mode_t md,
njs_bool_t recursive, njs_value_t *retval)
{
- size_t size;
+ int err;
ssize_t length;
njs_int_t ret;
- const char *p, *prev;
+ const char *p, *prev, *end;
njs_value_t value;
struct stat sb;
char path_buf[MAXPATHLEN];
njs_set_undefined(retval);
+ end = path + njs_strlen(path);
+
if (!recursive) {
ret = mkdir(path, md);
if (ret != 0) {
+ err = errno;
goto failed;
}
return NJS_OK;
}
- ret = stat(path, &sb);
- if (ret == 0) {
- if (!S_ISDIR(sb.st_mode)) {
- errno = ENOTDIR;
- goto failed;
- }
-
- return NJS_OK;
- }
-
- if (errno != ENOENT) {
- goto failed;
- }
-
p = path;
prev = p;
for ( ;; ) {
p = strchr(prev + 1, '/');
if (p == NULL) {
- break;
+ p = end;
}
if (njs_slow_path((p - path) > MAXPATHLEN)) {
njs_internal_error(vm, "too large path");
- return NJS_OK;
+ return NJS_ERROR;
}
memcpy(&path_buf[prev - path], &path[prev - path], p - prev);
path_buf[p - path] = '\0';
- ret = stat(path_buf, &sb);
- if (ret == 0) {
- if (!S_ISDIR(sb.st_mode)) {
- errno = ENOTDIR;
- goto failed;
+ ret = mkdir(path_buf, md);
+ err = errno;
+
+ switch (ret) {
+ case 0:
+ break;
+
+ case EACCES:
+ case ENOTDIR:
+ case EPERM:
+ goto failed;
+
+ case EEXIST:
+ default:
+ ret = stat(path_buf, &sb);
+ if (ret == 0) {
+ if (!S_ISDIR(sb.st_mode)) {
+ err = ENOTDIR;
+ goto failed;
+ }
+
+ break;
}
- } else {
- ret = mkdir(path_buf, md);
- if (ret != 0) {
- goto failed;
- }
+ goto failed;
+ }
+
+ if (p == end) {
+ break;
}
path_buf[p - path] = '/';
prev = p;
}
- ret = mkdir(path, md);
- if (ret != 0 && errno != EEXIST) {
- goto failed;
- }
-
return NJS_OK;
failed:
- size = njs_strlen(path);
- length = njs_utf8_length((u_char *) path, size);
+ length = njs_utf8_length((u_char *) path, end - path);
if (njs_slow_path(length < 0)) {
length = 0;
}
- ret = njs_string_new(vm, &value, (u_char *) path, size, length);
+ ret = njs_string_new(vm, &value, (u_char *) path, end - path, length);
if (ret != NJS_OK) {
return NJS_ERROR;
}
- return njs_fs_error(vm, "mkdir", strerror(errno), &value, errno,
- retval);
+ return njs_fs_error(vm, "mkdir", strerror(err), &value, err, retval);
}
More information about the nginx-devel
mailing list