aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2020-11-23 18:24:14 +0100
committerLibravatar smitsohu <smitsohu@gmail.com>2020-11-23 18:24:14 +0100
commita0b0d8fbbf063c9a2bb0b719e5fbd4cb766f2f6d (patch)
treee7dfcee2baf954a4370d7f3f18acd4652115f14a /src
parentadd read-only items for ksh and mksh (diff)
downloadfirejail-a0b0d8fbbf063c9a2bb0b719e5fbd4cb766f2f6d.tar.gz
firejail-a0b0d8fbbf063c9a2bb0b719e5fbd4cb766f2f6d.tar.zst
firejail-a0b0d8fbbf063c9a2bb0b719e5fbd4cb766f2f6d.zip
use openat2 syscall when available
Diffstat (limited to 'src')
-rw-r--r--src/firejail/util.c63
1 files changed, 37 insertions, 26 deletions
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 02befdc12..e8b35a64b 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -29,6 +29,7 @@
29#include <sys/ioctl.h> 29#include <sys/ioctl.h>
30#include <termios.h> 30#include <termios.h>
31#include <sys/wait.h> 31#include <sys/wait.h>
32#include <sys/syscall.h>
32#include <limits.h> 33#include <limits.h>
33 34
34#include <fcntl.h> 35#include <fcntl.h>
@@ -36,6 +37,10 @@
36#define O_PATH 010000000 37#define O_PATH 010000000
37#endif 38#endif
38 39
40#ifdef __NR_openat2
41#include <linux/openat2.h>
42#endif
43
39#define MAX_GROUPS 1024 44#define MAX_GROUPS 1024
40#define MAXBUF 4098 45#define MAXBUF 4098
41#define EMPTY_STRING ("") 46#define EMPTY_STRING ("")
@@ -1157,46 +1162,57 @@ void disable_file_path(const char *path, const char *file) {
1157 free(fname); 1162 free(fname);
1158} 1163}
1159 1164
1160// open file without following any symbolic link 1165// open an existing file without following any symbolic link
1161// returns a file descriptor on success, or -1 if a symlink is found
1162int safe_fd(const char *path, int flags) { 1166int safe_fd(const char *path, int flags) {
1163 assert(path); 1167 assert(path);
1164 if (*path != '/') 1168 if (*path != '/' || strstr(path, "..")) {
1165 goto errexit; 1169 fprintf(stderr, "Error: invalid path %s\n", path);
1166 if (strstr(path, "..")) 1170 exit(1);
1167 goto errexit; 1171 }
1168 1172 flags |= O_NOFOLLOW;
1169 int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC);
1170 if (parentfd == -1)
1171 errExit("open");
1172 int fd = -1; 1173 int fd = -1;
1173 1174
1174 char *last_tok = EMPTY_STRING; 1175#ifdef __NR_openat2 // kernel 5.6 or better
1176 struct open_how oh;
1177 memset(&oh, 0, sizeof(oh));
1178 oh.flags = flags;
1179 oh.resolve = RESOLVE_NO_SYMLINKS;
1180 fd = syscall(__NR_openat2, -1, path, &oh, sizeof(struct open_how));
1181 if (fd != -1 || errno != ENOSYS)
1182 return fd;
1183#endif
1184
1185 // openat2 syscall is not available, traverse path and
1186 // check each component if it is a symbolic link or not
1175 char *dup = strdup(path); 1187 char *dup = strdup(path);
1176 if (!dup) 1188 if (!dup)
1177 errExit("strdup"); 1189 errExit("strdup");
1178 char *tok = strtok(dup, "/"); 1190 char *tok = strtok(dup, "/");
1179 if (!tok) { // root directory 1191 if (!tok) { // root directory
1180 free(dup); 1192 free(dup);
1181 return parentfd; 1193 return open("/", flags);
1182 } 1194 }
1195 char *last_tok = EMPTY_STRING;
1196 int parentfd = open("/", O_PATH|O_CLOEXEC);
1197 if (parentfd == -1)
1198 errExit("open");
1183 1199
1184 while(1) { 1200 while(1) {
1185 // open the element, assuming it is a directory; this fails with ENOTDIR if it is a symbolic link 1201 // open path component, assuming it is a directory; this fails with ENOTDIR if it is a symbolic link
1186 // if token is a single dot, the previous directory is reopened 1202 // if token is a single dot, the previous directory is reopened
1187 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 1203 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
1188 if (fd == -1) { 1204 if (fd == -1) {
1189 // if the following token is NULL, the current token is the final path element 1205 // if the following token is NULL, the current token is the final path component
1190 // try again to open it, this time using the passed flags, and return -1 or the descriptor 1206 // try again to open it, this time using the passed flags, and return -1 or the descriptor
1191 last_tok = tok; 1207 last_tok = tok;
1192 tok = strtok(NULL, "/"); 1208 tok = strtok(NULL, "/");
1193 if (!tok) 1209 if (!tok)
1194 fd = openat(parentfd, last_tok, flags|O_NOFOLLOW); 1210 fd = openat(parentfd, last_tok, flags);
1195 close(parentfd); 1211 close(parentfd);
1196 free(dup); 1212 free(dup);
1197 return fd; // -1 if open failed 1213 return fd;
1198 } 1214 }
1199 // move on to next path segment 1215 // move on to next path component
1200 last_tok = tok; 1216 last_tok = tok;
1201 tok = strtok(NULL, "/"); 1217 tok = strtok(NULL, "/");
1202 if (!tok) 1218 if (!tok)
@@ -1204,18 +1220,13 @@ int safe_fd(const char *path, int flags) {
1204 close(parentfd); 1220 close(parentfd);
1205 parentfd = fd; 1221 parentfd = fd;
1206 } 1222 }
1207 1223 // getting here when the last path component exists and is of file type directory
1208 // we are here because the last path element exists and is of file type directory
1209 // reopen it using the passed flags 1224 // reopen it using the passed flags
1210 close(fd); 1225 close(fd);
1211 fd = openat(parentfd, last_tok, flags|O_NOFOLLOW); 1226 fd = openat(parentfd, last_tok, flags);
1212 close(parentfd); 1227 close(parentfd);
1213 free(dup); 1228 free(dup);
1214 return fd; // -1 if open failed 1229 return fd;
1215
1216errexit:
1217 fprintf(stderr, "Error: cannot open \"%s\": invalid path\n", path);
1218 exit(1);
1219} 1230}
1220 1231
1221int has_handler(pid_t pid, int signal) { 1232int has_handler(pid_t pid, int signal) {
@@ -1321,7 +1332,7 @@ static int has_link(const char *dir) {
1321 assert(dir); 1332 assert(dir);
1322 int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 1333 int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
1323 if (fd == -1) { 1334 if (fd == -1) {
1324 if (errno == ENOTDIR && is_dir(dir)) 1335 if ((errno == ELOOP || errno == ENOTDIR) && is_dir(dir))
1325 return 1; 1336 return 1;
1326 } 1337 }
1327 else 1338 else