diff options
Diffstat (limited to 'src/firejail/fs_dev.c')
-rw-r--r-- | src/firejail/fs_dev.c | 181 |
1 files changed, 117 insertions, 64 deletions
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c index 2fd450391..d710e98f2 100644 --- a/src/firejail/fs_dev.c +++ b/src/firejail/fs_dev.c | |||
@@ -30,17 +30,75 @@ | |||
30 | #endif | 30 | #endif |
31 | #include <sys/types.h> | 31 | #include <sys/types.h> |
32 | 32 | ||
33 | typedef struct { | ||
34 | const char *dev_fname; | ||
35 | const char *run_fname; | ||
36 | int sound; | ||
37 | int hw3d; | ||
38 | } DevEntry; | ||
39 | |||
40 | static DevEntry dev[] = { | ||
41 | {"/dev/snd", RUN_DEV_DIR "/snd", 1, 0}, // sound device | ||
42 | {"/dev/dri", RUN_DEV_DIR "/dri", 0, 1}, // 3d device | ||
43 | {"/dev/nvidia0", RUN_DEV_DIR "/nvidia0", 0, 1}, | ||
44 | {"/dev/nvidia1", RUN_DEV_DIR "/nvidia1", 0, 1}, | ||
45 | {"/dev/nvidia2", RUN_DEV_DIR "/nvidia2", 0, 1}, | ||
46 | {"/dev/nvidia3", RUN_DEV_DIR "/nvidia3", 0, 1}, | ||
47 | {"/dev/nvidia4", RUN_DEV_DIR "/nvidia4", 0, 1}, | ||
48 | {"/dev/nvidia5", RUN_DEV_DIR "/nvidia5", 0, 1}, | ||
49 | {"/dev/nvidia6", RUN_DEV_DIR "/nvidia6", 0, 1}, | ||
50 | {"/dev/nvidia7", RUN_DEV_DIR "/nvidia7", 0, 1}, | ||
51 | {"/dev/nvidia8", RUN_DEV_DIR "/nvidia8", 0, 1}, | ||
52 | {"/dev/nvidia9", RUN_DEV_DIR "/nvidia9", 0, 1}, | ||
53 | {"/dev/nvidiactl", RUN_DEV_DIR "/nvidiactl", 0, 1}, | ||
54 | {"/dev/nvidia-modset", RUN_DEV_DIR "/nvidia-modset", 0, 1}, | ||
55 | {"/dev/nvidia-uvm", RUN_DEV_DIR "/nvidia-uvm", 0, 1}, | ||
56 | {NULL, NULL, 0, 0} | ||
57 | }; | ||
58 | |||
59 | static void deventry_mount(void) { | ||
60 | int i = 0; | ||
61 | while (dev[i].dev_fname != NULL) { | ||
62 | struct stat s; | ||
63 | if (stat(dev[i].run_fname, &s) == 0) { | ||
64 | int dir = is_dir(dev[i].run_fname); | ||
65 | if (arg_debug) | ||
66 | printf("mounting %s %s\n", dev[i].run_fname, (dir)? "directory": "file"); | ||
67 | if (dir) { | ||
68 | mkdir_attr(dev[i].dev_fname, 0755, 0, 0); | ||
69 | } | ||
70 | else { | ||
71 | struct stat s; | ||
72 | if (stat(dev[i].run_fname, &s) == -1) { | ||
73 | if (arg_debug) | ||
74 | printf("Warning: cannot stat %s file\n", dev[i].run_fname); | ||
75 | i++; | ||
76 | continue; | ||
77 | } | ||
78 | FILE *fp = fopen(dev[i].dev_fname, "w"); | ||
79 | if (fp) { | ||
80 | fprintf(fp, "\n"); | ||
81 | SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode); | ||
82 | fclose(fp); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | if (mount(dev[i].run_fname, dev[i].dev_fname, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
87 | errExit("mounting dev file"); | ||
88 | fs_logger2("whitelist", dev[i].dev_fname); | ||
89 | } | ||
90 | |||
91 | i++; | ||
92 | } | ||
93 | } | ||
94 | |||
33 | static void create_char_dev(const char *path, mode_t mode, int major, int minor) { | 95 | static void create_char_dev(const char *path, mode_t mode, int major, int minor) { |
34 | dev_t dev = makedev(major, minor); | 96 | dev_t dev = makedev(major, minor); |
35 | int rv = mknod(path, S_IFCHR | mode, dev); | 97 | if (mknod(path, S_IFCHR | mode, dev) == -1) |
36 | if (rv == -1) | ||
37 | goto errexit; | 98 | goto errexit; |
38 | |||
39 | |||
40 | if (chmod(path, mode) < 0) | 99 | if (chmod(path, mode) < 0) |
41 | goto errexit; | 100 | goto errexit; |
42 | if (chown(path, 0, 0) < 0) | 101 | ASSERT_PERMS(path, 0, 0, mode); |
43 | goto errexit; | ||
44 | 102 | ||
45 | return; | 103 | return; |
46 | 104 | ||
@@ -62,35 +120,19 @@ errexit: | |||
62 | } | 120 | } |
63 | 121 | ||
64 | void fs_private_dev(void){ | 122 | void fs_private_dev(void){ |
65 | int rv; | ||
66 | // install a new /dev directory | 123 | // install a new /dev directory |
67 | if (arg_debug) | 124 | if (arg_debug) |
68 | printf("Mounting tmpfs on /dev\n"); | 125 | printf("Mounting tmpfs on /dev\n"); |
69 | 126 | ||
70 | int have_dri = 0; | ||
71 | struct stat s; | ||
72 | if (stat("/dev/dri", &s) == 0) | ||
73 | have_dri = 1; | ||
74 | |||
75 | // create DRI_DIR | 127 | // create DRI_DIR |
76 | fs_build_mnt_dir(); | 128 | // keep a copy of dev directory |
77 | if (have_dri) { | 129 | mkdir_attr(RUN_DEV_DIR, 0755, 0, 0); |
78 | /* coverity[toctou] */ | 130 | if (mount("/dev", RUN_DEV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) |
79 | rv = mkdir(RUN_DRI_DIR, 0755); | 131 | errExit("mounting /dev/dri"); |
80 | if (rv == -1) | 132 | |
81 | errExit("mkdir"); | 133 | // create DEVLOG_FILE |
82 | if (chown(RUN_DRI_DIR, 0, 0) < 0) | ||
83 | errExit("chown"); | ||
84 | if (chmod(RUN_DRI_DIR, 0755) < 0) | ||
85 | errExit("chmod"); | ||
86 | |||
87 | // keep a copy of /dev/dri under DRI_DIR | ||
88 | if (mount("/dev/dri", RUN_DRI_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
89 | errExit("mounting /dev/dri"); | ||
90 | } | ||
91 | |||
92 | // restore /dev/log | ||
93 | int have_devlog = 0; | 134 | int have_devlog = 0; |
135 | struct stat s; | ||
94 | if (stat("/dev/log", &s) == 0) { | 136 | if (stat("/dev/log", &s) == 0) { |
95 | have_devlog = 1; | 137 | have_devlog = 1; |
96 | FILE *fp = fopen(RUN_DEVLOG_FILE, "w"); | 138 | FILE *fp = fopen(RUN_DEVLOG_FILE, "w"); |
@@ -108,6 +150,8 @@ void fs_private_dev(void){ | |||
108 | if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | 150 | if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) |
109 | errExit("mounting /dev"); | 151 | errExit("mounting /dev"); |
110 | fs_logger("tmpfs /dev"); | 152 | fs_logger("tmpfs /dev"); |
153 | |||
154 | deventry_mount(); | ||
111 | 155 | ||
112 | // bring back /dev/log | 156 | // bring back /dev/log |
113 | if (have_devlog) { | 157 | if (have_devlog) { |
@@ -120,32 +164,14 @@ void fs_private_dev(void){ | |||
120 | fs_logger("clone /dev/log"); | 164 | fs_logger("clone /dev/log"); |
121 | } | 165 | } |
122 | } | 166 | } |
167 | if (mount(RUN_RO_DIR, RUN_DEV_DIR, "none", MS_BIND, "mode=400,gid=0") < 0) | ||
168 | errExit("disable /dev/snd"); | ||
123 | 169 | ||
124 | // bring back the /dev/dri directory | ||
125 | if (have_dri) { | ||
126 | /* coverity[toctou] */ | ||
127 | rv = mkdir("/dev/dri", 0755); | ||
128 | if (rv == -1) | ||
129 | errExit("mkdir"); | ||
130 | if (chown("/dev/dri", 0, 0) < 0) | ||
131 | errExit("chown"); | ||
132 | if (chmod("/dev/dri",0755) < 0) | ||
133 | errExit("chmod"); | ||
134 | if (mount(RUN_DRI_DIR, "/dev/dri", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
135 | errExit("mounting /dev/dri"); | ||
136 | fs_logger("whitelist /dev/dri"); | ||
137 | } | ||
138 | 170 | ||
139 | // create /dev/shm | 171 | // create /dev/shm |
140 | if (arg_debug) | 172 | if (arg_debug) |
141 | printf("Create /dev/shm directory\n"); | 173 | printf("Create /dev/shm directory\n"); |
142 | rv = mkdir("/dev/shm", 01777); | 174 | mkdir_attr("/dev/shm", 01777, 0, 0); |
143 | if (rv == -1) | ||
144 | errExit("mkdir"); | ||
145 | if (chown("/dev/shm", 0, 0) < 0) | ||
146 | errExit("chown"); | ||
147 | if (chmod("/dev/shm", 01777) < 0) | ||
148 | errExit("chmod"); | ||
149 | fs_logger("mkdir /dev/shm"); | 175 | fs_logger("mkdir /dev/shm"); |
150 | 176 | ||
151 | // create devices | 177 | // create devices |
@@ -167,13 +193,7 @@ void fs_private_dev(void){ | |||
167 | #endif | 193 | #endif |
168 | 194 | ||
169 | // pseudo-terminal | 195 | // pseudo-terminal |
170 | rv = mkdir("/dev/pts", 0755); | 196 | mkdir_attr("/dev/pts", 0755, 0, 0); |
171 | if (rv == -1) | ||
172 | errExit("mkdir"); | ||
173 | if (chown("/dev/pts", 0, 0) < 0) | ||
174 | errExit("chown"); | ||
175 | if (chmod("/dev/pts", 0755) < 0) | ||
176 | errExit("chmod"); | ||
177 | fs_logger("mkdir /dev/pts"); | 197 | fs_logger("mkdir /dev/pts"); |
178 | create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2"); | 198 | create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2"); |
179 | fs_logger("mknod /dev/pts/ptmx"); | 199 | fs_logger("mknod /dev/pts/ptmx"); |
@@ -186,7 +206,7 @@ void fs_private_dev(void){ | |||
186 | 206 | ||
187 | 207 | ||
188 | // mount /dev/pts | 208 | // mount /dev/pts |
189 | gid_t ttygid = get_tty_gid(); | 209 | gid_t ttygid = get_group_id("tty"); |
190 | char *data; | 210 | char *data; |
191 | if (asprintf(&data, "newinstance,gid=%d,mode=620,ptmxmode=0666", (int) ttygid) == -1) | 211 | if (asprintf(&data, "newinstance,gid=%d,mode=620,ptmxmode=0666", (int) ttygid) == -1) |
192 | errExit("asprintf"); | 212 | errExit("asprintf"); |
@@ -205,6 +225,7 @@ void fs_private_dev(void){ | |||
205 | } | 225 | } |
206 | 226 | ||
207 | 227 | ||
228 | #if 0 | ||
208 | void fs_dev_shm(void) { | 229 | void fs_dev_shm(void) { |
209 | uid_t uid = getuid(); // set a new shm only if we started as root | 230 | uid_t uid = getuid(); // set a new shm only if we started as root |
210 | if (uid) | 231 | if (uid) |
@@ -222,12 +243,7 @@ void fs_dev_shm(void) { | |||
222 | if (lnk) { | 243 | if (lnk) { |
223 | if (!is_dir(lnk)) { | 244 | if (!is_dir(lnk)) { |
224 | // create directory | 245 | // create directory |
225 | if (mkdir(lnk, 01777)) | 246 | mkdir_attr(lnk, 01777, 0, 0); |
226 | errExit("mkdir"); | ||
227 | if (chown(lnk, 0, 0)) | ||
228 | errExit("chown"); | ||
229 | if (chmod(lnk, 01777)) | ||
230 | errExit("chmod"); | ||
231 | } | 247 | } |
232 | if (arg_debug) | 248 | if (arg_debug) |
233 | printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk); | 249 | printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk); |
@@ -243,3 +259,40 @@ void fs_dev_shm(void) { | |||
243 | 259 | ||
244 | } | 260 | } |
245 | } | 261 | } |
262 | #endif | ||
263 | |||
264 | static void disable_file_or_dir(const char *fname) { | ||
265 | if (arg_debug) | ||
266 | printf("disable %s\n", fname); | ||
267 | struct stat s; | ||
268 | if (stat(fname, &s) != -1) { | ||
269 | if (is_dir(fname)) { | ||
270 | if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | ||
271 | errExit("disable directory"); | ||
272 | } | ||
273 | else { | ||
274 | if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | ||
275 | errExit("disable file"); | ||
276 | } | ||
277 | } | ||
278 | fs_logger2("blacklist", fname); | ||
279 | |||
280 | } | ||
281 | |||
282 | void fs_dev_disable_sound(void) { | ||
283 | int i = 0; | ||
284 | while (dev[i].dev_fname != NULL) { | ||
285 | if (dev[i].sound) | ||
286 | disable_file_or_dir(dev[i].dev_fname); | ||
287 | i++; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | void fs_dev_disable_3d(void) { | ||
292 | int i = 0; | ||
293 | while (dev[i].dev_fname != NULL) { | ||
294 | if (dev[i].hw3d) | ||
295 | disable_file_or_dir(dev[i].dev_fname); | ||
296 | i++; | ||
297 | } | ||
298 | } | ||