aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/util.c
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-08-01 15:23:26 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2018-08-01 15:23:26 +0200
commita1b84d1552655be4d981352ec6d04fe1a1d1cb13 (patch)
tree1859e2bae6088b3fd2863e5b6e0a40fc57614090 /src/firejail/util.c
parentMerges (diff)
downloadfirejail-a1b84d1552655be4d981352ec6d04fe1a1d1cb13.tar.gz
firejail-a1b84d1552655be4d981352ec6d04fe1a1d1cb13.tar.zst
firejail-a1b84d1552655be4d981352ec6d04fe1a1d1cb13.zip
enhance safe_fd function so it can digest arbitrary pathnames
Diffstat (limited to 'src/firejail/util.c')
-rw-r--r--src/firejail/util.c53
1 files changed, 35 insertions, 18 deletions
diff --git a/src/firejail/util.c b/src/firejail/util.c
index fa32ffcc8..18f837d7e 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -1059,54 +1059,71 @@ void disable_file_path(const char *path, const char *file) {
1059// user controlled paths. Passed flags are ignored if path is a top level directory. 1059// user controlled paths. Passed flags are ignored if path is a top level directory.
1060int safe_fd(const char *path, int flags) { 1060int safe_fd(const char *path, int flags) {
1061 assert(path); 1061 assert(path);
1062 int fd = -1; 1062
1063 // reject empty string, relative path
1064 if (*path != '/')
1065 goto errexit;
1066 // reject ".."
1067 if (strstr(path, ".."))
1068 goto errexit;
1063 1069
1064 // work with a copy of path 1070 // work with a copy of path
1065 char *dup = strdup(path); 1071 char *dup = strdup(path);
1066 if (dup == NULL) 1072 if (dup == NULL)
1067 errExit("strdup"); 1073 errExit("strdup");
1068 // reject relative path and empty string
1069 if (*dup != '/') {
1070 fprintf(stderr, "Error: invalid pathname: %s\n", path);
1071 exit(1);
1072 }
1073 1074
1074 char *p = strrchr(dup, '/'); 1075 char *p = strrchr(dup, '/');
1075 if (p == NULL) 1076 if (p == NULL)
1076 errExit("strrchr"); 1077 errExit("strrchr");
1077 // reject trailing slash and root dir 1078 // reject trailing slash, root directory
1078 if (*(p + 1) == '\0') { 1079 if (*(p + 1) == '\0')
1079 fprintf(stderr, "Error: invalid pathname: %s\n", path); 1080 goto errexit;
1080 exit(1); 1081 // reject trailing dot
1081 } 1082 if (*(p + 1) == '.' && *(p + 2) == '\0')
1083 goto errexit;
1084 // if there is more than one path segment, keep the last one for later
1085 if (p != dup)
1086 *p = '\0';
1082 1087
1083 int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC); 1088 int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC);
1084 if (parentfd == -1) 1089 if (parentfd == -1)
1085 errExit("open"); 1090 errExit("open");
1086 1091
1087 // if there is more than one path segment, keep the last one for later 1092 // traverse the path and return -1 if a symlink is encountered
1088 if (p != dup) 1093 int entered = 0;
1089 *p = '\0'; 1094 int fd = -1;
1090
1091 // traverse the path, return -1 if a symlink is encountered
1092 char *tok = strtok(dup, "/"); 1095 char *tok = strtok(dup, "/");
1093 if (tok == NULL)
1094 errExit("strtok");
1095 while (tok) { 1096 while (tok) {
1097 // skip all "/./"
1098 if (strcmp(tok, ".") == 0) {
1099 tok = strtok(NULL, "/");
1100 continue;
1101 }
1102 entered = 1;
1103
1104 // open the directory
1096 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 1105 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
1097 close(parentfd); 1106 close(parentfd);
1098 if (fd == -1) { 1107 if (fd == -1) {
1099 free(dup); 1108 free(dup);
1100 return -1; 1109 return -1;
1101 } 1110 }
1111
1102 parentfd = fd; 1112 parentfd = fd;
1103 tok = strtok(NULL, "/"); 1113 tok = strtok(NULL, "/");
1104 } 1114 }
1105 if (p != dup) { 1115 if (p != dup) {
1116 // consistent flags for top level directories (////foo, /.///foo)
1117 if (!entered)
1118 flags = O_PATH|O_DIRECTORY|O_CLOEXEC;
1106 // open last path segment 1119 // open last path segment
1107 fd = openat(parentfd, p + 1, flags|O_NOFOLLOW); 1120 fd = openat(parentfd, p + 1, flags|O_NOFOLLOW);
1108 close(parentfd); 1121 close(parentfd);
1109 } 1122 }
1110 free(dup); 1123 free(dup);
1111 return fd; // -1 if open failed 1124 return fd; // -1 if open failed
1125
1126errexit:
1127 fprintf(stderr, "Error: cannot open \"%s\", invalid filename\n", path);
1128 exit(1);
1112} 1129}