aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/fs_var.c
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2015-08-08 19:12:30 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2015-08-08 19:12:30 -0400
commit1379851360349d6617ad32944a25ee5e2bb74fc2 (patch)
treef69b48e90708bfa3c2723d5a27ed3e024c827b43 /src/firejail/fs_var.c
parentdelete files (diff)
downloadfirejail-1379851360349d6617ad32944a25ee5e2bb74fc2.tar.gz
firejail-1379851360349d6617ad32944a25ee5e2bb74fc2.tar.zst
firejail-1379851360349d6617ad32944a25ee5e2bb74fc2.zip
Baseline firejail 0.9.28
Diffstat (limited to 'src/firejail/fs_var.c')
-rw-r--r--src/firejail/fs_var.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c
new file mode 100644
index 000000000..ee0f81828
--- /dev/null
+++ b/src/firejail/fs_var.c
@@ -0,0 +1,388 @@
1/*
2 * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com)
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#include "firejail.h"
21#include <sys/mount.h>
22#include <sys/stat.h>
23#include <linux/limits.h>
24#include <glob.h>
25#include <dirent.h>
26#include <fcntl.h>
27#include <pwd.h>
28#include <utmp.h>
29#include <time.h>
30
31typedef struct dirdata_t{
32 struct dirdata_t *next;
33 char *name;
34 mode_t st_mode;
35 uid_t st_uid;
36 gid_t st_gid;
37} DirData;
38
39static DirData *dirlist = NULL;
40
41static void release_all(void) {
42 DirData *ptr = dirlist;
43 while (ptr) {
44 DirData *next = ptr->next;
45 free(ptr->name);
46 free(ptr);
47 ptr = next;
48 }
49 dirlist = NULL;
50}
51
52static void build_list(const char *srcdir) {
53 // extract current /var/log directory data
54 struct dirent *dir;
55 DIR *d = opendir(srcdir);
56 if (d == NULL)
57 return;
58
59 while ((dir = readdir(d))) {
60 if(strcmp(dir->d_name, "." ) == 0 || strcmp(dir->d_name, ".." ) == 0)
61 continue;
62
63 if (dir->d_type == DT_DIR ) {
64 // get properties
65 struct stat s;
66 char *name;
67 if (asprintf(&name, "%s/%s", srcdir, dir->d_name) == -1)
68 continue;
69 if (stat(name, &s) == -1)
70 continue;
71 if (S_ISLNK(s.st_mode)) {
72 free(name);
73 continue;
74 }
75
76// printf("directory %u %u:%u %s\n",
77// s.st_mode,
78// s.st_uid,
79// s.st_gid,
80// dir->d_name);
81
82 DirData *ptr = malloc(sizeof(DirData));
83 if (ptr == NULL)
84 errExit("malloc");
85 memset(ptr, 0, sizeof(DirData));
86 ptr->name = name;
87 ptr->st_mode = s.st_mode;
88 ptr->st_uid = s.st_uid;
89 ptr->st_gid = s.st_gid;
90 ptr->next = dirlist;
91 dirlist = ptr;
92 }
93 }
94 closedir(d);
95}
96
97static void build_dirs(void) {
98 // create directories under /var/log
99 DirData *ptr = dirlist;
100 while (ptr) {
101 if (mkdir(ptr->name, ptr->st_mode))
102 errExit("mkdir");
103 if (chown(ptr->name, ptr->st_uid, ptr->st_gid))
104 errExit("chown");
105 ptr = ptr->next;
106 }
107}
108
109void fs_var_log(void) {
110 build_list("/var/log");
111
112 // create /var/log if it does't exit
113 if (is_dir("/var/log")) {
114 // extract group id for /var/log/wtmp
115 struct stat s;
116 gid_t wtmp_group = 0;
117 if (stat("/var/log/wtmp", &s) == 0)
118 wtmp_group = s.st_gid;
119
120 // mount a tmpfs on top of /var/log
121 if (arg_debug)
122 printf("Mounting tmpfs on /var/log\n");
123 if (mount("tmpfs", "/var/log", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
124 errExit("mounting /var/log");
125
126 build_dirs();
127 release_all();
128
129 // create an empty /var/log/wtmp file
130 /* coverity[toctou] */
131 FILE *fp = fopen("/var/log/wtmp", "w");
132 if (fp)
133 fclose(fp);
134 if (chown("/var/log/wtmp", 0, wtmp_group) < 0)
135 errExit("chown");
136 if (chmod("/var/log/wtmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0)
137 errExit("chmod");
138
139 // create an empty /var/log/btmp file
140 fp = fopen("/var/log/btmp", "w");
141 if (fp)
142 fclose(fp);
143 if (chown("/var/log/btmp", 0, wtmp_group) < 0)
144 errExit("chown");
145 if (chmod("/var/log/btmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP) < 0)
146 errExit("chmod");
147 }
148 else
149 fprintf(stderr, "Warning: cannot mount tmpfs in top of /var/log\n");
150}
151
152void fs_var_lib(void) {
153 struct stat s;
154
155 // ISC DHCP multiserver
156 if (stat("/var/lib/dhcp", &s) == 0) {
157 if (arg_debug)
158 printf("Mounting tmpfs on /var/lib/dhcp\n");
159 if (mount("tmpfs", "/var/lib/dhcp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
160 errExit("mounting /var/lib/dhcp");
161
162 // isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file
163 FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "w");
164
165 if (fp) {
166 fprintf(fp, "\n");
167 fclose(fp);
168 if (chown("/var/lib/dhcp/dhcpd.leases", 0, 0) == -1)
169 errExit("chown");
170 if (chmod("/var/lib/dhcp/dhcpd.leases", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))
171 errExit("chmod");
172 }
173 }
174
175 // nginx multiserver
176 if (stat("/var/lib/nginx", &s) == 0) {
177 if (arg_debug)
178 printf("Mounting tmpfs on /var/lib/nginx\n");
179 if (mount("tmpfs", "/var/lib/nginx", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
180 errExit("mounting /var/lib/nginx");
181 }
182
183 // net-snmp multiserver
184 if (stat("/var/lib/snmp", &s) == 0) {
185 if (arg_debug)
186 printf("Mounting tmpfs on /var/lib/snmp\n");
187 if (mount("tmpfs", "/var/lib/snmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
188 errExit("mounting /var/lib/snmp");
189 }
190
191 // this is where sudo remembers its state
192 if (stat("/var/lib/sudo", &s) == 0) {
193 if (arg_debug)
194 printf("Mounting tmpfs on /var/lib/sudo\n");
195 if (mount("tmpfs", "/var/lib/sudo", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
196 errExit("mounting /var/lib/sudo");
197 }
198}
199
200void fs_var_cache(void) {
201 struct stat s;
202
203 if (stat("/var/cache/apache2", &s) == 0) {
204 if (arg_debug)
205 printf("Mounting tmpfs on /var/cache/apache2\n");
206 if (mount("tmpfs", "/var/cache/apache2", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
207 errExit("mounting /var/cahce/apache2");
208 }
209
210 if (stat("/var/cache/lighttpd", &s) == 0) {
211 if (arg_debug)
212 printf("Mounting tmpfs on /var/cache/lighttpd\n");
213 if (mount("tmpfs", "/var/cache/lighttpd", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
214 errExit("mounting /var/cache/lighttpd");
215
216 struct passwd *p = getpwnam("www-data");
217 uid_t uid = 0;
218 gid_t gid = 0;
219 if (p) {
220 uid = p->pw_uid;
221 gid = p->pw_gid;
222 }
223
224 int rv = mkdir("/var/cache/lighttpd/compress", S_IRWXU | S_IRWXG | S_IRWXO);
225 if (rv == -1)
226 errExit("mkdir");
227 if (chown("/var/cache/lighttpd/compress", uid, gid) < 0)
228 errExit("chown");
229
230 rv = mkdir("/var/cache/lighttpd/uploads", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
231 if (rv == -1)
232 errExit("mkdir");
233 if (chown("/var/cache/lighttpd/uploads", uid, gid) < 0)
234 errExit("chown");
235 }
236}
237
238void dbg_test_dir(const char *dir) {
239 if (arg_debug) {
240 if (is_dir(dir))
241 printf("%s is a directory\n", dir);
242 if (is_link(dir)) {
243 char *lnk = get_link(dir);
244 if (lnk) {
245 printf("%s is a symbolic link to %s\n", dir, lnk);
246 free(lnk);
247 }
248 }
249 }
250}
251
252
253void fs_var_lock(void) {
254
255 if (is_dir("/var/lock")) {
256 if (arg_debug)
257 printf("Mounting tmpfs on /var/lock\n");
258 if (mount("tmpfs", "/var/lock", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0)
259 errExit("mounting /lock");
260 }
261 else {
262 char *lnk = get_link("/var/lock");
263 if (lnk) {
264 // convert a link such as "../shm" into "/shm"
265 char *lnk2 = lnk;
266 int cnt = 0;
267 while (strncmp(lnk2, "../", 3) == 0) {
268 cnt++;
269 lnk2 = lnk2 + 3;
270 }
271 if (cnt != 0)
272 lnk2 = lnk + (cnt - 1) * 3 + 2;
273
274 if (!is_dir(lnk2)) {
275 // create directory
276 if (mkdir(lnk2, S_IRWXU|S_IRWXG|S_IRWXO))
277 errExit("mkdir");
278 if (chown(lnk2, 0, 0))
279 errExit("chown");
280 if (chmod(lnk2, S_IRWXU|S_IRWXG|S_IRWXO))
281 errExit("chmod");
282 }
283 if (arg_debug)
284 printf("Mounting tmpfs on %s on behalf of /var/lock\n", lnk2);
285 if (mount("tmpfs", lnk2, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0)
286 errExit("mounting /var/lock");
287 free(lnk);
288 }
289 else {
290 fprintf(stderr, "Warning: /var/lock not mounted\n");
291 dbg_test_dir("/var/lock");
292 }
293 }
294}
295
296void fs_var_tmp(void) {
297
298 if (!is_link("/var/tmp")) {
299 if (arg_debug)
300 printf("Mounting tmpfs on /var/tmp\n");
301 if (mount("tmpfs", "/var/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0)
302 errExit("mounting /var/tmp");
303 }
304 else {
305 fprintf(stderr, "Warning: /var/tmp not mounted\n");
306 dbg_test_dir("/var/tmp");
307 }
308}
309
310void fs_var_utmp(void) {
311 struct stat s;
312
313 // extract utmp group id
314 gid_t utmp_group = 0;
315 if (stat("/var/run/utmp", &s) == 0)
316 utmp_group = s.st_gid;
317 else {
318 fprintf(stderr, "Warning: cannot find /var/run/utmp\n");
319 return;
320 }
321
322 // create /tmp/firejail/mnt directory
323 fs_build_mnt_dir();
324
325 // create a new utmp file
326 if (arg_debug)
327 printf("Create the new utmp file\n");
328 char *utmp;
329 if (asprintf(&utmp, "%s/utmp", MNT_DIR) == -1)
330 errExit("asprintf");
331 FILE *fp = fopen(utmp, "w");
332 if (!fp)
333 errExit("fopen");
334
335 // read current utmp
336 struct utmp *u;
337 struct utmp u_boot;
338 setutent();
339 while ((u = getutent()) != NULL) {
340 if (u->ut_type == BOOT_TIME) {
341 memcpy(&u_boot, u, sizeof(u_boot));
342 u_boot.ut_tv.tv_sec = (unsigned) time(NULL);
343 }
344 }
345 endutent();
346
347 // save new utmp file
348 fwrite(&u_boot, sizeof(u_boot), 1, fp);
349 fclose(fp);
350 if (chown(utmp, 0, utmp_group) < 0)
351 errExit("chown");
352 if (chmod(utmp, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0)
353 errExit("chmod");
354
355 // mount the new utmp file
356 if (arg_debug)
357 printf("Mount the new utmp file\n");
358 if (mount(utmp, "/var/run/utmp", NULL, MS_BIND|MS_REC, NULL) < 0)
359 errExit("mount bind utmp");
360}
361
362
363#if 0
364Testing servers:
365
366brctl addbr br0
367ifconfig br0 10.10.20.1/24
368
369apt-get install snmpd
370insserv -r snmpd
371sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/snmpd start; sleep inf"
372
373apt-get install apache2
374insserv -r apache2
375sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/apache2 start; sleep inf"
376
377apt-get install nginx
378insserv -r nginx
379sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/nginx start; sleep inf"
380
381apt-get install lighttpd
382insserv -r lighttpd
383sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/lighttpd start; sleep inf"
384
385apt-get install isc-dhcp-server
386insserv -r isc-dhcp-server
387sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/isc-dhcp-server start; sleep inf"
388#endif