diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/join.c | 19 | ||||
-rw-r--r-- | src/firejail/main.c | 13 | ||||
-rw-r--r-- | src/firejail/mountinfo.c | 129 | ||||
-rw-r--r-- | src/firejail/run_symlink.c | 3 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 21 | ||||
-rw-r--r-- | src/firejail/util.c | 104 |
7 files changed, 184 insertions, 107 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 7a711cef3..0654439d6 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -98,6 +98,7 @@ | |||
98 | #define RUN_PASSWD_FILE "/run/firejail/mnt/passwd" | 98 | #define RUN_PASSWD_FILE "/run/firejail/mnt/passwd" |
99 | #define RUN_GROUP_FILE "/run/firejail/mnt/group" | 99 | #define RUN_GROUP_FILE "/run/firejail/mnt/group" |
100 | #define RUN_FSLOGGER_FILE "/run/firejail/mnt/fslogger" | 100 | #define RUN_FSLOGGER_FILE "/run/firejail/mnt/fslogger" |
101 | #define RUN_UMASK_FILE "/run/firejail/mnt/umask" | ||
101 | #define RUN_OVERLAY_ROOT "/run/firejail/mnt/oroot" | 102 | #define RUN_OVERLAY_ROOT "/run/firejail/mnt/oroot" |
102 | 103 | ||
103 | 104 | ||
@@ -391,6 +392,7 @@ extern int login_shell; | |||
391 | extern int parent_to_child_fds[2]; | 392 | extern int parent_to_child_fds[2]; |
392 | extern int child_to_parent_fds[2]; | 393 | extern int child_to_parent_fds[2]; |
393 | extern pid_t sandbox_pid; | 394 | extern pid_t sandbox_pid; |
395 | extern mode_t orig_umask; | ||
394 | extern unsigned long long start_timestamp; | 396 | extern unsigned long long start_timestamp; |
395 | 397 | ||
396 | #define MAX_ARGS 128 // maximum number of command arguments (argc) | 398 | #define MAX_ARGS 128 // maximum number of command arguments (argc) |
diff --git a/src/firejail/join.c b/src/firejail/join.c index d4a2389c6..e6da4c248 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -205,6 +205,22 @@ static void extract_user_namespace(pid_t pid) { | |||
205 | free(uidmap); | 205 | free(uidmap); |
206 | } | 206 | } |
207 | 207 | ||
208 | static void extract_umask(pid_t pid) { | ||
209 | char *fname; | ||
210 | if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_UMASK_FILE) == -1) | ||
211 | errExit("asprintf"); | ||
212 | |||
213 | FILE *fp = fopen(fname, "re"); | ||
214 | free(fname); | ||
215 | if (!fp) | ||
216 | return; | ||
217 | if (fscanf(fp, "%4o", &orig_umask) < 1) { | ||
218 | fprintf(stderr, "Error: cannot read umask\n"); | ||
219 | exit(1); | ||
220 | } | ||
221 | fclose(fp); | ||
222 | } | ||
223 | |||
208 | void join(pid_t pid, int argc, char **argv, int index) { | 224 | void join(pid_t pid, int argc, char **argv, int index) { |
209 | EUID_ASSERT(); | 225 | EUID_ASSERT(); |
210 | char *homedir = cfg.homedir; | 226 | char *homedir = cfg.homedir; |
@@ -254,6 +270,9 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
254 | if (cfg.cgroup) // not available for uid 0 | 270 | if (cfg.cgroup) // not available for uid 0 |
255 | set_cgroup(cfg.cgroup); | 271 | set_cgroup(cfg.cgroup); |
256 | 272 | ||
273 | // get umask, it will be set by start_application() | ||
274 | extract_umask(pid); | ||
275 | |||
257 | // join namespaces | 276 | // join namespaces |
258 | if (arg_join_network) { | 277 | if (arg_join_network) { |
259 | if (join_namespace(pid, "net")) | 278 | if (join_namespace(pid, "net")) |
diff --git a/src/firejail/main.c b/src/firejail/main.c index ef8d8172f..42ed504f9 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -135,6 +135,7 @@ char *fullargv[MAX_ARGS]; // expanded argv for restricted shell | |||
135 | int fullargc = 0; | 135 | int fullargc = 0; |
136 | static pid_t child = 0; | 136 | static pid_t child = 0; |
137 | pid_t sandbox_pid; | 137 | pid_t sandbox_pid; |
138 | mode_t orig_umask = 022; | ||
138 | unsigned long long start_timestamp; | 139 | unsigned long long start_timestamp; |
139 | 140 | ||
140 | static void clear_atexit(void) { | 141 | static void clear_atexit(void) { |
@@ -833,7 +834,9 @@ static void run_builder(int argc, char **argv) { | |||
833 | errExit("setgid/getgid"); | 834 | errExit("setgid/getgid"); |
834 | if (setuid(getuid()) < 0) | 835 | if (setuid(getuid()) < 0) |
835 | errExit("setuid/getuid"); | 836 | errExit("setuid/getuid"); |
837 | |||
836 | assert(getenv("LD_PRELOAD") == NULL); | 838 | assert(getenv("LD_PRELOAD") == NULL); |
839 | umask(orig_umask); | ||
837 | 840 | ||
838 | argv[0] = LIBDIR "/firejail/fbuilder"; | 841 | argv[0] = LIBDIR "/firejail/fbuilder"; |
839 | execvp(argv[0], argv); | 842 | execvp(argv[0], argv); |
@@ -858,6 +861,9 @@ int main(int argc, char **argv) { | |||
858 | EUID_INIT(); | 861 | EUID_INIT(); |
859 | EUID_USER(); | 862 | EUID_USER(); |
860 | 863 | ||
864 | // sanitize the umask | ||
865 | orig_umask = umask(022); | ||
866 | |||
861 | // check if the user is allowed to use firejail | 867 | // check if the user is allowed to use firejail |
862 | init_cfg(argc, argv); | 868 | init_cfg(argc, argv); |
863 | 869 | ||
@@ -991,9 +997,10 @@ int main(int argc, char **argv) { | |||
991 | EUID_USER();} | 997 | EUID_USER();} |
992 | #endif | 998 | #endif |
993 | 999 | ||
994 | drop_privs(1); | 1000 | drop_privs(1); |
995 | int rv = system(argv[2]); | 1001 | umask(orig_umask); |
996 | exit(rv); | 1002 | int rv = system(argv[2]); |
1003 | exit(rv); | ||
997 | } | 1004 | } |
998 | } | 1005 | } |
999 | } | 1006 | } |
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c new file mode 100644 index 000000000..4a7816901 --- /dev/null +++ b/src/firejail/mountinfo.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2018 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "firejail.h" | ||
22 | |||
23 | #define MAX_BUF 4096 | ||
24 | static char mbuf[MAX_BUF]; | ||
25 | static MountData mdata; | ||
26 | |||
27 | // Convert octal escape sequence to decimal value | ||
28 | static int read_oct(const char *path) { | ||
29 | int decimal = 0; | ||
30 | int digit, i; | ||
31 | // there are always three octal digits | ||
32 | for (i = 1; i < 4; i++) { | ||
33 | digit = *(path + i); | ||
34 | if (digit < '0' || digit > '7') { | ||
35 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | ||
36 | exit(1); | ||
37 | } | ||
38 | decimal = (decimal + digit - '0') * 8; | ||
39 | } | ||
40 | decimal /= 8; | ||
41 | return decimal; | ||
42 | } | ||
43 | |||
44 | // Restore empty spaces in pathnames extracted from /proc/self/mountinfo | ||
45 | static void unmangle_path(char *path) { | ||
46 | char *p = strchr(path, '\\'); | ||
47 | if (p) { | ||
48 | if (read_oct(p) == ' ') { | ||
49 | *p = ' '; | ||
50 | int i = 3; | ||
51 | do { | ||
52 | p++; | ||
53 | if (*(p + i) == '\\' && read_oct(p + i) == ' ') { | ||
54 | *p = ' '; | ||
55 | i += 3; | ||
56 | } | ||
57 | else | ||
58 | *p = *(p + i); | ||
59 | } while (*p); | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // Get info regarding the last kernel mount operation. | ||
65 | // The return value points to a static area, and will be overwritten by subsequent calls. | ||
66 | // The function does an exit(1) if anything goes wrong. | ||
67 | MountData *get_last_mount(void) { | ||
68 | // open /proc/self/mountinfo | ||
69 | FILE *fp = fopen("/proc/self/mountinfo", "r"); | ||
70 | if (!fp) | ||
71 | goto errexit; | ||
72 | |||
73 | mbuf[0] = '\0'; | ||
74 | while (fgets(mbuf, MAX_BUF, fp)); | ||
75 | fclose(fp); | ||
76 | if (arg_debug) | ||
77 | printf("%s", mbuf); | ||
78 | |||
79 | // extract filesystem name, directory and filesystem type | ||
80 | // examples: | ||
81 | // 587 543 8:1 /tmp /etc rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=ordered | ||
82 | // mdata.fsname: /tmp | ||
83 | // mdata.dir: /etc | ||
84 | // mdata.fstype: ext4 | ||
85 | // 585 564 0:76 / /home/netblue/.cache rw,nosuid,nodev - tmpfs tmpfs rw | ||
86 | // mdata.fsname: / | ||
87 | // mdata.dir: /home/netblue/.cache | ||
88 | // mdata.fstype: tmpfs | ||
89 | memset(&mdata, 0, sizeof(mdata)); | ||
90 | char *ptr = strtok(mbuf, " "); | ||
91 | if (!ptr) | ||
92 | goto errexit; | ||
93 | |||
94 | int cnt = 1; | ||
95 | while ((ptr = strtok(NULL, " ")) != NULL) { | ||
96 | cnt++; | ||
97 | if (cnt == 4) | ||
98 | mdata.fsname = ptr; | ||
99 | else if (cnt == 5) { | ||
100 | mdata.dir = ptr; | ||
101 | break; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | ptr = strtok(NULL, "-"); | ||
106 | if (!ptr) | ||
107 | goto errexit; | ||
108 | |||
109 | ptr = strtok(NULL, " "); | ||
110 | if (!ptr) | ||
111 | goto errexit; | ||
112 | mdata.fstype = ptr++; | ||
113 | |||
114 | if (mdata.fsname == NULL || | ||
115 | mdata.dir == NULL || | ||
116 | mdata.fstype == NULL) | ||
117 | goto errexit; | ||
118 | |||
119 | unmangle_path(mdata.fsname); | ||
120 | unmangle_path(mdata.dir); | ||
121 | |||
122 | if (arg_debug) | ||
123 | printf("fsname=%s dir=%s fstype=%s\n", mdata.fsname, mdata.dir, mdata.fstype); | ||
124 | return &mdata; | ||
125 | |||
126 | errexit: | ||
127 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | ||
128 | exit(1); | ||
129 | } | ||
diff --git a/src/firejail/run_symlink.c b/src/firejail/run_symlink.c index 2bb4a2ed7..5714206d4 100644 --- a/src/firejail/run_symlink.c +++ b/src/firejail/run_symlink.c | |||
@@ -89,6 +89,9 @@ void run_symlink(int argc, char **argv, int run_as_is) { | |||
89 | 89 | ||
90 | free(selfpath); | 90 | free(selfpath); |
91 | 91 | ||
92 | // restore original umask | ||
93 | umask(orig_umask); | ||
94 | |||
92 | // desktop integration is not supported for root user; instead, the original program is started | 95 | // desktop integration is not supported for root user; instead, the original program is started |
93 | if (getuid() == 0 || run_as_is) { | 96 | if (getuid() == 0 || run_as_is) { |
94 | argv[0] = program; | 97 | argv[0] = program; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 7922da9b9..66881c040 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -126,6 +126,19 @@ void save_nogroups(void) { | |||
126 | 126 | ||
127 | } | 127 | } |
128 | 128 | ||
129 | void save_umask(void) { | ||
130 | FILE *fp = fopen(RUN_UMASK_FILE, "wxe"); | ||
131 | if (fp) { | ||
132 | fprintf(fp, "%o\n", orig_umask); | ||
133 | SET_PERMS_STREAM(fp, 0, 0, 0644); // assume mode 0644 | ||
134 | fclose(fp); | ||
135 | } | ||
136 | else { | ||
137 | fprintf(stderr, "Error: cannot save umask\n"); | ||
138 | exit(1); | ||
139 | } | ||
140 | } | ||
141 | |||
129 | static void sandbox_if_up(Bridge *br) { | 142 | static void sandbox_if_up(Bridge *br) { |
130 | assert(br); | 143 | assert(br); |
131 | if (!br->configured) | 144 | if (!br->configured) |
@@ -367,6 +380,9 @@ void start_application(int no_sandbox) { | |||
367 | env_defaults(); | 380 | env_defaults(); |
368 | env_apply(); | 381 | env_apply(); |
369 | } | 382 | } |
383 | // restore original umask | ||
384 | umask(orig_umask); | ||
385 | |||
370 | if (arg_debug) { | 386 | if (arg_debug) { |
371 | printf("starting application\n"); | 387 | printf("starting application\n"); |
372 | printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); | 388 | printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); |
@@ -555,6 +571,11 @@ int sandbox(void* sandbox_arg) { | |||
555 | fs_logger("install mount namespace"); | 571 | fs_logger("install mount namespace"); |
556 | 572 | ||
557 | //**************************** | 573 | //**************************** |
574 | // save the umask | ||
575 | //**************************** | ||
576 | save_umask(); | ||
577 | |||
578 | //**************************** | ||
558 | // netfilter | 579 | // netfilter |
559 | //**************************** | 580 | //**************************** |
560 | if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter | 581 | if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter |
diff --git a/src/firejail/util.c b/src/firejail/util.c index 52db987b7..f634ff700 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -1045,110 +1045,6 @@ void disable_file_path(const char *path, const char *file) { | |||
1045 | free(fname); | 1045 | free(fname); |
1046 | } | 1046 | } |
1047 | 1047 | ||
1048 | // Restore empty spaces in pathnames extracted from /proc/self/mountinfo | ||
1049 | static void unmangle_path(char *path) { | ||
1050 | int i, decimal; | ||
1051 | char *worker; | ||
1052 | |||
1053 | char *p = strchr(path, '\\'); | ||
1054 | while (p) { | ||
1055 | // convert octal to decimal | ||
1056 | decimal = 0; | ||
1057 | for (i = 1; i < 4; i++) { | ||
1058 | worker = p + i; | ||
1059 | // there are always three octal digits | ||
1060 | if (*worker < '0' || *worker > '7') { | ||
1061 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | ||
1062 | exit(1); | ||
1063 | } | ||
1064 | decimal = (*worker - '0' + decimal) * 8; | ||
1065 | } | ||
1066 | decimal /= 8; | ||
1067 | // do the replacement | ||
1068 | if (decimal == ' ') { | ||
1069 | *p = ' '; | ||
1070 | worker = p; | ||
1071 | do { | ||
1072 | worker++; | ||
1073 | *worker = *(worker + 3); | ||
1074 | } while (*worker); | ||
1075 | } | ||
1076 | |||
1077 | p = strchr(p + 1, '\\'); | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | #define MAX_BUF 4096 | ||
1082 | static char mbuf[MAX_BUF]; | ||
1083 | static MountData mdata; | ||
1084 | |||
1085 | // Get info regarding the last kernel mount operation. | ||
1086 | // The return value points to a static area, and will be overwritten by subsequent calls. | ||
1087 | // The function does an exit(1) if anything goes wrong. | ||
1088 | MountData *get_last_mount(void) { | ||
1089 | // open /proc/self/mountinfo | ||
1090 | FILE *fp = fopen("/proc/self/mountinfo", "r"); | ||
1091 | if (!fp) | ||
1092 | goto errexit; | ||
1093 | |||
1094 | mbuf[0] = '\0'; | ||
1095 | while (fgets(mbuf, MAX_BUF, fp)); | ||
1096 | fclose(fp); | ||
1097 | if (arg_debug) | ||
1098 | printf("%s", mbuf); | ||
1099 | |||
1100 | // extract filesystem name, directory and filesystem type | ||
1101 | // examples: | ||
1102 | // 587 543 8:1 /tmp /etc rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=ordered | ||
1103 | // mdata.fsname: /tmp | ||
1104 | // mdata.dir: /etc | ||
1105 | // mdata.fstype: ext4 | ||
1106 | // 585 564 0:76 / /home/netblue/.cache rw,nosuid,nodev - tmpfs tmpfs rw | ||
1107 | // mdata.fsname: / | ||
1108 | // mdata.dir: /home/netblue/.cache | ||
1109 | // mdata.fstype: tmpfs | ||
1110 | memset(&mdata, 0, sizeof(mdata)); | ||
1111 | char *ptr = strtok(mbuf, " "); | ||
1112 | if (!ptr) | ||
1113 | goto errexit; | ||
1114 | |||
1115 | int cnt = 1; | ||
1116 | while ((ptr = strtok(NULL, " ")) != NULL) { | ||
1117 | cnt++; | ||
1118 | if (cnt == 4) | ||
1119 | mdata.fsname = ptr; | ||
1120 | else if (cnt == 5) { | ||
1121 | mdata.dir = ptr; | ||
1122 | break; | ||
1123 | } | ||
1124 | } | ||
1125 | |||
1126 | ptr = strtok(NULL, "-"); | ||
1127 | if (!ptr) | ||
1128 | goto errexit; | ||
1129 | |||
1130 | ptr = strtok(NULL, " "); | ||
1131 | if (!ptr) | ||
1132 | goto errexit; | ||
1133 | mdata.fstype = ptr++; | ||
1134 | |||
1135 | if (mdata.fsname == NULL || | ||
1136 | mdata.dir == NULL || | ||
1137 | mdata.fstype == NULL) | ||
1138 | goto errexit; | ||
1139 | |||
1140 | unmangle_path(mdata.fsname); | ||
1141 | unmangle_path(mdata.dir); | ||
1142 | |||
1143 | if (arg_debug) | ||
1144 | printf("fsname=%s dir=%s fstype=%s\n", mdata.fsname, mdata.dir, mdata.fstype); | ||
1145 | return &mdata; | ||
1146 | |||
1147 | errexit: | ||
1148 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | ||
1149 | exit(1); | ||
1150 | } | ||
1151 | |||
1152 | // The returned file descriptor should be suitable for privileged operations on | 1048 | // The returned file descriptor should be suitable for privileged operations on |
1153 | // user controlled paths. Passed flags are ignored if path is a top level directory. | 1049 | // user controlled paths. Passed flags are ignored if path is a top level directory. |
1154 | int safe_fd(const char *path, int flags) { | 1050 | int safe_fd(const char *path, int flags) { |