diff options
Diffstat (limited to 'src/firejail/util.c')
-rw-r--r-- | src/firejail/util.c | 54 |
1 files changed, 21 insertions, 33 deletions
diff --git a/src/firejail/util.c b/src/firejail/util.c index fff0bbf2f..918077235 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -50,7 +50,7 @@ void errLogExit(char* fmt, ...) { | |||
50 | char *msg1; | 50 | char *msg1; |
51 | char *msg2 = "Access error"; | 51 | char *msg2 = "Access error"; |
52 | if (vasprintf(&msg1, fmt, args) != -1 && | 52 | if (vasprintf(&msg1, fmt, args) != -1 && |
53 | asprintf(&msg2, "Access error: pid %d, last mount name:%s dir:%s type:%s - %s", getuid(), m->fsname, m->dir, m->fstype, msg1) != -1) | 53 | asprintf(&msg2, "Access error: uid %d, last mount name:%s dir:%s type:%s - %s", getuid(), m->fsname, m->dir, m->fstype, msg1) != -1) |
54 | syslog(LOG_CRIT, "%s", msg2); | 54 | syslog(LOG_CRIT, "%s", msg2); |
55 | va_end(args); | 55 | va_end(args); |
56 | closelog(); | 56 | closelog(); |
@@ -487,7 +487,6 @@ char *line_remove_spaces(const char *buf) { | |||
487 | size_t len = strlen(buf); | 487 | size_t len = strlen(buf); |
488 | if (len == 0) | 488 | if (len == 0) |
489 | return NULL; | 489 | return NULL; |
490 | assert(len + 1 != 0 && buf[len] == '\0'); | ||
491 | 490 | ||
492 | // allocate memory for the new string | 491 | // allocate memory for the new string |
493 | char *rv = malloc(len + 1); | 492 | char *rv = malloc(len + 1); |
@@ -554,15 +553,13 @@ char *split_comma(char *str) { | |||
554 | char *clean_pathname(const char *path) { | 553 | char *clean_pathname(const char *path) { |
555 | assert(path); | 554 | assert(path); |
556 | size_t len = strlen(path); | 555 | size_t len = strlen(path); |
557 | assert(len + 1 != 0 && path[len] == '\0'); | ||
558 | |||
559 | char *rv = malloc(len + 1); | 556 | char *rv = malloc(len + 1); |
560 | if (!rv) | 557 | if (!rv) |
561 | errExit("malloc"); | 558 | errExit("malloc"); |
562 | 559 | ||
563 | if (len > 0) { | 560 | if (len > 0) { |
564 | size_t i, j, cnt; | 561 | size_t i = 0, j = 0, cnt = 0; |
565 | for (i = 0, j = 0, cnt = 0; i < len; i++) { | 562 | for (; i < len; i++) { |
566 | if (path[i] == '/') | 563 | if (path[i] == '/') |
567 | cnt++; | 564 | cnt++; |
568 | else | 565 | else |
@@ -1142,56 +1139,47 @@ void disable_file_path(const char *path, const char *file) { | |||
1142 | free(fname); | 1139 | free(fname); |
1143 | } | 1140 | } |
1144 | 1141 | ||
1145 | // The returned file descriptor should be suitable for privileged operations on | 1142 | // open file without following any symbolic link |
1146 | // user controlled paths | 1143 | // returns a file descriptor on success, or -1 if a symlink is found |
1147 | int safe_fd(const char *path, int flags) { | 1144 | int safe_fd(const char *path, int flags) { |
1148 | assert(path); | 1145 | assert(path); |
1149 | |||
1150 | // reject empty string, relative path | ||
1151 | if (*path != '/') | 1146 | if (*path != '/') |
1152 | goto errexit; | 1147 | goto errexit; |
1153 | // reject ".." | ||
1154 | if (strstr(path, "..")) | 1148 | if (strstr(path, "..")) |
1155 | goto errexit; | 1149 | goto errexit; |
1156 | char *p = strrchr(path, '/'); | ||
1157 | assert(p); | ||
1158 | // reject trailing slash, root directory | ||
1159 | if (*(p + 1) == '\0') | ||
1160 | goto errexit; | ||
1161 | // reject trailing dot | ||
1162 | if (*(p + 1) == '.' && *(p + 2) == '\0') | ||
1163 | goto errexit; | ||
1164 | |||
1165 | // work with a copy of path | ||
1166 | char *dup = strdup(path); | ||
1167 | if (!dup) | ||
1168 | errExit("strdup"); | ||
1169 | 1150 | ||
1170 | int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC); | 1151 | int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC); |
1171 | if (parentfd == -1) | 1152 | if (parentfd == -1) |
1172 | errExit("open"); | 1153 | errExit("open"); |
1173 | |||
1174 | // traverse the path and return -1 if a symlink is encountered | ||
1175 | int fd = -1; | 1154 | int fd = -1; |
1176 | char *current_tok = EMPTY_STRING; | 1155 | |
1156 | char *last_tok = EMPTY_STRING; | ||
1157 | char *dup = strdup(path); | ||
1158 | if (!dup) | ||
1159 | errExit("strdup"); | ||
1177 | char *tok = strtok(dup, "/"); | 1160 | char *tok = strtok(dup, "/"); |
1178 | assert(tok); | 1161 | if (!tok) { // root directory |
1162 | free(dup); | ||
1163 | return parentfd; | ||
1164 | } | ||
1165 | |||
1179 | while (tok) { | 1166 | while (tok) { |
1180 | // open the element, assuming it is a directory; this fails with ENOTDIR if it is a symbolic link | 1167 | // open the element, assuming it is a directory; this fails with ENOTDIR if it is a symbolic link |
1168 | // if token is a single dot, the previous directory is reopened | ||
1181 | fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 1169 | fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
1182 | if (fd == -1) { | 1170 | if (fd == -1) { |
1183 | // if the following token is NULL, the current token is the final path element | 1171 | // if the following token is NULL, the current token is the final path element |
1184 | // try again to open it, this time using the passed flags, and return -1 or the descriptor | 1172 | // try again to open it, this time using the passed flags, and return -1 or the descriptor |
1185 | current_tok = tok; | 1173 | last_tok = tok; |
1186 | tok = strtok(NULL, "/"); | 1174 | tok = strtok(NULL, "/"); |
1187 | if (!tok) | 1175 | if (!tok) |
1188 | fd = openat(parentfd, current_tok, flags|O_NOFOLLOW); | 1176 | fd = openat(parentfd, last_tok, flags|O_NOFOLLOW); |
1189 | close(parentfd); | 1177 | close(parentfd); |
1190 | free(dup); | 1178 | free(dup); |
1191 | return fd; // -1 if open failed | 1179 | return fd; // -1 if open failed |
1192 | } | 1180 | } |
1193 | // move on to next path segment | 1181 | // move on to next path segment |
1194 | current_tok = tok; | 1182 | last_tok = tok; |
1195 | tok = strtok(NULL, "/"); | 1183 | tok = strtok(NULL, "/"); |
1196 | if (tok) { | 1184 | if (tok) { |
1197 | close(parentfd); | 1185 | close(parentfd); |
@@ -1202,13 +1190,13 @@ int safe_fd(const char *path, int flags) { | |||
1202 | // we are here because the last path element exists and is of file type directory | 1190 | // we are here because the last path element exists and is of file type directory |
1203 | // reopen it using the passed flags | 1191 | // reopen it using the passed flags |
1204 | close(fd); | 1192 | close(fd); |
1205 | fd = openat(parentfd, current_tok, flags|O_NOFOLLOW); | 1193 | fd = openat(parentfd, last_tok, flags|O_NOFOLLOW); |
1206 | close(parentfd); | 1194 | close(parentfd); |
1207 | free(dup); | 1195 | free(dup); |
1208 | return fd; // -1 if open failed | 1196 | return fd; // -1 if open failed |
1209 | 1197 | ||
1210 | errexit: | 1198 | errexit: |
1211 | fprintf(stderr, "Error: cannot open \"%s\", invalid filename\n", path); | 1199 | fprintf(stderr, "Error: cannot open \"%s\": invalid path\n", path); |
1212 | exit(1); | 1200 | exit(1); |
1213 | } | 1201 | } |
1214 | 1202 | ||