diff options
Diffstat (limited to 'src')
180 files changed, 10813 insertions, 3533 deletions
diff --git a/src/bash_completion/firejail.bash_completion.in b/src/bash_completion/firejail.bash_completion.in index f68edf380..ff411c807 100644 --- a/src/bash_completion/firejail.bash_completion.in +++ b/src/bash_completion/firejail.bash_completion.in | |||
@@ -5,7 +5,7 @@ | |||
5 | # http://bash-completion.alioth.debian.org | 5 | # http://bash-completion.alioth.debian.org |
6 | #******************************************************************* | 6 | #******************************************************************* |
7 | 7 | ||
8 | __interfaces(){ | 8 | __interfaces() { |
9 | cut -f 1 -d ':' /proc/net/dev | tail -n +3 | grep -v lo | xargs | 9 | cut -f 1 -d ':' /proc/net/dev | tail -n +3 | grep -v lo | xargs |
10 | } | 10 | } |
11 | 11 | ||
@@ -90,11 +90,11 @@ _firejail() | |||
90 | _filedir | 90 | _filedir |
91 | return 0 | 91 | return 0 |
92 | ;; | 92 | ;; |
93 | --net) | 93 | --net) |
94 | comps=$(__interfaces) | 94 | comps=$(__interfaces) |
95 | COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) | 95 | COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) |
96 | return 0 | 96 | return 0 |
97 | ;; | 97 | ;; |
98 | esac | 98 | esac |
99 | 99 | ||
100 | $split && return 0 | 100 | $split && return 0 |
diff --git a/src/common.mk.in b/src/common.mk.in index b379aef7f..38c05bc69 100644 --- a/src/common.mk.in +++ b/src/common.mk.in | |||
@@ -15,7 +15,6 @@ HAVE_NETWORK=@HAVE_NETWORK@ | |||
15 | HAVE_USERNS=@HAVE_USERNS@ | 15 | HAVE_USERNS=@HAVE_USERNS@ |
16 | HAVE_X11=@HAVE_X11@ | 16 | HAVE_X11=@HAVE_X11@ |
17 | HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ | 17 | HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ |
18 | HAVE_WHITELIST=@HAVE_WHITELIST@ | ||
19 | HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ | 18 | HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ |
20 | HAVE_APPARMOR=@HAVE_APPARMOR@ | 19 | HAVE_APPARMOR=@HAVE_APPARMOR@ |
21 | HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ | 20 | HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ |
@@ -23,11 +22,13 @@ HAVE_FIRETUNNEL=@HAVE_FIRETUNNEL@ | |||
23 | HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ | 22 | HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ |
24 | HAVE_GCOV=@HAVE_GCOV@ | 23 | HAVE_GCOV=@HAVE_GCOV@ |
25 | HAVE_SELINUX=@HAVE_SELINUX@ | 24 | HAVE_SELINUX=@HAVE_SELINUX@ |
25 | HAVE_SUID=@HAVE_SUID@ | ||
26 | HAVE_DBUSPROXY=@HAVE_DBUSPROXY@ | 26 | HAVE_DBUSPROXY=@HAVE_DBUSPROXY@ |
27 | HAVE_USERTMPFS=@HAVE_USERTMPFS@ | 27 | HAVE_USERTMPFS=@HAVE_USERTMPFS@ |
28 | HAVE_OUTPUT=@HAVE_OUTPUT@ | 28 | HAVE_OUTPUT=@HAVE_OUTPUT@ |
29 | HAVE_LTS=@HAVE_LTS@ | 29 | HAVE_LTS=@HAVE_LTS@ |
30 | HAVE_FORCE_NONEWPRIVS=@HAVE_FORCE_NONEWPRIVS@ | 30 | HAVE_FORCE_NONEWPRIVS=@HAVE_FORCE_NONEWPRIVS@ |
31 | HAVE_ONLY_SYSCFG_PROFILES=@HAVE_ONLY_SYSCFG_PROFILES@ | ||
31 | 32 | ||
32 | H_FILE_LIST = $(sort $(wildcard *.h)) | 33 | H_FILE_LIST = $(sort $(wildcard *.h)) |
33 | C_FILE_LIST = $(sort $(wildcard *.c)) | 34 | C_FILE_LIST = $(sort $(wildcard *.c)) |
@@ -36,11 +37,11 @@ BINOBJS = $(foreach file, $(OBJS), $file) | |||
36 | 37 | ||
37 | CFLAGS = @CFLAGS@ | 38 | CFLAGS = @CFLAGS@ |
38 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) | 39 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) |
39 | CFLAGS += -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' -DBINDIR='"$(bindir)"' | 40 | CFLAGS += -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' -DBINDIR='"$(bindir)"' -DVARDIR='"/var/lib/firejail"' |
40 | MANFLAGS = $(HAVE_LTS) $(HAVE_OUTPUT) $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_USERTMPFS) $(HAVE_DBUSPROXY) $(HAVE_FIRETUNNEL) $(HAVE_GLOBALCFG) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) $(HAVE_SELINUX) $(HAVE_FORCE_NONEWPRIVS) | 41 | MANFLAGS = $(HAVE_LTS) $(HAVE_OUTPUT) $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_USERTMPFS) $(HAVE_DBUSPROXY) $(HAVE_FIRETUNNEL) $(HAVE_GLOBALCFG) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_FILE_TRANSFER) $(HAVE_SELINUX) $(HAVE_SUID) $(HAVE_FORCE_NONEWPRIVS) $(HAVE_ONLY_SYSCFG_PROFILES) |
41 | CFLAGS += $(MANFLAGS) | 42 | CFLAGS += $(MANFLAGS) |
42 | CFLAGS += -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -Wformat -Wformat-security | 43 | CFLAGS += -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -Wformat -Wformat-security |
43 | LDFLAGS += -pie -fPIE -Wl,-z,relro -Wl,-z,now -lpthread | 44 | LDFLAGS += -pie -fPIE -Wl,-z,relro -Wl,-z,now |
44 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | 45 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ |
45 | 46 | ||
46 | ifdef NO_EXTRA_CFLAGS | 47 | ifdef NO_EXTRA_CFLAGS |
diff --git a/src/fbuilder/build_bin.c b/src/fbuilder/build_bin.c index 9577042c4..041c52629 100644 --- a/src/fbuilder/build_bin.c +++ b/src/fbuilder/build_bin.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fbuilder/build_fs.c b/src/fbuilder/build_fs.c index 8700e0ba1..4766337ff 100644 --- a/src/fbuilder/build_fs.c +++ b/src/fbuilder/build_fs.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -236,9 +236,6 @@ void build_share(const char *fname, FILE *fp) { | |||
236 | //******************************************* | 236 | //******************************************* |
237 | static FileDB *tmp_out = NULL; | 237 | static FileDB *tmp_out = NULL; |
238 | static void tmp_callback(char *ptr) { | 238 | static void tmp_callback(char *ptr) { |
239 | // skip strace file | ||
240 | if (strncmp(ptr, "/tmp/firejail-strace", 20) == 0) | ||
241 | return; | ||
242 | if (strncmp(ptr, "/tmp/runtime-", 13) == 0) | 239 | if (strncmp(ptr, "/tmp/runtime-", 13) == 0) |
243 | return; | 240 | return; |
244 | if (strcmp(ptr, "/tmp") == 0) | 241 | if (strcmp(ptr, "/tmp") == 0) |
diff --git a/src/fbuilder/build_home.c b/src/fbuilder/build_home.c index b3ec6cffd..d6d421259 100644 --- a/src/fbuilder/build_home.c +++ b/src/fbuilder/build_home.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -68,6 +68,8 @@ void process_home(const char *fname, char *home, int home_len) { | |||
68 | ptr += 7; | 68 | ptr += 7; |
69 | else if (strncmp(ptr, "open /home", 10) == 0) | 69 | else if (strncmp(ptr, "open /home", 10) == 0) |
70 | ptr += 5; | 70 | ptr += 5; |
71 | else if (strncmp(ptr, "opendir /home", 13) == 0) | ||
72 | ptr += 8; | ||
71 | else | 73 | else |
72 | continue; | 74 | continue; |
73 | 75 | ||
diff --git a/src/fbuilder/build_profile.c b/src/fbuilder/build_profile.c index fb53f70a6..941f43562 100644 --- a/src/fbuilder/build_profile.c +++ b/src/fbuilder/build_profile.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -22,22 +22,6 @@ | |||
22 | #include <sys/wait.h> | 22 | #include <sys/wait.h> |
23 | 23 | ||
24 | #define TRACE_OUTPUT "/tmp/firejail-trace.XXXXXX" | 24 | #define TRACE_OUTPUT "/tmp/firejail-trace.XXXXXX" |
25 | #define STRACE_OUTPUT "/tmp/firejail-strace.XXXXXX" | ||
26 | |||
27 | /* static char *cmdlist[] = { */ | ||
28 | /* "/usr/bin/firejail", */ | ||
29 | /* "--quiet", */ | ||
30 | /* "--output=" TRACE_OUTPUT, */ | ||
31 | /* "--noprofile", */ | ||
32 | /* "--caps.drop=all", */ | ||
33 | /* "--nonewprivs", */ | ||
34 | /* "--trace", */ | ||
35 | /* "--shell=none", */ | ||
36 | /* "/usr/bin/strace", // also used as a marker in build_profile() */ | ||
37 | /* "-c", */ | ||
38 | /* "-f", */ | ||
39 | /* "-o" STRACE_OUTPUT, */ | ||
40 | /* }; */ | ||
41 | 25 | ||
42 | void build_profile(int argc, char **argv, int index, FILE *fp) { | 26 | void build_profile(int argc, char **argv, int index, FILE *fp) { |
43 | // next index is the application name | 27 | // next index is the application name |
@@ -47,78 +31,42 @@ void build_profile(int argc, char **argv, int index, FILE *fp) { | |||
47 | } | 31 | } |
48 | 32 | ||
49 | char trace_output[] = "/tmp/firejail-trace.XXXXXX"; | 33 | char trace_output[] = "/tmp/firejail-trace.XXXXXX"; |
50 | char strace_output[] = "/tmp/firejail-strace.XXXXXX"; | ||
51 | |||
52 | int tfile = mkstemp(trace_output); | 34 | int tfile = mkstemp(trace_output); |
53 | int stfile = mkstemp(strace_output); | 35 | if(tfile == -1) |
54 | if(tfile == -1 || stfile == -1) | ||
55 | errExit("mkstemp"); | 36 | errExit("mkstemp"); |
56 | |||
57 | // close the files, firejail/strace will overwrite them! | ||
58 | close(tfile); | 37 | close(tfile); |
59 | close(stfile); | ||
60 | |||
61 | 38 | ||
62 | char *output; | 39 | char *output; |
63 | char *stroutput; | ||
64 | if(asprintf(&output,"--trace=%s",trace_output) == -1) | 40 | if(asprintf(&output,"--trace=%s",trace_output) == -1) |
65 | errExit("asprintf"); | 41 | errExit("asprintf"); |
66 | if(asprintf(&stroutput,"-o%s",strace_output) == -1) | ||
67 | errExit("asprintf"); | ||
68 | |||
69 | char *cmdlist[] = { | ||
70 | BINDIR "/firejail", | ||
71 | "--quiet", | ||
72 | "--noprofile", | ||
73 | "--caps.drop=all", | ||
74 | "--nonewprivs", | ||
75 | output, | ||
76 | "--shell=none", | ||
77 | "/usr/bin/strace", // also used as a marker in build_profile() | ||
78 | "-c", | ||
79 | "-f", | ||
80 | stroutput, | ||
81 | }; | ||
82 | |||
83 | // detect strace and check if Yama LSM allows us to use it | ||
84 | int have_strace = 0; | ||
85 | int have_yama_permission = 1; | ||
86 | if (access("/usr/bin/strace", X_OK) == 0) { | ||
87 | have_strace = 1; | ||
88 | FILE *ps = fopen("/proc/sys/kernel/yama/ptrace_scope", "r"); | ||
89 | if (ps) { | ||
90 | unsigned val; | ||
91 | if (fscanf(ps, "%u", &val) == 1) | ||
92 | have_yama_permission = (val < 2); | ||
93 | fclose(ps); | ||
94 | } | ||
95 | } | ||
96 | 42 | ||
97 | // calculate command length | 43 | // calculate command length |
98 | unsigned len = (int) sizeof(cmdlist) / sizeof(char*) + argc - index + 1; | 44 | unsigned len = 64; // plenty of space for firejail command line |
99 | if (arg_debug) | 45 | len += argc - index; // program command line |
100 | printf("command len %d + %d + 1\n", (int) (sizeof(cmdlist) / sizeof(char*)), argc - index); | 46 | len += 1; // NULL |
101 | char *cmd[len]; | ||
102 | cmd[0] = cmdlist[0]; // explicit assignment to clean scan-build error | ||
103 | 47 | ||
104 | // build command | 48 | // build command |
105 | // skip strace if not installed, or no permission to use it | 49 | char *cmd[len]; |
106 | int skip_strace = !(have_strace && have_yama_permission); | 50 | unsigned curr_len = 0; |
107 | unsigned i = 0; | 51 | cmd[curr_len++] = BINDIR "/firejail"; |
108 | for (i = 0; i < (int) sizeof(cmdlist) / sizeof(char*); i++) { | 52 | cmd[curr_len++] = "--quiet"; |
109 | if (skip_strace && strcmp(cmdlist[i], "/usr/bin/strace") == 0) | 53 | cmd[curr_len++] = "--noprofile"; |
110 | break; | 54 | cmd[curr_len++] = "--caps.drop=all"; |
111 | cmd[i] = cmdlist[i]; | 55 | cmd[curr_len++] = "--seccomp=!chroot"; |
112 | } | 56 | cmd[curr_len++] = "--shell=none"; |
113 | 57 | cmd[curr_len++] = output; | |
114 | int i2 = index; | 58 | if (arg_appimage) |
115 | for (; i < (len - 1); i++, i2++) | 59 | cmd[curr_len++] = "--appimage"; |
116 | cmd[i] = argv[i2]; | 60 | |
117 | assert(i < len); | 61 | int i; |
118 | cmd[i] = NULL; | 62 | for (i = index; i < argc; i++) |
63 | cmd[curr_len++] = argv[i]; | ||
64 | |||
65 | assert(curr_len < len); | ||
66 | cmd[curr_len] = NULL; | ||
119 | 67 | ||
120 | if (arg_debug) { | 68 | if (arg_debug) { |
121 | for (i = 0; i < len; i++) | 69 | for (i = 0; cmd[i]; i++) |
122 | printf("%s%s\n", (i)?"\t":"", cmd[i]); | 70 | printf("%s%s\n", (i)?"\t":"", cmd[i]); |
123 | } | 71 | } |
124 | 72 | ||
@@ -140,14 +88,14 @@ void build_profile(int argc, char **argv, int index, FILE *fp) { | |||
140 | 88 | ||
141 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { | 89 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { |
142 | if (fp == stdout) | 90 | if (fp == stdout) |
143 | printf("--- Built profile beings after this line ---\n"); | 91 | printf("--- Built profile begins after this line ---\n"); |
144 | fprintf(fp, "# Save this file as \"application.profile\" (change \"application\" with the\n"); | 92 | fprintf(fp, "# Save this file as \"application.profile\" (change \"application\" with the\n"); |
145 | fprintf(fp, "# program name) in ~/.config/firejail directory. Firejail will find it\n"); | 93 | fprintf(fp, "# program name) in ~/.config/firejail directory. Firejail will find it\n"); |
146 | fprintf(fp, "# automatically every time you sandbox your application.\n#\n"); | 94 | fprintf(fp, "# automatically every time you sandbox your application.\n#\n"); |
147 | fprintf(fp, "# Run \"firejail application\" to test it. In the file there are\n"); | 95 | fprintf(fp, "# Run \"firejail application\" to test it. In the file there are\n"); |
148 | fprintf(fp, "# some other commands you can try. Enable them by removing the \"#\".\n"); | 96 | fprintf(fp, "# some other commands you can try. Enable them by removing the \"#\".\n\n"); |
149 | 97 | ||
150 | fprintf(fp, "\n# Firejail profile for %s\n", argv[index]); | 98 | fprintf(fp, "# Firejail profile for %s\n", argv[index]); |
151 | fprintf(fp, "# Persistent local customizations\n"); | 99 | fprintf(fp, "# Persistent local customizations\n"); |
152 | fprintf(fp, "#include %s.local\n", argv[index]); | 100 | fprintf(fp, "#include %s.local\n", argv[index]); |
153 | fprintf(fp, "# Persistent global definitions\n"); | 101 | fprintf(fp, "# Persistent global definitions\n"); |
@@ -158,58 +106,62 @@ void build_profile(int argc, char **argv, int index, FILE *fp) { | |||
158 | fprintf(fp, "### Enable as many of them as you can! A very important one is\n"); | 106 | fprintf(fp, "### Enable as many of them as you can! A very important one is\n"); |
159 | fprintf(fp, "### \"disable-exec.inc\". This will make among other things your home\n"); | 107 | fprintf(fp, "### \"disable-exec.inc\". This will make among other things your home\n"); |
160 | fprintf(fp, "### and /tmp directories non-executable.\n"); | 108 | fprintf(fp, "### and /tmp directories non-executable.\n"); |
161 | fprintf(fp, "include disable-common.inc\n"); | 109 | fprintf(fp, "include disable-common.inc\t# dangerous directories like ~/.ssh and ~/.gnupg\n"); |
162 | fprintf(fp, "#include disable-devel.inc\n"); | 110 | fprintf(fp, "#include disable-devel.inc\t# development tools such as gcc and gdb\n"); |
163 | fprintf(fp, "#include disable-exec.inc\n"); | 111 | fprintf(fp, "#include disable-exec.inc\t# non-executable directories such as /var, /tmp, and /home\n"); |
164 | fprintf(fp, "#include disable-interpreters.inc\n"); | 112 | fprintf(fp, "#include disable-interpreters.inc\t# perl, python, lua etc.\n"); |
165 | fprintf(fp, "include disable-passwdmgr.inc\n"); | 113 | fprintf(fp, "include disable-programs.inc\t# user configuration for programs such as firefox, vlc etc.\n"); |
166 | fprintf(fp, "include disable-programs.inc\n"); | 114 | fprintf(fp, "#include disable-shell.inc\t# sh, bash, zsh etc.\n"); |
167 | fprintf(fp, "#include disable-xdg.inc\n"); | 115 | fprintf(fp, "#include disable-xdg.inc\t# standard user directories: Documents, Pictures, Videos, Music\n"); |
168 | fprintf(fp, "\n"); | 116 | fprintf(fp, "\n"); |
169 | 117 | ||
170 | fprintf(fp, "### Home Directory Whitelisting ###\n"); | 118 | fprintf(fp, "### Home Directory Whitelisting ###\n"); |
171 | fprintf(fp, "### If something goes wrong, this section is the first one to comment out.\n"); | 119 | fprintf(fp, "### If something goes wrong, this section is the first one to comment out.\n"); |
172 | fprintf(fp, "### Instead, you'll have to relay on the basic blacklisting above.\n"); | 120 | fprintf(fp, "### Instead, you'll have to relay on the basic blacklisting above.\n"); |
173 | build_home(trace_output, fp); | 121 | build_home(trace_output, fp); |
122 | fprintf(fp, "\n"); | ||
174 | 123 | ||
175 | fprintf(fp, "\n### The Rest of the Filesystem ###\n"); | 124 | fprintf(fp, "### Filesystem Whitelisting ###\n"); |
176 | build_share(trace_output, fp); | 125 | build_share(trace_output, fp); |
126 | //todo: include whitelist-runuser-common.inc | ||
177 | build_var(trace_output, fp); | 127 | build_var(trace_output, fp); |
178 | build_bin(trace_output, fp); | 128 | fprintf(fp, "\n"); |
179 | build_dev(trace_output, fp); | ||
180 | fprintf(fp, "#nodvd\n"); | ||
181 | fprintf(fp, "#noinput\n"); | ||
182 | fprintf(fp, "#notv\n"); | ||
183 | fprintf(fp, "#nou2f\n"); | ||
184 | fprintf(fp, "#novideo\n"); | ||
185 | build_etc(trace_output, fp); | ||
186 | build_tmp(trace_output, fp); | ||
187 | 129 | ||
188 | fprintf(fp, "\n### Security Filters ###\n"); | 130 | fprintf(fp, "#apparmor\t# if you have AppArmor running, try this one!\n"); |
189 | fprintf(fp, "#apparmor\n"); | ||
190 | fprintf(fp, "caps.drop all\n"); | 131 | fprintf(fp, "caps.drop all\n"); |
132 | fprintf(fp, "ipc-namespace\n"); | ||
191 | fprintf(fp, "netfilter\n"); | 133 | fprintf(fp, "netfilter\n"); |
192 | fprintf(fp, "#nogroups\n"); | 134 | fprintf(fp, "#no3d\t# disable 3D acceleration\n"); |
193 | fprintf(fp, "#noroot\n"); | 135 | fprintf(fp, "#nodvd\t# disable DVD and CD devices\n"); |
136 | fprintf(fp, "#nogroups\t# disable supplementary user groups\n"); | ||
137 | fprintf(fp, "#noinput\t# disable input devices\n"); | ||
194 | fprintf(fp, "nonewprivs\n"); | 138 | fprintf(fp, "nonewprivs\n"); |
139 | fprintf(fp, "noroot\n"); | ||
140 | fprintf(fp, "#notv\t# disable DVB TV devices\n"); | ||
141 | fprintf(fp, "#nou2f\t# disable U2F devices\n"); | ||
142 | fprintf(fp, "#novideo\t# disable video capture devices\n"); | ||
195 | build_protocol(trace_output, fp); | 143 | build_protocol(trace_output, fp); |
144 | fprintf(fp, "seccomp !chroot\t# allowing chroot, just in case this is an Electron app\n"); | ||
145 | fprintf(fp, "shell none\n"); | ||
146 | fprintf(fp, "tracelog\n"); | ||
147 | fprintf(fp, "\n"); | ||
148 | |||
149 | fprintf(fp, "#disable-mnt\t# no access to /mnt, /media, /run/mount and /run/media\n"); | ||
150 | build_bin(trace_output, fp); | ||
151 | fprintf(fp, "#private-cache\t# run with an empty ~/.cache directory\n"); | ||
152 | build_dev(trace_output, fp); | ||
153 | build_etc(trace_output, fp); | ||
154 | fprintf(fp, "#private-lib\n"); | ||
155 | build_tmp(trace_output, fp); | ||
156 | fprintf(fp, "\n"); | ||
157 | |||
158 | fprintf(fp, "#dbus-user none\n"); | ||
159 | fprintf(fp, "#dbus-system none\n"); | ||
160 | fprintf(fp, "\n"); | ||
161 | fprintf(fp, "#memory-deny-write-execute\n"); | ||
196 | 162 | ||
197 | fprintf(fp, "seccomp\n"); | 163 | if (!arg_debug) |
198 | if (!have_strace) { | ||
199 | fprintf(fp, "### If you install strace on your system, Firejail will also create a\n"); | ||
200 | fprintf(fp, "### whitelisted seccomp filter.\n"); | ||
201 | } | ||
202 | else if (!have_yama_permission) | ||
203 | fprintf(fp, "### Yama security module prevents creation of a whitelisted seccomp filter\n"); | ||
204 | else | ||
205 | build_seccomp(strace_output, fp); | ||
206 | fprintf(fp, "#shell none\n"); | ||
207 | fprintf(fp, "#tracelog\n"); | ||
208 | |||
209 | if (!arg_debug) { | ||
210 | unlink(trace_output); | 164 | unlink(trace_output); |
211 | unlink(strace_output); | ||
212 | } | ||
213 | } | 165 | } |
214 | else { | 166 | else { |
215 | fprintf(stderr, "Error: cannot run the sandbox\n"); | 167 | fprintf(stderr, "Error: cannot run the sandbox\n"); |
diff --git a/src/fbuilder/build_seccomp.c b/src/fbuilder/build_seccomp.c index dc3cce456..7b4727e1a 100644 --- a/src/fbuilder/build_seccomp.c +++ b/src/fbuilder/build_seccomp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include "fbuilder.h" | 21 | #include "fbuilder.h" |
22 | 22 | ||
23 | #if 0 | ||
23 | void build_seccomp(const char *fname, FILE *fp) { | 24 | void build_seccomp(const char *fname, FILE *fp) { |
24 | assert(fname); | 25 | assert(fname); |
25 | assert(fp); | 26 | assert(fp); |
@@ -78,15 +79,17 @@ void build_seccomp(const char *fname, FILE *fp) { | |||
78 | 79 | ||
79 | fclose(fp2); | 80 | fclose(fp2); |
80 | } | 81 | } |
82 | #endif | ||
81 | 83 | ||
82 | //*************************************** | 84 | //*************************************** |
83 | // protocol | 85 | // protocol |
84 | //*************************************** | 86 | //*************************************** |
85 | int unix_s = 0; | 87 | static int unix_s = 0; |
86 | int inet = 0; | 88 | static int inet = 0; |
87 | int inet6 = 0; | 89 | static int inet6 = 0; |
88 | int netlink = 0; | 90 | static int netlink = 0; |
89 | int packet = 0; | 91 | static int packet = 0; |
92 | static int bluetooth = 0; | ||
90 | static void process_protocol(const char *fname) { | 93 | static void process_protocol(const char *fname) { |
91 | assert(fname); | 94 | assert(fname); |
92 | 95 | ||
@@ -135,6 +138,8 @@ static void process_protocol(const char *fname) { | |||
135 | netlink = 1; | 138 | netlink = 1; |
136 | else if (strncmp(ptr, "AF_PACKET ", 10) == 0) | 139 | else if (strncmp(ptr, "AF_PACKET ", 10) == 0) |
137 | packet = 1; | 140 | packet = 1; |
141 | else if (strncmp(ptr, "AF_BLUETOOTH ", 13) == 0) | ||
142 | bluetooth = 1; | ||
138 | } | 143 | } |
139 | 144 | ||
140 | fclose(fp); | 145 | fclose(fp); |
@@ -161,22 +166,22 @@ void build_protocol(const char *fname, FILE *fp) { | |||
161 | } | 166 | } |
162 | 167 | ||
163 | int net = 0; | 168 | int net = 0; |
164 | if (unix_s || inet || inet6 || netlink || packet) { | 169 | if (unix_s || inet || inet6 || netlink || packet || bluetooth) { |
165 | fprintf(fp, "protocol "); | 170 | fprintf(fp, "protocol "); |
166 | if (unix_s) | 171 | if (unix_s) |
167 | fprintf(fp, "unix,"); | 172 | fprintf(fp, "unix,"); |
168 | if (inet) { | 173 | if (inet || inet6) { |
169 | fprintf(fp, "inet,"); | 174 | fprintf(fp, "inet,inet6,"); |
170 | net = 1; | ||
171 | } | ||
172 | if (inet6) { | ||
173 | fprintf(fp, "inet6,"); | ||
174 | net = 1; | 175 | net = 1; |
175 | } | 176 | } |
176 | if (netlink) | 177 | if (netlink) |
177 | fprintf(fp, "netlink,"); | 178 | fprintf(fp, "netlink,"); |
178 | if (packet) { | 179 | if (packet) { |
179 | fprintf(fp, "packet"); | 180 | fprintf(fp, "packet,"); |
181 | net = 1; | ||
182 | } | ||
183 | if (bluetooth) { | ||
184 | fprintf(fp, "bluetooth"); | ||
180 | net = 1; | 185 | net = 1; |
181 | } | 186 | } |
182 | fprintf(fp, "\n"); | 187 | fprintf(fp, "\n"); |
diff --git a/src/fbuilder/fbuilder.h b/src/fbuilder/fbuilder.h index 08dd35e10..3e23d7854 100644 --- a/src/fbuilder/fbuilder.h +++ b/src/fbuilder/fbuilder.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -31,6 +31,7 @@ | |||
31 | #define MAX_BUF 4096 | 31 | #define MAX_BUF 4096 |
32 | // main.c | 32 | // main.c |
33 | extern int arg_debug; | 33 | extern int arg_debug; |
34 | extern int arg_appimage; | ||
34 | 35 | ||
35 | // build_profile.c | 36 | // build_profile.c |
36 | void build_profile(int argc, char **argv, int index, FILE *fp); | 37 | void build_profile(int argc, char **argv, int index, FILE *fp); |
diff --git a/src/fbuilder/filedb.c b/src/fbuilder/filedb.c index 94a226cb7..454b9f40b 100644 --- a/src/fbuilder/filedb.c +++ b/src/fbuilder/filedb.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fbuilder/main.c b/src/fbuilder/main.c index f4917aefc..aa49b2489 100644 --- a/src/fbuilder/main.c +++ b/src/fbuilder/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -19,6 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | #include "fbuilder.h" | 20 | #include "fbuilder.h" |
21 | int arg_debug = 0; | 21 | int arg_debug = 0; |
22 | int arg_appimage = 0; | ||
22 | 23 | ||
23 | static void usage(void) { | 24 | static void usage(void) { |
24 | printf("Firejail profile builder\n"); | 25 | printf("Firejail profile builder\n"); |
@@ -39,7 +40,7 @@ printf("\n"); | |||
39 | int i; | 40 | int i; |
40 | int prog_index = 0; | 41 | int prog_index = 0; |
41 | FILE *fp = stdout; | 42 | FILE *fp = stdout; |
42 | int prof_file = 0; | 43 | char *prof_file = NULL; |
43 | 44 | ||
44 | // parse arguments and extract program index | 45 | // parse arguments and extract program index |
45 | for (i = 1; i < argc; i++) { | 46 | for (i = 1; i < argc; i++) { |
@@ -49,6 +50,8 @@ printf("\n"); | |||
49 | } | 50 | } |
50 | else if (strcmp(argv[i], "--debug") == 0) | 51 | else if (strcmp(argv[i], "--debug") == 0) |
51 | arg_debug = 1; | 52 | arg_debug = 1; |
53 | else if (strcmp(argv[i], "--appimage") == 0) | ||
54 | arg_appimage = 1; | ||
52 | else if (strcmp(argv[i], "--build") == 0) | 55 | else if (strcmp(argv[i], "--build") == 0) |
53 | ; // do nothing, this is passed down from firejail | 56 | ; // do nothing, this is passed down from firejail |
54 | else if (strncmp(argv[i], "--build=", 8) == 0) { | 57 | else if (strncmp(argv[i], "--build=", 8) == 0) { |
@@ -58,18 +61,23 @@ printf("\n"); | |||
58 | exit(1); | 61 | exit(1); |
59 | } | 62 | } |
60 | 63 | ||
64 | // don't run if the file exists | ||
65 | if (access(argv[i] + 8, F_OK) == 0) { | ||
66 | fprintf(stderr, "Error: the profile file already exists. Please use a different file name.\n"); | ||
67 | exit(1); | ||
68 | } | ||
69 | |||
61 | // check file access | 70 | // check file access |
62 | fp = fopen(argv[i] + 8, "w"); | 71 | fp = fopen(argv[i] + 8, "w"); |
63 | if (!fp) { | 72 | if (!fp) { |
64 | fprintf(stderr, "Error fbuild: cannot open profile file.\n"); | 73 | fprintf(stderr, "Error: cannot open profile file.\n"); |
65 | exit(1); | 74 | exit(1); |
66 | } | 75 | } |
67 | prof_file = 1; | 76 | prof_file = argv[i] + 8; |
68 | // do nothing, this is passed down from firejail | ||
69 | } | 77 | } |
70 | else { | 78 | else { |
71 | if (*argv[i] == '-') { | 79 | if (*argv[i] == '-') { |
72 | fprintf(stderr, "Error fbuilder: invalid program\n"); | 80 | fprintf(stderr, "Error: invalid program\n"); |
73 | usage(); | 81 | usage(); |
74 | exit(1); | 82 | exit(1); |
75 | } | 83 | } |
@@ -79,10 +87,13 @@ printf("\n"); | |||
79 | } | 87 | } |
80 | 88 | ||
81 | if (prog_index == 0) { | 89 | if (prog_index == 0) { |
82 | fprintf(stderr, "Error fbuilder: program and arguments required\n"); | 90 | fprintf(stderr, "Error : program and arguments required\n"); |
83 | usage(); | 91 | usage(); |
84 | if (prof_file) | 92 | if (prof_file) { |
85 | fclose(fp); | 93 | fclose(fp); |
94 | int rv = unlink(prof_file); | ||
95 | (void) rv; | ||
96 | } | ||
86 | exit(1); | 97 | exit(1); |
87 | } | 98 | } |
88 | 99 | ||
diff --git a/src/fbuilder/utils.c b/src/fbuilder/utils.c index 52493f470..f89e69679 100644 --- a/src/fbuilder/utils.c +++ b/src/fbuilder/utils.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 572e9f601..e56d853c8 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -19,11 +19,15 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include "../include/common.h" | 21 | #include "../include/common.h" |
22 | #include <fcntl.h> | ||
23 | #include <ftw.h> | 22 | #include <ftw.h> |
24 | #include <errno.h> | 23 | #include <errno.h> |
25 | #include <pwd.h> | 24 | #include <pwd.h> |
26 | 25 | ||
26 | #include <fcntl.h> | ||
27 | #ifndef O_PATH | ||
28 | #define O_PATH 010000000 | ||
29 | #endif | ||
30 | |||
27 | #if HAVE_SELINUX | 31 | #if HAVE_SELINUX |
28 | #include <sys/stat.h> | 32 | #include <sys/stat.h> |
29 | #include <sys/types.h> | 33 | #include <sys/types.h> |
@@ -55,7 +59,7 @@ static void selinux_relabel_path(const char *path, const char *inside_path) { | |||
55 | assert(path); | 59 | assert(path); |
56 | assert(inside_path); | 60 | assert(inside_path); |
57 | #if HAVE_SELINUX | 61 | #if HAVE_SELINUX |
58 | char procfs_path[64]; | 62 | char procfs_path[64]; |
59 | char *fcon = NULL; | 63 | char *fcon = NULL; |
60 | int fd; | 64 | int fd; |
61 | struct stat st; | 65 | struct stat st; |
@@ -69,20 +73,24 @@ static void selinux_relabel_path(const char *path, const char *inside_path) { | |||
69 | if (!label_hnd) | 73 | if (!label_hnd) |
70 | label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); | 74 | label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); |
71 | 75 | ||
76 | if (!label_hnd) | ||
77 | errExit("selabel_open"); | ||
78 | |||
72 | /* Open the file as O_PATH, to pin it while we determine and adjust the label */ | 79 | /* Open the file as O_PATH, to pin it while we determine and adjust the label */ |
73 | fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); | 80 | fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); |
74 | if (fd < 0) | 81 | if (fd < 0) |
75 | return; | 82 | return; |
76 | if (fstat(fd, &st) < 0) | 83 | if (fstat(fd, &st) < 0) |
77 | goto close; | 84 | goto close; |
78 | 85 | ||
79 | if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) == 0) { | 86 | if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) == 0) { |
80 | sprintf(procfs_path, "/proc/self/fd/%i", fd); | 87 | sprintf(procfs_path, "/proc/self/fd/%i", fd); |
81 | if (arg_debug) | 88 | if (arg_debug) |
82 | printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); | 89 | printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); |
83 | 90 | ||
84 | setfilecon_raw(procfs_path, fcon); | 91 | if (setfilecon_raw(procfs_path, fcon) != 0 && arg_debug) |
85 | } | 92 | printf("Cannot relabel %s: %s\n", path, strerror(errno)); |
93 | } | ||
86 | freecon(fcon); | 94 | freecon(fcon); |
87 | close: | 95 | close: |
88 | close(fd); | 96 | close(fd); |
@@ -192,7 +200,8 @@ static char *proc_pid_to_self(const char *target) { | |||
192 | 200 | ||
193 | // check where /proc/self points to | 201 | // check where /proc/self points to |
194 | static const char proc_self[] = "/proc/self"; | 202 | static const char proc_self[] = "/proc/self"; |
195 | if (!(proc_pid = realpath(proc_self, NULL))) | 203 | proc_pid = realpath(proc_self, NULL); |
204 | if (proc_pid == NULL) | ||
196 | goto done; | 205 | goto done; |
197 | 206 | ||
198 | // redirect /proc/PID/xxx -> /proc/self/XXX | 207 | // redirect /proc/PID/xxx -> /proc/self/XXX |
@@ -340,7 +349,7 @@ static char *check(const char *src) { | |||
340 | 349 | ||
341 | errexit: | 350 | errexit: |
342 | free(rsrc); | 351 | free(rsrc); |
343 | fprintf(stderr, "Error fcopy: invalid file %s\n", src); | 352 | fprintf(stderr, "Error fcopy: invalid ownership for file %s\n", src); |
344 | exit(1); | 353 | exit(1); |
345 | } | 354 | } |
346 | 355 | ||
@@ -463,18 +472,12 @@ int main(int argc, char **argv) { | |||
463 | size_t len = strlen(src); | 472 | size_t len = strlen(src); |
464 | while (len > 1 && src[len - 1] == '/') | 473 | while (len > 1 && src[len - 1] == '/') |
465 | src[--len] = '\0'; | 474 | src[--len] = '\0'; |
466 | if (strcspn(src, "\\*&!?\"'<>%^(){}[];,") != len) { | 475 | reject_meta_chars(src, 0); |
467 | fprintf(stderr, "Error fcopy: invalid source file name %s\n", src); | ||
468 | exit(1); | ||
469 | } | ||
470 | 476 | ||
471 | len = strlen(dest); | 477 | len = strlen(dest); |
472 | while (len > 1 && dest[len - 1] == '/') | 478 | while (len > 1 && dest[len - 1] == '/') |
473 | dest[--len] = '\0'; | 479 | dest[--len] = '\0'; |
474 | if (strcspn(dest, "\\*&!?\"'<>%^(){}[];,~") != len) { | 480 | reject_meta_chars(dest, 0); |
475 | fprintf(stderr, "Error fcopy: invalid dest file name %s\n", dest); | ||
476 | exit(1); | ||
477 | } | ||
478 | 481 | ||
479 | // the destination should be a directory; | 482 | // the destination should be a directory; |
480 | struct stat s; | 483 | struct stat s; |
diff --git a/src/fids/Makefile.in b/src/fids/Makefile.in new file mode 100644 index 000000000..5530bcee2 --- /dev/null +++ b/src/fids/Makefile.in | |||
@@ -0,0 +1,18 @@ | |||
1 | .PHONY: all | ||
2 | all: fids | ||
3 | |||
4 | include ../common.mk | ||
5 | |||
6 | %.o : %.c $(H_FILE_LIST) ../include/common.h | ||
7 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | ||
8 | |||
9 | #fseccomp: $(OBJS) ../lib/common.o ../lib/errno.o ../lib/syscall.o | ||
10 | fids: $(OBJS) | ||
11 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | ||
12 | |||
13 | .PHONY: clean | ||
14 | clean:; rm -fr *.o fids *.gcov *.gcda *.gcno *.plist | ||
15 | |||
16 | .PHONY: distclean | ||
17 | distclean: clean | ||
18 | rm -fr Makefile | ||
diff --git a/src/fids/blake2b.c b/src/fids/blake2b.c new file mode 100644 index 000000000..ec7cf8602 --- /dev/null +++ b/src/fids/blake2b.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | /* A simple unkeyed BLAKE2b Implementation based on the official reference | ||
22 | * from https://github.com/BLAKE2/BLAKE2. | ||
23 | * | ||
24 | * The original code was released under CC0 1.0 Universal license (Creative Commons), | ||
25 | * a public domain license. | ||
26 | */ | ||
27 | |||
28 | #include "fids.h" | ||
29 | |||
30 | // little-endian vs big-endian is irrelevant since the checksum is calculated and checked on the same computer. | ||
31 | static inline uint64_t load64( const void *src ) { | ||
32 | uint64_t w; | ||
33 | memcpy( &w, src, sizeof( w ) ); | ||
34 | return w; | ||
35 | } | ||
36 | |||
37 | // mixing function | ||
38 | #define ROTR64(x, y) (((x) >> (y)) ^ ((x) << (64 - (y)))) | ||
39 | #define G(a, b, c, d, x, y) { \ | ||
40 | v[a] = v[a] + v[b] + x; \ | ||
41 | v[d] = ROTR64(v[d] ^ v[a], 32); \ | ||
42 | v[c] = v[c] + v[d]; \ | ||
43 | v[b] = ROTR64(v[b] ^ v[c], 24); \ | ||
44 | v[a] = v[a] + v[b] + y; \ | ||
45 | v[d] = ROTR64(v[d] ^ v[a], 16); \ | ||
46 | v[c] = v[c] + v[d]; \ | ||
47 | v[b] = ROTR64(v[b] ^ v[c], 63); } | ||
48 | |||
49 | // init vector | ||
50 | static const uint64_t iv[8] = { | ||
51 | 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, | ||
52 | 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, | ||
53 | 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, | ||
54 | 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 | ||
55 | }; | ||
56 | |||
57 | |||
58 | const uint8_t sigma[12][16] = { | ||
59 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, | ||
60 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, | ||
61 | { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, | ||
62 | { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, | ||
63 | { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, | ||
64 | { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, | ||
65 | { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, | ||
66 | { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, | ||
67 | { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, | ||
68 | { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, | ||
69 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, | ||
70 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } | ||
71 | }; | ||
72 | |||
73 | // blake2b context | ||
74 | typedef struct { | ||
75 | uint8_t b[128]; // input buffer | ||
76 | uint64_t h[8]; // chained state | ||
77 | uint64_t t[2]; // total number of bytes | ||
78 | size_t c; // pointer for b[] | ||
79 | size_t outlen; // digest size | ||
80 | } CTX; | ||
81 | |||
82 | // compress function | ||
83 | static void compress(CTX *ctx, int last) { | ||
84 | uint64_t m[16]; | ||
85 | uint64_t v[16]; | ||
86 | size_t i; | ||
87 | |||
88 | for (i = 0; i < 16; i++) | ||
89 | m[i] = load64(&ctx->b[8 * i]); | ||
90 | |||
91 | for (i = 0; i < 8; i++) { | ||
92 | v[i] = ctx->h[i]; | ||
93 | v[i + 8] = iv[i]; | ||
94 | } | ||
95 | |||
96 | v[12] ^= ctx->t[0]; | ||
97 | v[13] ^= ctx->t[1]; | ||
98 | if (last) | ||
99 | v[14] = ~v[14]; | ||
100 | |||
101 | for (i = 0; i < 12; i++) { | ||
102 | G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]); | ||
103 | G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]); | ||
104 | G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]); | ||
105 | G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]); | ||
106 | G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]); | ||
107 | G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]); | ||
108 | G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]); | ||
109 | G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]); | ||
110 | } | ||
111 | |||
112 | for( i = 0; i < 8; ++i ) | ||
113 | ctx->h[i] ^= v[i] ^ v[i + 8]; | ||
114 | } | ||
115 | |||
116 | static int init(CTX *ctx, size_t outlen) { // (keylen=0: no key) | ||
117 | size_t i; | ||
118 | |||
119 | if (outlen == 0 || outlen > 64) | ||
120 | return -1; | ||
121 | |||
122 | for (i = 0; i < 8; i++) | ||
123 | ctx->h[i] = iv[i]; | ||
124 | ctx->h[0] ^= 0x01010000 ^ outlen; | ||
125 | |||
126 | ctx->t[0] = 0; | ||
127 | ctx->t[1] = 0; | ||
128 | ctx->c = 0; | ||
129 | ctx->outlen = outlen; | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static void update(CTX *ctx, const void *in, size_t inlen) { | ||
135 | size_t i; | ||
136 | |||
137 | for (i = 0; i < inlen; i++) { | ||
138 | if (ctx->c == 128) { | ||
139 | ctx->t[0] += ctx->c; | ||
140 | if (ctx->t[0] < ctx->c) | ||
141 | ctx->t[1]++; | ||
142 | compress(ctx, 0); | ||
143 | ctx->c = 0; | ||
144 | } | ||
145 | ctx->b[ctx->c++] = ((const uint8_t *) in)[i]; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void final(CTX *ctx, void *out) { | ||
150 | size_t i; | ||
151 | |||
152 | ctx->t[0] += ctx->c; | ||
153 | if (ctx->t[0] < ctx->c) | ||
154 | ctx->t[1]++; | ||
155 | |||
156 | while (ctx->c < 128) | ||
157 | ctx->b[ctx->c++] = 0; | ||
158 | compress(ctx, 1); | ||
159 | |||
160 | for (i = 0; i < ctx->outlen; i++) { | ||
161 | ((uint8_t *) out)[i] = | ||
162 | (ctx->h[i >> 3] >> (8 * (i & 7))) & 0xFF; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | // public function | ||
167 | int blake2b(void *out, size_t outlen, const void *in, size_t inlen) { | ||
168 | CTX ctx; | ||
169 | |||
170 | if (init(&ctx, outlen)) | ||
171 | return -1; | ||
172 | update(&ctx, in, inlen); | ||
173 | final(&ctx, out); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
diff --git a/src/fids/config b/src/fids/config new file mode 100644 index 000000000..c18c97260 --- /dev/null +++ b/src/fids/config | |||
@@ -0,0 +1,16 @@ | |||
1 | /bin | ||
2 | /sbin | ||
3 | /usr/bin | ||
4 | /usr/sbin | ||
5 | /usr/games | ||
6 | /opt | ||
7 | /usr/share/ca-certificates | ||
8 | |||
9 | |||
10 | /home/netblue/.bashrc | ||
11 | /home/netblue/.config/firejail | ||
12 | /home/netblue/.config/autostart | ||
13 | /home/netblue/Desktop/*.desktop | ||
14 | /home/netblue/.ssh | ||
15 | /home/netblue/.gnupg | ||
16 | |||
diff --git a/src/fids/db.c b/src/fids/db.c new file mode 100644 index 000000000..e8dfab1ac --- /dev/null +++ b/src/fids/db.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include"fids.h" | ||
21 | |||
22 | typedef struct db_t { | ||
23 | struct db_t *next; | ||
24 | char *fname; | ||
25 | char *checksum; | ||
26 | char *mode; | ||
27 | int checked; | ||
28 | } DB; | ||
29 | |||
30 | #define MAXBUF 4096 | ||
31 | static DB *database[HASH_MAX] = {NULL}; | ||
32 | |||
33 | // djb2 hash function by Dan Bernstein | ||
34 | static unsigned hash(const char *str) { | ||
35 | unsigned long hash = 5381; | ||
36 | int c; | ||
37 | |||
38 | while ((c = *str++) != '\0') | ||
39 | hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ | ||
40 | |||
41 | return hash & (HASH_MAX - 1); | ||
42 | } | ||
43 | |||
44 | #if 0 | ||
45 | // for testing the hash table | ||
46 | static void db_print(void) { | ||
47 | int i; | ||
48 | for (i = 0; i < HASH_MAX; i++) { | ||
49 | int cnt = 0; | ||
50 | DB *ptr = database[i]; | ||
51 | while (ptr) { | ||
52 | cnt++; | ||
53 | ptr = ptr->next; | ||
54 | } | ||
55 | printf("%d ", cnt); | ||
56 | fflush(0); | ||
57 | } | ||
58 | printf("\n"); | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | static void db_add(const char *fname, const char *checksum, const char *mode) { | ||
63 | DB *ptr = malloc(sizeof(DB)); | ||
64 | if (!ptr) | ||
65 | errExit("malloc"); | ||
66 | ptr->fname = strdup(fname); | ||
67 | ptr->checksum = strdup(checksum); | ||
68 | ptr->mode = strdup(mode); | ||
69 | ptr->checked = 0; | ||
70 | if (!ptr->fname || !ptr->checksum || !ptr->mode) | ||
71 | errExit("strdup"); | ||
72 | |||
73 | unsigned h = hash(fname); | ||
74 | ptr->next = database[h]; | ||
75 | database[h] = ptr; | ||
76 | } | ||
77 | |||
78 | void db_check(const char *fname, const char *checksum, const char *mode) { | ||
79 | assert(fname); | ||
80 | assert(checksum); | ||
81 | assert(mode); | ||
82 | |||
83 | unsigned h =hash(fname); | ||
84 | DB *ptr = database[h]; | ||
85 | while (ptr) { | ||
86 | if (strcmp(fname, ptr->fname) == 0) { | ||
87 | ptr->checked = 1; | ||
88 | break; | ||
89 | } | ||
90 | ptr = ptr->next; | ||
91 | } | ||
92 | |||
93 | if (ptr ) { | ||
94 | if (strcmp(checksum, ptr->checksum)) { | ||
95 | f_modified++; | ||
96 | fprintf(stderr, "\nWarning: modified %s\n", fname); | ||
97 | } | ||
98 | if (strcmp(mode, ptr->mode)) { | ||
99 | f_permissions++; | ||
100 | fprintf(stderr, "\nWarning: permissions %s: old %s, new %s\n", | ||
101 | fname, ptr->mode, mode); | ||
102 | } | ||
103 | } | ||
104 | else { | ||
105 | f_new++; | ||
106 | fprintf(stderr, "\nWarning: new file %s\n", fname); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | void db_missing(void) { | ||
111 | int i; | ||
112 | for (i = 0; i < HASH_MAX; i++) { | ||
113 | DB *ptr = database[i]; | ||
114 | while (ptr) { | ||
115 | if (!ptr->checked) { | ||
116 | f_removed++; | ||
117 | fprintf(stderr, "Warning: removed %s\n", ptr->fname); | ||
118 | } | ||
119 | ptr = ptr->next; | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | // return 0 if ok, 1 if error | ||
125 | int db_init(void) { | ||
126 | char buf[MAXBUF]; | ||
127 | while(fgets(buf, MAXBUF, stdin)) { | ||
128 | // split - tab separated | ||
129 | |||
130 | char *mode = buf; | ||
131 | char *ptr = strchr(buf, '\t'); | ||
132 | if (!ptr) | ||
133 | goto errexit; | ||
134 | *ptr = '\0'; | ||
135 | |||
136 | char *checksum = ptr + 1; | ||
137 | ptr = strchr(checksum, '\t'); | ||
138 | if (!ptr) | ||
139 | goto errexit; | ||
140 | *ptr = '\0'; | ||
141 | |||
142 | char *fname = ptr + 1; | ||
143 | ptr = strchr(fname, '\n'); | ||
144 | if (!ptr) | ||
145 | goto errexit; | ||
146 | *ptr = '\0'; | ||
147 | |||
148 | db_add(fname, checksum, mode); | ||
149 | } | ||
150 | // db_print(); | ||
151 | |||
152 | return 0; | ||
153 | |||
154 | errexit: | ||
155 | fprintf(stderr, "Error fids: database corrupted\n"); | ||
156 | exit(1); | ||
157 | } | ||
158 | |||
diff --git a/src/fids/db_exclude.c b/src/fids/db_exclude.c new file mode 100644 index 000000000..cfb37219c --- /dev/null +++ b/src/fids/db_exclude.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include"fids.h" | ||
21 | |||
22 | typedef struct db_exclude_t { | ||
23 | struct db_exclude_t *next; | ||
24 | char *fname; | ||
25 | int len; | ||
26 | } DB_EXCLUDE; | ||
27 | static DB_EXCLUDE *database = NULL; | ||
28 | |||
29 | void db_exclude_add(const char *fname) { | ||
30 | assert(fname); | ||
31 | |||
32 | DB_EXCLUDE *ptr = malloc(sizeof(DB_EXCLUDE)); | ||
33 | if (!ptr) | ||
34 | errExit("malloc"); | ||
35 | |||
36 | ptr->fname = strdup(fname); | ||
37 | if (!ptr->fname) | ||
38 | errExit("strdup"); | ||
39 | ptr->len = strlen(fname); | ||
40 | ptr->next = database; | ||
41 | database = ptr; | ||
42 | } | ||
43 | |||
44 | int db_exclude_check(const char *fname) { | ||
45 | assert(fname); | ||
46 | |||
47 | DB_EXCLUDE *ptr = database; | ||
48 | while (ptr != NULL) { | ||
49 | if (strncmp(fname, ptr->fname, ptr->len) == 0) | ||
50 | return 1; | ||
51 | ptr = ptr->next; | ||
52 | } | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
diff --git a/src/fids/fids.h b/src/fids/fids.h new file mode 100644 index 000000000..93ae106a1 --- /dev/null +++ b/src/fids/fids.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #ifndef FIDS_H | ||
21 | #define FIDS_H | ||
22 | |||
23 | #include "../include/common.h" | ||
24 | |||
25 | // main.c | ||
26 | #define MAX_DIR_LEVEL 20 // max directory tree depth | ||
27 | #define MAX_INCLUDE_LEVEL 10 // max include level for config files | ||
28 | extern int f_scanned; | ||
29 | extern int f_modified; | ||
30 | extern int f_new; | ||
31 | extern int f_removed; | ||
32 | extern int f_permissions; | ||
33 | |||
34 | // db.c | ||
35 | #define HASH_MAX 2048 // power of 2 | ||
36 | int db_init(void); | ||
37 | void db_check(const char *fname, const char *checksum, const char *mode); | ||
38 | void db_missing(void); | ||
39 | |||
40 | // db_exclude.c | ||
41 | void db_exclude_add(const char *fname); | ||
42 | int db_exclude_check(const char *fname); | ||
43 | |||
44 | |||
45 | // blake2b.c | ||
46 | //#define KEY_SIZE 128 // key size in bytes | ||
47 | #define KEY_SIZE 256 | ||
48 | //#define KEY_SIZE 512 | ||
49 | int blake2b(void *out, size_t outlen, const void *in, size_t inlen); | ||
50 | |||
51 | #endif | ||
diff --git a/src/fids/main.c b/src/fids/main.c new file mode 100644 index 000000000..e6be365d1 --- /dev/null +++ b/src/fids/main.c | |||
@@ -0,0 +1,378 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include "fids.h" | ||
21 | #include <sys/types.h> | ||
22 | #include <sys/stat.h> | ||
23 | #include <unistd.h> | ||
24 | #include <fcntl.h> | ||
25 | #include <sys/mman.h> | ||
26 | #include <dirent.h> | ||
27 | #include <glob.h> | ||
28 | |||
29 | #define MAXBUF 4096 | ||
30 | |||
31 | static int dir_level = 1; | ||
32 | static int include_level = 0; | ||
33 | int arg_init = 0; | ||
34 | int arg_check = 0; | ||
35 | char *arg_homedir = NULL; | ||
36 | char *arg_dbfile = NULL; | ||
37 | |||
38 | int f_scanned = 0; | ||
39 | int f_modified = 0; | ||
40 | int f_new = 0; | ||
41 | int f_removed = 0; | ||
42 | int f_permissions = 0; | ||
43 | |||
44 | |||
45 | |||
46 | static inline int is_dir(const char *fname) { | ||
47 | assert(fname); | ||
48 | |||
49 | struct stat s; | ||
50 | if (stat(fname, &s) == 0) { | ||
51 | if (S_ISDIR(s.st_mode)) | ||
52 | return 1; | ||
53 | } | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static inline int is_link(const char *fname) { | ||
58 | assert(fname); | ||
59 | |||
60 | char c; | ||
61 | ssize_t rv = readlink(fname, &c, 1); | ||
62 | return (rv != -1); | ||
63 | } | ||
64 | |||
65 | // mode is an array of 10 chars or more | ||
66 | static inline void file_mode(const char *fname, char *mode) { | ||
67 | assert(fname); | ||
68 | assert(mode); | ||
69 | |||
70 | struct stat s; | ||
71 | if (stat(fname, &s)) { | ||
72 | *mode = '\0'; | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | sprintf(mode, (s.st_mode & S_IRUSR) ? "r" : "-"); | ||
77 | sprintf(mode + 1, (s.st_mode & S_IWUSR) ? "w" : "-"); | ||
78 | sprintf(mode + 2, (s.st_mode & S_IXUSR) ? "x" : "-"); | ||
79 | sprintf(mode + 3, (s.st_mode & S_IRGRP) ? "r" : "-"); | ||
80 | sprintf(mode + 4, (s.st_mode & S_IWGRP) ? "w" : "-"); | ||
81 | sprintf(mode + 5, (s.st_mode & S_IXGRP) ? "x" : "-"); | ||
82 | sprintf(mode + 6, (s.st_mode & S_IROTH) ? "r" : "-"); | ||
83 | sprintf(mode + 7, (s.st_mode & S_IWOTH) ? "w" : "-"); | ||
84 | sprintf(mode + 8, (s.st_mode & S_IXOTH) ? "x" : "-"); | ||
85 | } | ||
86 | |||
87 | |||
88 | static void file_checksum(const char *fname) { | ||
89 | assert(fname); | ||
90 | |||
91 | int fd = open(fname, O_RDONLY); | ||
92 | if (fd == -1) | ||
93 | return; | ||
94 | |||
95 | off_t size = lseek(fd, 0, SEEK_END); | ||
96 | if (size < 0) { | ||
97 | close(fd); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | char *content = "empty"; | ||
102 | int mmapped = 0; | ||
103 | if (size == 0) { | ||
104 | // empty files don't mmap - use "empty" string as the file content | ||
105 | size = 6; // strlen("empty") + 1 | ||
106 | } | ||
107 | else { | ||
108 | content = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); | ||
109 | close(fd); | ||
110 | mmapped = 1; | ||
111 | } | ||
112 | |||
113 | unsigned char checksum[KEY_SIZE / 8]; | ||
114 | blake2b(checksum, sizeof(checksum), content, size); | ||
115 | if (mmapped) | ||
116 | munmap(content, size); | ||
117 | |||
118 | // calculate blake2 checksum | ||
119 | char str_checksum[(KEY_SIZE / 8) * 2 + 1]; | ||
120 | int long unsigned i; | ||
121 | char *ptr = str_checksum; | ||
122 | for (i = 0; i < sizeof(checksum); i++, ptr += 2) | ||
123 | sprintf(ptr, "%02x", (unsigned char ) checksum[i]); | ||
124 | |||
125 | // build permissions string | ||
126 | char mode[10]; | ||
127 | file_mode(fname, mode); | ||
128 | |||
129 | if (arg_init) | ||
130 | printf("%s\t%s\t%s\n", mode, str_checksum, fname); | ||
131 | else if (arg_check) | ||
132 | db_check(fname, str_checksum, mode); | ||
133 | else | ||
134 | assert(0); | ||
135 | |||
136 | f_scanned++; | ||
137 | if (f_scanned % 500 == 0) | ||
138 | fprintf(stderr, "%d ", f_scanned); | ||
139 | fflush(0); | ||
140 | } | ||
141 | |||
142 | void list_directory(const char *fname) { | ||
143 | assert(fname); | ||
144 | if (dir_level > MAX_DIR_LEVEL) { | ||
145 | fprintf(stderr, "Warning fids: maximum depth level exceeded for %s\n", fname); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | if (db_exclude_check(fname)) | ||
150 | return; | ||
151 | |||
152 | if (is_link(fname)) | ||
153 | return; | ||
154 | |||
155 | if (!is_dir(fname)) { | ||
156 | file_checksum(fname); | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | DIR *dir; | ||
161 | struct dirent *entry; | ||
162 | |||
163 | if (!(dir = opendir(fname))) | ||
164 | return; | ||
165 | |||
166 | dir_level++; | ||
167 | while ((entry = readdir(dir)) != NULL) { | ||
168 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||
169 | continue; | ||
170 | char *path; | ||
171 | if (asprintf(&path, "%s/%s", fname, entry->d_name) == -1) | ||
172 | errExit("asprintf"); | ||
173 | list_directory(path); | ||
174 | free(path); | ||
175 | } | ||
176 | closedir(dir); | ||
177 | dir_level--; | ||
178 | } | ||
179 | |||
180 | void globbing(const char *fname) { | ||
181 | assert(fname); | ||
182 | |||
183 | // filter top directory | ||
184 | if (strcmp(fname, "/") == 0) | ||
185 | return; | ||
186 | |||
187 | glob_t globbuf; | ||
188 | int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf); | ||
189 | if (globerr) { | ||
190 | fprintf(stderr, "Error fids: failed to glob pattern %s\n", fname); | ||
191 | exit(1); | ||
192 | } | ||
193 | |||
194 | long unsigned i; | ||
195 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
196 | char *path = globbuf.gl_pathv[i]; | ||
197 | assert(path); | ||
198 | |||
199 | list_directory(path); | ||
200 | } | ||
201 | |||
202 | globfree(&globbuf); | ||
203 | } | ||
204 | |||
205 | static void process_config(const char *fname) { | ||
206 | assert(fname); | ||
207 | |||
208 | if (++include_level >= MAX_INCLUDE_LEVEL) { | ||
209 | fprintf(stderr, "Error ids: maximum include level for config files exceeded\n"); | ||
210 | exit(1); | ||
211 | } | ||
212 | |||
213 | fprintf(stderr, "Opening config file %s\n", fname); | ||
214 | int fd = open(fname, O_RDONLY|O_CLOEXEC); | ||
215 | if (fd < 0) { | ||
216 | if (include_level == 1) { | ||
217 | fprintf(stderr, "Error ids: cannot open config file %s\n", fname); | ||
218 | exit(1); | ||
219 | } | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | // make sure the file is owned by root | ||
224 | struct stat s; | ||
225 | if (fstat(fd, &s)) { | ||
226 | fprintf(stderr, "Error ids: cannot stat config file %s\n", fname); | ||
227 | exit(1); | ||
228 | } | ||
229 | if (s.st_uid || s.st_gid) { | ||
230 | fprintf(stderr, "Error ids: config file not owned by root\n"); | ||
231 | exit(1); | ||
232 | } | ||
233 | |||
234 | fprintf(stderr, "Loading config file %s\n", fname); | ||
235 | FILE *fp = fdopen(fd, "r"); | ||
236 | if (!fp) { | ||
237 | fprintf(stderr, "Error fids: cannot open config file %s\n", fname); | ||
238 | exit(1); | ||
239 | } | ||
240 | |||
241 | char buf[MAXBUF]; | ||
242 | int line = 0; | ||
243 | while (fgets(buf, MAXBUF, fp)) { | ||
244 | line++; | ||
245 | |||
246 | // trim \n | ||
247 | char *ptr = strchr(buf, '\n'); | ||
248 | if (ptr) | ||
249 | *ptr = '\0'; | ||
250 | |||
251 | // comments | ||
252 | ptr = strchr(buf, '#'); | ||
253 | if (ptr) | ||
254 | *ptr = '\0'; | ||
255 | |||
256 | // empty space | ||
257 | ptr = buf; | ||
258 | while (*ptr == ' ' || *ptr == '\t') | ||
259 | ptr++; | ||
260 | char *start = ptr; | ||
261 | |||
262 | // empty line | ||
263 | if (*start == '\0') | ||
264 | continue; | ||
265 | |||
266 | // trailing spaces | ||
267 | ptr = start + strlen(start); | ||
268 | ptr--; | ||
269 | while (*ptr == ' ' || *ptr == '\t') | ||
270 | *ptr-- = '\0'; | ||
271 | |||
272 | // replace ${HOME} | ||
273 | if (strncmp(start, "include", 7) == 0) { | ||
274 | ptr = start + 7; | ||
275 | if ((*ptr != ' ' && *ptr != '\t') || *ptr == '\0') { | ||
276 | fprintf(stderr, "Error fids: invalid line %d in %s\n", line, fname); | ||
277 | exit(1); | ||
278 | } | ||
279 | while (*ptr == ' ' || *ptr == '\t') | ||
280 | ptr++; | ||
281 | |||
282 | if (*ptr == '/') | ||
283 | process_config(ptr); | ||
284 | else { | ||
285 | // assume the file is in /etc/firejail | ||
286 | char *tmp; | ||
287 | if (asprintf(&tmp, "/etc/firejail/%s", ptr) == -1) | ||
288 | errExit("asprintf"); | ||
289 | process_config(tmp); | ||
290 | free(tmp); | ||
291 | } | ||
292 | } | ||
293 | else if (*start == '!') { | ||
294 | // exclude file or dir | ||
295 | start++; | ||
296 | if (strncmp(start, "${HOME}", 7)) | ||
297 | db_exclude_add(start); | ||
298 | else { | ||
299 | char *fname; | ||
300 | if (asprintf(&fname, "%s%s", arg_homedir, start + 7) == -1) | ||
301 | errExit("asprintf"); | ||
302 | db_exclude_add(fname); | ||
303 | free(fname); | ||
304 | } | ||
305 | } | ||
306 | else if (strncmp(start, "${HOME}", 7)) | ||
307 | globbing(start); | ||
308 | else { | ||
309 | char *fname; | ||
310 | if (asprintf(&fname, "%s%s", arg_homedir, start + 7) == -1) | ||
311 | errExit("asprintf"); | ||
312 | globbing(fname); | ||
313 | free(fname); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | fclose(fp); | ||
318 | include_level--; | ||
319 | } | ||
320 | |||
321 | |||
322 | |||
323 | void usage(void) { | ||
324 | printf("Usage: fids [--help|-h|-?] --init|--check homedir\n"); | ||
325 | } | ||
326 | |||
327 | int main(int argc, char **argv) { | ||
328 | int i; | ||
329 | for (i = 1; i < argc; i++) { | ||
330 | if (strcmp(argv[i], "-h") == 0 || | ||
331 | strcmp(argv[i], "-?") == 0 || | ||
332 | strcmp(argv[i], "--help") == 0) { | ||
333 | usage(); | ||
334 | return 0; | ||
335 | } | ||
336 | else if (strcmp(argv[i], "--init") == 0) | ||
337 | arg_init = 1; | ||
338 | else if (strcmp(argv[i], "--check") == 0) | ||
339 | arg_check = 1; | ||
340 | else if (strncmp(argv[i], "--", 2) == 0) { | ||
341 | fprintf(stderr, "Error fids: invalid argument %s\n", argv[i]); | ||
342 | exit(1); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | if (argc != 3) { | ||
347 | fprintf(stderr, "Error fids: invalid number of arguments\n"); | ||
348 | exit(1); | ||
349 | } | ||
350 | arg_homedir = argv[2]; | ||
351 | |||
352 | int op = arg_check + arg_init; | ||
353 | if (op == 0 || op == 2) { | ||
354 | fprintf(stderr, "Error fids: use either --init or --check\n"); | ||
355 | exit(1); | ||
356 | } | ||
357 | |||
358 | if (arg_init) { | ||
359 | process_config(SYSCONFDIR"/ids.config"); | ||
360 | fprintf(stderr, "\n%d files scanned\n", f_scanned); | ||
361 | fprintf(stderr, "IDS database initialized\n"); | ||
362 | } | ||
363 | else if (arg_check) { | ||
364 | if (db_init()) { | ||
365 | fprintf(stderr, "Error: IDS database not initialized, please run \"firejail --ids-init\"\n"); | ||
366 | exit(1); | ||
367 | } | ||
368 | |||
369 | process_config(SYSCONFDIR"/ids.config"); | ||
370 | fprintf(stderr, "\n%d files scanned: modified %d, permissions %d, new %d, removed %d\n", | ||
371 | f_scanned, f_modified, f_permissions, f_new, f_removed); | ||
372 | db_missing(); | ||
373 | } | ||
374 | else | ||
375 | assert(0); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
diff --git a/src/firecfg/desktop_files.c b/src/firecfg/desktop_files.c index 06b0a117f..408662907 100644 --- a/src/firecfg/desktop_files.c +++ b/src/firecfg/desktop_files.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -24,11 +24,16 @@ | |||
24 | static int check_profile(const char *name, const char *homedir) { | 24 | static int check_profile(const char *name, const char *homedir) { |
25 | // build profile name | 25 | // build profile name |
26 | char *profname1; | 26 | char *profname1; |
27 | #ifndef HAVE_ONLY_SYSCFG_PROFILES | ||
27 | char *profname2; | 28 | char *profname2; |
29 | #endif | ||
28 | if (asprintf(&profname1, "%s/%s.profile", SYSCONFDIR, name) == -1) | 30 | if (asprintf(&profname1, "%s/%s.profile", SYSCONFDIR, name) == -1) |
29 | errExit("asprintf"); | 31 | errExit("asprintf"); |
32 | |||
33 | #ifndef HAVE_ONLY_SYSCFG_PROFILES | ||
30 | if (asprintf(&profname2, "%s/.config/firejail/%s.profile", homedir, name) == -1) | 34 | if (asprintf(&profname2, "%s/.config/firejail/%s.profile", homedir, name) == -1) |
31 | errExit("asprintf"); | 35 | errExit("asprintf"); |
36 | #endif | ||
32 | 37 | ||
33 | int rv = 0; | 38 | int rv = 0; |
34 | if (access(profname1, R_OK) == 0) { | 39 | if (access(profname1, R_OK) == 0) { |
@@ -36,14 +41,18 @@ static int check_profile(const char *name, const char *homedir) { | |||
36 | printf("found %s\n", profname1); | 41 | printf("found %s\n", profname1); |
37 | rv = 1; | 42 | rv = 1; |
38 | } | 43 | } |
44 | #ifndef HAVE_ONLY_SYSCFG_PROFILES | ||
39 | else if (access(profname2, R_OK) == 0) { | 45 | else if (access(profname2, R_OK) == 0) { |
40 | if (arg_debug) | 46 | if (arg_debug) |
41 | printf("found %s\n", profname2); | 47 | printf("found %s\n", profname2); |
42 | rv = 1; | 48 | rv = 1; |
43 | } | 49 | } |
50 | #endif | ||
44 | 51 | ||
45 | free(profname1); | 52 | free(profname1); |
53 | #ifndef HAVE_ONLY_SYSCFG_PROFILES | ||
46 | free(profname2); | 54 | free(profname2); |
55 | #endif | ||
47 | return rv; | 56 | return rv; |
48 | } | 57 | } |
49 | 58 | ||
@@ -168,9 +177,9 @@ void fix_desktop_files(char *homedir) { | |||
168 | 177 | ||
169 | char *filename = entry->d_name; | 178 | char *filename = entry->d_name; |
170 | 179 | ||
171 | // skip links | 180 | // skip links - Discord on Arch #4235 seems to be a symlink to /opt directory |
172 | if (is_link(filename)) | 181 | // if (is_link(filename)) |
173 | continue; | 182 | // continue; |
174 | 183 | ||
175 | // no profile in /etc/firejail, no desktop file fixing | 184 | // no profile in /etc/firejail, no desktop file fixing |
176 | if (!have_profile(filename, homedir)) | 185 | if (!have_profile(filename, homedir)) |
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config index 474904ebf..618093193 100644 --- a/src/firecfg/firecfg.config +++ b/src/firecfg/firecfg.config | |||
@@ -1,8 +1,8 @@ | |||
1 | # /usr/lib/firejail/firecfg.config - firecfg utility configuration file | 1 | # /etc/firejail/firecfg.config - firecfg utility configuration file |
2 | # This is the list of programs in alphabetical order handled by firecfg utility | 2 | # This is the list of programs in alphabetical order handled by firecfg utility |
3 | # | 3 | # |
4 | #qemu-system-x86_64 | ||
5 | 0ad | 4 | 0ad |
5 | 1password | ||
6 | 2048-qt | 6 | 2048-qt |
7 | Books | 7 | Books |
8 | Builder | 8 | Builder |
@@ -38,13 +38,15 @@ abrowser | |||
38 | akonadi_control | 38 | akonadi_control |
39 | akregator | 39 | akregator |
40 | alacarte | 40 | alacarte |
41 | alpine | ||
42 | alpinef | ||
41 | amarok | 43 | amarok |
42 | amule | 44 | amule |
43 | amuled | 45 | amuled |
44 | android-studio | 46 | android-studio |
45 | anydesk | 47 | anydesk |
46 | apostrophe | ||
47 | apktool | 48 | apktool |
49 | apostrophe | ||
48 | # ar - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) | 50 | # ar - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) |
49 | arch-audit | 51 | arch-audit |
50 | archaudit-report | 52 | archaudit-report |
@@ -92,6 +94,7 @@ bleachbit | |||
92 | blender | 94 | blender |
93 | blender-2.8 | 95 | blender-2.8 |
94 | bless | 96 | bless |
97 | blobby | ||
95 | blobwars | 98 | blobwars |
96 | bluefish | 99 | bluefish |
97 | bnox | 100 | bnox |
@@ -107,6 +110,7 @@ brave-browser-stable | |||
107 | # bzcat - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) | 110 | # bzcat - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) |
108 | bzflag | 111 | bzflag |
109 | # bzip2 - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) | 112 | # bzip2 - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) |
113 | cachy-browser | ||
110 | calibre | 114 | calibre |
111 | calligra | 115 | calligra |
112 | calligraauthor | 116 | calligraauthor |
@@ -136,23 +140,27 @@ clamdscan | |||
136 | clamdtop | 140 | clamdtop |
137 | clamscan | 141 | clamscan |
138 | clamtk | 142 | clamtk |
139 | claws-mail | ||
140 | clawsker | 143 | clawsker |
144 | claws-mail | ||
141 | clementine | 145 | clementine |
142 | clion | 146 | clion |
143 | clipit | 147 | clion-eap |
144 | clipgrab | 148 | clipgrab |
149 | clipit | ||
145 | cliqz | 150 | cliqz |
146 | clocks | 151 | clocks |
147 | cmus | 152 | cmus |
148 | code | 153 | code |
149 | code-oss | 154 | code-oss |
155 | codium | ||
156 | cointop | ||
150 | cola | 157 | cola |
151 | colorful | 158 | colorful |
152 | com.github.bleakgrey.tootle | 159 | com.github.bleakgrey.tootle |
153 | com.github.dahenson.agenda | 160 | com.github.dahenson.agenda |
154 | com.github.johnfactotum.Foliate | 161 | com.github.johnfactotum.Foliate |
155 | com.github.phase1geo.minder | 162 | com.github.phase1geo.minder |
163 | com.github.tchx84.Flatseal | ||
156 | com.gitlab.newsflash | 164 | com.gitlab.newsflash |
157 | conkeror | 165 | conkeror |
158 | conky | 166 | conky |
@@ -167,12 +175,14 @@ cvlc | |||
167 | cyberfox | 175 | cyberfox |
168 | darktable | 176 | darktable |
169 | dconf-editor | 177 | dconf-editor |
178 | ddgr | ||
170 | ddgtk | 179 | ddgtk |
171 | deadbeef | 180 | deadbeef |
172 | deluge | 181 | deluge |
173 | desktopeditors | 182 | desktopeditors |
174 | devhelp | 183 | devhelp |
175 | dex2jar | 184 | dex2jar |
185 | d-feet | ||
176 | dia | 186 | dia |
177 | dig | 187 | dig |
178 | digikam | 188 | digikam |
@@ -186,7 +196,6 @@ display-im6.q16 | |||
186 | dnox | 196 | dnox |
187 | dnscrypt-proxy | 197 | dnscrypt-proxy |
188 | dnsmasq | 198 | dnsmasq |
189 | dolphin | ||
190 | dolphin-emu | 199 | dolphin-emu |
191 | dooble | 200 | dooble |
192 | dooble-qt4 | 201 | dooble-qt4 |
@@ -195,13 +204,12 @@ dragon | |||
195 | drawio | 204 | drawio |
196 | drill | 205 | drill |
197 | dropbox | 206 | dropbox |
198 | d-feet | ||
199 | easystroke | 207 | easystroke |
200 | ebook-viewer | ||
201 | ebook-convert | 208 | ebook-convert |
202 | ebook-edit | 209 | ebook-edit |
203 | ebook-meta | 210 | ebook-meta |
204 | ebook-polish | 211 | ebook-polish |
212 | ebook-viewer | ||
205 | electron-mail | 213 | electron-mail |
206 | electrum | 214 | electrum |
207 | element-desktop | 215 | element-desktop |
@@ -251,8 +259,8 @@ flacsplt | |||
251 | flameshot | 259 | flameshot |
252 | flashpeak-slimjet | 260 | flashpeak-slimjet |
253 | flowblade | 261 | flowblade |
254 | font-manager | ||
255 | fontforge | 262 | fontforge |
263 | font-manager | ||
256 | fossamail | 264 | fossamail |
257 | four-in-a-row | 265 | four-in-a-row |
258 | fractal | 266 | fractal |
@@ -271,9 +279,12 @@ freetube | |||
271 | freshclam | 279 | freshclam |
272 | frogatto | 280 | frogatto |
273 | frozen-bubble | 281 | frozen-bubble |
282 | ftp | ||
283 | funnyboat | ||
274 | gajim | 284 | gajim |
275 | gajim-history-manager | 285 | gajim-history-manager |
276 | galculator | 286 | galculator |
287 | gallery-dl | ||
277 | gapplication | 288 | gapplication |
278 | gcalccmd | 289 | gcalccmd |
279 | gcloud | 290 | gcloud |
@@ -291,8 +302,8 @@ gimp-2.10 | |||
291 | gimp-2.8 | 302 | gimp-2.8 |
292 | gist | 303 | gist |
293 | gist-paste | 304 | gist-paste |
294 | gitg | ||
295 | git-cola | 305 | git-cola |
306 | gitg | ||
296 | github-desktop | 307 | github-desktop |
297 | gitter | 308 | gitter |
298 | # gjs -- https://github.com/netblue30/firejail/issues/3333#issuecomment-612601102 | 309 | # gjs -- https://github.com/netblue30/firejail/issues/3333#issuecomment-612601102 |
@@ -342,6 +353,7 @@ gnome-weather | |||
342 | gnote | 353 | gnote |
343 | gnubik | 354 | gnubik |
344 | godot | 355 | godot |
356 | goldendict | ||
345 | goobox | 357 | goobox |
346 | google-chrome | 358 | google-chrome |
347 | google-chrome-beta | 359 | google-chrome-beta |
@@ -350,6 +362,7 @@ google-chrome-unstable | |||
350 | google-earth | 362 | google-earth |
351 | google-earth-pro | 363 | google-earth-pro |
352 | google-play-music-desktop-player | 364 | google-play-music-desktop-player |
365 | googler | ||
353 | gpa | 366 | gpa |
354 | gpicview | 367 | gpicview |
355 | gpredict | 368 | gpredict |
@@ -357,10 +370,11 @@ gradio | |||
357 | gramps | 370 | gramps |
358 | gravity-beams-and-evaporating-stars | 371 | gravity-beams-and-evaporating-stars |
359 | gthumb | 372 | gthumb |
360 | gtk-straw-viewer | ||
361 | gtk-youtube-viewer | ||
362 | gtk2-youtube-viewer | 373 | gtk2-youtube-viewer |
363 | gtk3-youtube-viewer | 374 | gtk3-youtube-viewer |
375 | gtk-pipe-viewer | ||
376 | gtk-straw-viewer | ||
377 | gtk-youtube-viewer | ||
364 | guayadeque | 378 | guayadeque |
365 | gucharmap | 379 | gucharmap |
366 | gummi | 380 | gummi |
@@ -386,9 +400,11 @@ idea.sh | |||
386 | imagej | 400 | imagej |
387 | img2txt | 401 | img2txt |
388 | impressive | 402 | impressive |
403 | imv | ||
389 | inkscape | 404 | inkscape |
390 | inkview | 405 | inkview |
391 | inox | 406 | inox |
407 | io.github.lainsce.Notejot | ||
392 | ipcalc | 408 | ipcalc |
393 | ipcalc-ng | 409 | ipcalc-ng |
394 | iridium | 410 | iridium |
@@ -443,13 +459,16 @@ kube | |||
443 | kwrite | 459 | kwrite |
444 | leafpad | 460 | leafpad |
445 | # less - breaks man | 461 | # less - breaks man |
462 | librecad | ||
446 | libreoffice | 463 | libreoffice |
447 | librewolf | 464 | librewolf |
448 | librewolf-nightly | 465 | librewolf-nightly |
466 | lifeograph | ||
449 | liferea | 467 | liferea |
450 | lightsoff | 468 | lightsoff |
451 | lincity-ng | 469 | lincity-ng |
452 | links | 470 | links |
471 | links2 | ||
453 | linphone | 472 | linphone |
454 | lmms | 473 | lmms |
455 | lobase | 474 | lobase |
@@ -489,6 +508,7 @@ mathematica | |||
489 | matrix-mirage | 508 | matrix-mirage |
490 | mattermost-desktop | 509 | mattermost-desktop |
491 | mcabber | 510 | mcabber |
511 | mcomix | ||
492 | mediainfo | 512 | mediainfo |
493 | mediathekview | 513 | mediathekview |
494 | megaglest | 514 | megaglest |
@@ -499,6 +519,7 @@ mendeleydesktop | |||
499 | menulibre | 519 | menulibre |
500 | meteo-qt | 520 | meteo-qt |
501 | microsoft-edge | 521 | microsoft-edge |
522 | microsoft-edge-beta | ||
502 | microsoft-edge-dev | 523 | microsoft-edge-dev |
503 | midori | 524 | midori |
504 | min | 525 | min |
@@ -515,8 +536,8 @@ mp3splt-gtk | |||
515 | mp3wrap | 536 | mp3wrap |
516 | mpDris2 | 537 | mpDris2 |
517 | mpg123 | 538 | mpg123 |
518 | mpg123.bin | ||
519 | mpg123-alsa | 539 | mpg123-alsa |
540 | mpg123.bin | ||
520 | mpg123-id3dump | 541 | mpg123-id3dump |
521 | mpg123-jack | 542 | mpg123-jack |
522 | mpg123-nas | 543 | mpg123-nas |
@@ -555,6 +576,7 @@ mypaint | |||
555 | mypaint-ora-thumbnailer | 576 | mypaint-ora-thumbnailer |
556 | natron | 577 | natron |
557 | ncdu | 578 | ncdu |
579 | ncdu2 | ||
558 | neochat | 580 | neochat |
559 | neomutt | 581 | neomutt |
560 | netactview | 582 | netactview |
@@ -575,6 +597,7 @@ nitroshare-nmh | |||
575 | nitroshare-send | 597 | nitroshare-send |
576 | nitroshare-ui | 598 | nitroshare-ui |
577 | nomacs | 599 | nomacs |
600 | notable | ||
578 | nslookup | 601 | nslookup |
579 | nuclear | 602 | nuclear |
580 | nylas | 603 | nylas |
@@ -585,22 +608,26 @@ odt2txt | |||
585 | oggsplt | 608 | oggsplt |
586 | okular | 609 | okular |
587 | onboard | 610 | onboard |
611 | onionshare | ||
612 | onionshare-cli | ||
588 | onionshare-gui | 613 | onionshare-gui |
589 | ooffice | 614 | ooffice |
590 | ooviewdoc | 615 | ooviewdoc |
591 | open-invaders | ||
592 | openarena | 616 | openarena |
593 | openarena_ded | 617 | openarena_ded |
594 | opencity | 618 | opencity |
595 | openclonk | 619 | openclonk |
620 | open-invaders | ||
596 | openmw | 621 | openmw |
597 | openmw-launcher | 622 | openmw-launcher |
598 | openoffice.org | 623 | openoffice.org |
599 | openshot | 624 | openshot |
600 | openshot-qt | 625 | openshot-qt |
626 | openstego | ||
601 | openttd | 627 | openttd |
602 | opera | 628 | opera |
603 | opera-beta | 629 | opera-beta |
630 | opera-developer | ||
604 | orage | 631 | orage |
605 | ostrichriders | 632 | ostrichriders |
606 | otter-browser | 633 | otter-browser |
@@ -626,6 +653,7 @@ pinball | |||
626 | pingus | 653 | pingus |
627 | pinta | 654 | pinta |
628 | pioneer | 655 | pioneer |
656 | pipe-viewer | ||
629 | pithos | 657 | pithos |
630 | pitivi | 658 | pitivi |
631 | pix | 659 | pix |
@@ -648,7 +676,9 @@ pybitmessage | |||
648 | # pycharm-professional | 676 | # pycharm-professional |
649 | # pzstd - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) | 677 | # pzstd - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) |
650 | qbittorrent | 678 | qbittorrent |
679 | qcomicbook | ||
651 | qemu-launcher | 680 | qemu-launcher |
681 | #qemu-system-x86_64 | ||
652 | qgis | 682 | qgis |
653 | qlipper | 683 | qlipper |
654 | qmmp | 684 | qmmp |
@@ -662,11 +692,14 @@ quaternion | |||
662 | quiterss | 692 | quiterss |
663 | qupzilla | 693 | qupzilla |
664 | qutebrowser | 694 | qutebrowser |
695 | raincat | ||
665 | rambox | 696 | rambox |
666 | redeclipse | 697 | redeclipse |
698 | rednotebook | ||
667 | redshift | 699 | redshift |
668 | regextester | 700 | regextester |
669 | remmina | 701 | remmina |
702 | retroarch | ||
670 | rhythmbox | 703 | rhythmbox |
671 | rhythmbox-client | 704 | rhythmbox-client |
672 | ricochet | 705 | ricochet |
@@ -675,6 +708,7 @@ riot-web | |||
675 | ripperx | 708 | ripperx |
676 | ristretto | 709 | ristretto |
677 | rocketchat | 710 | rocketchat |
711 | rpcs3 | ||
678 | rtorrent | 712 | rtorrent |
679 | runenpass.sh | 713 | runenpass.sh |
680 | sayonara | 714 | sayonara |
@@ -683,6 +717,7 @@ scorched3d | |||
683 | scorchwentbonkers | 717 | scorchwentbonkers |
684 | scribus | 718 | scribus |
685 | sdat2img | 719 | sdat2img |
720 | seafile-applet | ||
686 | seahorse | 721 | seahorse |
687 | seahorse-adventures | 722 | seahorse-adventures |
688 | seahorse-daemon | 723 | seahorse-daemon |
@@ -710,8 +745,8 @@ smuxi-frontend-gnome | |||
710 | snox | 745 | snox |
711 | soffice | 746 | soffice |
712 | sol | 747 | sol |
713 | sound-juicer | ||
714 | soundconverter | 748 | soundconverter |
749 | sound-juicer | ||
715 | spectacle | 750 | spectacle |
716 | spectral | 751 | spectral |
717 | spotify | 752 | spotify |
@@ -745,6 +780,7 @@ teamspeak3 | |||
745 | teeworlds | 780 | teeworlds |
746 | telegram | 781 | telegram |
747 | telegram-desktop | 782 | telegram-desktop |
783 | telnet | ||
748 | terasology | 784 | terasology |
749 | textmaker18 | 785 | textmaker18 |
750 | textmaker18free | 786 | textmaker18free |
@@ -753,6 +789,7 @@ thunderbird-beta | |||
753 | thunderbird-wayland | 789 | thunderbird-wayland |
754 | tilp | 790 | tilp |
755 | tor-browser | 791 | tor-browser |
792 | torbrowser | ||
756 | tor-browser-ar | 793 | tor-browser-ar |
757 | tor-browser-ca | 794 | tor-browser-ca |
758 | tor-browser-cs | 795 | tor-browser-cs |
@@ -774,6 +811,7 @@ tor-browser-it | |||
774 | tor-browser-ja | 811 | tor-browser-ja |
775 | tor-browser-ka | 812 | tor-browser-ka |
776 | tor-browser-ko | 813 | tor-browser-ko |
814 | torbrowser-launcher | ||
777 | tor-browser-nb | 815 | tor-browser-nb |
778 | tor-browser-nl | 816 | tor-browser-nl |
779 | tor-browser-pl | 817 | tor-browser-pl |
@@ -784,7 +822,6 @@ tor-browser-tr | |||
784 | tor-browser-vi | 822 | tor-browser-vi |
785 | tor-browser-zh-cn | 823 | tor-browser-zh-cn |
786 | tor-browser-zh-tw | 824 | tor-browser-zh-tw |
787 | torbrowser-launcher | ||
788 | torcs | 825 | torcs |
789 | totem | 826 | totem |
790 | tracker | 827 | tracker |
@@ -844,6 +881,7 @@ weechat | |||
844 | weechat-curses | 881 | weechat-curses |
845 | wesnoth | 882 | wesnoth |
846 | wget | 883 | wget |
884 | wget2 | ||
847 | whalebird | 885 | whalebird |
848 | whois | 886 | whois |
849 | widelands | 887 | widelands |
@@ -852,10 +890,10 @@ wire-desktop | |||
852 | wireshark | 890 | wireshark |
853 | wireshark-gtk | 891 | wireshark-gtk |
854 | wireshark-qt | 892 | wireshark-qt |
893 | wordwarvi | ||
855 | wpp | 894 | wpp |
856 | wps | 895 | wps |
857 | wpspdf | 896 | wpspdf |
858 | wordwarvi | ||
859 | x2goclient | 897 | x2goclient |
860 | xbill | 898 | xbill |
861 | xcalc | 899 | xcalc |
@@ -868,6 +906,7 @@ xfce4-notes | |||
868 | xfce4-screenshooter | 906 | xfce4-screenshooter |
869 | xiphos | 907 | xiphos |
870 | xlinks | 908 | xlinks |
909 | xlinks2 | ||
871 | xmms | 910 | xmms |
872 | xmr-stak | 911 | xmr-stak |
873 | xonotic | 912 | xonotic |
@@ -889,13 +928,15 @@ yelp | |||
889 | youtube | 928 | youtube |
890 | youtube-dl | 929 | youtube-dl |
891 | youtube-dl-gui | 930 | youtube-dl-gui |
892 | youtube-viewer | ||
893 | youtubemusic-nativefier | 931 | youtubemusic-nativefier |
932 | youtube-viewer | ||
933 | yt-dlp | ||
894 | ytmdesktop | 934 | ytmdesktop |
895 | zaproxy | 935 | zaproxy |
896 | zart | 936 | zart |
897 | zathura | 937 | zathura |
898 | zeal | 938 | zeal |
939 | zim | ||
899 | zoom | 940 | zoom |
900 | # zpaq - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) | 941 | # zpaq - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) |
901 | # zstd - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) | 942 | # zstd - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) |
diff --git a/src/firecfg/firecfg.h b/src/firecfg/firecfg.h index 15826cf37..f54bfd5b5 100644 --- a/src/firecfg/firecfg.h +++ b/src/firecfg/firecfg.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firecfg/main.c b/src/firecfg/main.c index 363000e15..2f346fecd 100644 --- a/src/firecfg/main.c +++ b/src/firecfg/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -171,17 +171,17 @@ static void set_file(const char *name, const char *firejail_exec) { | |||
171 | free(fname); | 171 | free(fname); |
172 | } | 172 | } |
173 | 173 | ||
174 | // parse /usr/lib/firejail/firecfg.cfg file | 174 | // parse /etc/firejail/firecfg.config file |
175 | static void set_links_firecfg(void) { | 175 | static void set_links_firecfg(void) { |
176 | char *cfgfile; | 176 | char *cfgfile; |
177 | if (asprintf(&cfgfile, "%s/firejail/firecfg.config", LIBDIR) == -1) | 177 | if (asprintf(&cfgfile, "%s/firecfg.config", SYSCONFDIR) == -1) |
178 | errExit("asprintf"); | 178 | errExit("asprintf"); |
179 | 179 | ||
180 | char *firejail_exec; | 180 | char *firejail_exec; |
181 | if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1) | 181 | if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1) |
182 | errExit("asprintf"); | 182 | errExit("asprintf"); |
183 | 183 | ||
184 | // parse /usr/lib/firejail/firecfg.cfg file | 184 | // parse /etc/firejail/firecfg.config file |
185 | FILE *fp = fopen(cfgfile, "r"); | 185 | FILE *fp = fopen(cfgfile, "r"); |
186 | if (!fp) { | 186 | if (!fp) { |
187 | perror("fopen"); | 187 | perror("fopen"); |
@@ -440,7 +440,7 @@ int main(int argc, char **argv) { | |||
440 | // clear all symlinks | 440 | // clear all symlinks |
441 | clean(); | 441 | clean(); |
442 | 442 | ||
443 | // set new symlinks based on /usr/lib/firejail/firecfg.cfg | 443 | // set new symlinks based on /etc/firejail/firecfg.config |
444 | set_links_firecfg(); | 444 | set_links_firecfg(); |
445 | 445 | ||
446 | if (getuid() == 0) { | 446 | if (getuid() == 0) { |
diff --git a/src/firecfg/sound.c b/src/firecfg/sound.c index e3fcdbd83..9d04c951b 100644 --- a/src/firecfg/sound.c +++ b/src/firecfg/sound.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firecfg/util.c b/src/firecfg/util.c index 14d90b549..4697e7dd9 100644 --- a/src/firecfg/util.c +++ b/src/firecfg/util.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c index 59758bf2d..479473572 100644 --- a/src/firejail/appimage.c +++ b/src/firejail/appimage.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -21,6 +21,7 @@ | |||
21 | // sudo mount -o loop krita-3.0-x86_64.appimage mnt | 21 | // sudo mount -o loop krita-3.0-x86_64.appimage mnt |
22 | 22 | ||
23 | #include "firejail.h" | 23 | #include "firejail.h" |
24 | #include "../include/gcov_wrapper.h" | ||
24 | #include <sys/types.h> | 25 | #include <sys/types.h> |
25 | #include <sys/stat.h> | 26 | #include <sys/stat.h> |
26 | #include <sys/mount.h> | 27 | #include <sys/mount.h> |
@@ -30,6 +31,7 @@ | |||
30 | 31 | ||
31 | static char *devloop = NULL; // device file | 32 | static char *devloop = NULL; // device file |
32 | static long unsigned size = 0; // offset into appimage file | 33 | static long unsigned size = 0; // offset into appimage file |
34 | #define MAXBUF 4096 | ||
33 | 35 | ||
34 | #ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h | 36 | #ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h |
35 | static void err_loop(void) { | 37 | static void err_loop(void) { |
@@ -38,6 +40,36 @@ static void err_loop(void) { | |||
38 | } | 40 | } |
39 | #endif | 41 | #endif |
40 | 42 | ||
43 | // return 1 if found | ||
44 | int appimage_find_profile(const char *archive) { | ||
45 | assert(archive); | ||
46 | assert(strlen(archive)); | ||
47 | |||
48 | // try to match the name of the archive with the list of programs in /etc/firejail/firecfg.config | ||
49 | FILE *fp = fopen(SYSCONFDIR "/firecfg.config", "r"); | ||
50 | if (!fp) { | ||
51 | fprintf(stderr, "Error: cannot find %s, firejail is not correctly installed\n", SYSCONFDIR "/firecfg.config"); | ||
52 | exit(1); | ||
53 | } | ||
54 | char buf[MAXBUF]; | ||
55 | while (fgets(buf, MAXBUF, fp)) { | ||
56 | if (*buf == '#') | ||
57 | continue; | ||
58 | char *ptr = strchr(buf, '\n'); | ||
59 | if (ptr) | ||
60 | *ptr = '\0'; | ||
61 | if (strcasestr(archive, buf)) { | ||
62 | fclose(fp); | ||
63 | return profile_find_firejail(buf, 1); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | fclose(fp); | ||
68 | return 0; | ||
69 | |||
70 | } | ||
71 | |||
72 | |||
41 | void appimage_set(const char *appimage) { | 73 | void appimage_set(const char *appimage) { |
42 | assert(appimage); | 74 | assert(appimage); |
43 | assert(devloop == NULL); // don't call this twice! | 75 | assert(devloop == NULL); // don't call this twice! |
@@ -67,7 +99,7 @@ void appimage_set(const char *appimage) { | |||
67 | 99 | ||
68 | // find or allocate a free loop device to use | 100 | // find or allocate a free loop device to use |
69 | EUID_ROOT(); | 101 | EUID_ROOT(); |
70 | int cfd = open("/dev/loop-control", O_RDWR); | 102 | int cfd = open("/dev/loop-control", O_RDWR|O_CLOEXEC); |
71 | if (cfd == -1) | 103 | if (cfd == -1) |
72 | err_loop(); | 104 | err_loop(); |
73 | int devnr = ioctl(cfd, LOOP_CTL_GET_FREE); | 105 | int devnr = ioctl(cfd, LOOP_CTL_GET_FREE); |
@@ -78,7 +110,7 @@ void appimage_set(const char *appimage) { | |||
78 | errExit("asprintf"); | 110 | errExit("asprintf"); |
79 | 111 | ||
80 | // associate loop device with appimage | 112 | // associate loop device with appimage |
81 | int lfd = open(devloop, O_RDONLY); | 113 | int lfd = open(devloop, O_RDONLY|O_CLOEXEC); |
82 | if (lfd == -1) | 114 | if (lfd == -1) |
83 | err_loop(); | 115 | err_loop(); |
84 | if (ioctl(lfd, LOOP_SET_FD, ffd) == -1) | 116 | if (ioctl(lfd, LOOP_SET_FD, ffd) == -1) |
@@ -109,9 +141,8 @@ void appimage_set(const char *appimage) { | |||
109 | 141 | ||
110 | if (cfg.cwd) | 142 | if (cfg.cwd) |
111 | env_store_name_val("OWD", cfg.cwd, SETENV); | 143 | env_store_name_val("OWD", cfg.cwd, SETENV); |
112 | #ifdef HAVE_GCOV | 144 | |
113 | __gcov_flush(); | 145 | __gcov_flush(); |
114 | #endif | ||
115 | #else | 146 | #else |
116 | fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n"); | 147 | fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n"); |
117 | exit(1); | 148 | exit(1); |
@@ -146,7 +177,7 @@ void appimage_mount(void) { | |||
146 | void appimage_clear(void) { | 177 | void appimage_clear(void) { |
147 | EUID_ROOT(); | 178 | EUID_ROOT(); |
148 | if (devloop) { | 179 | if (devloop) { |
149 | int lfd = open(devloop, O_RDONLY); | 180 | int lfd = open(devloop, O_RDONLY|O_CLOEXEC); |
150 | if (lfd != -1) { | 181 | if (lfd != -1) { |
151 | if (ioctl(lfd, LOOP_CLR_FD, 0) != -1) | 182 | if (ioctl(lfd, LOOP_CLR_FD, 0) != -1) |
152 | fmessage("AppImage detached\n"); | 183 | fmessage("AppImage detached\n"); |
diff --git a/src/firejail/appimage_size.c b/src/firejail/appimage_size.c index 43ca501da..4f8c7a7aa 100644 --- a/src/firejail/appimage_size.c +++ b/src/firejail/appimage_size.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firejail/arp.c b/src/firejail/arp.c index 1e9641097..cbd80dee0 100644 --- a/src/firejail/arp.c +++ b/src/firejail/arp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,6 +20,7 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/socket.h> | 21 | #include <sys/socket.h> |
22 | #include <sys/ioctl.h> | 22 | #include <sys/ioctl.h> |
23 | #include <sys/time.h> | ||
23 | #include <linux/if_ether.h> //TCP/IP Protocol Suite for Linux | 24 | #include <linux/if_ether.h> //TCP/IP Protocol Suite for Linux |
24 | #include <net/if.h> | 25 | #include <net/if.h> |
25 | #include <netinet/in.h> | 26 | #include <netinet/in.h> |
@@ -188,9 +189,14 @@ int arp_check(const char *dev, uint32_t destaddr) { | |||
188 | FD_SET(sock, &fds); | 189 | FD_SET(sock, &fds); |
189 | int maxfd = sock; | 190 | int maxfd = sock; |
190 | struct timeval ts; | 191 | struct timeval ts; |
191 | ts.tv_sec = 0; // 0.5 seconds wait time | 192 | gettimeofday(&ts, NULL); |
192 | ts.tv_usec = 500000; | 193 | double timerend = ts.tv_sec + ts.tv_usec / 1000000.0 + 0.5; |
193 | while (1) { | 194 | while (1) { |
195 | gettimeofday(&ts, NULL); | ||
196 | double now = ts.tv_sec + ts.tv_usec / 1000000.0; | ||
197 | double timeout = timerend - now; | ||
198 | ts.tv_sec = timeout; | ||
199 | ts.tv_usec = (timeout - ts.tv_sec) * 1000000; | ||
194 | int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts); | 200 | int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts); |
195 | if (nready < 0) | 201 | if (nready < 0) |
196 | errExit("select"); | 202 | errExit("select"); |
@@ -201,8 +207,8 @@ int arp_check(const char *dev, uint32_t destaddr) { | |||
201 | } | 207 | } |
202 | if (sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr)) <= 0) | 208 | if (sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr)) <= 0) |
203 | errExit("send"); | 209 | errExit("send"); |
204 | ts.tv_sec = 0; // 0.5 seconds wait time | 210 | gettimeofday(&ts, NULL); |
205 | ts.tv_usec = 500000; | 211 | timerend = ts.tv_sec + ts.tv_usec / 1000000.0 + 0.5; |
206 | fflush(0); | 212 | fflush(0); |
207 | } | 213 | } |
208 | else { | 214 | else { |
@@ -277,7 +283,7 @@ static uint32_t arp_random(const char *dev, Bridge *br) { | |||
277 | int i = 0; | 283 | int i = 0; |
278 | for (i = 0; i < 10; i++) { | 284 | for (i = 0; i < 10; i++) { |
279 | dest = start + ((uint32_t) rand()) % range; | 285 | dest = start + ((uint32_t) rand()) % range; |
280 | if (dest == ifip) // do not allow the interface address | 286 | if (dest == ifip || dest == cfg.defaultgw) // do not allow the interface address or the default gateway |
281 | continue; // try again | 287 | continue; // try again |
282 | 288 | ||
283 | // if we've made it up to here, we have a valid address | 289 | // if we've made it up to here, we have a valid address |
@@ -325,7 +331,7 @@ static uint32_t arp_sequential(const char *dev, Bridge *br) { | |||
325 | 331 | ||
326 | // loop through addresses and stop as soon as you find an unused one | 332 | // loop through addresses and stop as soon as you find an unused one |
327 | while (dest <= last) { | 333 | while (dest <= last) { |
328 | if (dest == ifip) { | 334 | if (dest == ifip || dest == cfg.defaultgw) { |
329 | dest++; | 335 | dest++; |
330 | continue; | 336 | continue; |
331 | } | 337 | } |
diff --git a/src/firejail/bandwidth.c b/src/firejail/bandwidth.c index 1c952c0bc..fa9d3a940 100644 --- a/src/firejail/bandwidth.c +++ b/src/firejail/bandwidth.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -22,6 +22,7 @@ | |||
22 | #include <sys/types.h> | 22 | #include <sys/types.h> |
23 | #include <sys/stat.h> | 23 | #include <sys/stat.h> |
24 | #include <unistd.h> | 24 | #include <unistd.h> |
25 | #include <errno.h> | ||
25 | #include <net/if.h> | 26 | #include <net/if.h> |
26 | #include "firejail.h" | 27 | #include "firejail.h" |
27 | 28 | ||
@@ -119,26 +120,19 @@ static void bandwidth_create_run_file(pid_t pid) { | |||
119 | if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) | 120 | if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) |
120 | errExit("asprintf"); | 121 | errExit("asprintf"); |
121 | 122 | ||
122 | // if the file already exists, do nothing | ||
123 | struct stat s; | ||
124 | if (stat(fname, &s) == 0) { | ||
125 | free(fname); | ||
126 | return; | ||
127 | } | ||
128 | |||
129 | // create an empty file and set mod and ownership | 123 | // create an empty file and set mod and ownership |
130 | /* coverity[toctou] */ | 124 | // if the file already exists, do nothing |
131 | FILE *fp = fopen(fname, "w"); | 125 | FILE *fp = fopen(fname, "wxe"); |
132 | if (fp) { | 126 | free(fname); |
133 | SET_PERMS_STREAM(fp, 0, 0, 0644); | 127 | if (!fp) { |
134 | fclose(fp); | 128 | if (errno == EEXIST) |
135 | } | 129 | return; |
136 | else { | ||
137 | fprintf(stderr, "Error: cannot create bandwidth file\n"); | 130 | fprintf(stderr, "Error: cannot create bandwidth file\n"); |
138 | exit(1); | 131 | exit(1); |
139 | } | 132 | } |
140 | 133 | ||
141 | free(fname); | 134 | SET_PERMS_STREAM(fp, 0, 0, 0644); |
135 | fclose(fp); | ||
142 | } | 136 | } |
143 | 137 | ||
144 | 138 | ||
@@ -148,7 +142,7 @@ void network_set_run_file(pid_t pid) { | |||
148 | errExit("asprintf"); | 142 | errExit("asprintf"); |
149 | 143 | ||
150 | // create an empty file and set mod and ownership | 144 | // create an empty file and set mod and ownership |
151 | FILE *fp = fopen(fname, "w"); | 145 | FILE *fp = fopen(fname, "we"); |
152 | if (fp) { | 146 | if (fp) { |
153 | if (cfg.bridge0.configured) | 147 | if (cfg.bridge0.configured) |
154 | fprintf(fp, "%s:%s\n", cfg.bridge0.dev, cfg.bridge0.devsandbox); | 148 | fprintf(fp, "%s:%s\n", cfg.bridge0.dev, cfg.bridge0.devsandbox); |
@@ -178,7 +172,7 @@ static void read_bandwidth_file(pid_t pid) { | |||
178 | if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) | 172 | if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) |
179 | errExit("asprintf"); | 173 | errExit("asprintf"); |
180 | 174 | ||
181 | FILE *fp = fopen(fname, "r"); | 175 | FILE *fp = fopen(fname, "re"); |
182 | if (fp) { | 176 | if (fp) { |
183 | char buf[1024]; | 177 | char buf[1024]; |
184 | while (fgets(buf, 1024,fp)) { | 178 | while (fgets(buf, 1024,fp)) { |
@@ -214,7 +208,7 @@ static void write_bandwidth_file(pid_t pid) { | |||
214 | if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) | 208 | if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) |
215 | errExit("asprintf"); | 209 | errExit("asprintf"); |
216 | 210 | ||
217 | FILE *fp = fopen(fname, "w"); | 211 | FILE *fp = fopen(fname, "we"); |
218 | if (fp) { | 212 | if (fp) { |
219 | IFBW *ptr = ifbw; | 213 | IFBW *ptr = ifbw; |
220 | while (ptr) { | 214 | while (ptr) { |
@@ -307,7 +301,7 @@ void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, in | |||
307 | char *fname; | 301 | char *fname; |
308 | if (asprintf(&fname, "%s/%d-netmap", RUN_FIREJAIL_NETWORK_DIR, (int) pid) == -1) | 302 | if (asprintf(&fname, "%s/%d-netmap", RUN_FIREJAIL_NETWORK_DIR, (int) pid) == -1) |
309 | errExit("asprintf"); | 303 | errExit("asprintf"); |
310 | FILE *fp = fopen(fname, "r"); | 304 | FILE *fp = fopen(fname, "re"); |
311 | if (!fp) { | 305 | if (!fp) { |
312 | fprintf(stderr, "Error: cannot read network map file %s\n", fname); | 306 | fprintf(stderr, "Error: cannot read network map file %s\n", fname); |
313 | exit(1); | 307 | exit(1); |
diff --git a/src/firejail/caps.c b/src/firejail/caps.c index 597f9915b..c5c06c675 100644 --- a/src/firejail/caps.c +++ b/src/firejail/caps.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -389,7 +389,7 @@ static uint64_t extract_caps(int pid) { | |||
389 | errExit("asprintf"); | 389 | errExit("asprintf"); |
390 | 390 | ||
391 | EUID_ROOT(); // grsecurity | 391 | EUID_ROOT(); // grsecurity |
392 | FILE *fp = fopen(file, "r"); | 392 | FILE *fp = fopen(file, "re"); |
393 | EUID_USER(); // grsecurity | 393 | EUID_USER(); // grsecurity |
394 | if (!fp) | 394 | if (!fp) |
395 | goto errexit; | 395 | goto errexit; |
diff --git a/src/firejail/cgroup.c b/src/firejail/cgroup.c index 986b1157d..f1e16187f 100644 --- a/src/firejail/cgroup.c +++ b/src/firejail/cgroup.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,7 +18,9 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/stat.h> | 21 | #include "../include/gcov_wrapper.h" |
22 | #include <sys/wait.h> | ||
23 | #include <errno.h> | ||
22 | 24 | ||
23 | #define MAXBUF 4096 | 25 | #define MAXBUF 4096 |
24 | 26 | ||
@@ -26,7 +28,7 @@ void save_cgroup(void) { | |||
26 | if (cfg.cgroup == NULL) | 28 | if (cfg.cgroup == NULL) |
27 | return; | 29 | return; |
28 | 30 | ||
29 | FILE *fp = fopen(RUN_CGROUP_CFG, "w"); | 31 | FILE *fp = fopen(RUN_CGROUP_CFG, "wxe"); |
30 | if (fp) { | 32 | if (fp) { |
31 | fprintf(fp, "%s", cfg.cgroup); | 33 | fprintf(fp, "%s", cfg.cgroup); |
32 | fflush(0); | 34 | fflush(0); |
@@ -48,7 +50,7 @@ void load_cgroup(const char *fname) { | |||
48 | if (!fname) | 50 | if (!fname) |
49 | return; | 51 | return; |
50 | 52 | ||
51 | FILE *fp = fopen(fname, "r"); | 53 | FILE *fp = fopen(fname, "re"); |
52 | if (fp) { | 54 | if (fp) { |
53 | char buf[MAXBUF]; | 55 | char buf[MAXBUF]; |
54 | if (fgets(buf, MAXBUF, fp)) { | 56 | if (fgets(buf, MAXBUF, fp)) { |
@@ -68,52 +70,63 @@ errout: | |||
68 | fclose(fp); | 70 | fclose(fp); |
69 | } | 71 | } |
70 | 72 | ||
73 | static int is_cgroup_path(const char *fname) { | ||
74 | // path starts with /sys/fs/cgroup | ||
75 | if (strncmp(fname, "/sys/fs/cgroup", 14) != 0) | ||
76 | return 0; | ||
71 | 77 | ||
72 | void set_cgroup(const char *path) { | 78 | // no .. traversal |
73 | EUID_ASSERT(); | 79 | char *ptr = strstr(fname, ".."); |
80 | if (ptr) | ||
81 | return 0; | ||
74 | 82 | ||
75 | invalid_filename(path, 0); // no globbing | 83 | return 1; |
84 | } | ||
76 | 85 | ||
77 | // path starts with /sys/fs/cgroup | 86 | void check_cgroup_file(const char *fname) { |
78 | if (strncmp(path, "/sys/fs/cgroup", 14) != 0) | 87 | assert(fname); |
79 | goto errout; | 88 | invalid_filename(fname, 0); // no globbing |
80 | 89 | ||
81 | // path ends in tasks | 90 | if (!is_cgroup_path(fname)) |
82 | char *ptr = strstr(path, "tasks"); | ||
83 | if (!ptr) | ||
84 | goto errout; | ||
85 | if (*(ptr + 5) != '\0') | ||
86 | goto errout; | 91 | goto errout; |
87 | 92 | ||
88 | // no .. traversal | 93 | const char *base = gnu_basename(fname); |
89 | ptr = strstr(path, ".."); | 94 | if (strcmp(base, "tasks") != 0 && // cgroup v1 |
90 | if (ptr) | 95 | strcmp(base, "cgroup.procs") != 0) |
91 | goto errout; | 96 | goto errout; |
92 | 97 | ||
93 | // tasks file exists | 98 | if (access(fname, W_OK) == 0) |
94 | struct stat s; | 99 | return; |
95 | if (stat(path, &s) == -1) | ||
96 | goto errout; | ||
97 | 100 | ||
98 | // task file belongs to the user running the sandbox | 101 | errout: |
99 | if (s.st_uid != getuid() && s.st_gid != getgid()) | 102 | fprintf(stderr, "Error: invalid cgroup\n"); |
100 | goto errout2; | 103 | exit(1); |
104 | } | ||
105 | |||
106 | static void do_set_cgroup(const char *fname, pid_t pid) { | ||
107 | FILE *fp = fopen(fname, "ae"); | ||
108 | if (!fp) { | ||
109 | fwarning("cannot open %s for writing: %s\n", fname, strerror(errno)); | ||
110 | return; | ||
111 | } | ||
101 | 112 | ||
102 | // add the task to cgroup | ||
103 | /* coverity[toctou] */ | ||
104 | FILE *fp = fopen(path, "a"); | ||
105 | if (!fp) | ||
106 | goto errout; | ||
107 | pid_t pid = getpid(); | ||
108 | int rv = fprintf(fp, "%d\n", pid); | 113 | int rv = fprintf(fp, "%d\n", pid); |
109 | (void) rv; | 114 | (void) rv; |
110 | fclose(fp); | 115 | fclose(fp); |
111 | return; | 116 | } |
112 | 117 | ||
113 | errout: | 118 | void set_cgroup(const char *fname, pid_t pid) { |
114 | fprintf(stderr, "Error: invalid cgroup\n"); | 119 | pid_t child = fork(); |
115 | exit(1); | 120 | if (child < 0) |
116 | errout2: | 121 | errExit("fork"); |
117 | fprintf(stderr, "Error: you don't have permissions to use this control group\n"); | 122 | if (child == 0) { |
118 | exit(1); | 123 | drop_privs(0); |
124 | |||
125 | do_set_cgroup(fname, pid); | ||
126 | |||
127 | __gcov_flush(); | ||
128 | |||
129 | _exit(0); | ||
130 | } | ||
131 | waitpid(child, NULL, 0); | ||
119 | } | 132 | } |
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index e1613b325..6fc70318b 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -35,6 +35,8 @@ char *xvfb_extra_params = ""; | |||
35 | char *netfilter_default = NULL; | 35 | char *netfilter_default = NULL; |
36 | unsigned long join_timeout = 5000000; // microseconds | 36 | unsigned long join_timeout = 5000000; // microseconds |
37 | char *config_seccomp_error_action_str = "EPERM"; | 37 | char *config_seccomp_error_action_str = "EPERM"; |
38 | char *config_seccomp_filter_add = NULL; | ||
39 | char **whitelist_reject_topdirs = NULL; | ||
38 | 40 | ||
39 | int checkcfg(int val) { | 41 | int checkcfg(int val) { |
40 | assert(val < CFG_MAX); | 42 | assert(val < CFG_MAX); |
@@ -56,10 +58,11 @@ int checkcfg(int val) { | |||
56 | cfg_val[CFG_XPRA_ATTACH] = 0; | 58 | cfg_val[CFG_XPRA_ATTACH] = 0; |
57 | cfg_val[CFG_SECCOMP_ERROR_ACTION] = -1; | 59 | cfg_val[CFG_SECCOMP_ERROR_ACTION] = -1; |
58 | cfg_val[CFG_BROWSER_ALLOW_DRM] = 0; | 60 | cfg_val[CFG_BROWSER_ALLOW_DRM] = 0; |
61 | cfg_val[CFG_ALLOW_TRAY] = 0; | ||
59 | 62 | ||
60 | // open configuration file | 63 | // open configuration file |
61 | const char *fname = SYSCONFDIR "/firejail.config"; | 64 | const char *fname = SYSCONFDIR "/firejail.config"; |
62 | fp = fopen(fname, "r"); | 65 | fp = fopen(fname, "re"); |
63 | if (!fp) { | 66 | if (!fp) { |
64 | #ifdef HAVE_GLOBALCFG | 67 | #ifdef HAVE_GLOBALCFG |
65 | fprintf(stderr, "Error: Firejail configuration file %s not found\n", fname); | 68 | fprintf(stderr, "Error: Firejail configuration file %s not found\n", fname); |
@@ -102,22 +105,25 @@ int checkcfg(int val) { | |||
102 | PARSE_YESNO(CFG_USERNS, "userns") | 105 | PARSE_YESNO(CFG_USERNS, "userns") |
103 | PARSE_YESNO(CFG_CHROOT, "chroot") | 106 | PARSE_YESNO(CFG_CHROOT, "chroot") |
104 | PARSE_YESNO(CFG_FIREJAIL_PROMPT, "firejail-prompt") | 107 | PARSE_YESNO(CFG_FIREJAIL_PROMPT, "firejail-prompt") |
105 | PARSE_YESNO(CFG_FOLLOW_SYMLINK_AS_USER, "follow-symlink-as-user") | ||
106 | PARSE_YESNO(CFG_FORCE_NONEWPRIVS, "force-nonewprivs") | 108 | PARSE_YESNO(CFG_FORCE_NONEWPRIVS, "force-nonewprivs") |
107 | PARSE_YESNO(CFG_SECCOMP, "seccomp") | 109 | PARSE_YESNO(CFG_SECCOMP, "seccomp") |
108 | PARSE_YESNO(CFG_WHITELIST, "whitelist") | ||
109 | PARSE_YESNO(CFG_NETWORK, "network") | 110 | PARSE_YESNO(CFG_NETWORK, "network") |
110 | PARSE_YESNO(CFG_RESTRICTED_NETWORK, "restricted-network") | 111 | PARSE_YESNO(CFG_RESTRICTED_NETWORK, "restricted-network") |
111 | PARSE_YESNO(CFG_XEPHYR_WINDOW_TITLE, "xephyr-window-title") | 112 | PARSE_YESNO(CFG_XEPHYR_WINDOW_TITLE, "xephyr-window-title") |
112 | PARSE_YESNO(CFG_OVERLAYFS, "overlayfs") | 113 | PARSE_YESNO(CFG_OVERLAYFS, "overlayfs") |
113 | PARSE_YESNO(CFG_PRIVATE_HOME, "private-home") | 114 | PARSE_YESNO(CFG_PRIVATE_BIN, "private-bin") |
115 | PARSE_YESNO(CFG_PRIVATE_BIN_NO_LOCAL, "private-bin-no-local") | ||
114 | PARSE_YESNO(CFG_PRIVATE_CACHE, "private-cache") | 116 | PARSE_YESNO(CFG_PRIVATE_CACHE, "private-cache") |
117 | PARSE_YESNO(CFG_PRIVATE_ETC, "private-etc") | ||
118 | PARSE_YESNO(CFG_PRIVATE_HOME, "private-home") | ||
115 | PARSE_YESNO(CFG_PRIVATE_LIB, "private-lib") | 119 | PARSE_YESNO(CFG_PRIVATE_LIB, "private-lib") |
116 | PARSE_YESNO(CFG_PRIVATE_BIN_NO_LOCAL, "private-bin-no-local") | 120 | PARSE_YESNO(CFG_PRIVATE_OPT, "private-opt") |
121 | PARSE_YESNO(CFG_PRIVATE_SRV, "private-srv") | ||
117 | PARSE_YESNO(CFG_DISABLE_MNT, "disable-mnt") | 122 | PARSE_YESNO(CFG_DISABLE_MNT, "disable-mnt") |
118 | PARSE_YESNO(CFG_XPRA_ATTACH, "xpra-attach") | 123 | PARSE_YESNO(CFG_XPRA_ATTACH, "xpra-attach") |
119 | PARSE_YESNO(CFG_BROWSER_DISABLE_U2F, "browser-disable-u2f") | 124 | PARSE_YESNO(CFG_BROWSER_DISABLE_U2F, "browser-disable-u2f") |
120 | PARSE_YESNO(CFG_BROWSER_ALLOW_DRM, "browser-allow-drm") | 125 | PARSE_YESNO(CFG_BROWSER_ALLOW_DRM, "browser-allow-drm") |
126 | PARSE_YESNO(CFG_ALLOW_TRAY, "allow-tray") | ||
121 | #undef PARSE_YESNO | 127 | #undef PARSE_YESNO |
122 | 128 | ||
123 | // netfilter | 129 | // netfilter |
@@ -130,8 +136,7 @@ int checkcfg(int val) { | |||
130 | *end = '\0'; | 136 | *end = '\0'; |
131 | 137 | ||
132 | // is the file present? | 138 | // is the file present? |
133 | struct stat s; | 139 | if (access(fname, F_OK) == -1) { |
134 | if (stat(fname, &s) == -1) { | ||
135 | fprintf(stderr, "Error: netfilter-default file %s not available\n", fname); | 140 | fprintf(stderr, "Error: netfilter-default file %s not available\n", fname); |
136 | exit(1); | 141 | exit(1); |
137 | } | 142 | } |
@@ -222,6 +227,10 @@ int checkcfg(int val) { | |||
222 | else if (strncmp(ptr, "join-timeout ", 13) == 0) | 227 | else if (strncmp(ptr, "join-timeout ", 13) == 0) |
223 | join_timeout = strtoul(ptr + 13, NULL, 10) * 1000000; // seconds to microseconds | 228 | join_timeout = strtoul(ptr + 13, NULL, 10) * 1000000; // seconds to microseconds |
224 | 229 | ||
230 | // add rules to default seccomp filter | ||
231 | else if (strncmp(ptr, "seccomp-filter-add ", 19) == 0) | ||
232 | config_seccomp_filter_add = seccomp_check_list(ptr + 19); | ||
233 | |||
225 | // seccomp error action | 234 | // seccomp error action |
226 | else if (strncmp(ptr, "seccomp-error-action ", 21) == 0) { | 235 | else if (strncmp(ptr, "seccomp-error-action ", 21) == 0) { |
227 | if (strcmp(ptr + 21, "kill") == 0) | 236 | if (strcmp(ptr + 21, "kill") == 0) |
@@ -238,6 +247,31 @@ int checkcfg(int val) { | |||
238 | errExit("strdup"); | 247 | errExit("strdup"); |
239 | } | 248 | } |
240 | 249 | ||
250 | else if (strncmp(ptr, "whitelist-disable-topdir ", 25) == 0) { | ||
251 | char *str = strdup(ptr + 25); | ||
252 | if (!str) | ||
253 | errExit("strdup"); | ||
254 | |||
255 | size_t cnt = 0; | ||
256 | size_t sz = 4; | ||
257 | whitelist_reject_topdirs = malloc(sz * sizeof(char *)); | ||
258 | if (!whitelist_reject_topdirs) | ||
259 | errExit("malloc"); | ||
260 | |||
261 | char *tok = strtok(str, ","); | ||
262 | while (tok) { | ||
263 | whitelist_reject_topdirs[cnt++] = tok; | ||
264 | if (cnt >= sz) { | ||
265 | sz *= 2; | ||
266 | whitelist_reject_topdirs = realloc(whitelist_reject_topdirs, sz * sizeof(char *)); | ||
267 | if (!whitelist_reject_topdirs) | ||
268 | errExit("realloc"); | ||
269 | } | ||
270 | tok = strtok(NULL, ","); | ||
271 | } | ||
272 | whitelist_reject_topdirs[cnt] = NULL; | ||
273 | } | ||
274 | |||
241 | else | 275 | else |
242 | goto errout; | 276 | goto errout; |
243 | 277 | ||
@@ -269,7 +303,7 @@ errout: | |||
269 | 303 | ||
270 | void print_compiletime_support(void) { | 304 | void print_compiletime_support(void) { |
271 | printf("Compile time support:\n"); | 305 | printf("Compile time support:\n"); |
272 | printf("\t- Always force nonewprivs support is %s\n", | 306 | printf("\t- always force nonewprivs support is %s\n", |
273 | #ifdef HAVE_FORCE_NONEWPRIVS | 307 | #ifdef HAVE_FORCE_NONEWPRIVS |
274 | "enabled" | 308 | "enabled" |
275 | #else | 309 | #else |
@@ -309,14 +343,6 @@ void print_compiletime_support(void) { | |||
309 | #endif | 343 | #endif |
310 | ); | 344 | ); |
311 | 345 | ||
312 | printf("\t- file and directory whitelisting support is %s\n", | ||
313 | #ifdef HAVE_WHITELIST | ||
314 | "enabled" | ||
315 | #else | ||
316 | "disabled" | ||
317 | #endif | ||
318 | ); | ||
319 | |||
320 | printf("\t- file transfer support is %s\n", | 346 | printf("\t- file transfer support is %s\n", |
321 | #ifdef HAVE_FILE_TRANSFER | 347 | #ifdef HAVE_FILE_TRANSFER |
322 | "enabled" | 348 | "enabled" |
diff --git a/src/firejail/chroot.c b/src/firejail/chroot.c index d7e96cf4c..551948318 100644 --- a/src/firejail/chroot.c +++ b/src/firejail/chroot.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #ifdef HAVE_CHROOT | 21 | #ifdef HAVE_CHROOT |
22 | #include "firejail.h" | 22 | #include "firejail.h" |
23 | #include "../include/gcov_wrapper.h" | ||
23 | #include <sys/mount.h> | 24 | #include <sys/mount.h> |
24 | #include <sys/sendfile.h> | 25 | #include <sys/sendfile.h> |
25 | #include <errno.h> | 26 | #include <errno.h> |
@@ -29,7 +30,6 @@ | |||
29 | #define O_PATH 010000000 | 30 | #define O_PATH 010000000 |
30 | #endif | 31 | #endif |
31 | 32 | ||
32 | |||
33 | // exit if error | 33 | // exit if error |
34 | void fs_check_chroot_dir(void) { | 34 | void fs_check_chroot_dir(void) { |
35 | EUID_ASSERT(); | 35 | EUID_ASSERT(); |
@@ -86,7 +86,7 @@ static void update_file(int parentfd, const char *relpath) { | |||
86 | if (arg_debug) | 86 | if (arg_debug) |
87 | printf("Updating chroot /%s\n", relpath); | 87 | printf("Updating chroot /%s\n", relpath); |
88 | unlinkat(parentfd, relpath, 0); | 88 | unlinkat(parentfd, relpath, 0); |
89 | int out = openat(parentfd, relpath, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 89 | int out = openat(parentfd, relpath, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
90 | if (out == -1) { | 90 | if (out == -1) { |
91 | close(in); | 91 | close(in); |
92 | goto errout; | 92 | goto errout; |
@@ -131,9 +131,9 @@ void fs_chroot(const char *rootdir) { | |||
131 | assert(rootdir); | 131 | assert(rootdir); |
132 | 132 | ||
133 | // fails if there is any symlink or if rootdir is not a directory | 133 | // fails if there is any symlink or if rootdir is not a directory |
134 | int parentfd = safe_fd(rootdir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 134 | int parentfd = safer_openat(-1, rootdir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
135 | if (parentfd == -1) | 135 | if (parentfd == -1) |
136 | errExit("safe_fd"); | 136 | errExit("safer_openat"); |
137 | // rootdir has to be owned by root and is not allowed to be generally writable, | 137 | // rootdir has to be owned by root and is not allowed to be generally writable, |
138 | // this also excludes /tmp and friends | 138 | // this also excludes /tmp and friends |
139 | struct stat s; | 139 | struct stat s; |
@@ -163,12 +163,8 @@ void fs_chroot(const char *rootdir) { | |||
163 | int fd = openat(parentfd, "dev", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 163 | int fd = openat(parentfd, "dev", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
164 | if (fd == -1) | 164 | if (fd == -1) |
165 | errExit("open"); | 165 | errExit("open"); |
166 | char *proc; | 166 | if (bind_mount_path_to_fd("/dev", fd)) |
167 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
168 | errExit("asprintf"); | ||
169 | if (mount("/dev", proc, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
170 | errExit("mounting /dev"); | 167 | errExit("mounting /dev"); |
171 | free(proc); | ||
172 | close(fd); | 168 | close(fd); |
173 | 169 | ||
174 | #ifdef HAVE_X11 | 170 | #ifdef HAVE_X11 |
@@ -192,11 +188,8 @@ void fs_chroot(const char *rootdir) { | |||
192 | fd = openat(parentfd, "tmp/.X11-unix", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 188 | fd = openat(parentfd, "tmp/.X11-unix", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
193 | if (fd == -1) | 189 | if (fd == -1) |
194 | errExit("open"); | 190 | errExit("open"); |
195 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 191 | if (bind_mount_path_to_fd("/tmp/.X11-unix", fd)) |
196 | errExit("asprintf"); | ||
197 | if (mount("/tmp/.X11-unix", proc, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
198 | errExit("mounting /tmp/.X11-unix"); | 192 | errExit("mounting /tmp/.X11-unix"); |
199 | free(proc); | ||
200 | close(fd); | 193 | close(fd); |
201 | } | 194 | } |
202 | #endif // HAVE_X11 | 195 | #endif // HAVE_X11 |
@@ -215,29 +208,21 @@ void fs_chroot(const char *rootdir) { | |||
215 | 208 | ||
216 | if (arg_debug) | 209 | if (arg_debug) |
217 | printf("Mounting %s on chroot %s\n", orig_pulse, orig_pulse); | 210 | printf("Mounting %s on chroot %s\n", orig_pulse, orig_pulse); |
218 | int src = safe_fd(orig_pulse, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 211 | int src = safer_openat(-1, orig_pulse, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
219 | if (src == -1) { | 212 | if (src == -1) { |
220 | fprintf(stderr, "Error: cannot open %s\n", orig_pulse); | 213 | fprintf(stderr, "Error: cannot open %s\n", orig_pulse); |
221 | exit(1); | 214 | exit(1); |
222 | } | 215 | } |
223 | int dst = safe_fd(pulse, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 216 | int dst = safer_openat(-1, pulse, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
224 | if (dst == -1) { | 217 | if (dst == -1) { |
225 | fprintf(stderr, "Error: cannot open %s\n", pulse); | 218 | fprintf(stderr, "Error: cannot open %s\n", pulse); |
226 | exit(1); | 219 | exit(1); |
227 | } | 220 | } |
228 | free(pulse); | 221 | if (bind_mount_by_fd(src, dst)) |
229 | 222 | errExit("mounting pulseaudio"); | |
230 | char *proc_src, *proc_dst; | ||
231 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) | ||
232 | errExit("asprintf"); | ||
233 | if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1) | ||
234 | errExit("asprintf"); | ||
235 | if (mount(proc_src, proc_dst, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
236 | errExit("mount bind"); | ||
237 | free(proc_src); | ||
238 | free(proc_dst); | ||
239 | close(src); | 223 | close(src); |
240 | close(dst); | 224 | close(dst); |
225 | free(pulse); | ||
241 | 226 | ||
242 | // update /etc/machine-id in chroot | 227 | // update /etc/machine-id in chroot |
243 | update_file(parentfd, "etc/machine-id"); | 228 | update_file(parentfd, "etc/machine-id"); |
@@ -256,11 +241,8 @@ void fs_chroot(const char *rootdir) { | |||
256 | fd = openat(parentfd, &RUN_FIREJAIL_LIB_DIR[1], O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 241 | fd = openat(parentfd, &RUN_FIREJAIL_LIB_DIR[1], O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
257 | if (fd == -1) | 242 | if (fd == -1) |
258 | errExit("open"); | 243 | errExit("open"); |
259 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 244 | if (bind_mount_path_to_fd(RUN_FIREJAIL_LIB_DIR, fd)) |
260 | errExit("asprintf"); | ||
261 | if (mount(RUN_FIREJAIL_LIB_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
262 | errExit("mount bind"); | 245 | errExit("mount bind"); |
263 | free(proc); | ||
264 | close(fd); | 246 | close(fd); |
265 | 247 | ||
266 | // create /run/firejail/mnt directory in chroot | 248 | // create /run/firejail/mnt directory in chroot |
@@ -271,29 +253,22 @@ void fs_chroot(const char *rootdir) { | |||
271 | fd = openat(parentfd, &RUN_MNT_DIR[1], O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 253 | fd = openat(parentfd, &RUN_MNT_DIR[1], O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
272 | if (fd == -1) | 254 | if (fd == -1) |
273 | errExit("open"); | 255 | errExit("open"); |
274 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 256 | if (bind_mount_path_to_fd(RUN_MNT_DIR, fd)) |
275 | errExit("asprintf"); | ||
276 | if (mount(RUN_MNT_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
277 | errExit("mount bind"); | 257 | errExit("mount bind"); |
278 | free(proc); | ||
279 | close(fd); | 258 | close(fd); |
280 | 259 | ||
281 | // update chroot resolv.conf | 260 | // update chroot resolv.conf |
282 | update_file(parentfd, "etc/resolv.conf"); | 261 | update_file(parentfd, "etc/resolv.conf"); |
283 | 262 | ||
284 | #ifdef HAVE_GCOV | ||
285 | __gcov_flush(); | 263 | __gcov_flush(); |
286 | #endif | 264 | |
287 | // create /run/firejail/mnt/oroot | 265 | // create /run/firejail/mnt/oroot |
288 | char *oroot = RUN_OVERLAY_ROOT; | 266 | char *oroot = RUN_OVERLAY_ROOT; |
289 | if (mkdir(oroot, 0755) == -1) | 267 | if (mkdir(oroot, 0755) == -1) |
290 | errExit("mkdir"); | 268 | errExit("mkdir"); |
291 | // mount the chroot dir on top of /run/firejail/mnt/oroot in order to reuse the apparmor rules for overlay | 269 | // mount the chroot dir on top of /run/firejail/mnt/oroot in order to reuse the apparmor rules for overlay |
292 | if (asprintf(&proc, "/proc/self/fd/%d", parentfd) == -1) | 270 | if (bind_mount_fd_to_path(parentfd, oroot)) |
293 | errExit("asprintf"); | ||
294 | if (mount(proc, oroot, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
295 | errExit("mounting rootdir oroot"); | 271 | errExit("mounting rootdir oroot"); |
296 | free(proc); | ||
297 | close(parentfd); | 272 | close(parentfd); |
298 | // chroot into the new directory | 273 | // chroot into the new directory |
299 | if (arg_debug) | 274 | if (arg_debug) |
diff --git a/src/firejail/cmdline.c b/src/firejail/cmdline.c index f902c4e1c..6f7739da0 100644 --- a/src/firejail/cmdline.c +++ b/src/firejail/cmdline.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -26,7 +26,7 @@ | |||
26 | #include <assert.h> | 26 | #include <assert.h> |
27 | #include <errno.h> | 27 | #include <errno.h> |
28 | 28 | ||
29 | static int cmdline_length(int argc, char **argv, int index) { | 29 | static int cmdline_length(int argc, char **argv, int index, bool want_extra_quotes) { |
30 | assert(index != -1); | 30 | assert(index != -1); |
31 | 31 | ||
32 | unsigned i,j; | 32 | unsigned i,j; |
@@ -46,10 +46,11 @@ static int cmdline_length(int argc, char **argv, int index) { | |||
46 | len += 3; | 46 | len += 3; |
47 | in_quotes = false; | 47 | in_quotes = false; |
48 | } else { | 48 | } else { |
49 | if (!in_quotes) | 49 | if (!in_quotes && want_extra_quotes) |
50 | len++; | 50 | len++; |
51 | len++; | 51 | len++; |
52 | in_quotes = true; | 52 | if (want_extra_quotes) |
53 | in_quotes = true; | ||
53 | } | 54 | } |
54 | } | 55 | } |
55 | if (in_quotes) { | 56 | if (in_quotes) { |
@@ -64,7 +65,7 @@ static int cmdline_length(int argc, char **argv, int index) { | |||
64 | return len; | 65 | return len; |
65 | } | 66 | } |
66 | 67 | ||
67 | static void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) { | 68 | static void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index, bool want_extra_quotes) { |
68 | assert(index != -1); | 69 | assert(index != -1); |
69 | 70 | ||
70 | unsigned i,j; | 71 | unsigned i,j; |
@@ -103,14 +104,15 @@ static void quote_cmdline(char *command_line, char *window_title, int len, int a | |||
103 | // anything other | 104 | // anything other |
104 | else | 105 | else |
105 | { | 106 | { |
106 | if (!in_quotes) { | 107 | if (!in_quotes && want_extra_quotes) { |
107 | // open quotes | 108 | // open quotes |
108 | ptr1[0] = '\''; | 109 | ptr1[0] = '\''; |
109 | ptr1++; | 110 | ptr1++; |
110 | } | 111 | } |
111 | ptr1[0] = argv[i + index][j]; | 112 | ptr1[0] = argv[i + index][j]; |
112 | ptr1++; | 113 | ptr1++; |
113 | in_quotes = true; | 114 | if (want_extra_quotes) |
115 | in_quotes = true; | ||
114 | } | 116 | } |
115 | } | 117 | } |
116 | // close quotes | 118 | // close quotes |
@@ -134,12 +136,12 @@ static void quote_cmdline(char *command_line, char *window_title, int len, int a | |||
134 | assert((unsigned) len == strlen(command_line)); | 136 | assert((unsigned) len == strlen(command_line)); |
135 | } | 137 | } |
136 | 138 | ||
137 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { | 139 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, bool want_extra_quotes) { |
138 | // index == -1 could happen if we have --shell=none and no program was specified | 140 | // index == -1 could happen if we have --shell=none and no program was specified |
139 | // the program should exit with an error before entering this function | 141 | // the program should exit with an error before entering this function |
140 | assert(index != -1); | 142 | assert(index != -1); |
141 | 143 | ||
142 | int len = cmdline_length(argc, argv, index); | 144 | int len = cmdline_length(argc, argv, index, want_extra_quotes); |
143 | if (len > ARG_MAX) { | 145 | if (len > ARG_MAX) { |
144 | errno = E2BIG; | 146 | errno = E2BIG; |
145 | errExit("cmdline_length"); | 147 | errExit("cmdline_length"); |
@@ -152,7 +154,7 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar | |||
152 | if (!*window_title) | 154 | if (!*window_title) |
153 | errExit("malloc"); | 155 | errExit("malloc"); |
154 | 156 | ||
155 | quote_cmdline(*command_line, *window_title, len, argc, argv, index); | 157 | quote_cmdline(*command_line, *window_title, len, argc, argv, index, want_extra_quotes); |
156 | 158 | ||
157 | if (arg_debug) | 159 | if (arg_debug) |
158 | printf("Building quoted command line: %s\n", *command_line); | 160 | printf("Building quoted command line: %s\n", *command_line); |
@@ -161,17 +163,17 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar | |||
161 | assert(*window_title); | 163 | assert(*window_title); |
162 | } | 164 | } |
163 | 165 | ||
164 | void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { | 166 | void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, bool want_extra_quotes) { |
165 | // index == -1 could happen if we have --shell=none and no program was specified | 167 | // index == -1 could happen if we have --shell=none and no program was specified |
166 | // the program should exit with an error before entering this function | 168 | // the program should exit with an error before entering this function |
167 | assert(index != -1); | 169 | assert(index != -1); |
168 | 170 | ||
169 | char *apprun_path = RUN_FIREJAIL_APPIMAGE_DIR "/AppRun"; | 171 | char *apprun_path = RUN_FIREJAIL_APPIMAGE_DIR "/AppRun"; |
170 | 172 | ||
171 | int len1 = cmdline_length(argc, argv, index); // length of argv w/o changes | 173 | int len1 = cmdline_length(argc, argv, index, want_extra_quotes); // length of argv w/o changes |
172 | int len2 = cmdline_length(1, &argv[index], 0); // apptest.AppImage | 174 | int len2 = cmdline_length(1, &argv[index], 0, want_extra_quotes); // apptest.AppImage |
173 | int len3 = cmdline_length(1, &apprun_path, 0); // /run/firejail/appimage/AppRun | 175 | int len3 = cmdline_length(1, &apprun_path, 0, want_extra_quotes); // /run/firejail/appimage/AppRun |
174 | int len4 = (len1 - len2 + len3) + 1; // apptest.AppImage is replaced by /path/to/AppRun | 176 | int len4 = (len1 - len2 + len3) + 1; // apptest.AppImage is replaced by /path/to/AppRun |
175 | 177 | ||
176 | if (len4 > ARG_MAX) { | 178 | if (len4 > ARG_MAX) { |
177 | errno = E2BIG; | 179 | errno = E2BIG; |
@@ -187,7 +189,7 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, | |||
187 | errExit("malloc"); | 189 | errExit("malloc"); |
188 | 190 | ||
189 | // run default quote_cmdline | 191 | // run default quote_cmdline |
190 | quote_cmdline(command_line_tmp, *window_title, len1, argc, argv, index); | 192 | quote_cmdline(command_line_tmp, *window_title, len1, argc, argv, index, want_extra_quotes); |
191 | 193 | ||
192 | assert(command_line_tmp); | 194 | assert(command_line_tmp); |
193 | assert(*window_title); | 195 | assert(*window_title); |
diff --git a/src/firejail/cpu.c b/src/firejail/cpu.c index 3427e8ade..1ec510456 100644 --- a/src/firejail/cpu.c +++ b/src/firejail/cpu.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -75,7 +75,7 @@ void save_cpu(void) { | |||
75 | if (cfg.cpus == 0) | 75 | if (cfg.cpus == 0) |
76 | return; | 76 | return; |
77 | 77 | ||
78 | FILE *fp = fopen(RUN_CPU_CFG, "w"); | 78 | FILE *fp = fopen(RUN_CPU_CFG, "wxe"); |
79 | if (fp) { | 79 | if (fp) { |
80 | fprintf(fp, "%x\n", cfg.cpus); | 80 | fprintf(fp, "%x\n", cfg.cpus); |
81 | SET_PERMS_STREAM(fp, 0, 0, 0600); | 81 | SET_PERMS_STREAM(fp, 0, 0, 0600); |
@@ -91,7 +91,7 @@ void load_cpu(const char *fname) { | |||
91 | if (!fname) | 91 | if (!fname) |
92 | return; | 92 | return; |
93 | 93 | ||
94 | FILE *fp = fopen(fname, "r"); | 94 | FILE *fp = fopen(fname, "re"); |
95 | if (fp) { | 95 | if (fp) { |
96 | unsigned tmp; | 96 | unsigned tmp; |
97 | int rv = fscanf(fp, "%x", &tmp); | 97 | int rv = fscanf(fp, "%x", &tmp); |
@@ -139,7 +139,7 @@ static void print_cpu(int pid) { | |||
139 | } | 139 | } |
140 | 140 | ||
141 | EUID_ROOT(); // grsecurity | 141 | EUID_ROOT(); // grsecurity |
142 | FILE *fp = fopen(file, "r"); | 142 | FILE *fp = fopen(file, "re"); |
143 | EUID_USER(); // grsecurity | 143 | EUID_USER(); // grsecurity |
144 | if (!fp) { | 144 | if (!fp) { |
145 | printf(" Error: cannot open %s\n", file); | 145 | printf(" Error: cannot open %s\n", file); |
diff --git a/src/firejail/dbus.c b/src/firejail/dbus.c index 658b84537..66738bd4b 100644 --- a/src/firejail/dbus.c +++ b/src/firejail/dbus.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -180,7 +180,7 @@ static void dbus_check_bus_profile(char const *prefix, DbusPolicy *policy) { | |||
180 | } | 180 | } |
181 | } | 181 | } |
182 | 182 | ||
183 | if (num_matches > 0) { | 183 | if (num_matches > 0 && !arg_quiet) { |
184 | assert(first_match != NULL); | 184 | assert(first_match != NULL); |
185 | if (num_matches == 1) { | 185 | if (num_matches == 1) { |
186 | fprintf(stderr, "Ignoring \"%s\".\n", first_match); | 186 | fprintf(stderr, "Ignoring \"%s\".\n", first_match); |
@@ -258,12 +258,8 @@ static char *find_user_socket_by_format(char *format) { | |||
258 | if (asprintf(&dbus_user_socket, format, (int) getuid()) == -1) | 258 | if (asprintf(&dbus_user_socket, format, (int) getuid()) == -1) |
259 | errExit("asprintf"); | 259 | errExit("asprintf"); |
260 | struct stat s; | 260 | struct stat s; |
261 | if (stat(dbus_user_socket, &s) == -1) { | 261 | if (lstat(dbus_user_socket, &s) == -1) |
262 | if (errno == ENOENT) | 262 | goto fail; |
263 | goto fail; | ||
264 | return NULL; | ||
265 | errExit("stat"); | ||
266 | } | ||
267 | if (!S_ISSOCK(s.st_mode)) | 263 | if (!S_ISSOCK(s.st_mode)) |
268 | goto fail; | 264 | goto fail; |
269 | return dbus_user_socket; | 265 | return dbus_user_socket; |
@@ -301,11 +297,12 @@ void dbus_proxy_start(void) { | |||
301 | if (dbus_proxy_pid == -1) | 297 | if (dbus_proxy_pid == -1) |
302 | errExit("fork"); | 298 | errExit("fork"); |
303 | if (dbus_proxy_pid == 0) { | 299 | if (dbus_proxy_pid == 0) { |
304 | int i; | 300 | // close open files |
305 | for (i = STDERR_FILENO + 1; i < FIREJAIL_MAX_FD; i++) { | 301 | int keep[2]; |
306 | if (i != status_pipe[1] && i != args_pipe[0]) | 302 | keep[0] = status_pipe[1]; |
307 | close(i); // close open files | 303 | keep[1] = args_pipe[0]; |
308 | } | 304 | close_all(keep, ARRAY_SIZE(keep)); |
305 | |||
309 | if (arg_dbus_log_file != NULL) { | 306 | if (arg_dbus_log_file != NULL) { |
310 | int output_fd = creat(arg_dbus_log_file, 0666); | 307 | int output_fd = creat(arg_dbus_log_file, 0666); |
311 | if (output_fd < 0) | 308 | if (output_fd < 0) |
@@ -416,7 +413,7 @@ void dbus_proxy_stop(void) { | |||
416 | } | 413 | } |
417 | 414 | ||
418 | static void socket_overlay(char *socket_path, char *proxy_path) { | 415 | static void socket_overlay(char *socket_path, char *proxy_path) { |
419 | int fd = safe_fd(proxy_path, O_PATH | O_NOFOLLOW | O_CLOEXEC); | 416 | int fd = safer_openat(-1, proxy_path, O_PATH | O_NOFOLLOW | O_CLOEXEC); |
420 | if (fd == -1) | 417 | if (fd == -1) |
421 | errExit("opening DBus proxy socket"); | 418 | errExit("opening DBus proxy socket"); |
422 | struct stat s; | 419 | struct stat s; |
@@ -426,12 +423,8 @@ static void socket_overlay(char *socket_path, char *proxy_path) { | |||
426 | errno = ENOTSOCK; | 423 | errno = ENOTSOCK; |
427 | errExit("mounting DBus proxy socket"); | 424 | errExit("mounting DBus proxy socket"); |
428 | } | 425 | } |
429 | char *proxy_fd_path; | 426 | if (bind_mount_fd_to_path(fd, socket_path)) |
430 | if (asprintf(&proxy_fd_path, "/proc/self/fd/%d", fd) == -1) | ||
431 | errExit("asprintf"); | ||
432 | if (mount(proxy_path, socket_path, NULL, MS_BIND | MS_REC, NULL) == -1) | ||
433 | errExit("mount bind"); | 427 | errExit("mount bind"); |
434 | free(proxy_fd_path); | ||
435 | close(fd); | 428 | close(fd); |
436 | } | 429 | } |
437 | 430 | ||
@@ -478,7 +471,7 @@ void dbus_apply_policy(void) { | |||
478 | create_empty_dir_as_root(RUN_DBUS_DIR, 0755); | 471 | create_empty_dir_as_root(RUN_DBUS_DIR, 0755); |
479 | 472 | ||
480 | if (arg_dbus_user != DBUS_POLICY_ALLOW) { | 473 | if (arg_dbus_user != DBUS_POLICY_ALLOW) { |
481 | create_empty_file_as_root(RUN_DBUS_USER_SOCKET, 0700); | 474 | create_empty_file_as_root(RUN_DBUS_USER_SOCKET, 0600); |
482 | 475 | ||
483 | if (arg_dbus_user == DBUS_POLICY_FILTER) { | 476 | if (arg_dbus_user == DBUS_POLICY_FILTER) { |
484 | assert(dbus_user_proxy_socket != NULL); | 477 | assert(dbus_user_proxy_socket != NULL); |
@@ -517,7 +510,7 @@ void dbus_apply_policy(void) { | |||
517 | } | 510 | } |
518 | 511 | ||
519 | if (arg_dbus_system != DBUS_POLICY_ALLOW) { | 512 | if (arg_dbus_system != DBUS_POLICY_ALLOW) { |
520 | create_empty_file_as_root(RUN_DBUS_SYSTEM_SOCKET, 0700); | 513 | create_empty_file_as_root(RUN_DBUS_SYSTEM_SOCKET, 0600); |
521 | 514 | ||
522 | if (arg_dbus_system == DBUS_POLICY_FILTER) { | 515 | if (arg_dbus_system == DBUS_POLICY_FILTER) { |
523 | assert(dbus_system_proxy_socket != NULL); | 516 | assert(dbus_system_proxy_socket != NULL); |
diff --git a/src/firejail/dhcp.c b/src/firejail/dhcp.c index bdbb338d5..fb66d74ff 100644 --- a/src/firejail/dhcp.c +++ b/src/firejail/dhcp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -93,7 +93,7 @@ static pid_t dhcp_read_pidfile(const Dhclient *client) { | |||
93 | while (found == 0 && tries < 10) { | 93 | while (found == 0 && tries < 10) { |
94 | if (tries >= 1) | 94 | if (tries >= 1) |
95 | usleep(100000); | 95 | usleep(100000); |
96 | FILE *pidfile = fopen(client->pid_file, "r"); | 96 | FILE *pidfile = fopen(client->pid_file, "re"); |
97 | if (pidfile) { | 97 | if (pidfile) { |
98 | long pid; | 98 | long pid; |
99 | if (fscanf(pidfile, "%ld", &pid) == 1) | 99 | if (fscanf(pidfile, "%ld", &pid) == 1) |
@@ -153,19 +153,13 @@ void dhcp_start(void) { | |||
153 | if (!any_dhcp()) | 153 | if (!any_dhcp()) |
154 | return; | 154 | return; |
155 | 155 | ||
156 | char *dhclient_path = RUN_MNT_DIR "/dhclient";; | 156 | char *dhclient_path = RUN_MNT_DIR "/dhclient"; |
157 | struct stat s; | 157 | struct stat s; |
158 | if (stat(dhclient_path, &s) == -1) { | 158 | if (stat(dhclient_path, &s) == -1) { |
159 | dhclient_path = "/usr/sbin/dhclient"; | 159 | fprintf(stderr, "Error: %s was not found.\n", dhclient_path); |
160 | if (stat(dhclient_path, &s) == -1) { | 160 | exit(1); |
161 | fprintf(stderr, "Error: dhclient was not found.\n"); | ||
162 | exit(1); | ||
163 | } | ||
164 | } | 161 | } |
165 | 162 | ||
166 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", dhclient_path, RUN_MNT_DIR); | ||
167 | dhclient_path = RUN_MNT_DIR "/dhclient"; | ||
168 | |||
169 | EUID_ROOT(); | 163 | EUID_ROOT(); |
170 | if (mkdir(RUN_DHCLIENT_DIR, 0700)) | 164 | if (mkdir(RUN_DHCLIENT_DIR, 0700)) |
171 | errExit("mkdir"); | 165 | errExit("mkdir"); |
diff --git a/src/firejail/env.c b/src/firejail/env.c index 03818df0b..963288459 100644 --- a/src/firejail/env.c +++ b/src/firejail/env.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -22,6 +22,7 @@ | |||
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <unistd.h> | 23 | #include <unistd.h> |
24 | #include <dirent.h> | 24 | #include <dirent.h> |
25 | #include <limits.h> | ||
25 | 26 | ||
26 | typedef struct env_t { | 27 | typedef struct env_t { |
27 | struct env_t *next; | 28 | struct env_t *next; |
@@ -59,12 +60,7 @@ void env_ibus_load(void) { | |||
59 | if (asprintf(&dirname, "%s/.config/ibus/bus", cfg.homedir) == -1) | 60 | if (asprintf(&dirname, "%s/.config/ibus/bus", cfg.homedir) == -1) |
60 | errExit("asprintf"); | 61 | errExit("asprintf"); |
61 | 62 | ||
62 | struct stat s; | ||
63 | if (stat(dirname, &s) == -1) | ||
64 | return; | ||
65 | |||
66 | // find the file | 63 | // find the file |
67 | /* coverity[toctou] */ | ||
68 | DIR *dir = opendir(dirname); | 64 | DIR *dir = opendir(dirname); |
69 | if (!dir) { | 65 | if (!dir) { |
70 | free(dirname); | 66 | free(dirname); |
@@ -84,7 +80,7 @@ void env_ibus_load(void) { | |||
84 | char *fname; | 80 | char *fname; |
85 | if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1) | 81 | if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1) |
86 | errExit("asprintf"); | 82 | errExit("asprintf"); |
87 | FILE *fp = fopen(fname, "r"); | 83 | FILE *fp = fopen(fname, "re"); |
88 | free(fname); | 84 | free(fname); |
89 | if (!fp) | 85 | if (!fp) |
90 | continue; | 86 | continue; |
@@ -267,7 +263,7 @@ static const char * const env_whitelist[] = { | |||
267 | "LANG", | 263 | "LANG", |
268 | "LANGUAGE", | 264 | "LANGUAGE", |
269 | "LC_MESSAGES", | 265 | "LC_MESSAGES", |
270 | "PATH", | 266 | // "PATH", |
271 | "DISPLAY" // required by X11 | 267 | "DISPLAY" // required by X11 |
272 | }; | 268 | }; |
273 | 269 | ||
@@ -316,6 +312,10 @@ void env_apply_whitelist(void) { | |||
316 | errExit("clearenv"); | 312 | errExit("clearenv"); |
317 | 313 | ||
318 | env_apply_list(env_whitelist, ARRAY_SIZE(env_whitelist)); | 314 | env_apply_list(env_whitelist, ARRAY_SIZE(env_whitelist)); |
315 | |||
316 | // hardcoding PATH | ||
317 | if (setenv("PATH", "/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin", 1) < 0) | ||
318 | errExit("setenv"); | ||
319 | } | 319 | } |
320 | 320 | ||
321 | // Filter env variables for a sbox app | 321 | // Filter env variables for a sbox app |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index e07035ae6..316518534 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -22,6 +22,7 @@ | |||
22 | #include "../include/common.h" | 22 | #include "../include/common.h" |
23 | #include "../include/euid_common.h" | 23 | #include "../include/euid_common.h" |
24 | #include "../include/rundefs.h" | 24 | #include "../include/rundefs.h" |
25 | #include <linux/limits.h> // Note: Plain limits.h may break ARG_MAX (see #4583) | ||
25 | #include <stdarg.h> | 26 | #include <stdarg.h> |
26 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
27 | 28 | ||
@@ -45,6 +46,15 @@ | |||
45 | assert(s.st_gid == gid);\ | 46 | assert(s.st_gid == gid);\ |
46 | assert((s.st_mode & 07777) == (mode));\ | 47 | assert((s.st_mode & 07777) == (mode));\ |
47 | } while (0) | 48 | } while (0) |
49 | #define ASSERT_PERMS_AS_USER(file, uid, gid, mode) \ | ||
50 | do { \ | ||
51 | assert(file);\ | ||
52 | struct stat s;\ | ||
53 | if (stat_as_user(file, &s) == -1) errExit("stat");\ | ||
54 | assert(s.st_uid == uid);\ | ||
55 | assert(s.st_gid == gid);\ | ||
56 | assert((s.st_mode & 07777) == (mode));\ | ||
57 | } while (0) | ||
48 | #define ASSERT_PERMS_FD(fd, uid, gid, mode) \ | 58 | #define ASSERT_PERMS_FD(fd, uid, gid, mode) \ |
49 | do { \ | 59 | do { \ |
50 | struct stat s;\ | 60 | struct stat s;\ |
@@ -122,26 +132,22 @@ typedef struct interface_t { | |||
122 | uint8_t configured; | 132 | uint8_t configured; |
123 | } Interface; | 133 | } Interface; |
124 | 134 | ||
135 | typedef struct topdir_t { | ||
136 | char *path; | ||
137 | int fd; | ||
138 | } TopDir; | ||
139 | |||
125 | typedef struct profile_entry_t { | 140 | typedef struct profile_entry_t { |
126 | struct profile_entry_t *next; | 141 | struct profile_entry_t *next; |
127 | char *data; // command | 142 | char *data; // command |
128 | 143 | ||
129 | // whitelist command parameters | 144 | // whitelist command parameters |
130 | char *link; // link name - set if the file is a link | 145 | struct wparam_t { |
131 | enum { | 146 | char *file; // resolved file path |
132 | WLDIR_HOME = 1, // whitelist in home directory | 147 | char *link; // link path |
133 | WLDIR_TMP, // whitelist in /tmp directory | 148 | TopDir *top; // top level directory |
134 | WLDIR_MEDIA, // whitelist in /media directory | 149 | } *wparam; |
135 | WLDIR_MNT, // whitelist in /mnt directory | 150 | |
136 | WLDIR_VAR, // whitelist in /var directory | ||
137 | WLDIR_DEV, // whitelist in /dev directory | ||
138 | WLDIR_OPT, // whitelist in /opt directory | ||
139 | WLDIR_SRV, // whitelist in /srv directory | ||
140 | WLDIR_ETC, // whitelist in /etc directory | ||
141 | WLDIR_SHARE, // whitelist in /usr/share directory | ||
142 | WLDIR_MODULE, // whitelist in /sys/module directory | ||
143 | WLDIR_RUN // whitelist in /run/user/$uid directory | ||
144 | } wldir; | ||
145 | } ProfileEntry; | 151 | } ProfileEntry; |
146 | 152 | ||
147 | typedef struct config_t { | 153 | typedef struct config_t { |
@@ -151,8 +157,11 @@ typedef struct config_t { | |||
151 | 157 | ||
152 | // filesystem | 158 | // filesystem |
153 | ProfileEntry *profile; | 159 | ProfileEntry *profile; |
160 | ProfileEntry *profile_rebuild_etc; // blacklist files in /etc directory used by fs_rebuild_etc() | ||
161 | |||
154 | #define MAX_PROFILE_IGNORE 32 | 162 | #define MAX_PROFILE_IGNORE 32 |
155 | char *profile_ignore[MAX_PROFILE_IGNORE]; | 163 | char *profile_ignore[MAX_PROFILE_IGNORE]; |
164 | char *keep_fd; // inherit file descriptors to sandbox | ||
156 | char *chrootdir; // chroot directory | 165 | char *chrootdir; // chroot directory |
157 | char *home_private; // private home directory | 166 | char *home_private; // private home directory |
158 | char *home_private_keep; // keep list for private home directory | 167 | char *home_private_keep; // keep list for private home directory |
@@ -314,15 +323,16 @@ extern int arg_private_cwd; // private working directory | |||
314 | extern int arg_scan; // arp-scan all interfaces | 323 | extern int arg_scan; // arp-scan all interfaces |
315 | extern int arg_whitelist; // whitelist command | 324 | extern int arg_whitelist; // whitelist command |
316 | extern int arg_nosound; // disable sound | 325 | extern int arg_nosound; // disable sound |
317 | extern int arg_noautopulse; // disable automatic ~/.config/pulse init | ||
318 | extern int arg_novideo; //disable video devices in /dev | 326 | extern int arg_novideo; //disable video devices in /dev |
319 | extern int arg_no3d; // disable 3d hardware acceleration | 327 | extern int arg_no3d; // disable 3d hardware acceleration |
328 | extern int arg_noprinters; // disable printers | ||
320 | extern int arg_quiet; // no output for scripting | 329 | extern int arg_quiet; // no output for scripting |
321 | extern int arg_join_network; // join only the network namespace | 330 | extern int arg_join_network; // join only the network namespace |
322 | extern int arg_join_filesystem; // join only the mount namespace | 331 | extern int arg_join_filesystem; // join only the mount namespace |
323 | extern int arg_nice; // nice value configured | 332 | extern int arg_nice; // nice value configured |
324 | extern int arg_ipc; // enable ipc namespace | 333 | extern int arg_ipc; // enable ipc namespace |
325 | extern int arg_writable_etc; // writable etc | 334 | extern int arg_writable_etc; // writable etc |
335 | extern int arg_keep_config_pulse; // disable automatic ~/.config/pulse init | ||
326 | extern int arg_writable_var; // writable var | 336 | extern int arg_writable_var; // writable var |
327 | extern int arg_keep_var_tmp; // don't overwrite /var/tmp | 337 | extern int arg_keep_var_tmp; // don't overwrite /var/tmp |
328 | extern int arg_writable_run_user; // writable /run/user | 338 | extern int arg_writable_run_user; // writable /run/user |
@@ -333,7 +343,7 @@ extern int arg_allow_debuggers; // allow debuggers | |||
333 | extern int arg_x11_block; // block X11 | 343 | extern int arg_x11_block; // block X11 |
334 | extern int arg_x11_xorg; // use X11 security extension | 344 | extern int arg_x11_xorg; // use X11 security extension |
335 | extern int arg_allusers; // all user home directories visible | 345 | extern int arg_allusers; // all user home directories visible |
336 | extern int arg_machineid; // preserve /etc/machine-id | 346 | extern int arg_machineid; // spoof /etc/machine-id |
337 | extern int arg_disable_mnt; // disable /mnt and /media | 347 | extern int arg_disable_mnt; // disable /mnt and /media |
338 | extern int arg_noprofile; // use default.profile if none other found/specified | 348 | extern int arg_noprofile; // use default.profile if none other found/specified |
339 | extern int arg_memory_deny_write_execute; // block writable and executable memory | 349 | extern int arg_memory_deny_write_execute; // block writable and executable memory |
@@ -342,6 +352,8 @@ extern int arg_nodvd; // --nodvd | |||
342 | extern int arg_nou2f; // --nou2f | 352 | extern int arg_nou2f; // --nou2f |
343 | extern int arg_noinput; // --noinput | 353 | extern int arg_noinput; // --noinput |
344 | extern int arg_deterministic_exit_code; // always exit with first child's exit status | 354 | extern int arg_deterministic_exit_code; // always exit with first child's exit status |
355 | extern int arg_deterministic_shutdown; // shut down the sandbox if first child dies | ||
356 | extern int arg_keep_fd_all; // inherit all file descriptors to sandbox | ||
345 | 357 | ||
346 | typedef enum { | 358 | typedef enum { |
347 | DBUS_POLICY_ALLOW, // Allow unrestricted access to the bus | 359 | DBUS_POLICY_ALLOW, // Allow unrestricted access to the bus |
@@ -353,6 +365,7 @@ extern DbusPolicy arg_dbus_system; // --dbus-system | |||
353 | extern int arg_dbus_log_user; | 365 | extern int arg_dbus_log_user; |
354 | extern int arg_dbus_log_system; | 366 | extern int arg_dbus_log_system; |
355 | extern const char *arg_dbus_log_file; | 367 | extern const char *arg_dbus_log_file; |
368 | extern int arg_tab; | ||
356 | 369 | ||
357 | extern int login_shell; | 370 | extern int login_shell; |
358 | extern int parent_to_child_fds[2]; | 371 | extern int parent_to_child_fds[2]; |
@@ -426,13 +439,15 @@ void fs_proc_sys_dev_boot(void); | |||
426 | void disable_config(void); | 439 | void disable_config(void); |
427 | // build a basic read-only filesystem | 440 | // build a basic read-only filesystem |
428 | void fs_basic_fs(void); | 441 | void fs_basic_fs(void); |
429 | // mount overlayfs on top of / directory | ||
430 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse); | ||
431 | void fs_overlayfs(void); | ||
432 | void fs_private_tmp(void); | 442 | void fs_private_tmp(void); |
433 | void fs_private_cache(void); | 443 | void fs_private_cache(void); |
434 | void fs_mnt(const int enforce); | 444 | void fs_mnt(const int enforce); |
435 | 445 | ||
446 | // fs_overlayfs.c | ||
447 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse); | ||
448 | void fs_overlayfs(void); | ||
449 | int remove_overlay_directory(void); | ||
450 | |||
436 | // chroot.c | 451 | // chroot.c |
437 | // chroot into an existing directory; mount existing /dev and update /etc/resolv.conf | 452 | // chroot into an existing directory; mount existing /dev and update /etc/resolv.conf |
438 | void fs_check_chroot_dir(void); | 453 | void fs_check_chroot_dir(void); |
@@ -493,7 +508,9 @@ int macro_id(const char *name); | |||
493 | void errLogExit(char* fmt, ...) __attribute__((noreturn)); | 508 | void errLogExit(char* fmt, ...) __attribute__((noreturn)); |
494 | void fwarning(char* fmt, ...); | 509 | void fwarning(char* fmt, ...); |
495 | void fmessage(char* fmt, ...); | 510 | void fmessage(char* fmt, ...); |
496 | void drop_privs(int nogroups); | 511 | long long unsigned parse_arg_size(char *str); |
512 | int check_can_drop_all_groups(); | ||
513 | void drop_privs(int force_nogroups); | ||
497 | int mkpath_as_root(const char* path); | 514 | int mkpath_as_root(const char* path); |
498 | void extract_command_name(int index, char **argv); | 515 | void extract_command_name(int index, char **argv); |
499 | void logsignal(int s); | 516 | void logsignal(int s); |
@@ -502,11 +519,15 @@ void logargs(int argc, char **argv) ; | |||
502 | void logerr(const char *msg); | 519 | void logerr(const char *msg); |
503 | void set_nice(int inc); | 520 | void set_nice(int inc); |
504 | int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); | 521 | int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); |
505 | void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); | 522 | void copy_file_as_user(const char *srcname, const char *destname, mode_t mode); |
506 | void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); | 523 | void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); |
507 | void touch_file_as_user(const char *fname, mode_t mode); | 524 | void touch_file_as_user(const char *fname, mode_t mode); |
508 | int is_dir(const char *fname); | 525 | int is_dir(const char *fname); |
509 | int is_link(const char *fname); | 526 | int is_link(const char *fname); |
527 | char *realpath_as_user(const char *fname); | ||
528 | ssize_t readlink_as_user(const char *fname, char *buf, size_t sz); | ||
529 | int stat_as_user(const char *fname, struct stat *s); | ||
530 | int lstat_as_user(const char *fname, struct stat *s); | ||
510 | void trim_trailing_slash_or_dot(char *path); | 531 | void trim_trailing_slash_or_dot(char *path); |
511 | char *line_remove_spaces(const char *buf); | 532 | char *line_remove_spaces(const char *buf); |
512 | char *split_comma(char *str); | 533 | char *split_comma(char *str); |
@@ -518,8 +539,7 @@ void update_map(char *mapping, char *map_file); | |||
518 | void wait_for_other(int fd); | 539 | void wait_for_other(int fd); |
519 | void notify_other(int fd); | 540 | void notify_other(int fd); |
520 | uid_t pid_get_uid(pid_t pid); | 541 | uid_t pid_get_uid(pid_t pid); |
521 | uid_t get_group_id(const char *group); | 542 | gid_t get_group_id(const char *groupname); |
522 | int remove_overlay_directory(void); | ||
523 | void flush_stdin(void); | 543 | void flush_stdin(void); |
524 | int create_empty_dir_as_user(const char *dir, mode_t mode); | 544 | int create_empty_dir_as_user(const char *dir, mode_t mode); |
525 | void create_empty_dir_as_root(const char *dir, mode_t mode); | 545 | void create_empty_dir_as_root(const char *dir, mode_t mode); |
@@ -529,12 +549,17 @@ void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid); | |||
529 | unsigned extract_timeout(const char *str); | 549 | unsigned extract_timeout(const char *str); |
530 | void disable_file_or_dir(const char *fname); | 550 | void disable_file_or_dir(const char *fname); |
531 | void disable_file_path(const char *path, const char *file); | 551 | void disable_file_path(const char *path, const char *file); |
532 | int safe_fd(const char *path, int flags); | 552 | int safer_openat(int dirfd, const char *path, int flags); |
553 | int remount_by_fd(int dst, unsigned long mountflags); | ||
554 | int bind_mount_by_fd(int src, int dst); | ||
555 | int bind_mount_path_to_fd(const char *srcname, int dst); | ||
556 | int bind_mount_fd_to_path(int src, const char *destname); | ||
557 | void close_all(int *keep_list, size_t sz); | ||
533 | int has_handler(pid_t pid, int signal); | 558 | int has_handler(pid_t pid, int signal); |
534 | void enter_network_namespace(pid_t pid); | 559 | void enter_network_namespace(pid_t pid); |
535 | int read_pid(const char *name, pid_t *pid); | 560 | int read_pid(const char *name, pid_t *pid); |
536 | pid_t require_pid(const char *name); | 561 | pid_t require_pid(const char *name); |
537 | void check_homedir(void); | 562 | void check_homedir(const char *dir); |
538 | 563 | ||
539 | // Get info regarding the last kernel mount operation from /proc/self/mountinfo | 564 | // Get info regarding the last kernel mount operation from /proc/self/mountinfo |
540 | // The return value points to a static area, and will be overwritten by subsequent calls. | 565 | // The return value points to a static area, and will be overwritten by subsequent calls. |
@@ -548,8 +573,8 @@ typedef struct { | |||
548 | 573 | ||
549 | // mountinfo.c | 574 | // mountinfo.c |
550 | MountData *get_last_mount(void); | 575 | MountData *get_last_mount(void); |
551 | int get_mount_id(const char *path); | 576 | int get_mount_id(int fd); |
552 | char **build_mount_array(const int mount_id, const char *path); | 577 | char **build_mount_array(const int mountid, const char *path); |
553 | 578 | ||
554 | // fs_var.c | 579 | // fs_var.c |
555 | void fs_var_log(void); // mounting /var/log | 580 | void fs_var_log(void); // mounting /var/log |
@@ -606,13 +631,13 @@ void caps_print_filter(pid_t pid) __attribute__((noreturn)); | |||
606 | void caps_drop_dac_override(void); | 631 | void caps_drop_dac_override(void); |
607 | 632 | ||
608 | // fs_trace.c | 633 | // fs_trace.c |
609 | void fs_trace_preload(void); | 634 | void fs_trace_touch_preload(void); |
635 | void fs_trace_touch_or_store_preload(void); | ||
610 | void fs_tracefile(void); | 636 | void fs_tracefile(void); |
611 | void fs_trace(void); | 637 | void fs_trace(void); |
612 | 638 | ||
613 | // fs_hostname.c | 639 | // fs_hostname.c |
614 | void fs_hostname(const char *hostname); | 640 | void fs_hostname(const char *hostname); |
615 | void fs_resolvconf(void); | ||
616 | char *fs_check_hosts_file(const char *fname); | 641 | char *fs_check_hosts_file(const char *fname); |
617 | void fs_store_hosts_file(void); | 642 | void fs_store_hosts_file(void); |
618 | void fs_mount_hosts_file(void); | 643 | void fs_mount_hosts_file(void); |
@@ -630,12 +655,15 @@ void cpu_print_filter(pid_t pid) __attribute__((noreturn)); | |||
630 | // cgroup.c | 655 | // cgroup.c |
631 | void save_cgroup(void); | 656 | void save_cgroup(void); |
632 | void load_cgroup(const char *fname); | 657 | void load_cgroup(const char *fname); |
633 | void set_cgroup(const char *path); | 658 | void check_cgroup_file(const char *fname); |
659 | void set_cgroup(const char *fname, pid_t pid); | ||
634 | 660 | ||
635 | // output.c | 661 | // output.c |
636 | void check_output(int argc, char **argv); | 662 | void check_output(int argc, char **argv); |
637 | 663 | ||
638 | // netfilter.c | 664 | // netfilter.c |
665 | void netfilter_netlock(pid_t pid); | ||
666 | void netfilter_trace(pid_t pid); | ||
639 | void check_netfilter_file(const char *fname); | 667 | void check_netfilter_file(const char *fname); |
640 | void netfilter(const char *fname); | 668 | void netfilter(const char *fname); |
641 | void netfilter6(const char *fname); | 669 | void netfilter6(const char *fname); |
@@ -655,6 +683,7 @@ void fs_machineid(void); | |||
655 | void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list); | 683 | void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list); |
656 | void fs_private_dir_mount(const char *private_dir, const char *private_run_dir); | 684 | void fs_private_dir_mount(const char *private_dir, const char *private_run_dir); |
657 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list); | 685 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list); |
686 | void fs_rebuild_etc(void); | ||
658 | 687 | ||
659 | // no_sandbox.c | 688 | // no_sandbox.c |
660 | int check_namespace_virt(void); | 689 | int check_namespace_virt(void); |
@@ -682,6 +711,7 @@ void env_ibus_load(void); | |||
682 | void fs_whitelist(void); | 711 | void fs_whitelist(void); |
683 | 712 | ||
684 | // pulseaudio.c | 713 | // pulseaudio.c |
714 | void pipewire_disable(void); | ||
685 | void pulseaudio_init(void); | 715 | void pulseaudio_init(void); |
686 | void pulseaudio_disable(void); | 716 | void pulseaudio_disable(void); |
687 | 717 | ||
@@ -689,6 +719,8 @@ void pulseaudio_disable(void); | |||
689 | void fs_private_bin_list(void); | 719 | void fs_private_bin_list(void); |
690 | 720 | ||
691 | // fs_lib.c | 721 | // fs_lib.c |
722 | int is_firejail_link(const char *fname); | ||
723 | char *find_in_path(const char *program); | ||
692 | void fs_private_lib(void); | 724 | void fs_private_lib(void); |
693 | 725 | ||
694 | // protocol.c | 726 | // protocol.c |
@@ -763,27 +795,30 @@ enum { | |||
763 | CFG_NETWORK, | 795 | CFG_NETWORK, |
764 | CFG_RESTRICTED_NETWORK, | 796 | CFG_RESTRICTED_NETWORK, |
765 | CFG_FORCE_NONEWPRIVS, | 797 | CFG_FORCE_NONEWPRIVS, |
766 | CFG_WHITELIST, | ||
767 | CFG_XEPHYR_WINDOW_TITLE, | 798 | CFG_XEPHYR_WINDOW_TITLE, |
768 | CFG_OVERLAYFS, | 799 | CFG_OVERLAYFS, |
769 | CFG_PRIVATE_HOME, | 800 | CFG_PRIVATE_BIN, |
770 | CFG_PRIVATE_BIN_NO_LOCAL, | 801 | CFG_PRIVATE_BIN_NO_LOCAL, |
802 | CFG_PRIVATE_CACHE, | ||
803 | CFG_PRIVATE_ETC, | ||
804 | CFG_PRIVATE_HOME, | ||
805 | CFG_PRIVATE_LIB, | ||
806 | CFG_PRIVATE_OPT, | ||
807 | CFG_PRIVATE_SRV, | ||
771 | CFG_FIREJAIL_PROMPT, | 808 | CFG_FIREJAIL_PROMPT, |
772 | CFG_FOLLOW_SYMLINK_AS_USER, | ||
773 | CFG_DISABLE_MNT, | 809 | CFG_DISABLE_MNT, |
774 | CFG_JOIN, | 810 | CFG_JOIN, |
775 | CFG_ARP_PROBES, | 811 | CFG_ARP_PROBES, |
776 | CFG_XPRA_ATTACH, | 812 | CFG_XPRA_ATTACH, |
777 | CFG_BROWSER_DISABLE_U2F, | 813 | CFG_BROWSER_DISABLE_U2F, |
778 | CFG_BROWSER_ALLOW_DRM, | 814 | CFG_BROWSER_ALLOW_DRM, |
779 | CFG_PRIVATE_LIB, | ||
780 | CFG_APPARMOR, | 815 | CFG_APPARMOR, |
781 | CFG_DBUS, | 816 | CFG_DBUS, |
782 | CFG_PRIVATE_CACHE, | ||
783 | CFG_CGROUP, | 817 | CFG_CGROUP, |
784 | CFG_NAME_CHANGE, | 818 | CFG_NAME_CHANGE, |
785 | CFG_SECCOMP_ERROR_ACTION, | 819 | CFG_SECCOMP_ERROR_ACTION, |
786 | // CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv | 820 | // CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv |
821 | CFG_ALLOW_TRAY, | ||
787 | CFG_MAX // this should always be the last entry | 822 | CFG_MAX // this should always be the last entry |
788 | }; | 823 | }; |
789 | extern char *xephyr_screen; | 824 | extern char *xephyr_screen; |
@@ -794,11 +829,14 @@ extern char *xvfb_extra_params; | |||
794 | extern char *netfilter_default; | 829 | extern char *netfilter_default; |
795 | extern unsigned long join_timeout; | 830 | extern unsigned long join_timeout; |
796 | extern char *config_seccomp_error_action_str; | 831 | extern char *config_seccomp_error_action_str; |
832 | extern char *config_seccomp_filter_add; | ||
833 | extern char **whitelist_reject_topdirs; | ||
797 | 834 | ||
798 | int checkcfg(int val); | 835 | int checkcfg(int val); |
799 | void print_compiletime_support(void); | 836 | void print_compiletime_support(void); |
800 | 837 | ||
801 | // appimage.c | 838 | // appimage.c |
839 | int appimage_find_profile(const char *archive); | ||
802 | void appimage_set(const char *appimage_path); | 840 | void appimage_set(const char *appimage_path); |
803 | void appimage_mount(void); | 841 | void appimage_mount(void); |
804 | void appimage_clear(void); | 842 | void appimage_clear(void); |
@@ -807,15 +845,14 @@ void appimage_clear(void); | |||
807 | long unsigned int appimage2_size(int fd); | 845 | long unsigned int appimage2_size(int fd); |
808 | 846 | ||
809 | // cmdline.c | 847 | // cmdline.c |
810 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); | 848 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, bool want_extra_quotes); |
811 | void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); | 849 | void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, bool want_extra_quotes); |
812 | 850 | ||
813 | // sbox.c | 851 | // sbox.c |
814 | // programs | 852 | // programs |
815 | #define PATH_FNET_MAIN (LIBDIR "/firejail/fnet") // when called from main thread | 853 | #define PATH_FNET_MAIN (LIBDIR "/firejail/fnet") // when called from main thread |
816 | #define PATH_FNET (RUN_FIREJAIL_LIB_DIR "/fnet") // when called from sandbox thread | 854 | #define PATH_FNET (RUN_FIREJAIL_LIB_DIR "/fnet") // when called from sandbox thread |
817 | 855 | ||
818 | //#define PATH_FNETFILTER (LIBDIR "/firejail/fnetfilter") | ||
819 | #define PATH_FNETFILTER (RUN_FIREJAIL_LIB_DIR "/fnetfilter") | 856 | #define PATH_FNETFILTER (RUN_FIREJAIL_LIB_DIR "/fnetfilter") |
820 | 857 | ||
821 | #define PATH_FIREMON (PREFIX "/bin/firemon") | 858 | #define PATH_FIREMON (PREFIX "/bin/firemon") |
@@ -828,17 +865,16 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, | |||
828 | // it is also run from inside the sandbox by --debug; in this case we do an access(filename, X_OK) test first | 865 | // it is also run from inside the sandbox by --debug; in this case we do an access(filename, X_OK) test first |
829 | #define PATH_FSEC_PRINT (LIBDIR "/firejail/fsec-print") | 866 | #define PATH_FSEC_PRINT (LIBDIR "/firejail/fsec-print") |
830 | 867 | ||
831 | //#define PATH_FSEC_OPTIMIZE (LIBDIR "/firejail/fsec-optimize") | ||
832 | #define PATH_FSEC_OPTIMIZE (RUN_FIREJAIL_LIB_DIR "/fsec-optimize") | 868 | #define PATH_FSEC_OPTIMIZE (RUN_FIREJAIL_LIB_DIR "/fsec-optimize") |
833 | 869 | ||
834 | //#define PATH_FCOPY (LIBDIR "/firejail/fcopy") | ||
835 | #define PATH_FCOPY (RUN_FIREJAIL_LIB_DIR "/fcopy") | 870 | #define PATH_FCOPY (RUN_FIREJAIL_LIB_DIR "/fcopy") |
836 | 871 | ||
837 | #define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin" | 872 | #define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin" |
838 | 873 | ||
839 | //#define PATH_FLDD (LIBDIR "/firejail/fldd") | ||
840 | #define PATH_FLDD (RUN_FIREJAIL_LIB_DIR "/fldd") | 874 | #define PATH_FLDD (RUN_FIREJAIL_LIB_DIR "/fldd") |
841 | 875 | ||
876 | #define PATH_FIDS (LIBDIR "/firejail/fids") | ||
877 | |||
842 | // bitmapped filters for sbox_run | 878 | // bitmapped filters for sbox_run |
843 | #define SBOX_ROOT (1 << 0) // run the sandbox as root | 879 | #define SBOX_ROOT (1 << 0) // run the sandbox as root |
844 | #define SBOX_USER (1 << 1) // run the sandbox as a regular user | 880 | #define SBOX_USER (1 << 1) // run the sandbox as a regular user |
@@ -850,7 +886,6 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, | |||
850 | #define SBOX_CAPS_HIDEPID (1 << 7) // hidepid caps filter for running firemon | 886 | #define SBOX_CAPS_HIDEPID (1 << 7) // hidepid caps filter for running firemon |
851 | #define SBOX_CAPS_NET_SERVICE (1 << 8) // caps filter for programs running network services | 887 | #define SBOX_CAPS_NET_SERVICE (1 << 8) // caps filter for programs running network services |
852 | #define SBOX_KEEP_FDS (1 << 9) // keep file descriptors open | 888 | #define SBOX_KEEP_FDS (1 << 9) // keep file descriptors open |
853 | #define FIREJAIL_MAX_FD 20 // getdtablesize() is overkill for a firejail process | ||
854 | 889 | ||
855 | // run sbox | 890 | // run sbox |
856 | int sbox_run(unsigned filter, int num, ...); | 891 | int sbox_run(unsigned filter, int num, ...); |
@@ -883,4 +918,7 @@ void dhcp_start(void); | |||
883 | // selinux.c | 918 | // selinux.c |
884 | void selinux_relabel_path(const char *path, const char *inside_path); | 919 | void selinux_relabel_path(const char *path, const char *inside_path); |
885 | 920 | ||
921 | // ids.c | ||
922 | void run_ids(int argc, char **argv); | ||
923 | |||
886 | #endif | 924 | #endif |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index fc67a15f3..c03cd7a12 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,11 +18,9 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include "../include/gcov_wrapper.h" | ||
21 | #include <sys/mount.h> | 22 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | ||
23 | #include <sys/statvfs.h> | 23 | #include <sys/statvfs.h> |
24 | #include <sys/wait.h> | ||
25 | #include <linux/limits.h> | ||
26 | #include <fnmatch.h> | 24 | #include <fnmatch.h> |
27 | #include <glob.h> | 25 | #include <glob.h> |
28 | #include <dirent.h> | 26 | #include <dirent.h> |
@@ -34,7 +32,7 @@ | |||
34 | #endif | 32 | #endif |
35 | 33 | ||
36 | #define MAX_BUF 4096 | 34 | #define MAX_BUF 4096 |
37 | #define EMPTY_STRING ("") | 35 | |
38 | // check noblacklist statements not matched by a proper blacklist in disable-*.inc files | 36 | // check noblacklist statements not matched by a proper blacklist in disable-*.inc files |
39 | //#define TEST_NO_BLACKLIST_MATCHING | 37 | //#define TEST_NO_BLACKLIST_MATCHING |
40 | 38 | ||
@@ -54,16 +52,10 @@ static char *opstr[] = { | |||
54 | [MOUNT_RDWR_NOCHECK] = "read-write", | 52 | [MOUNT_RDWR_NOCHECK] = "read-write", |
55 | }; | 53 | }; |
56 | 54 | ||
57 | typedef enum { | ||
58 | UNSUCCESSFUL, | ||
59 | SUCCESSFUL | ||
60 | } LAST_DISABLE_OPERATION; | ||
61 | LAST_DISABLE_OPERATION last_disable = UNSUCCESSFUL; | ||
62 | |||
63 | static void disable_file(OPERATION op, const char *filename) { | 55 | static void disable_file(OPERATION op, const char *filename) { |
64 | assert(filename); | 56 | assert(filename); |
65 | assert(op <OPERATION_MAX); | 57 | assert(op <OPERATION_MAX); |
66 | last_disable = UNSUCCESSFUL; | 58 | EUID_ASSERT(); |
67 | 59 | ||
68 | // Resolve all symlinks | 60 | // Resolve all symlinks |
69 | char* fname = realpath(filename, NULL); | 61 | char* fname = realpath(filename, NULL); |
@@ -71,20 +63,24 @@ static void disable_file(OPERATION op, const char *filename) { | |||
71 | return; | 63 | return; |
72 | } | 64 | } |
73 | if (fname == NULL && errno == EACCES) { | 65 | if (fname == NULL && errno == EACCES) { |
74 | if (arg_debug) | ||
75 | printf("Debug: no access to file %s, forcing mount\n", filename); | ||
76 | // realpath and stat functions will fail on FUSE filesystems | 66 | // realpath and stat functions will fail on FUSE filesystems |
77 | // they don't seem to like a uid of 0 | 67 | // they don't seem to like a uid of 0 |
78 | // force mounting | 68 | // force mounting |
79 | int rv = mount(RUN_RO_DIR, filename, "none", MS_BIND, "mode=400,gid=0"); | 69 | int fd = open(filename, O_PATH|O_CLOEXEC); |
80 | if (rv == 0) | 70 | if (fd < 0) { |
81 | last_disable = SUCCESSFUL; | 71 | if (arg_debug) |
82 | else { | 72 | printf("Warning (blacklisting): cannot open %s: %s\n", filename, strerror(errno)); |
83 | rv = mount(RUN_RO_FILE, filename, "none", MS_BIND, "mode=400,gid=0"); | 73 | return; |
84 | if (rv == 0) | ||
85 | last_disable = SUCCESSFUL; | ||
86 | } | 74 | } |
87 | if (last_disable == SUCCESSFUL) { | 75 | |
76 | EUID_ROOT(); | ||
77 | int err = bind_mount_path_to_fd(RUN_RO_DIR, fd); | ||
78 | if (err != 0) | ||
79 | err = bind_mount_path_to_fd(RUN_RO_FILE, fd); | ||
80 | EUID_USER(); | ||
81 | close(fd); | ||
82 | |||
83 | if (err == 0) { | ||
88 | if (arg_debug) | 84 | if (arg_debug) |
89 | printf("Disable %s\n", filename); | 85 | printf("Disable %s\n", filename); |
90 | if (op == BLACKLIST_FILE) | 86 | if (op == BLACKLIST_FILE) |
@@ -92,31 +88,39 @@ static void disable_file(OPERATION op, const char *filename) { | |||
92 | else | 88 | else |
93 | fs_logger2("blacklist-nolog", filename); | 89 | fs_logger2("blacklist-nolog", filename); |
94 | } | 90 | } |
95 | else { | 91 | else if (arg_debug) |
96 | if (arg_debug) | 92 | printf("Warning (blacklisting): cannot mount on %s\n", filename); |
97 | printf("Warning (blacklisting): %s is an invalid file, skipping...\n", filename); | ||
98 | } | ||
99 | 93 | ||
100 | return; | 94 | return; |
101 | } | 95 | } |
102 | 96 | ||
103 | // if the file is not present, do nothing | 97 | assert(fname); |
104 | struct stat s; | 98 | // check for firejail executable |
105 | if (fname == NULL) | 99 | // we might have a file found in ${PATH} pointing to /usr/bin/firejail |
100 | // blacklisting it here will end up breaking situations like user clicks on a link in Thunderbird | ||
101 | // and expects Firefox to open in the same sandbox | ||
102 | if (strcmp(BINDIR "/firejail", fname) == 0) { | ||
103 | free(fname); | ||
106 | return; | 104 | return; |
107 | if (stat(fname, &s) == -1) { | 105 | } |
106 | |||
107 | // if the file is not present, do nothing | ||
108 | int fd = open(fname, O_PATH|O_CLOEXEC); | ||
109 | if (fd < 0) { | ||
108 | if (arg_debug) | 110 | if (arg_debug) |
109 | fwarning("%s does not exist, skipping...\n", fname); | 111 | printf("Warning (blacklisting): cannot open %s: %s\n", fname, strerror(errno)); |
110 | free(fname); | 112 | free(fname); |
111 | return; | 113 | return; |
112 | } | 114 | } |
113 | 115 | ||
114 | // check for firejail executable | 116 | struct stat s; |
115 | // we migth have a file found in ${PATH} pointing to /usr/bin/firejail | 117 | if (fstat(fd, &s) < 0) { |
116 | // blacklisting it here will end up breaking situations like user clicks on a link in Thunderbird | 118 | if (arg_debug) |
117 | // and expects Firefox to open in the same sandbox | 119 | printf("Warning (blacklisting): cannot stat %s: %s\n", fname, strerror(errno)); |
118 | if (strcmp(BINDIR "/firejail", fname) == 0) | 120 | free(fname); |
121 | close(fd); | ||
119 | return; | 122 | return; |
123 | } | ||
120 | 124 | ||
121 | // modify the file | 125 | // modify the file |
122 | if (op == BLACKLIST_FILE || op == BLACKLIST_NOLOG) { | 126 | if (op == BLACKLIST_FILE || op == BLACKLIST_NOLOG) { |
@@ -141,44 +145,64 @@ static void disable_file(OPERATION op, const char *filename) { | |||
141 | printf(" - no logging\n"); | 145 | printf(" - no logging\n"); |
142 | } | 146 | } |
143 | 147 | ||
148 | EUID_ROOT(); | ||
144 | if (S_ISDIR(s.st_mode)) { | 149 | if (S_ISDIR(s.st_mode)) { |
145 | if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | 150 | if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0) |
146 | errExit("disable file"); | 151 | errExit("disable file"); |
147 | } | 152 | } |
148 | else { | 153 | else { |
149 | if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | 154 | if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0) |
150 | errExit("disable file"); | 155 | errExit("disable file"); |
151 | } | 156 | } |
152 | last_disable = SUCCESSFUL; | 157 | EUID_USER(); |
158 | |||
153 | if (op == BLACKLIST_FILE) | 159 | if (op == BLACKLIST_FILE) |
154 | fs_logger2("blacklist", fname); | 160 | fs_logger2("blacklist", fname); |
155 | else | 161 | else |
156 | fs_logger2("blacklist-nolog", fname); | 162 | fs_logger2("blacklist-nolog", fname); |
163 | |||
164 | // files in /etc will be reprocessed during /etc rebuild | ||
165 | if (strncmp(fname, "/etc/", 5) == 0) { | ||
166 | ProfileEntry *prf = malloc(sizeof(ProfileEntry)); | ||
167 | if (!prf) | ||
168 | errExit("malloc"); | ||
169 | memset(prf, 0, sizeof(ProfileEntry)); | ||
170 | prf->data = strdup(fname); | ||
171 | if (!prf->data) | ||
172 | errExit("strdup"); | ||
173 | prf->next = cfg.profile_rebuild_etc; | ||
174 | cfg.profile_rebuild_etc = prf; | ||
175 | } | ||
157 | } | 176 | } |
158 | } | 177 | } |
159 | else if (op == MOUNT_READONLY || op == MOUNT_RDWR || op == MOUNT_NOEXEC) { | 178 | else if (op == MOUNT_READONLY || op == MOUNT_RDWR || op == MOUNT_NOEXEC) { |
160 | fs_remount_rec(fname, op); | 179 | fs_remount_rec(fname, op); |
161 | // todo: last_disable = SUCCESSFUL; | ||
162 | } | 180 | } |
163 | else if (op == MOUNT_TMPFS) { | 181 | else if (op == MOUNT_TMPFS) { |
164 | if (S_ISDIR(s.st_mode)) { | 182 | if (!S_ISDIR(s.st_mode)) { |
165 | if (getuid()) { | 183 | fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname); |
166 | if (strncmp(cfg.homedir, fname, strlen(cfg.homedir)) != 0 || | 184 | goto out; |
167 | fname[strlen(cfg.homedir)] != '/') { | 185 | } |
168 | fprintf(stderr, "Error: tmpfs outside $HOME is only available for root\n"); | 186 | |
169 | exit(1); | 187 | uid_t uid = getuid(); |
170 | } | 188 | if (uid != 0) { |
189 | // only user owned directories in user home | ||
190 | if (s.st_uid != uid || | ||
191 | strncmp(cfg.homedir, fname, strlen(cfg.homedir)) != 0 || | ||
192 | fname[strlen(cfg.homedir)] != '/') { | ||
193 | fwarning("you are not allowed to mount a tmpfs on %s\n", fname); | ||
194 | goto out; | ||
171 | } | 195 | } |
172 | fs_tmpfs(fname, getuid()); | ||
173 | selinux_relabel_path(fname, fname); | ||
174 | last_disable = SUCCESSFUL; | ||
175 | } | 196 | } |
176 | else | 197 | |
177 | fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname); | 198 | fs_tmpfs(fname, uid); |
199 | selinux_relabel_path(fname, fname); | ||
178 | } | 200 | } |
179 | else | 201 | else |
180 | assert(0); | 202 | assert(0); |
181 | 203 | ||
204 | out: | ||
205 | close(fd); | ||
182 | free(fname); | 206 | free(fname); |
183 | } | 207 | } |
184 | 208 | ||
@@ -191,6 +215,7 @@ static int *nbcheck = NULL; | |||
191 | // Treat pattern as a shell glob pattern and blacklist matching files | 215 | // Treat pattern as a shell glob pattern and blacklist matching files |
192 | static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len) { | 216 | static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len) { |
193 | assert(pattern); | 217 | assert(pattern); |
218 | EUID_ASSERT(); | ||
194 | 219 | ||
195 | #ifdef TEST_NO_BLACKLIST_MATCHING | 220 | #ifdef TEST_NO_BLACKLIST_MATCHING |
196 | if (nbcheck_start == 0) { | 221 | if (nbcheck_start == 0) { |
@@ -253,6 +278,8 @@ static void globbing(OPERATION op, const char *pattern, const char *noblacklist[ | |||
253 | 278 | ||
254 | // blacklist files or directories by mounting empty files on top of them | 279 | // blacklist files or directories by mounting empty files on top of them |
255 | void fs_blacklist(void) { | 280 | void fs_blacklist(void) { |
281 | EUID_ASSERT(); | ||
282 | |||
256 | ProfileEntry *entry = cfg.profile; | 283 | ProfileEntry *entry = cfg.profile; |
257 | if (!entry) | 284 | if (!entry) |
258 | return; | 285 | return; |
@@ -294,11 +321,13 @@ void fs_blacklist(void) { | |||
294 | if (arg_debug) | 321 | if (arg_debug) |
295 | printf("Mount-bind %s on top of %s\n", dname1, dname2); | 322 | printf("Mount-bind %s on top of %s\n", dname1, dname2); |
296 | // preserve dname2 mode and ownership | 323 | // preserve dname2 mode and ownership |
324 | // EUID_ROOT(); - option not accessible to non-root users | ||
297 | if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0) | 325 | if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0) |
298 | errExit("mount bind"); | 326 | errExit("mount bind"); |
299 | /* coverity[toctou] */ | 327 | /* coverity[toctou] */ |
300 | if (set_perms(dname2, s.st_uid, s.st_gid,s.st_mode)) | 328 | if (set_perms(dname2, s.st_uid, s.st_gid,s.st_mode)) |
301 | errExit("set_perms"); | 329 | errExit("set_perms"); |
330 | // EUID_USER(); | ||
302 | 331 | ||
303 | entry = entry->next; | 332 | entry = entry->next; |
304 | continue; | 333 | continue; |
@@ -376,16 +405,12 @@ void fs_blacklist(void) { | |||
376 | op = MOUNT_TMPFS; | 405 | op = MOUNT_TMPFS; |
377 | } | 406 | } |
378 | else if (strncmp(entry->data, "mkdir ", 6) == 0) { | 407 | else if (strncmp(entry->data, "mkdir ", 6) == 0) { |
379 | EUID_USER(); | ||
380 | fs_mkdir(entry->data + 6); | 408 | fs_mkdir(entry->data + 6); |
381 | EUID_ROOT(); | ||
382 | entry = entry->next; | 409 | entry = entry->next; |
383 | continue; | 410 | continue; |
384 | } | 411 | } |
385 | else if (strncmp(entry->data, "mkfile ", 7) == 0) { | 412 | else if (strncmp(entry->data, "mkfile ", 7) == 0) { |
386 | EUID_USER(); | ||
387 | fs_mkfile(entry->data + 7); | 413 | fs_mkfile(entry->data + 7); |
388 | EUID_ROOT(); | ||
389 | entry = entry->next; | 414 | entry = entry->next; |
390 | continue; | 415 | continue; |
391 | } | 416 | } |
@@ -449,11 +474,12 @@ void fs_blacklist(void) { | |||
449 | 474 | ||
450 | // mount a writable tmpfs on directory; requires a resolved path | 475 | // mount a writable tmpfs on directory; requires a resolved path |
451 | void fs_tmpfs(const char *dir, unsigned check_owner) { | 476 | void fs_tmpfs(const char *dir, unsigned check_owner) { |
477 | EUID_ASSERT(); | ||
452 | assert(dir); | 478 | assert(dir); |
453 | if (arg_debug) | 479 | if (arg_debug) |
454 | printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no"); | 480 | printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no"); |
455 | // get a file descriptor for dir, fails if there is any symlink | 481 | // get a file descriptor for dir, fails if there is any symlink |
456 | int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 482 | int fd = safer_openat(-1, dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
457 | if (fd == -1) | 483 | if (fd == -1) |
458 | errExit("while opening directory"); | 484 | errExit("while opening directory"); |
459 | struct stat s; | 485 | struct stat s; |
@@ -471,13 +497,15 @@ void fs_tmpfs(const char *dir, unsigned check_owner) { | |||
471 | struct statvfs buf; | 497 | struct statvfs buf; |
472 | if (fstatvfs(fd, &buf) == -1) | 498 | if (fstatvfs(fd, &buf) == -1) |
473 | errExit("fstatvfs"); | 499 | errExit("fstatvfs"); |
474 | unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND); | 500 | unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND|MS_REMOUNT); |
475 | // mount via the symbolic link in /proc/self/fd | 501 | // mount via the symbolic link in /proc/self/fd |
476 | char *proc; | 502 | char *proc; |
477 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 503 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) |
478 | errExit("asprintf"); | 504 | errExit("asprintf"); |
505 | EUID_ROOT(); | ||
479 | if (mount("tmpfs", proc, "tmpfs", flags|MS_NOSUID|MS_NODEV, options) < 0) | 506 | if (mount("tmpfs", proc, "tmpfs", flags|MS_NOSUID|MS_NODEV, options) < 0) |
480 | errExit("mounting tmpfs"); | 507 | errExit("mounting tmpfs"); |
508 | EUID_USER(); | ||
481 | // check the last mount operation | 509 | // check the last mount operation |
482 | MountData *mdata = get_last_mount(); | 510 | MountData *mdata = get_last_mount(); |
483 | if (strcmp(mdata->fstype, "tmpfs") != 0 || strcmp(mdata->dir, dir) != 0) | 511 | if (strcmp(mdata->fstype, "tmpfs") != 0 || strcmp(mdata->dir, dir) != 0) |
@@ -490,38 +518,42 @@ void fs_tmpfs(const char *dir, unsigned check_owner) { | |||
490 | 518 | ||
491 | // remount path, preserving other mount flags; requires a resolved path | 519 | // remount path, preserving other mount flags; requires a resolved path |
492 | static void fs_remount_simple(const char *path, OPERATION op) { | 520 | static void fs_remount_simple(const char *path, OPERATION op) { |
521 | EUID_ASSERT(); | ||
493 | assert(path); | 522 | assert(path); |
494 | 523 | ||
495 | // open path without following symbolic links | 524 | // open path without following symbolic links |
496 | int fd1 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); | 525 | int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
497 | if (fd1 == -1) | 526 | if (fd < 0) |
498 | goto out; | 527 | goto out; |
499 | struct stat s1; | 528 | |
500 | if (fstat(fd1, &s1) == -1) { | 529 | struct stat s; |
530 | if (fstat(fd, &s) < 0) { | ||
501 | // fstat can fail with EACCES if path is a FUSE mount, | 531 | // fstat can fail with EACCES if path is a FUSE mount, |
502 | // mounted without 'allow_root' or 'allow_other' | 532 | // mounted without 'allow_root' or 'allow_other' |
503 | if (errno != EACCES) | 533 | if (errno != EACCES) |
504 | errExit("fstat"); | 534 | errExit("fstat"); |
505 | close(fd1); | 535 | close(fd); |
506 | goto out; | 536 | goto out; |
507 | } | 537 | } |
508 | // get mount flags | 538 | // get mount flags |
509 | struct statvfs buf; | 539 | struct statvfs buf; |
510 | if (fstatvfs(fd1, &buf) == -1) | 540 | if (fstatvfs(fd, &buf) < 0) { |
511 | errExit("fstatvfs"); | 541 | close(fd); |
542 | goto out; | ||
543 | } | ||
512 | unsigned long flags = buf.f_flag; | 544 | unsigned long flags = buf.f_flag; |
513 | 545 | ||
514 | // read-write option | 546 | // read-write option |
515 | if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) { | 547 | if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) { |
516 | // nothing to do if there is no read-only flag | 548 | // nothing to do if there is no read-only flag |
517 | if ((flags & MS_RDONLY) == 0) { | 549 | if ((flags & MS_RDONLY) == 0) { |
518 | close(fd1); | 550 | close(fd); |
519 | return; | 551 | return; |
520 | } | 552 | } |
521 | // allow only user owned directories, except the user is root | 553 | // allow only user owned directories, except the user is root |
522 | if (op != MOUNT_RDWR_NOCHECK && getuid() != 0 && s1.st_uid != getuid()) { | 554 | if (op != MOUNT_RDWR_NOCHECK && getuid() != 0 && s.st_uid != getuid()) { |
523 | fwarning("you are not allowed to change %s to read-write\n", path); | 555 | fwarning("you are not allowed to change %s to read-write\n", path); |
524 | close(fd1); | 556 | close(fd); |
525 | return; | 557 | return; |
526 | } | 558 | } |
527 | flags &= ~MS_RDONLY; | 559 | flags &= ~MS_RDONLY; |
@@ -530,7 +562,7 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
530 | else if (op == MOUNT_NOEXEC) { | 562 | else if (op == MOUNT_NOEXEC) { |
531 | // nothing to do if path is mounted noexec already | 563 | // nothing to do if path is mounted noexec already |
532 | if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) { | 564 | if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) { |
533 | close(fd1); | 565 | close(fd); |
534 | return; | 566 | return; |
535 | } | 567 | } |
536 | flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID; | 568 | flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID; |
@@ -539,7 +571,7 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
539 | else if (op == MOUNT_READONLY) { | 571 | else if (op == MOUNT_READONLY) { |
540 | // nothing to do if path is mounted read-only already | 572 | // nothing to do if path is mounted read-only already |
541 | if ((flags & MS_RDONLY) == MS_RDONLY) { | 573 | if ((flags & MS_RDONLY) == MS_RDONLY) { |
542 | close(fd1); | 574 | close(fd); |
543 | return; | 575 | return; |
544 | } | 576 | } |
545 | flags |= MS_RDONLY; | 577 | flags |= MS_RDONLY; |
@@ -549,29 +581,37 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
549 | 581 | ||
550 | if (arg_debug) | 582 | if (arg_debug) |
551 | printf("Mounting %s %s\n", opstr[op], path); | 583 | printf("Mounting %s %s\n", opstr[op], path); |
584 | |||
585 | // make path a mount point: | ||
552 | // mount --bind path path | 586 | // mount --bind path path |
553 | char *proc; | 587 | EUID_ROOT(); |
554 | if (asprintf(&proc, "/proc/self/fd/%d", fd1) == -1) | 588 | int err = bind_mount_by_fd(fd, fd); |
555 | errExit("asprintf"); | 589 | EUID_USER(); |
556 | if (mount(proc, proc, NULL, MS_BIND|MS_REC, NULL) < 0) | 590 | if (err) { |
557 | errExit("mount"); | 591 | close(fd); |
558 | free(proc); | 592 | goto out; |
593 | } | ||
559 | 594 | ||
560 | // mount --bind -o remount,ro path | 595 | // remount the mount point |
561 | // need to open path again without following symbolic links | 596 | // need to open path again |
562 | int fd2 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); | 597 | int fd2 = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
563 | if (fd2 == -1) | 598 | close(fd); // earliest timepoint to close fd |
564 | errExit("open"); | 599 | if (fd2 < 0) |
600 | goto out; | ||
601 | |||
602 | // device and inode number should be the same | ||
565 | struct stat s2; | 603 | struct stat s2; |
566 | if (fstat(fd2, &s2) == -1) | 604 | if (fstat(fd2, &s2) < 0) |
567 | errExit("fstat"); | 605 | errExit("fstat"); |
568 | // device and inode number should be the same | 606 | if (s.st_dev != s2.st_dev || s.st_ino != s2.st_ino) |
569 | if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino) | ||
570 | errLogExit("invalid %s mount", opstr[op]); | 607 | errLogExit("invalid %s mount", opstr[op]); |
571 | if (asprintf(&proc, "/proc/self/fd/%d", fd2) == -1) | 608 | |
572 | errExit("asprintf"); | 609 | EUID_ROOT(); |
573 | if (mount(NULL, proc, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0) | 610 | err = remount_by_fd(fd2, flags); |
574 | errExit("mount"); | 611 | EUID_USER(); |
612 | close(fd2); | ||
613 | if (err) | ||
614 | goto out; | ||
575 | 615 | ||
576 | // run a sanity check on /proc/self/mountinfo and confirm that target of the last | 616 | // run a sanity check on /proc/self/mountinfo and confirm that target of the last |
577 | // mount operation was path; if there are other mount points contained inside path, | 617 | // mount operation was path; if there are other mount points contained inside path, |
@@ -582,10 +622,8 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
582 | (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) | 622 | (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) |
583 | && strcmp(path, "/") != 0) // support read-only=/ | 623 | && strcmp(path, "/") != 0) // support read-only=/ |
584 | errLogExit("invalid %s mount", opstr[op]); | 624 | errLogExit("invalid %s mount", opstr[op]); |
625 | |||
585 | fs_logger2(opstr[op], path); | 626 | fs_logger2(opstr[op], path); |
586 | free(proc); | ||
587 | close(fd1); | ||
588 | close(fd2); | ||
589 | return; | 627 | return; |
590 | 628 | ||
591 | out: | 629 | out: |
@@ -593,38 +631,37 @@ out: | |||
593 | } | 631 | } |
594 | 632 | ||
595 | // remount recursively; requires a resolved path | 633 | // remount recursively; requires a resolved path |
596 | static void fs_remount_rec(const char *dir, OPERATION op) { | 634 | static void fs_remount_rec(const char *path, OPERATION op) { |
597 | assert(dir); | 635 | EUID_ASSERT(); |
598 | struct stat s; | 636 | assert(op < OPERATION_MAX); |
599 | if (stat(dir, &s) != 0) | 637 | assert(path); |
600 | return; | 638 | |
601 | if (!S_ISDIR(s.st_mode)) { | 639 | // no need to search /proc/self/mountinfo for submounts if not a directory |
602 | // no need to search in /proc/self/mountinfo for submounts if not a directory | 640 | int fd = open(path, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
603 | fs_remount_simple(dir, op); | 641 | if (fd < 0) { |
642 | fs_remount_simple(path, op); | ||
604 | return; | 643 | return; |
605 | } | 644 | } |
606 | // get mount point of the directory | 645 | |
607 | int mountid = get_mount_id(dir); | 646 | // get mount id of the directory |
608 | if (mountid == -1) | 647 | int mountid = get_mount_id(fd); |
609 | return; | 648 | close(fd); |
610 | if (mountid == -2) { | 649 | if (mountid < 0) { |
611 | // falling back to a simple remount on old kernels | 650 | // falling back to a simple remount |
612 | static int mount_warning = 0; | 651 | fwarning("%s %s not applied recursively\n", opstr[op], path); |
613 | if (!mount_warning) { | 652 | fs_remount_simple(path, op); |
614 | fwarning("read-only, read-write and noexec options are not applied recursively\n"); | ||
615 | mount_warning = 1; | ||
616 | } | ||
617 | fs_remount_simple(dir, op); | ||
618 | return; | 653 | return; |
619 | } | 654 | } |
655 | |||
620 | // build array with all mount points that need to get remounted | 656 | // build array with all mount points that need to get remounted |
621 | char **arr = build_mount_array(mountid, dir); | 657 | char **arr = build_mount_array(mountid, path); |
622 | assert(arr); | 658 | if (!arr) |
659 | return; | ||
623 | // remount | 660 | // remount |
624 | char **tmp = arr; | 661 | int i; |
625 | while (*tmp) { | 662 | for (i = 0; arr[i]; i++) { |
626 | fs_remount_simple(*tmp, op); | 663 | fs_remount_simple(arr[i], op); |
627 | free(*tmp++); | 664 | free(arr[i]); |
628 | } | 665 | } |
629 | free(arr); | 666 | free(arr); |
630 | } | 667 | } |
@@ -632,6 +669,14 @@ static void fs_remount_rec(const char *dir, OPERATION op) { | |||
632 | // resolve a path and remount it | 669 | // resolve a path and remount it |
633 | void fs_remount(const char *path, OPERATION op, int rec) { | 670 | void fs_remount(const char *path, OPERATION op, int rec) { |
634 | assert(path); | 671 | assert(path); |
672 | |||
673 | int called_as_root = 0; | ||
674 | if (geteuid() == 0) | ||
675 | called_as_root = 1; | ||
676 | |||
677 | if (called_as_root) | ||
678 | EUID_USER(); | ||
679 | |||
635 | char *rpath = realpath(path, NULL); | 680 | char *rpath = realpath(path, NULL); |
636 | if (rpath) { | 681 | if (rpath) { |
637 | if (rec) | 682 | if (rec) |
@@ -640,10 +685,14 @@ void fs_remount(const char *path, OPERATION op, int rec) { | |||
640 | fs_remount_simple(rpath, op); | 685 | fs_remount_simple(rpath, op); |
641 | free(rpath); | 686 | free(rpath); |
642 | } | 687 | } |
688 | |||
689 | if (called_as_root) | ||
690 | EUID_ROOT(); | ||
643 | } | 691 | } |
644 | 692 | ||
645 | // Disable /mnt, /media, /run/mount and /run/media access | 693 | // Disable /mnt, /media, /run/mount and /run/media access |
646 | void fs_mnt(const int enforce) { | 694 | void fs_mnt(const int enforce) { |
695 | EUID_USER(); | ||
647 | if (enforce) { | 696 | if (enforce) { |
648 | // disable-mnt set in firejail.config | 697 | // disable-mnt set in firejail.config |
649 | // overriding with noblacklist is not possible in this case | 698 | // overriding with noblacklist is not possible in this case |
@@ -653,13 +702,12 @@ void fs_mnt(const int enforce) { | |||
653 | disable_file(BLACKLIST_FILE, "/run/media"); | 702 | disable_file(BLACKLIST_FILE, "/run/media"); |
654 | } | 703 | } |
655 | else { | 704 | else { |
656 | EUID_USER(); | ||
657 | profile_add("blacklist /mnt"); | 705 | profile_add("blacklist /mnt"); |
658 | profile_add("blacklist /media"); | 706 | profile_add("blacklist /media"); |
659 | profile_add("blacklist /run/mount"); | 707 | profile_add("blacklist /run/mount"); |
660 | profile_add("blacklist /run/media"); | 708 | profile_add("blacklist /run/media"); |
661 | EUID_ROOT(); | ||
662 | } | 709 | } |
710 | EUID_ROOT(); | ||
663 | } | 711 | } |
664 | 712 | ||
665 | 713 | ||
@@ -674,7 +722,6 @@ void fs_proc_sys_dev_boot(void) { | |||
674 | errExit("mounting /proc/sys"); | 722 | errExit("mounting /proc/sys"); |
675 | fs_logger("read-only /proc/sys"); | 723 | fs_logger("read-only /proc/sys"); |
676 | 724 | ||
677 | |||
678 | /* Mount a version of /sys that describes the network namespace */ | 725 | /* Mount a version of /sys that describes the network namespace */ |
679 | if (arg_debug) | 726 | if (arg_debug) |
680 | printf("Remounting /sys directory\n"); | 727 | printf("Remounting /sys directory\n"); |
@@ -689,13 +736,13 @@ void fs_proc_sys_dev_boot(void) { | |||
689 | else | 736 | else |
690 | fs_logger("remount /sys"); | 737 | fs_logger("remount /sys"); |
691 | 738 | ||
739 | EUID_USER(); | ||
740 | |||
692 | disable_file(BLACKLIST_FILE, "/sys/firmware"); | 741 | disable_file(BLACKLIST_FILE, "/sys/firmware"); |
693 | disable_file(BLACKLIST_FILE, "/sys/hypervisor"); | 742 | disable_file(BLACKLIST_FILE, "/sys/hypervisor"); |
694 | { // allow user access to some directories in /sys/ by specifying 'noblacklist' option | 743 | { // allow user access to some directories in /sys/ by specifying 'noblacklist' option |
695 | EUID_USER(); | ||
696 | profile_add("blacklist /sys/fs"); | 744 | profile_add("blacklist /sys/fs"); |
697 | profile_add("blacklist /sys/module"); | 745 | profile_add("blacklist /sys/module"); |
698 | EUID_ROOT(); | ||
699 | } | 746 | } |
700 | disable_file(BLACKLIST_FILE, "/sys/power"); | 747 | disable_file(BLACKLIST_FILE, "/sys/power"); |
701 | disable_file(BLACKLIST_FILE, "/sys/kernel/debug"); | 748 | disable_file(BLACKLIST_FILE, "/sys/kernel/debug"); |
@@ -739,12 +786,8 @@ void fs_proc_sys_dev_boot(void) { | |||
739 | // disable /dev/port | 786 | // disable /dev/port |
740 | disable_file(BLACKLIST_FILE, "/dev/port"); | 787 | disable_file(BLACKLIST_FILE, "/dev/port"); |
741 | 788 | ||
742 | |||
743 | |||
744 | // disable various ipc sockets in /run/user | 789 | // disable various ipc sockets in /run/user |
745 | if (!arg_writable_run_user) { | 790 | if (!arg_writable_run_user) { |
746 | struct stat s; | ||
747 | |||
748 | char *fname; | 791 | char *fname; |
749 | if (asprintf(&fname, "/run/user/%d", getuid()) == -1) | 792 | if (asprintf(&fname, "/run/user/%d", getuid()) == -1) |
750 | errExit("asprintf"); | 793 | errExit("asprintf"); |
@@ -755,8 +798,7 @@ void fs_proc_sys_dev_boot(void) { | |||
755 | errExit("asprintf"); | 798 | errExit("asprintf"); |
756 | if (create_empty_dir_as_user(fnamegpg, 0700)) | 799 | if (create_empty_dir_as_user(fnamegpg, 0700)) |
757 | fs_logger2("create", fnamegpg); | 800 | fs_logger2("create", fnamegpg); |
758 | if (stat(fnamegpg, &s) == 0) | 801 | disable_file(BLACKLIST_FILE, fnamegpg); |
759 | disable_file(BLACKLIST_FILE, fnamegpg); | ||
760 | free(fnamegpg); | 802 | free(fnamegpg); |
761 | 803 | ||
762 | // disable /run/user/{uid}/systemd | 804 | // disable /run/user/{uid}/systemd |
@@ -765,8 +807,7 @@ void fs_proc_sys_dev_boot(void) { | |||
765 | errExit("asprintf"); | 807 | errExit("asprintf"); |
766 | if (create_empty_dir_as_user(fnamesysd, 0755)) | 808 | if (create_empty_dir_as_user(fnamesysd, 0755)) |
767 | fs_logger2("create", fnamesysd); | 809 | fs_logger2("create", fnamesysd); |
768 | if (stat(fnamesysd, &s) == 0) | 810 | disable_file(BLACKLIST_FILE, fnamesysd); |
769 | disable_file(BLACKLIST_FILE, fnamesysd); | ||
770 | free(fnamesysd); | 811 | free(fnamesysd); |
771 | } | 812 | } |
772 | free(fname); | 813 | free(fname); |
@@ -777,35 +818,32 @@ void fs_proc_sys_dev_boot(void) { | |||
777 | disable_file(BLACKLIST_FILE, "/dev/kmsg"); | 818 | disable_file(BLACKLIST_FILE, "/dev/kmsg"); |
778 | disable_file(BLACKLIST_FILE, "/proc/kmsg"); | 819 | disable_file(BLACKLIST_FILE, "/proc/kmsg"); |
779 | } | 820 | } |
821 | |||
822 | EUID_ROOT(); | ||
780 | } | 823 | } |
781 | 824 | ||
782 | // disable firejail configuration in ~/.config/firejail | 825 | // disable firejail configuration in ~/.config/firejail |
783 | void disable_config(void) { | 826 | void disable_config(void) { |
784 | struct stat s; | 827 | EUID_USER(); |
785 | 828 | #ifndef HAVE_ONLY_SYSCFG_PROFILES | |
786 | char *fname; | 829 | char *fname; |
787 | if (asprintf(&fname, "%s/.config/firejail", cfg.homedir) == -1) | 830 | if (asprintf(&fname, "%s/.config/firejail", cfg.homedir) == -1) |
788 | errExit("asprintf"); | 831 | errExit("asprintf"); |
789 | if (stat(fname, &s) == 0) | 832 | disable_file(BLACKLIST_FILE, fname); |
790 | disable_file(BLACKLIST_FILE, fname); | ||
791 | free(fname); | 833 | free(fname); |
834 | #endif | ||
792 | 835 | ||
793 | // disable run time information | 836 | // disable run time information |
794 | if (stat(RUN_FIREJAIL_NETWORK_DIR, &s) == 0) | 837 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NETWORK_DIR); |
795 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NETWORK_DIR); | 838 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_BANDWIDTH_DIR); |
796 | if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s) == 0) | 839 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NAME_DIR); |
797 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_BANDWIDTH_DIR); | 840 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); |
798 | if (stat(RUN_FIREJAIL_NAME_DIR, &s) == 0) | 841 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); |
799 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NAME_DIR); | 842 | EUID_ROOT(); |
800 | if (stat(RUN_FIREJAIL_PROFILE_DIR, &s) == 0) | ||
801 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); | ||
802 | if (stat(RUN_FIREJAIL_X11_DIR, &s) == 0) | ||
803 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); | ||
804 | } | 843 | } |
805 | 844 | ||
806 | 845 | ||
807 | // build a basic read-only filesystem | 846 | // build a basic read-only filesystem |
808 | // top level directories could be links, run no after-mount checks | ||
809 | void fs_basic_fs(void) { | 847 | void fs_basic_fs(void) { |
810 | uid_t uid = getuid(); | 848 | uid_t uid = getuid(); |
811 | 849 | ||
@@ -815,6 +853,7 @@ void fs_basic_fs(void) { | |||
815 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) | 853 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) |
816 | errExit("mounting /proc"); | 854 | errExit("mounting /proc"); |
817 | 855 | ||
856 | EUID_USER(); | ||
818 | if (arg_debug) | 857 | if (arg_debug) |
819 | printf("Basic read-only filesystem:\n"); | 858 | printf("Basic read-only filesystem:\n"); |
820 | if (!arg_writable_etc) { | 859 | if (!arg_writable_etc) { |
@@ -834,6 +873,7 @@ void fs_basic_fs(void) { | |||
834 | fs_remount("/lib64", MOUNT_READONLY, 1); | 873 | fs_remount("/lib64", MOUNT_READONLY, 1); |
835 | fs_remount("/lib32", MOUNT_READONLY, 1); | 874 | fs_remount("/lib32", MOUNT_READONLY, 1); |
836 | fs_remount("/libx32", MOUNT_READONLY, 1); | 875 | fs_remount("/libx32", MOUNT_READONLY, 1); |
876 | EUID_ROOT(); | ||
837 | 877 | ||
838 | // update /var directory in order to support multiple sandboxes running on the same root directory | 878 | // update /var directory in order to support multiple sandboxes running on the same root directory |
839 | fs_var_lock(); | 879 | fs_var_lock(); |
@@ -858,369 +898,9 @@ void fs_basic_fs(void) { | |||
858 | } | 898 | } |
859 | 899 | ||
860 | 900 | ||
861 | |||
862 | #ifdef HAVE_OVERLAYFS | ||
863 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | ||
864 | assert(subdirname); | ||
865 | struct stat s; | ||
866 | char *dirname; | ||
867 | |||
868 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) | ||
869 | errExit("asprintf"); | ||
870 | // check if ~/.firejail already exists | ||
871 | if (lstat(dirname, &s) == 0) { | ||
872 | if (!S_ISDIR(s.st_mode)) { | ||
873 | if (S_ISLNK(s.st_mode)) | ||
874 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); | ||
875 | else | ||
876 | fprintf(stderr, "Error: %s is not a directory\n", dirname); | ||
877 | exit(1); | ||
878 | } | ||
879 | if (s.st_uid != getuid()) { | ||
880 | fprintf(stderr, "Error: %s is not owned by the current user\n", dirname); | ||
881 | exit(1); | ||
882 | } | ||
883 | } | ||
884 | else { | ||
885 | // create ~/.firejail directory | ||
886 | create_empty_dir_as_user(dirname, 0700); | ||
887 | if (stat(dirname, &s) == -1) { | ||
888 | fprintf(stderr, "Error: cannot create directory %s\n", dirname); | ||
889 | exit(1); | ||
890 | } | ||
891 | } | ||
892 | free(dirname); | ||
893 | |||
894 | // check overlay directory | ||
895 | if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) | ||
896 | errExit("asprintf"); | ||
897 | if (lstat(dirname, &s) == 0) { | ||
898 | if (!S_ISDIR(s.st_mode)) { | ||
899 | if (S_ISLNK(s.st_mode)) | ||
900 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); | ||
901 | else | ||
902 | fprintf(stderr, "Error: %s is not a directory\n", dirname); | ||
903 | exit(1); | ||
904 | } | ||
905 | if (s.st_uid != 0) { | ||
906 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", dirname); | ||
907 | exit(1); | ||
908 | } | ||
909 | if (allow_reuse == 0) { | ||
910 | fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); | ||
911 | exit(1); | ||
912 | } | ||
913 | } | ||
914 | |||
915 | return dirname; | ||
916 | } | ||
917 | |||
918 | |||
919 | |||
920 | // mount overlayfs on top of / directory | ||
921 | // mounting an overlay and chrooting into it: | ||
922 | // | ||
923 | // Old Ubuntu kernel | ||
924 | // # cd ~ | ||
925 | // # mkdir -p overlay/root | ||
926 | // # mkdir -p overlay/diff | ||
927 | // # mount -t overlayfs -o lowerdir=/,upperdir=/root/overlay/diff overlayfs /root/overlay/root | ||
928 | // # chroot /root/overlay/root | ||
929 | // to shutdown, first exit the chroot and then unmount the overlay | ||
930 | // # exit | ||
931 | // # umount /root/overlay/root | ||
932 | // | ||
933 | // Kernels 3.18+ | ||
934 | // # cd ~ | ||
935 | // # mkdir -p overlay/root | ||
936 | // # mkdir -p overlay/diff | ||
937 | // # mkdir -p overlay/work | ||
938 | // # mount -t overlay -o lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work overlay /root/overlay/root | ||
939 | // # cat /etc/mtab | grep overlay | ||
940 | // /root/overlay /root/overlay/root overlay rw,relatime,lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work 0 0 | ||
941 | // # chroot /root/overlay/root | ||
942 | // to shutdown, first exit the chroot and then unmount the overlay | ||
943 | // # exit | ||
944 | // # umount /root/overlay/root | ||
945 | |||
946 | |||
947 | // to do: fix the code below; also, it might work without /dev, but consider keeping /dev/shm; add locking mechanism for overlay-clean | ||
948 | #include <sys/utsname.h> | ||
949 | void fs_overlayfs(void) { | ||
950 | struct stat s; | ||
951 | |||
952 | // check kernel version | ||
953 | struct utsname u; | ||
954 | int rv = uname(&u); | ||
955 | if (rv != 0) | ||
956 | errExit("uname"); | ||
957 | int major; | ||
958 | int minor; | ||
959 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
960 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
961 | exit(1); | ||
962 | } | ||
963 | |||
964 | if (arg_debug) | ||
965 | printf("Linux kernel version %d.%d\n", major, minor); | ||
966 | int oldkernel = 0; | ||
967 | if (major < 3) { | ||
968 | fprintf(stderr, "Error: minimum kernel version required 3.x\n"); | ||
969 | exit(1); | ||
970 | } | ||
971 | if (major == 3 && minor < 18) | ||
972 | oldkernel = 1; | ||
973 | |||
974 | // mounting an overlayfs on top of / seems to be broken for kernels > 4.19 | ||
975 | // we disable overlayfs for now, pending fixing | ||
976 | if (major >= 4 &&minor >= 19) { | ||
977 | fprintf(stderr, "Error: OverlayFS disabled for Linux kernels 4.19 and newer, pending fixing.\n"); | ||
978 | exit(1); | ||
979 | } | ||
980 | |||
981 | char *oroot = RUN_OVERLAY_ROOT; | ||
982 | mkdir_attr(oroot, 0755, 0, 0); | ||
983 | |||
984 | // set base for working and diff directories | ||
985 | char *basedir = RUN_MNT_DIR; | ||
986 | int basefd = -1; | ||
987 | |||
988 | if (arg_overlay_keep) { | ||
989 | basedir = cfg.overlay_dir; | ||
990 | assert(basedir); | ||
991 | // get a file descriptor for ~/.firejail, fails if there is any symlink | ||
992 | char *firejail; | ||
993 | if (asprintf(&firejail, "%s/.firejail", cfg.homedir) == -1) | ||
994 | errExit("asprintf"); | ||
995 | int fd = safe_fd(firejail, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
996 | if (fd == -1) | ||
997 | errExit("safe_fd"); | ||
998 | free(firejail); | ||
999 | // create basedir if it doesn't exist | ||
1000 | // the new directory will be owned by root | ||
1001 | const char *dirname = gnu_basename(basedir); | ||
1002 | if (mkdirat(fd, dirname, 0755) == -1 && errno != EEXIST) { | ||
1003 | perror("mkdir"); | ||
1004 | fprintf(stderr, "Error: cannot create overlay directory %s\n", basedir); | ||
1005 | exit(1); | ||
1006 | } | ||
1007 | // open basedir | ||
1008 | basefd = openat(fd, dirname, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
1009 | close(fd); | ||
1010 | } | ||
1011 | else { | ||
1012 | basefd = open(basedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
1013 | } | ||
1014 | if (basefd == -1) { | ||
1015 | perror("open"); | ||
1016 | fprintf(stderr, "Error: cannot open overlay directory %s\n", basedir); | ||
1017 | exit(1); | ||
1018 | } | ||
1019 | |||
1020 | // confirm once more base is owned by root | ||
1021 | if (fstat(basefd, &s) == -1) | ||
1022 | errExit("fstat"); | ||
1023 | if (s.st_uid != 0) { | ||
1024 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", basedir); | ||
1025 | exit(1); | ||
1026 | } | ||
1027 | // confirm permissions of base are 0755 | ||
1028 | if (((S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) & s.st_mode) != (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) { | ||
1029 | fprintf(stderr, "Error: invalid permissions on overlay directory %s\n", basedir); | ||
1030 | exit(1); | ||
1031 | } | ||
1032 | |||
1033 | // create diff and work directories inside base | ||
1034 | // no need to check arg_overlay_reuse | ||
1035 | char *odiff; | ||
1036 | if (asprintf(&odiff, "%s/odiff", basedir) == -1) | ||
1037 | errExit("asprintf"); | ||
1038 | // the new directory will be owned by root | ||
1039 | if (mkdirat(basefd, "odiff", 0755) == -1 && errno != EEXIST) { | ||
1040 | perror("mkdir"); | ||
1041 | fprintf(stderr, "Error: cannot create overlay directory %s\n", odiff); | ||
1042 | exit(1); | ||
1043 | } | ||
1044 | ASSERT_PERMS(odiff, 0, 0, 0755); | ||
1045 | |||
1046 | char *owork; | ||
1047 | if (asprintf(&owork, "%s/owork", basedir) == -1) | ||
1048 | errExit("asprintf"); | ||
1049 | // the new directory will be owned by root | ||
1050 | if (mkdirat(basefd, "owork", 0755) == -1 && errno != EEXIST) { | ||
1051 | perror("mkdir"); | ||
1052 | fprintf(stderr, "Error: cannot create overlay directory %s\n", owork); | ||
1053 | exit(1); | ||
1054 | } | ||
1055 | ASSERT_PERMS(owork, 0, 0, 0755); | ||
1056 | |||
1057 | // mount overlayfs | ||
1058 | if (arg_debug) | ||
1059 | printf("Mounting OverlayFS\n"); | ||
1060 | char *option; | ||
1061 | if (oldkernel) { // old Ubuntu/OpenSUSE kernels | ||
1062 | if (arg_overlay_keep) { | ||
1063 | fprintf(stderr, "Error: option --overlay= not available for kernels older than 3.18\n"); | ||
1064 | exit(1); | ||
1065 | } | ||
1066 | if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) | ||
1067 | errExit("asprintf"); | ||
1068 | if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) | ||
1069 | errExit("mounting overlayfs"); | ||
1070 | } | ||
1071 | else { // kernel 3.18 or newer | ||
1072 | if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) | ||
1073 | errExit("asprintf"); | ||
1074 | if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) { | ||
1075 | fprintf(stderr, "Debug: running on kernel version %d.%d\n", major, minor); | ||
1076 | errExit("mounting overlayfs"); | ||
1077 | } | ||
1078 | |||
1079 | //*************************** | ||
1080 | // issue #263 start code | ||
1081 | // My setup has a separate mount point for /home. When the overlay is mounted, | ||
1082 | // the overlay does not contain the original /home contents. | ||
1083 | // I added code to create a second overlay for /home if the overlay home dir is empty and this seems to work | ||
1084 | // @dshmgh, Jan 2016 | ||
1085 | { | ||
1086 | char *overlayhome; | ||
1087 | struct stat s; | ||
1088 | char *hroot; | ||
1089 | char *hdiff; | ||
1090 | char *hwork; | ||
1091 | |||
1092 | // dons add debug | ||
1093 | if (arg_debug) printf ("DEBUG: chroot dirs are oroot %s odiff %s owork %s\n",oroot,odiff,owork); | ||
1094 | |||
1095 | // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it? | ||
1096 | // must create var for oroot/cfg.homedir | ||
1097 | if (asprintf(&overlayhome, "%s%s", oroot, cfg.homedir) == -1) | ||
1098 | errExit("asprintf"); | ||
1099 | if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n", overlayhome); | ||
1100 | |||
1101 | // if no homedir in overlay -- create another overlay for /home | ||
1102 | if (stat(cfg.homedir, &s) == 0 && stat(overlayhome, &s) == -1) { | ||
1103 | |||
1104 | // no need to check arg_overlay_reuse | ||
1105 | if (asprintf(&hdiff, "%s/hdiff", basedir) == -1) | ||
1106 | errExit("asprintf"); | ||
1107 | // the new directory will be owned by root | ||
1108 | if (mkdirat(basefd, "hdiff", 0755) == -1 && errno != EEXIST) { | ||
1109 | perror("mkdir"); | ||
1110 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hdiff); | ||
1111 | exit(1); | ||
1112 | } | ||
1113 | ASSERT_PERMS(hdiff, 0, 0, 0755); | ||
1114 | |||
1115 | // no need to check arg_overlay_reuse | ||
1116 | if (asprintf(&hwork, "%s/hwork", basedir) == -1) | ||
1117 | errExit("asprintf"); | ||
1118 | // the new directory will be owned by root | ||
1119 | if (mkdirat(basefd, "hwork", 0755) == -1 && errno != EEXIST) { | ||
1120 | perror("mkdir"); | ||
1121 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hwork); | ||
1122 | exit(1); | ||
1123 | } | ||
1124 | ASSERT_PERMS(hwork, 0, 0, 0755); | ||
1125 | |||
1126 | // no homedir in overlay so now mount another overlay for /home | ||
1127 | if (asprintf(&hroot, "%s/home", oroot) == -1) | ||
1128 | errExit("asprintf"); | ||
1129 | if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) | ||
1130 | errExit("asprintf"); | ||
1131 | if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) | ||
1132 | errExit("mounting overlayfs for mounted home directory"); | ||
1133 | |||
1134 | printf("OverlayFS for /home configured in %s directory\n", basedir); | ||
1135 | free(hroot); | ||
1136 | free(hdiff); | ||
1137 | free(hwork); | ||
1138 | |||
1139 | } // stat(overlayhome) | ||
1140 | free(overlayhome); | ||
1141 | } | ||
1142 | // issue #263 end code | ||
1143 | //*************************** | ||
1144 | } | ||
1145 | fmessage("OverlayFS configured in %s directory\n", basedir); | ||
1146 | close(basefd); | ||
1147 | |||
1148 | // /dev, /run and /tmp are not covered by the overlay | ||
1149 | // mount-bind dev directory | ||
1150 | if (arg_debug) | ||
1151 | printf("Mounting /dev\n"); | ||
1152 | char *dev; | ||
1153 | if (asprintf(&dev, "%s/dev", oroot) == -1) | ||
1154 | errExit("asprintf"); | ||
1155 | if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1156 | errExit("mounting /dev"); | ||
1157 | fs_logger("whitelist /dev"); | ||
1158 | |||
1159 | // mount-bind run directory | ||
1160 | if (arg_debug) | ||
1161 | printf("Mounting /run\n"); | ||
1162 | char *run; | ||
1163 | if (asprintf(&run, "%s/run", oroot) == -1) | ||
1164 | errExit("asprintf"); | ||
1165 | if (mount("/run", run, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1166 | errExit("mounting /run"); | ||
1167 | fs_logger("whitelist /run"); | ||
1168 | |||
1169 | // mount-bind tmp directory | ||
1170 | if (arg_debug) | ||
1171 | printf("Mounting /tmp\n"); | ||
1172 | char *tmp; | ||
1173 | if (asprintf(&tmp, "%s/tmp", oroot) == -1) | ||
1174 | errExit("asprintf"); | ||
1175 | if (mount("/tmp", tmp, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1176 | errExit("mounting /tmp"); | ||
1177 | fs_logger("whitelist /tmp"); | ||
1178 | |||
1179 | // chroot in the new filesystem | ||
1180 | #ifdef HAVE_GCOV | ||
1181 | __gcov_flush(); | ||
1182 | #endif | ||
1183 | if (chroot(oroot) == -1) | ||
1184 | errExit("chroot"); | ||
1185 | |||
1186 | // mount a new proc filesystem | ||
1187 | if (arg_debug) | ||
1188 | printf("Mounting /proc filesystem representing the PID namespace\n"); | ||
1189 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) | ||
1190 | errExit("mounting /proc"); | ||
1191 | |||
1192 | // update /var directory in order to support multiple sandboxes running on the same root directory | ||
1193 | // if (!arg_private_dev) | ||
1194 | // fs_dev_shm(); | ||
1195 | fs_var_lock(); | ||
1196 | if (!arg_keep_var_tmp) | ||
1197 | fs_var_tmp(); | ||
1198 | if (!arg_writable_var_log) | ||
1199 | fs_var_log(); | ||
1200 | fs_var_lib(); | ||
1201 | fs_var_cache(); | ||
1202 | fs_var_utmp(); | ||
1203 | fs_machineid(); | ||
1204 | |||
1205 | // don't leak user information | ||
1206 | restrict_users(); | ||
1207 | |||
1208 | // when starting as root, firejail config is not disabled; | ||
1209 | if (getuid() != 0) | ||
1210 | disable_config(); | ||
1211 | |||
1212 | // cleanup and exit | ||
1213 | free(option); | ||
1214 | free(odiff); | ||
1215 | free(owork); | ||
1216 | free(dev); | ||
1217 | free(run); | ||
1218 | free(tmp); | ||
1219 | } | ||
1220 | #endif | ||
1221 | |||
1222 | // this function is called from sandbox.c before blacklist/whitelist functions | 901 | // this function is called from sandbox.c before blacklist/whitelist functions |
1223 | void fs_private_tmp(void) { | 902 | void fs_private_tmp(void) { |
903 | EUID_ASSERT(); | ||
1224 | if (arg_debug) | 904 | if (arg_debug) |
1225 | printf("Generate private-tmp whitelist commands\n"); | 905 | printf("Generate private-tmp whitelist commands\n"); |
1226 | 906 | ||
@@ -1241,8 +921,10 @@ void fs_private_tmp(void) { | |||
1241 | 921 | ||
1242 | // whitelist x11 directory | 922 | // whitelist x11 directory |
1243 | profile_add("whitelist /tmp/.X11-unix"); | 923 | profile_add("whitelist /tmp/.X11-unix"); |
1244 | // read-only x11 directory | 924 | profile_add("read-only /tmp/.X11-unix"); |
1245 | profile_add("read-only /tmp/.X11-unix"); | 925 | |
926 | // whitelist sndio directory | ||
927 | profile_add("whitelist /tmp/sndio"); | ||
1246 | 928 | ||
1247 | // whitelist any pulse* file in /tmp directory | 929 | // whitelist any pulse* file in /tmp directory |
1248 | // some distros use PulseAudio sockets under /tmp instead of the socket in /urn/user | 930 | // some distros use PulseAudio sockets under /tmp instead of the socket in /urn/user |
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c index 61398f12b..2b0b3003e 100644 --- a/src/firejail/fs_bin.c +++ b/src/firejail/fs_bin.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -41,9 +41,9 @@ static char *paths[] = { | |||
41 | 41 | ||
42 | // return 1 if found, 0 if not found | 42 | // return 1 if found, 0 if not found |
43 | static char *check_dir_or_file(const char *name) { | 43 | static char *check_dir_or_file(const char *name) { |
44 | EUID_ASSERT(); | ||
44 | assert(name); | 45 | assert(name); |
45 | struct stat s; | 46 | struct stat s; |
46 | char *fname = NULL; | ||
47 | 47 | ||
48 | int i = 0; | 48 | int i = 0; |
49 | while (paths[i]) { | 49 | while (paths[i]) { |
@@ -54,50 +54,34 @@ static char *check_dir_or_file(const char *name) { | |||
54 | } | 54 | } |
55 | 55 | ||
56 | // check file | 56 | // check file |
57 | char *fname; | ||
57 | if (asprintf(&fname, "%s/%s", paths[i], name) == -1) | 58 | if (asprintf(&fname, "%s/%s", paths[i], name) == -1) |
58 | errExit("asprintf"); | 59 | errExit("asprintf"); |
59 | if (arg_debug) | 60 | if (arg_debug) |
60 | printf("Checking %s/%s\n", paths[i], name); | 61 | printf("Checking %s/%s\n", paths[i], name); |
61 | if (stat(fname, &s) == 0 && !S_ISDIR(s.st_mode)) { // do not allow directories | 62 | if (stat(fname, &s) == 0 && |
62 | // check symlink to firejail executable in /usr/local/bin | 63 | !S_ISDIR(s.st_mode) && // do not allow directories |
63 | if (strcmp(paths[i], "/usr/local/bin") == 0 && is_link(fname)) { | 64 | !is_firejail_link(fname)) { // skip symlinks to firejail executable, as created by firecfg |
64 | /* coverity[toctou] */ | 65 | free(fname); |
65 | char *actual_path = realpath(fname, NULL); | ||
66 | if (actual_path) { | ||
67 | char *ptr = strstr(actual_path, "/firejail"); | ||
68 | if (ptr && strlen(ptr) == strlen("/firejail")) { | ||
69 | if (arg_debug) | ||
70 | printf("firejail exec symlink detected\n"); | ||
71 | free(actual_path); | ||
72 | free(fname); | ||
73 | fname = NULL; | ||
74 | i++; | ||
75 | continue; | ||
76 | } | ||
77 | free(actual_path); | ||
78 | } | ||
79 | |||
80 | } | ||
81 | break; // file found | 66 | break; // file found |
82 | } | 67 | } |
83 | 68 | ||
84 | free(fname); | 69 | free(fname); |
85 | fname = NULL; | ||
86 | i++; | 70 | i++; |
87 | } | 71 | } |
88 | 72 | ||
89 | if (!fname) { | 73 | if (!paths[i]) { |
90 | if (arg_debug) | 74 | if (arg_debug) |
91 | fwarning("file %s not found\n", name); | 75 | fwarning("file %s not found\n", name); |
92 | return NULL; | 76 | return NULL; |
93 | } | 77 | } |
94 | 78 | ||
95 | free(fname); | ||
96 | return paths[i]; | 79 | return paths[i]; |
97 | } | 80 | } |
98 | 81 | ||
99 | // return 1 if the file is in paths[] | 82 | // return 1 if the file is in paths[] |
100 | static int valid_full_path_file(const char *name) { | 83 | static int valid_full_path_file(const char *name) { |
84 | EUID_ASSERT(); | ||
101 | assert(name); | 85 | assert(name); |
102 | 86 | ||
103 | if (*name != '/') | 87 | if (*name != '/') |
@@ -149,6 +133,7 @@ static void report_duplication(const char *fname) { | |||
149 | } | 133 | } |
150 | 134 | ||
151 | static void duplicate(char *fname) { | 135 | static void duplicate(char *fname) { |
136 | EUID_ASSERT(); | ||
152 | assert(fname); | 137 | assert(fname); |
153 | 138 | ||
154 | if (*fname == '~' || strstr(fname, "..")) { | 139 | if (*fname == '~' || strstr(fname, "..")) { |
@@ -220,6 +205,7 @@ static void duplicate(char *fname) { | |||
220 | } | 205 | } |
221 | 206 | ||
222 | static void globbing(char *fname) { | 207 | static void globbing(char *fname) { |
208 | EUID_ASSERT(); | ||
223 | assert(fname); | 209 | assert(fname); |
224 | 210 | ||
225 | // go directly to duplicate() if no globbing char is present - see man 7 glob | 211 | // go directly to duplicate() if no globbing char is present - see man 7 glob |
@@ -256,6 +242,9 @@ static void globbing(char *fname) { | |||
256 | // testing for GLOB_NOCHECK - no pattern matched returns the original pattern | 242 | // testing for GLOB_NOCHECK - no pattern matched returns the original pattern |
257 | if (strcmp(globbuf.gl_pathv[j], pattern) == 0) | 243 | if (strcmp(globbuf.gl_pathv[j], pattern) == 0) |
258 | continue; | 244 | continue; |
245 | // skip symlinks to firejail executable, as created by firecfg | ||
246 | if (is_firejail_link(globbuf.gl_pathv[j])) | ||
247 | continue; | ||
259 | 248 | ||
260 | duplicate(globbuf.gl_pathv[j]); | 249 | duplicate(globbuf.gl_pathv[j]); |
261 | } | 250 | } |
@@ -267,6 +256,7 @@ static void globbing(char *fname) { | |||
267 | } | 256 | } |
268 | 257 | ||
269 | void fs_private_bin_list(void) { | 258 | void fs_private_bin_list(void) { |
259 | EUID_ASSERT(); | ||
270 | char *private_list = cfg.bin_private_keep; | 260 | char *private_list = cfg.bin_private_keep; |
271 | assert(private_list); | 261 | assert(private_list); |
272 | 262 | ||
@@ -274,7 +264,9 @@ void fs_private_bin_list(void) { | |||
274 | timetrace_start(); | 264 | timetrace_start(); |
275 | 265 | ||
276 | // create /run/firejail/mnt/bin directory | 266 | // create /run/firejail/mnt/bin directory |
267 | EUID_ROOT(); | ||
277 | mkdir_attr(RUN_BIN_DIR, 0755, 0, 0); | 268 | mkdir_attr(RUN_BIN_DIR, 0755, 0, 0); |
269 | EUID_USER(); | ||
278 | 270 | ||
279 | if (arg_debug) | 271 | if (arg_debug) |
280 | printf("Copying files in the new bin directory\n"); | 272 | printf("Copying files in the new bin directory\n"); |
@@ -293,9 +285,9 @@ void fs_private_bin_list(void) { | |||
293 | while ((ptr = strtok(NULL, ",")) != NULL) | 285 | while ((ptr = strtok(NULL, ",")) != NULL) |
294 | globbing(ptr); | 286 | globbing(ptr); |
295 | free(dlist); | 287 | free(dlist); |
296 | fs_logger_print(); | ||
297 | 288 | ||
298 | // mount-bind | 289 | // mount-bind |
290 | EUID_ROOT(); | ||
299 | int i = 0; | 291 | int i = 0; |
300 | while (paths[i]) { | 292 | while (paths[i]) { |
301 | struct stat s; | 293 | struct stat s; |
@@ -309,6 +301,9 @@ void fs_private_bin_list(void) { | |||
309 | } | 301 | } |
310 | i++; | 302 | i++; |
311 | } | 303 | } |
304 | fs_logger_print(); | ||
305 | EUID_USER(); | ||
306 | |||
312 | selinux_relabel_path(RUN_BIN_DIR, "/bin"); | 307 | selinux_relabel_path(RUN_BIN_DIR, "/bin"); |
313 | fmessage("%d %s installed in %0.2f ms\n", prog_cnt, (prog_cnt == 1)? "program": "programs", timetrace_end()); | 308 | fmessage("%d %s installed in %0.2f ms\n", prog_cnt, (prog_cnt == 1)? "program": "programs", timetrace_end()); |
314 | } | 309 | } |
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c index 2f0067c93..a6fbbb89a 100644 --- a/src/firejail/fs_dev.c +++ b/src/firejail/fs_dev.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,7 +20,6 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <glob.h> | 23 | #include <glob.h> |
25 | #include <dirent.h> | 24 | #include <dirent.h> |
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
@@ -122,7 +121,7 @@ static void deventry_mount(void) { | |||
122 | i++; | 121 | i++; |
123 | continue; | 122 | continue; |
124 | } | 123 | } |
125 | FILE *fp = fopen(dev[i].dev_fname, "w"); | 124 | FILE *fp = fopen(dev[i].dev_fname, "we"); |
126 | if (fp) { | 125 | if (fp) { |
127 | fprintf(fp, "\n"); | 126 | fprintf(fp, "\n"); |
128 | SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode); | 127 | SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode); |
@@ -187,8 +186,10 @@ static void mount_dev_shm(void) { | |||
187 | static void process_dev_shm(void) { | 186 | static void process_dev_shm(void) { |
188 | // Jack audio keeps an Unix socket under (/dev/shm/jack_default_1000_0 or /dev/shm/jack/...) | 187 | // Jack audio keeps an Unix socket under (/dev/shm/jack_default_1000_0 or /dev/shm/jack/...) |
189 | // looking for jack socket | 188 | // looking for jack socket |
189 | EUID_USER(); | ||
190 | glob_t globbuf; | 190 | glob_t globbuf; |
191 | int globerr = glob(RUN_DEV_DIR "/shm/jack*", GLOB_NOSORT, NULL, &globbuf); | 191 | int globerr = glob(RUN_DEV_DIR "/shm/jack*", GLOB_NOSORT, NULL, &globbuf); |
192 | EUID_ROOT(); | ||
192 | if (globerr && !arg_keep_dev_shm) { | 193 | if (globerr && !arg_keep_dev_shm) { |
193 | empty_dev_shm(); | 194 | empty_dev_shm(); |
194 | return; | 195 | return; |
@@ -218,7 +219,7 @@ void fs_private_dev(void){ | |||
218 | struct stat s; | 219 | struct stat s; |
219 | if (stat("/dev/log", &s) == 0) { | 220 | if (stat("/dev/log", &s) == 0) { |
220 | have_devlog = 1; | 221 | have_devlog = 1; |
221 | FILE *fp = fopen(RUN_DEVLOG_FILE, "w"); | 222 | FILE *fp = fopen(RUN_DEVLOG_FILE, "we"); |
222 | if (!fp) | 223 | if (!fp) |
223 | have_devlog = 0; | 224 | have_devlog = 0; |
224 | else { | 225 | else { |
@@ -239,7 +240,7 @@ void fs_private_dev(void){ | |||
239 | 240 | ||
240 | // bring back /dev/log | 241 | // bring back /dev/log |
241 | if (have_devlog) { | 242 | if (have_devlog) { |
242 | FILE *fp = fopen("/dev/log", "w"); | 243 | FILE *fp = fopen("/dev/log", "we"); |
243 | if (fp) { | 244 | if (fp) { |
244 | fprintf(fp, "\n"); | 245 | fprintf(fp, "\n"); |
245 | fclose(fp); | 246 | fclose(fp); |
@@ -328,8 +329,10 @@ void fs_dev_disable_sound(void) { | |||
328 | } | 329 | } |
329 | 330 | ||
330 | // disable all jack sockets in /dev/shm | 331 | // disable all jack sockets in /dev/shm |
332 | EUID_USER(); | ||
331 | glob_t globbuf; | 333 | glob_t globbuf; |
332 | int globerr = glob("/dev/shm/jack*", GLOB_NOSORT, NULL, &globbuf); | 334 | int globerr = glob("/dev/shm/jack*", GLOB_NOSORT, NULL, &globbuf); |
335 | EUID_ROOT(); | ||
333 | if (globerr) | 336 | if (globerr) |
334 | return; | 337 | return; |
335 | 338 | ||
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c index 8cb25a1ff..deaee31bb 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -24,6 +24,7 @@ | |||
24 | #include <sys/types.h> | 24 | #include <sys/types.h> |
25 | #include <time.h> | 25 | #include <time.h> |
26 | #include <unistd.h> | 26 | #include <unistd.h> |
27 | #include <dirent.h> | ||
27 | 28 | ||
28 | // spoof /etc/machine_id | 29 | // spoof /etc/machine_id |
29 | void fs_machineid(void) { | 30 | void fs_machineid(void) { |
@@ -52,7 +53,7 @@ void fs_machineid(void) { | |||
52 | mid.u8[8] = (mid.u8[8] & 0x3F) | 0x80; | 53 | mid.u8[8] = (mid.u8[8] & 0x3F) | 0x80; |
53 | 54 | ||
54 | // write it in a file | 55 | // write it in a file |
55 | FILE *fp = fopen(RUN_MACHINEID, "w"); | 56 | FILE *fp = fopen(RUN_MACHINEID, "we"); |
56 | if (!fp) | 57 | if (!fp) |
57 | errExit("fopen"); | 58 | errExit("fopen"); |
58 | fprintf(fp, "%08x%08x%08x%08x\n", mid.u32[0], mid.u32[1], mid.u32[2], mid.u32[3]); | 59 | fprintf(fp, "%08x%08x%08x%08x\n", mid.u32[0], mid.u32[1], mid.u32[2], mid.u32[3]); |
@@ -141,7 +142,7 @@ errexit: | |||
141 | static void duplicate(const char *fname, const char *private_dir, const char *private_run_dir) { | 142 | static void duplicate(const char *fname, const char *private_dir, const char *private_run_dir) { |
142 | assert(fname); | 143 | assert(fname); |
143 | 144 | ||
144 | if (*fname == '~' || *fname == '/' || strncmp(fname, "..", 2) == 0) { | 145 | if (*fname == '~' || *fname == '/' || strstr(fname, "..")) { |
145 | fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname); | 146 | fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname); |
146 | exit(1); | 147 | exit(1); |
147 | } | 148 | } |
@@ -164,7 +165,14 @@ static void duplicate(const char *fname, const char *private_dir, const char *pr | |||
164 | errExit("asprintf"); | 165 | errExit("asprintf"); |
165 | 166 | ||
166 | build_dirs(src, dst, strlen(private_dir), strlen(private_run_dir)); | 167 | build_dirs(src, dst, strlen(private_dir), strlen(private_run_dir)); |
167 | sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, PATH_FCOPY, src, dst); | 168 | |
169 | // follow links! this will make a copy of the file or directory pointed by the symlink | ||
170 | // this will solve problems such as NixOS #4887 | ||
171 | // don't follow links to dynamic directories such as /proc | ||
172 | if (strcmp(src, "/etc/mtab") == 0) | ||
173 | sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, PATH_FCOPY, src, dst); | ||
174 | else | ||
175 | sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", src, dst); | ||
168 | 176 | ||
169 | free(dst); | 177 | free(dst); |
170 | fs_logger2("clone", src); | 178 | fs_logger2("clone", src); |
@@ -250,3 +258,128 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c | |||
250 | fs_private_dir_mount(private_dir, private_run_dir); | 258 | fs_private_dir_mount(private_dir, private_run_dir); |
251 | fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end()); | 259 | fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end()); |
252 | } | 260 | } |
261 | |||
262 | void fs_rebuild_etc(void) { | ||
263 | int have_dhcp = 1; | ||
264 | if (cfg.dns1 == NULL && !any_dhcp()) | ||
265 | have_dhcp = 0; | ||
266 | |||
267 | if (arg_debug) | ||
268 | printf("rebuilding /etc directory\n"); | ||
269 | if (mkdir(RUN_DNS_ETC, 0755)) | ||
270 | errExit("mkdir"); | ||
271 | selinux_relabel_path(RUN_DNS_ETC, "/etc"); | ||
272 | fs_logger("tmpfs /etc"); | ||
273 | |||
274 | DIR *dir = opendir("/etc"); | ||
275 | if (!dir) | ||
276 | errExit("opendir"); | ||
277 | |||
278 | struct stat s; | ||
279 | struct dirent *entry; | ||
280 | while ((entry = readdir(dir))) { | ||
281 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||
282 | continue; | ||
283 | |||
284 | // skip files in cfg.profile_rebuild_etc list | ||
285 | // these files are already blacklisted | ||
286 | { | ||
287 | ProfileEntry *prf = cfg.profile_rebuild_etc; | ||
288 | int found = 0; | ||
289 | while (prf) { | ||
290 | if (strcmp(entry->d_name, prf->data + 5) == 0) { // 5 is strlen("/etc/") | ||
291 | found = 1; | ||
292 | break; | ||
293 | } | ||
294 | prf = prf->next; | ||
295 | } | ||
296 | if (found) | ||
297 | continue; | ||
298 | } | ||
299 | |||
300 | // for resolv.conf we might have to create a brand new file later | ||
301 | if (have_dhcp && | ||
302 | (strcmp(entry->d_name, "resolv.conf") == 0 || | ||
303 | strcmp(entry->d_name, "resolv.conf.dhclient-new") == 0)) | ||
304 | continue; | ||
305 | // printf("linking %s\n", entry->d_name); | ||
306 | |||
307 | char *src; | ||
308 | if (asprintf(&src, "/etc/%s", entry->d_name) == -1) | ||
309 | errExit("asprintf"); | ||
310 | if (stat(src, &s) != 0) { | ||
311 | free(src); | ||
312 | continue; | ||
313 | } | ||
314 | |||
315 | char *dest; | ||
316 | if (asprintf(&dest, "%s/%s", RUN_DNS_ETC, entry->d_name) == -1) | ||
317 | errExit("asprintf"); | ||
318 | |||
319 | int symlink_done = 0; | ||
320 | if (is_link(src)) { | ||
321 | char *rp =realpath(src, NULL); | ||
322 | if (rp == NULL) { | ||
323 | free(src); | ||
324 | free(dest); | ||
325 | continue; | ||
326 | } | ||
327 | if (symlink(rp, dest)) | ||
328 | errExit("symlink"); | ||
329 | else | ||
330 | symlink_done = 1; | ||
331 | } | ||
332 | else if (S_ISDIR(s.st_mode)) | ||
333 | create_empty_dir_as_root(dest, s.st_mode); | ||
334 | else | ||
335 | create_empty_file_as_root(dest, s.st_mode); | ||
336 | |||
337 | // bind-mount src on top of dest | ||
338 | if (!symlink_done) { | ||
339 | if (mount(src, dest, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
340 | errExit("mount bind mirroring /etc"); | ||
341 | } | ||
342 | fs_logger2("clone", src); | ||
343 | |||
344 | free(src); | ||
345 | free(dest); | ||
346 | } | ||
347 | closedir(dir); | ||
348 | |||
349 | // mount bind our private etc directory on top of /etc | ||
350 | if (arg_debug) | ||
351 | printf("Mount-bind %s on top of /etc\n", RUN_DNS_ETC); | ||
352 | if (mount(RUN_DNS_ETC, "/etc", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
353 | errExit("mount bind mirroring /etc"); | ||
354 | fs_logger("mount /etc"); | ||
355 | |||
356 | if (have_dhcp == 0) | ||
357 | return; | ||
358 | |||
359 | if (arg_debug) | ||
360 | printf("Creating a new /etc/resolv.conf file\n"); | ||
361 | FILE *fp = fopen("/etc/resolv.conf", "wxe"); | ||
362 | if (!fp) { | ||
363 | fprintf(stderr, "Error: cannot create /etc/resolv.conf file\n"); | ||
364 | exit(1); | ||
365 | } | ||
366 | |||
367 | if (cfg.dns1) { | ||
368 | if (any_dhcp()) | ||
369 | fwarning("network setup uses DHCP, nameservers will likely be overwritten\n"); | ||
370 | fprintf(fp, "nameserver %s\n", cfg.dns1); | ||
371 | } | ||
372 | if (cfg.dns2) | ||
373 | fprintf(fp, "nameserver %s\n", cfg.dns2); | ||
374 | if (cfg.dns3) | ||
375 | fprintf(fp, "nameserver %s\n", cfg.dns3); | ||
376 | if (cfg.dns4) | ||
377 | fprintf(fp, "nameserver %s\n", cfg.dns4); | ||
378 | |||
379 | // mode and owner | ||
380 | SET_PERMS_STREAM(fp, 0, 0, 0644); | ||
381 | |||
382 | fclose(fp); | ||
383 | |||
384 | fs_logger("create /etc/resolv.conf"); | ||
385 | } | ||
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 46f32d7ad..061461590 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -19,7 +19,6 @@ | |||
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <linux/limits.h> | ||
23 | #include <dirent.h> | 22 | #include <dirent.h> |
24 | #include <errno.h> | 23 | #include <errno.h> |
25 | #include <sys/stat.h> | 24 | #include <sys/stat.h> |
@@ -34,24 +33,48 @@ | |||
34 | #define O_PATH 010000000 | 33 | #define O_PATH 010000000 |
35 | #endif | 34 | #endif |
36 | 35 | ||
37 | static void skel(const char *homedir, uid_t u, gid_t g) { | 36 | static void disable_tab_completion(const char *homedir) { |
37 | if (arg_tab) | ||
38 | return; | ||
39 | |||
38 | char *fname; | 40 | char *fname; |
41 | if (asprintf(&fname, "%s/.inputrc", homedir) == -1) | ||
42 | errExit("asprintf"); | ||
43 | |||
44 | // don't create a new one if we already have it | ||
45 | if (access(fname, F_OK)) { | ||
46 | FILE *fp = fopen(fname, "w"); | ||
47 | if (!fp) | ||
48 | errExit("fopen"); | ||
49 | fprintf(fp, "set disable-completion on\n"); | ||
50 | fclose(fp); | ||
51 | if (chmod(fname, 0644)) | ||
52 | errExit("chmod"); | ||
53 | } | ||
54 | free(fname); | ||
55 | } | ||
56 | |||
57 | |||
58 | static void skel(const char *homedir) { | ||
59 | EUID_ASSERT(); | ||
60 | char *fname; | ||
61 | |||
62 | disable_tab_completion(homedir); | ||
39 | 63 | ||
40 | // zsh | 64 | // zsh |
41 | if (!arg_shell_none && (strcmp(cfg.shell,"/usr/bin/zsh") == 0 || strcmp(cfg.shell,"/bin/zsh") == 0)) { | 65 | if (!arg_shell_none && (strcmp(cfg.shell,"/usr/bin/zsh") == 0 || strcmp(cfg.shell,"/bin/zsh") == 0)) { |
42 | // copy skel files | 66 | // copy skel files |
43 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) | 67 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) |
44 | errExit("asprintf"); | 68 | errExit("asprintf"); |
45 | struct stat s; | ||
46 | // don't copy it if we already have the file | 69 | // don't copy it if we already have the file |
47 | if (stat(fname, &s) == 0) | 70 | if (access(fname, F_OK) == 0) |
48 | return; | 71 | return; |
49 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 72 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
50 | fprintf(stderr, "Error: invalid %s file\n", fname); | 73 | fprintf(stderr, "Error: invalid %s file\n", fname); |
51 | exit(1); | 74 | exit(1); |
52 | } | 75 | } |
53 | if (stat("/etc/skel/.zshrc", &s) == 0) { | 76 | if (access("/etc/skel/.zshrc", R_OK) == 0) { |
54 | copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user | 77 | copy_file_as_user("/etc/skel/.zshrc", fname, 0644); // regular user |
55 | fs_logger("clone /etc/skel/.zshrc"); | 78 | fs_logger("clone /etc/skel/.zshrc"); |
56 | fs_logger2("clone", fname); | 79 | fs_logger2("clone", fname); |
57 | } | 80 | } |
@@ -67,17 +90,15 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
67 | // copy skel files | 90 | // copy skel files |
68 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) | 91 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) |
69 | errExit("asprintf"); | 92 | errExit("asprintf"); |
70 | struct stat s; | ||
71 | |||
72 | // don't copy it if we already have the file | 93 | // don't copy it if we already have the file |
73 | if (stat(fname, &s) == 0) | 94 | if (access(fname, F_OK) == 0) |
74 | return; | 95 | return; |
75 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 96 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
76 | fprintf(stderr, "Error: invalid %s file\n", fname); | 97 | fprintf(stderr, "Error: invalid %s file\n", fname); |
77 | exit(1); | 98 | exit(1); |
78 | } | 99 | } |
79 | if (stat("/etc/skel/.cshrc", &s) == 0) { | 100 | if (access("/etc/skel/.cshrc", R_OK) == 0) { |
80 | copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user | 101 | copy_file_as_user("/etc/skel/.cshrc", fname, 0644); // regular user |
81 | fs_logger("clone /etc/skel/.cshrc"); | 102 | fs_logger("clone /etc/skel/.cshrc"); |
82 | fs_logger2("clone", fname); | 103 | fs_logger2("clone", fname); |
83 | } | 104 | } |
@@ -93,16 +114,15 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
93 | // copy skel files | 114 | // copy skel files |
94 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) | 115 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) |
95 | errExit("asprintf"); | 116 | errExit("asprintf"); |
96 | struct stat s; | ||
97 | // don't copy it if we already have the file | 117 | // don't copy it if we already have the file |
98 | if (stat(fname, &s) == 0) | 118 | if (access(fname, F_OK) == 0) |
99 | return; | 119 | return; |
100 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 120 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
101 | fprintf(stderr, "Error: invalid %s file\n", fname); | 121 | fprintf(stderr, "Error: invalid %s file\n", fname); |
102 | exit(1); | 122 | exit(1); |
103 | } | 123 | } |
104 | if (stat("/etc/skel/.bashrc", &s) == 0) { | 124 | if (access("/etc/skel/.bashrc", R_OK) == 0) { |
105 | copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user | 125 | copy_file_as_user("/etc/skel/.bashrc", fname, 0644); // regular user |
106 | fs_logger("clone /etc/skel/.bashrc"); | 126 | fs_logger("clone /etc/skel/.bashrc"); |
107 | fs_logger2("clone", fname); | 127 | fs_logger2("clone", fname); |
108 | } | 128 | } |
@@ -112,6 +132,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
112 | } | 132 | } |
113 | 133 | ||
114 | static int store_xauthority(void) { | 134 | static int store_xauthority(void) { |
135 | EUID_ASSERT(); | ||
115 | if (arg_x11_block) | 136 | if (arg_x11_block) |
116 | return 0; | 137 | return 0; |
117 | 138 | ||
@@ -122,15 +143,16 @@ static int store_xauthority(void) { | |||
122 | errExit("asprintf"); | 143 | errExit("asprintf"); |
123 | 144 | ||
124 | struct stat s; | 145 | struct stat s; |
125 | if (stat(src, &s) == 0) { | 146 | if (lstat(src, &s) == 0) { |
126 | if (is_link(src)) { | 147 | if (S_ISLNK(s.st_mode)) { |
127 | fwarning("invalid .Xauthority file\n"); | 148 | fwarning("invalid .Xauthority file\n"); |
128 | free(src); | 149 | free(src); |
129 | return 0; | 150 | return 0; |
130 | } | 151 | } |
131 | 152 | ||
132 | // create an empty file as root, and change ownership to user | 153 | // create an empty file as root, and change ownership to user |
133 | FILE *fp = fopen(dest, "w"); | 154 | EUID_ROOT(); |
155 | FILE *fp = fopen(dest, "we"); | ||
134 | if (fp) { | 156 | if (fp) { |
135 | fprintf(fp, "\n"); | 157 | fprintf(fp, "\n"); |
136 | SET_PERMS_STREAM(fp, getuid(), getgid(), 0600); | 158 | SET_PERMS_STREAM(fp, getuid(), getgid(), 0600); |
@@ -138,10 +160,11 @@ static int store_xauthority(void) { | |||
138 | } | 160 | } |
139 | else | 161 | else |
140 | errExit("fopen"); | 162 | errExit("fopen"); |
163 | EUID_USER(); | ||
141 | 164 | ||
142 | copy_file_as_user(src, dest, getuid(), getgid(), 0600); // regular user | 165 | copy_file_as_user(src, dest, 0600); // regular user |
143 | fs_logger2("clone", dest); | ||
144 | selinux_relabel_path(dest, src); | 166 | selinux_relabel_path(dest, src); |
167 | fs_logger2("clone", dest); | ||
145 | free(src); | 168 | free(src); |
146 | return 1; // file copied | 169 | return 1; // file copied |
147 | } | 170 | } |
@@ -151,6 +174,7 @@ static int store_xauthority(void) { | |||
151 | } | 174 | } |
152 | 175 | ||
153 | static int store_asoundrc(void) { | 176 | static int store_asoundrc(void) { |
177 | EUID_ASSERT(); | ||
154 | if (arg_nosound) | 178 | if (arg_nosound) |
155 | return 0; | 179 | return 0; |
156 | 180 | ||
@@ -161,11 +185,11 @@ static int store_asoundrc(void) { | |||
161 | errExit("asprintf"); | 185 | errExit("asprintf"); |
162 | 186 | ||
163 | struct stat s; | 187 | struct stat s; |
164 | if (stat(src, &s) == 0) { | 188 | if (lstat(src, &s) == 0) { |
165 | if (is_link(src)) { | 189 | if (S_ISLNK(s.st_mode)) { |
166 | // make sure the real path of the file is inside the home directory | 190 | // make sure the real path of the file is inside the home directory |
167 | /* coverity[toctou] */ | 191 | /* coverity[toctou] */ |
168 | char* rp = realpath(src, NULL); | 192 | char *rp = realpath(src, NULL); |
169 | if (!rp) { | 193 | if (!rp) { |
170 | fprintf(stderr, "Error: Cannot access %s\n", src); | 194 | fprintf(stderr, "Error: Cannot access %s\n", src); |
171 | exit(1); | 195 | exit(1); |
@@ -178,7 +202,8 @@ static int store_asoundrc(void) { | |||
178 | } | 202 | } |
179 | 203 | ||
180 | // create an empty file as root, and change ownership to user | 204 | // create an empty file as root, and change ownership to user |
181 | FILE *fp = fopen(dest, "w"); | 205 | EUID_ROOT(); |
206 | FILE *fp = fopen(dest, "we"); | ||
182 | if (fp) { | 207 | if (fp) { |
183 | fprintf(fp, "\n"); | 208 | fprintf(fp, "\n"); |
184 | SET_PERMS_STREAM(fp, getuid(), getgid(), 0644); | 209 | SET_PERMS_STREAM(fp, getuid(), getgid(), 0644); |
@@ -186,10 +211,11 @@ static int store_asoundrc(void) { | |||
186 | } | 211 | } |
187 | else | 212 | else |
188 | errExit("fopen"); | 213 | errExit("fopen"); |
214 | EUID_USER(); | ||
189 | 215 | ||
190 | copy_file_as_user(src, dest, getuid(), getgid(), 0644); // regular user | 216 | copy_file_as_user(src, dest, 0644); // regular user |
191 | selinux_relabel_path(dest, src); | ||
192 | fs_logger2("clone", dest); | 217 | fs_logger2("clone", dest); |
218 | selinux_relabel_path(dest, src); | ||
193 | free(src); | 219 | free(src); |
194 | return 1; // file copied | 220 | return 1; // file copied |
195 | } | 221 | } |
@@ -199,6 +225,7 @@ static int store_asoundrc(void) { | |||
199 | } | 225 | } |
200 | 226 | ||
201 | static void copy_xauthority(void) { | 227 | static void copy_xauthority(void) { |
228 | EUID_ASSERT(); | ||
202 | // copy XAUTHORITY_FILE in the new home directory | 229 | // copy XAUTHORITY_FILE in the new home directory |
203 | char *src = RUN_XAUTHORITY_FILE ; | 230 | char *src = RUN_XAUTHORITY_FILE ; |
204 | char *dest; | 231 | char *dest; |
@@ -211,16 +238,18 @@ static void copy_xauthority(void) { | |||
211 | exit(1); | 238 | exit(1); |
212 | } | 239 | } |
213 | 240 | ||
214 | copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user | 241 | copy_file_as_user(src, dest, S_IRUSR | S_IWUSR); // regular user |
215 | selinux_relabel_path(dest, src); | ||
216 | fs_logger2("clone", dest); | 242 | fs_logger2("clone", dest); |
243 | selinux_relabel_path(dest, dest); | ||
217 | free(dest); | 244 | free(dest); |
218 | 245 | ||
219 | // delete the temporary file | 246 | EUID_ROOT(); |
220 | unlink(src); | 247 | unlink(src); // delete the temporary file |
248 | EUID_USER(); | ||
221 | } | 249 | } |
222 | 250 | ||
223 | static void copy_asoundrc(void) { | 251 | static void copy_asoundrc(void) { |
252 | EUID_ASSERT(); | ||
224 | // copy ASOUNDRC_FILE in the new home directory | 253 | // copy ASOUNDRC_FILE in the new home directory |
225 | char *src = RUN_ASOUNDRC_FILE ; | 254 | char *src = RUN_ASOUNDRC_FILE ; |
226 | char *dest; | 255 | char *dest; |
@@ -233,12 +262,14 @@ static void copy_asoundrc(void) { | |||
233 | exit(1); | 262 | exit(1); |
234 | } | 263 | } |
235 | 264 | ||
236 | copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user | 265 | copy_file_as_user(src, dest, S_IRUSR | S_IWUSR); // regular user |
237 | fs_logger2("clone", dest); | 266 | fs_logger2("clone", dest); |
267 | selinux_relabel_path(dest, dest); | ||
238 | free(dest); | 268 | free(dest); |
239 | 269 | ||
240 | // delete the temporary file | 270 | EUID_ROOT(); |
241 | unlink(src); | 271 | unlink(src); // delete the temporary file |
272 | EUID_USER(); | ||
242 | } | 273 | } |
243 | 274 | ||
244 | // private mode (--private=homedir): | 275 | // private mode (--private=homedir): |
@@ -251,21 +282,22 @@ void fs_private_homedir(void) { | |||
251 | char *private_homedir = cfg.home_private; | 282 | char *private_homedir = cfg.home_private; |
252 | assert(homedir); | 283 | assert(homedir); |
253 | assert(private_homedir); | 284 | assert(private_homedir); |
285 | EUID_ASSERT(); | ||
286 | |||
287 | uid_t u = getuid(); | ||
288 | // gid_t g = getgid(); | ||
254 | 289 | ||
255 | int xflag = store_xauthority(); | 290 | int xflag = store_xauthority(); |
256 | int aflag = store_asoundrc(); | 291 | int aflag = store_asoundrc(); |
257 | 292 | ||
258 | uid_t u = getuid(); | ||
259 | gid_t g = getgid(); | ||
260 | |||
261 | // mount bind private_homedir on top of homedir | 293 | // mount bind private_homedir on top of homedir |
262 | if (arg_debug) | 294 | if (arg_debug) |
263 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); | 295 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); |
264 | // get file descriptors for homedir and private_homedir, fails if there is any symlink | 296 | // get file descriptors for homedir and private_homedir, fails if there is any symlink |
265 | int src = safe_fd(private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 297 | int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
266 | if (src == -1) | 298 | if (src == -1) |
267 | errExit("opening private directory"); | 299 | errExit("opening private directory"); |
268 | int dst = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 300 | int dst = safer_openat(-1, homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
269 | if (dst == -1) | 301 | if (dst == -1) |
270 | errExit("opening home directory"); | 302 | errExit("opening home directory"); |
271 | // both mount source and target should be owned by the user | 303 | // both mount source and target should be owned by the user |
@@ -286,17 +318,11 @@ void fs_private_homedir(void) { | |||
286 | exit(1); | 318 | exit(1); |
287 | } | 319 | } |
288 | // mount via the links in /proc/self/fd | 320 | // mount via the links in /proc/self/fd |
289 | char *proc_src, *proc_dst; | 321 | EUID_ROOT(); |
290 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) | 322 | if (bind_mount_by_fd(src, dst)) |
291 | errExit("asprintf"); | ||
292 | if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1) | ||
293 | errExit("asprintf"); | ||
294 | if (mount(proc_src, proc_dst, NULL, MS_NOSUID | MS_NODEV | MS_BIND | MS_REC, NULL) < 0) | ||
295 | errExit("mount bind"); | 323 | errExit("mount bind"); |
296 | free(proc_src); | 324 | EUID_USER(); |
297 | free(proc_dst); | 325 | |
298 | close(src); | ||
299 | close(dst); | ||
300 | // check /proc/self/mountinfo to confirm the mount is ok | 326 | // check /proc/self/mountinfo to confirm the mount is ok |
301 | MountData *mptr = get_last_mount(); | 327 | MountData *mptr = get_last_mount(); |
302 | size_t len = strlen(homedir); | 328 | size_t len = strlen(homedir); |
@@ -304,6 +330,8 @@ void fs_private_homedir(void) { | |||
304 | (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) | 330 | (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) |
305 | errLogExit("invalid private mount"); | 331 | errLogExit("invalid private mount"); |
306 | 332 | ||
333 | close(src); | ||
334 | close(dst); | ||
307 | fs_logger3("mount-bind", private_homedir, homedir); | 335 | fs_logger3("mount-bind", private_homedir, homedir); |
308 | fs_logger2("whitelist", homedir); | 336 | fs_logger2("whitelist", homedir); |
309 | // preserve mode and ownership | 337 | // preserve mode and ownership |
@@ -312,6 +340,7 @@ void fs_private_homedir(void) { | |||
312 | // if (chmod(homedir, s.st_mode) == -1) | 340 | // if (chmod(homedir, s.st_mode) == -1) |
313 | // errExit("mount-bind chmod"); | 341 | // errExit("mount-bind chmod"); |
314 | 342 | ||
343 | EUID_ROOT(); | ||
315 | if (u != 0) { | 344 | if (u != 0) { |
316 | // mask /root | 345 | // mask /root |
317 | if (arg_debug) | 346 | if (arg_debug) |
@@ -330,8 +359,9 @@ void fs_private_homedir(void) { | |||
330 | selinux_relabel_path("/home", "/home"); | 359 | selinux_relabel_path("/home", "/home"); |
331 | fs_logger("tmpfs /home"); | 360 | fs_logger("tmpfs /home"); |
332 | } | 361 | } |
362 | EUID_USER(); | ||
333 | 363 | ||
334 | skel(homedir, u, g); | 364 | skel(homedir); |
335 | if (xflag) | 365 | if (xflag) |
336 | copy_xauthority(); | 366 | copy_xauthority(); |
337 | if (aflag) | 367 | if (aflag) |
@@ -346,12 +376,15 @@ void fs_private_homedir(void) { | |||
346 | void fs_private(void) { | 376 | void fs_private(void) { |
347 | char *homedir = cfg.homedir; | 377 | char *homedir = cfg.homedir; |
348 | assert(homedir); | 378 | assert(homedir); |
379 | EUID_ASSERT(); | ||
380 | |||
349 | uid_t u = getuid(); | 381 | uid_t u = getuid(); |
350 | gid_t g = getgid(); | 382 | gid_t g = getgid(); |
351 | 383 | ||
352 | int xflag = store_xauthority(); | 384 | int xflag = store_xauthority(); |
353 | int aflag = store_asoundrc(); | 385 | int aflag = store_asoundrc(); |
354 | 386 | ||
387 | EUID_ROOT(); | ||
355 | // mask /root | 388 | // mask /root |
356 | if (arg_debug) | 389 | if (arg_debug) |
357 | printf("Mounting a new /root directory\n"); | 390 | printf("Mounting a new /root directory\n"); |
@@ -369,12 +402,14 @@ void fs_private(void) { | |||
369 | selinux_relabel_path("/home", "/home"); | 402 | selinux_relabel_path("/home", "/home"); |
370 | fs_logger("tmpfs /home"); | 403 | fs_logger("tmpfs /home"); |
371 | } | 404 | } |
405 | EUID_USER(); | ||
372 | 406 | ||
373 | if (u != 0) { | 407 | if (u != 0) { |
374 | if (!arg_allusers && strncmp(homedir, "/home/", 6) == 0) { | 408 | if (!arg_allusers && strncmp(homedir, "/home/", 6) == 0) { |
375 | // create new empty /home/user directory | 409 | // create new empty /home/user directory |
376 | if (arg_debug) | 410 | if (arg_debug) |
377 | printf("Create a new user directory\n"); | 411 | printf("Create a new user directory\n"); |
412 | EUID_ROOT(); | ||
378 | if (mkdir(homedir, S_IRWXU) == -1) { | 413 | if (mkdir(homedir, S_IRWXU) == -1) { |
379 | if (mkpath_as_root(homedir) == -1) | 414 | if (mkpath_as_root(homedir) == -1) |
380 | errExit("mkpath"); | 415 | errExit("mkpath"); |
@@ -383,7 +418,7 @@ void fs_private(void) { | |||
383 | } | 418 | } |
384 | if (chown(homedir, u, g) < 0) | 419 | if (chown(homedir, u, g) < 0) |
385 | errExit("chown"); | 420 | errExit("chown"); |
386 | 421 | EUID_USER(); | |
387 | fs_logger2("mkdir", homedir); | 422 | fs_logger2("mkdir", homedir); |
388 | fs_logger2("tmpfs", homedir); | 423 | fs_logger2("tmpfs", homedir); |
389 | } | 424 | } |
@@ -395,7 +430,7 @@ void fs_private(void) { | |||
395 | selinux_relabel_path(homedir, homedir); | 430 | selinux_relabel_path(homedir, homedir); |
396 | } | 431 | } |
397 | 432 | ||
398 | skel(homedir, u, g); | 433 | skel(homedir); |
399 | if (xflag) | 434 | if (xflag) |
400 | copy_xauthority(); | 435 | copy_xauthority(); |
401 | if (aflag) | 436 | if (aflag) |
@@ -420,24 +455,40 @@ void fs_check_private_dir(void) { | |||
420 | } | 455 | } |
421 | 456 | ||
422 | // check new private working directory (--private-cwd= option) - exit if it fails | 457 | // check new private working directory (--private-cwd= option) - exit if it fails |
458 | // for testing: | ||
459 | // $ firejail --private --private-cwd=. --noprofile ls | ||
460 | // issue #4780: exposes full home directory, not the --private one | ||
461 | // $ firejail --private-cwd=.. --noprofile ls -> error: full dir path required | ||
462 | // $ firejail --private-cwd=/etc --noprofile ls -> OK | ||
463 | // $ firejail --private-cwd=FULL-SYMLINK-PATH --noprofile ls -> error: no symlinks | ||
464 | // $ firejail --private --private-cwd="${HOME}" --noprofile ls -al --> OK | ||
465 | // $ firejail --private --private-cwd='${HOME}' --noprofile ls -al --> OK | ||
466 | // $ firejail --private-cwd --> OK: should go in top of the home dir | ||
467 | // profile with "private-cwd ${HOME} | ||
423 | void fs_check_private_cwd(const char *dir) { | 468 | void fs_check_private_cwd(const char *dir) { |
424 | EUID_ASSERT(); | 469 | EUID_ASSERT(); |
425 | invalid_filename(dir, 0); // no globbing | 470 | invalid_filename(dir, 0); // no globbing |
471 | if (strcmp(dir, ".") == 0) | ||
472 | goto errout; | ||
426 | 473 | ||
427 | // Expand the working directory | 474 | // Expand the working directory |
428 | cfg.cwd = expand_macros(dir); | 475 | cfg.cwd = expand_macros(dir); |
429 | 476 | ||
430 | // realpath/is_dir not used because path may not exist outside of jail | 477 | // realpath/is_dir not used because path may not exist outside of jail |
431 | if (strstr(cfg.cwd, "..")) { | 478 | if (strstr(cfg.cwd, "..") || *cfg.cwd != '/') |
432 | fprintf(stderr, "Error: invalid private working directory\n"); | 479 | goto errout; |
433 | exit(1); | 480 | |
434 | } | 481 | return; |
482 | errout: | ||
483 | fprintf(stderr, "Error: invalid private working directory\n"); | ||
484 | exit(1); | ||
435 | } | 485 | } |
436 | 486 | ||
437 | //*********************************************************************************** | 487 | //*********************************************************************************** |
438 | // --private-home | 488 | // --private-home |
439 | //*********************************************************************************** | 489 | //*********************************************************************************** |
440 | static char *check_dir_or_file(const char *name) { | 490 | static char *check_dir_or_file(const char *name) { |
491 | EUID_ASSERT(); | ||
441 | assert(name); | 492 | assert(name); |
442 | 493 | ||
443 | // basic checks | 494 | // basic checks |
@@ -498,6 +549,7 @@ errexit: | |||
498 | } | 549 | } |
499 | 550 | ||
500 | static void duplicate(char *name) { | 551 | static void duplicate(char *name) { |
552 | EUID_ASSERT(); | ||
501 | char *fname = check_dir_or_file(name); | 553 | char *fname = check_dir_or_file(name); |
502 | 554 | ||
503 | if (arg_debug) | 555 | if (arg_debug) |
@@ -535,28 +587,32 @@ static void duplicate(char *name) { | |||
535 | // set skel files, | 587 | // set skel files, |
536 | // restore .Xauthority | 588 | // restore .Xauthority |
537 | void fs_private_home_list(void) { | 589 | void fs_private_home_list(void) { |
538 | timetrace_start(); | ||
539 | |||
540 | char *homedir = cfg.homedir; | 590 | char *homedir = cfg.homedir; |
541 | char *private_list = cfg.home_private_keep; | 591 | char *private_list = cfg.home_private_keep; |
542 | assert(homedir); | 592 | assert(homedir); |
543 | assert(private_list); | 593 | assert(private_list); |
594 | EUID_ASSERT(); | ||
544 | 595 | ||
545 | int xflag = store_xauthority(); | 596 | timetrace_start(); |
546 | int aflag = store_asoundrc(); | ||
547 | 597 | ||
548 | uid_t uid = getuid(); | 598 | uid_t uid = getuid(); |
549 | gid_t gid = getgid(); | 599 | gid_t gid = getgid(); |
550 | 600 | ||
601 | int xflag = store_xauthority(); | ||
602 | int aflag = store_asoundrc(); | ||
603 | |||
604 | EUID_ROOT(); | ||
551 | // create /run/firejail/mnt/home directory | 605 | // create /run/firejail/mnt/home directory |
552 | mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); | 606 | mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); |
553 | selinux_relabel_path(RUN_HOME_DIR, homedir); | 607 | selinux_relabel_path(RUN_HOME_DIR, homedir); |
554 | fs_logger_print(); // save the current log | ||
555 | 608 | ||
556 | if (arg_debug) | 609 | // save the current log |
557 | printf("Copying files in the new home:\n"); | 610 | fs_logger_print(); |
611 | EUID_USER(); | ||
558 | 612 | ||
559 | // copy the list of files in the new home directory | 613 | // copy the list of files in the new home directory |
614 | if (arg_debug) | ||
615 | printf("Copying files in the new home:\n"); | ||
560 | char *dlist = strdup(cfg.home_private_keep); | 616 | char *dlist = strdup(cfg.home_private_keep); |
561 | if (!dlist) | 617 | if (!dlist) |
562 | errExit("strdup"); | 618 | errExit("strdup"); |
@@ -576,7 +632,7 @@ void fs_private_home_list(void) { | |||
576 | if (arg_debug) | 632 | if (arg_debug) |
577 | printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); | 633 | printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); |
578 | 634 | ||
579 | int fd = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 635 | int fd = safer_openat(-1, homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
580 | if (fd == -1) | 636 | if (fd == -1) |
581 | errExit("opening home directory"); | 637 | errExit("opening home directory"); |
582 | // home directory should be owned by the user | 638 | // home directory should be owned by the user |
@@ -589,24 +645,19 @@ void fs_private_home_list(void) { | |||
589 | exit(1); | 645 | exit(1); |
590 | } | 646 | } |
591 | // mount using the file descriptor | 647 | // mount using the file descriptor |
592 | char *proc; | 648 | EUID_ROOT(); |
593 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 649 | if (bind_mount_path_to_fd(RUN_HOME_DIR, fd)) |
594 | errExit("asprintf"); | ||
595 | if (mount(RUN_HOME_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
596 | errExit("mount bind"); | 650 | errExit("mount bind"); |
597 | free(proc); | 651 | EUID_USER(); |
598 | close(fd); | 652 | close(fd); |
653 | |||
599 | // check /proc/self/mountinfo to confirm the mount is ok | 654 | // check /proc/self/mountinfo to confirm the mount is ok |
600 | MountData *mptr = get_last_mount(); | 655 | MountData *mptr = get_last_mount(); |
601 | if (strcmp(mptr->dir, homedir) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) | 656 | if (strcmp(mptr->dir, homedir) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) |
602 | errLogExit("invalid private-home mount"); | 657 | errLogExit("invalid private-home mount"); |
603 | fs_logger2("tmpfs", homedir); | 658 | fs_logger2("tmpfs", homedir); |
604 | 659 | ||
605 | // mask RUN_HOME_DIR, it is writable and not noexec | 660 | EUID_ROOT(); |
606 | if (mount("tmpfs", RUN_HOME_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
607 | errExit("mounting tmpfs"); | ||
608 | fs_logger2("tmpfs", RUN_HOME_DIR); | ||
609 | |||
610 | if (uid != 0) { | 661 | if (uid != 0) { |
611 | // mask /root | 662 | // mask /root |
612 | if (arg_debug) | 663 | if (arg_debug) |
@@ -626,7 +677,12 @@ void fs_private_home_list(void) { | |||
626 | fs_logger("tmpfs /home"); | 677 | fs_logger("tmpfs /home"); |
627 | } | 678 | } |
628 | 679 | ||
629 | skel(homedir, uid, gid); | 680 | // mask RUN_HOME_DIR, it is writable and not noexec |
681 | if (mount("tmpfs", RUN_HOME_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
682 | errExit("mounting tmpfs"); | ||
683 | EUID_USER(); | ||
684 | |||
685 | skel(homedir); | ||
630 | if (xflag) | 686 | if (xflag) |
631 | copy_xauthority(); | 687 | copy_xauthority(); |
632 | if (aflag) | 688 | if (aflag) |
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index 8a3bb71ea..dca394865 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,7 +20,6 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <glob.h> | 23 | #include <glob.h> |
25 | #include <dirent.h> | 24 | #include <dirent.h> |
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
@@ -33,7 +32,7 @@ void fs_hostname(const char *hostname) { | |||
33 | if (arg_debug) | 32 | if (arg_debug) |
34 | printf("Creating a new /etc/hostname file\n"); | 33 | printf("Creating a new /etc/hostname file\n"); |
35 | 34 | ||
36 | create_empty_file_as_root(RUN_HOSTNAME_FILE, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 35 | create_empty_file_as_root(RUN_HOSTNAME_FILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
37 | 36 | ||
38 | // bind-mount the file on top of /etc/hostname | 37 | // bind-mount the file on top of /etc/hostname |
39 | if (mount(RUN_HOSTNAME_FILE, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) | 38 | if (mount(RUN_HOSTNAME_FILE, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) |
@@ -47,11 +46,11 @@ void fs_hostname(const char *hostname) { | |||
47 | printf("Creating a new /etc/hosts file\n"); | 46 | printf("Creating a new /etc/hosts file\n"); |
48 | // copy /etc/host into our new file, and modify it on the fly | 47 | // copy /etc/host into our new file, and modify it on the fly |
49 | /* coverity[toctou] */ | 48 | /* coverity[toctou] */ |
50 | FILE *fp1 = fopen("/etc/hosts", "r"); | 49 | FILE *fp1 = fopen("/etc/hosts", "re"); |
51 | if (!fp1) | 50 | if (!fp1) |
52 | goto errexit; | 51 | goto errexit; |
53 | 52 | ||
54 | FILE *fp2 = fopen(RUN_HOSTS_FILE, "w"); | 53 | FILE *fp2 = fopen(RUN_HOSTS_FILE, "we"); |
55 | if (!fp2) { | 54 | if (!fp2) { |
56 | fclose(fp1); | 55 | fclose(fp1); |
57 | goto errexit; | 56 | goto errexit; |
@@ -75,7 +74,7 @@ void fs_hostname(const char *hostname) { | |||
75 | } | 74 | } |
76 | fclose(fp1); | 75 | fclose(fp1); |
77 | // mode and owner | 76 | // mode and owner |
78 | SET_PERMS_STREAM(fp2, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 77 | SET_PERMS_STREAM(fp2, 0, 0, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
79 | fclose(fp2); | 78 | fclose(fp2); |
80 | 79 | ||
81 | // bind-mount the file on top of /etc/hostname | 80 | // bind-mount the file on top of /etc/hostname |
@@ -88,118 +87,11 @@ errexit: | |||
88 | exit(1); | 87 | exit(1); |
89 | } | 88 | } |
90 | 89 | ||
91 | void fs_resolvconf(void) { | ||
92 | if (cfg.dns1 == NULL && !any_dhcp()) | ||
93 | return; | ||
94 | |||
95 | if (arg_debug) | ||
96 | printf("mirroring /etc directory\n"); | ||
97 | if (mkdir(RUN_DNS_ETC, 0755)) | ||
98 | errExit("mkdir"); | ||
99 | selinux_relabel_path(RUN_DNS_ETC, "/etc"); | ||
100 | fs_logger("tmpfs /etc"); | ||
101 | |||
102 | DIR *dir = opendir("/etc"); | ||
103 | if (!dir) | ||
104 | errExit("opendir"); | ||
105 | |||
106 | struct stat s; | ||
107 | struct dirent *entry; | ||
108 | while ((entry = readdir(dir))) { | ||
109 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||
110 | continue; | ||
111 | // for resolv.conf we create a brand new file | ||
112 | if (strcmp(entry->d_name, "resolv.conf") == 0 || | ||
113 | strcmp(entry->d_name, "resolv.conf.dhclient-new") == 0) | ||
114 | continue; | ||
115 | // printf("linking %s\n", entry->d_name); | ||
116 | |||
117 | char *src; | ||
118 | if (asprintf(&src, "/etc/%s", entry->d_name) == -1) | ||
119 | errExit("asprintf"); | ||
120 | if (stat(src, &s) != 0) { | ||
121 | free(src); | ||
122 | continue; | ||
123 | } | ||
124 | |||
125 | char *dest; | ||
126 | if (asprintf(&dest, "%s/%s", RUN_DNS_ETC, entry->d_name) == -1) | ||
127 | errExit("asprintf"); | ||
128 | |||
129 | int symlink_done = 0; | ||
130 | if (is_link(src)) { | ||
131 | char *rp =realpath(src, NULL); | ||
132 | if (rp == NULL) { | ||
133 | free(src); | ||
134 | free(dest); | ||
135 | continue; | ||
136 | } | ||
137 | if (symlink(rp, dest)) | ||
138 | errExit("symlink"); | ||
139 | else | ||
140 | symlink_done = 1; | ||
141 | } | ||
142 | else if (S_ISDIR(s.st_mode)) | ||
143 | create_empty_dir_as_root(dest, s.st_mode); | ||
144 | else | ||
145 | create_empty_file_as_root(dest, s.st_mode); | ||
146 | |||
147 | // bind-mount src on top of dest | ||
148 | if (!symlink_done) { | ||
149 | if (mount(src, dest, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
150 | errExit("mount bind mirroring /etc"); | ||
151 | } | ||
152 | fs_logger2("clone", src); | ||
153 | |||
154 | free(src); | ||
155 | free(dest); | ||
156 | } | ||
157 | closedir(dir); | ||
158 | |||
159 | // mount bind our private etc directory on top of /etc | ||
160 | if (arg_debug) | ||
161 | printf("Mount-bind %s on top of /etc\n", RUN_DNS_ETC); | ||
162 | if (mount(RUN_DNS_ETC, "/etc", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
163 | errExit("mount bind mirroring /etc"); | ||
164 | fs_logger("mount /etc"); | ||
165 | |||
166 | if (arg_debug) | ||
167 | printf("Creating a new /etc/resolv.conf file\n"); | ||
168 | FILE *fp = fopen("/etc/resolv.conf", "w"); | ||
169 | if (!fp) { | ||
170 | fprintf(stderr, "Error: cannot create /etc/resolv.conf file\n"); | ||
171 | exit(1); | ||
172 | } | ||
173 | |||
174 | if (cfg.dns1) { | ||
175 | if (any_dhcp()) | ||
176 | fwarning("network setup uses DHCP, nameservers will likely be overwritten\n"); | ||
177 | fprintf(fp, "nameserver %s\n", cfg.dns1); | ||
178 | } | ||
179 | if (cfg.dns2) | ||
180 | fprintf(fp, "nameserver %s\n", cfg.dns2); | ||
181 | if (cfg.dns3) | ||
182 | fprintf(fp, "nameserver %s\n", cfg.dns3); | ||
183 | if (cfg.dns4) | ||
184 | fprintf(fp, "nameserver %s\n", cfg.dns4); | ||
185 | |||
186 | // mode and owner | ||
187 | SET_PERMS_STREAM(fp, 0, 0, 0644); | ||
188 | |||
189 | fclose(fp); | ||
190 | |||
191 | fs_logger("create /etc/resolv.conf"); | ||
192 | } | ||
193 | |||
194 | char *fs_check_hosts_file(const char *fname) { | 90 | char *fs_check_hosts_file(const char *fname) { |
195 | assert(fname); | 91 | assert(fname); |
196 | invalid_filename(fname, 0); // no globbing | 92 | invalid_filename(fname, 0); // no globbing |
197 | char *rv = expand_macros(fname); | 93 | char *rv = expand_macros(fname); |
198 | 94 | ||
199 | // no a link | ||
200 | if (is_link(rv)) | ||
201 | goto errexit; | ||
202 | |||
203 | // the user has read access to the file | 95 | // the user has read access to the file |
204 | if (access(rv, R_OK)) | 96 | if (access(rv, R_OK)) |
205 | goto errexit; | 97 | goto errexit; |
@@ -222,9 +114,6 @@ void fs_mount_hosts_file(void) { | |||
222 | struct stat s; | 114 | struct stat s; |
223 | if (stat("/etc/hosts", &s) == -1) | 115 | if (stat("/etc/hosts", &s) == -1) |
224 | goto errexit; | 116 | goto errexit; |
225 | // not a link | ||
226 | if (is_link("/etc/hosts")) | ||
227 | goto errexit; | ||
228 | // owned by root | 117 | // owned by root |
229 | if (s.st_uid != 0) | 118 | if (s.st_uid != 0) |
230 | goto errexit; | 119 | goto errexit; |
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index 85fb70854..848691a56 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -61,17 +61,31 @@ static int valid_full_path(const char *full_path) { | |||
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
64 | // return 1 if symlink to firejail executable | ||
65 | int is_firejail_link(const char *fname) { | ||
66 | EUID_ASSERT(); | ||
67 | |||
68 | if (!is_link(fname)) | ||
69 | return 0; | ||
70 | |||
71 | char *rp = realpath(fname, NULL); | ||
72 | if (!rp) | ||
73 | return 0; | ||
74 | |||
75 | int rv = 0; | ||
76 | const char *base = gnu_basename(rp); | ||
77 | if (strcmp(base, "firejail") == 0) | ||
78 | rv = 1; | ||
79 | |||
80 | free(rp); | ||
81 | return rv; | ||
82 | } | ||
83 | |||
64 | char *find_in_path(const char *program) { | 84 | char *find_in_path(const char *program) { |
65 | EUID_ASSERT(); | 85 | EUID_ASSERT(); |
66 | if (arg_debug) | 86 | if (arg_debug) |
67 | printf("Searching $PATH for %s\n", program); | 87 | printf("Searching $PATH for %s\n", program); |
68 | 88 | ||
69 | char self[MAXBUF]; | ||
70 | ssize_t len = readlink("/proc/self/exe", self, MAXBUF - 1); | ||
71 | if (len < 0) | ||
72 | errExit("readlink"); | ||
73 | self[len] = '\0'; | ||
74 | |||
75 | const char *path = env_get("PATH"); | 89 | const char *path = env_get("PATH"); |
76 | if (!path) | 90 | if (!path) |
77 | return NULL; | 91 | return NULL; |
@@ -88,18 +102,12 @@ char *find_in_path(const char *program) { | |||
88 | if (arg_debug) | 102 | if (arg_debug) |
89 | printf("trying #%s#\n", fname); | 103 | printf("trying #%s#\n", fname); |
90 | struct stat s; | 104 | struct stat s; |
91 | if (stat(fname, &s) == 0) { | 105 | if (stat(fname, &s) == 0 && |
92 | // but skip links created by firecfg | 106 | !is_firejail_link(fname)) { // skip links created by firecfg |
93 | char *rp = realpath(fname, NULL); | 107 | free(dup); |
94 | if (!rp) | 108 | return fname; |
95 | errExit("realpath"); | ||
96 | if (strcmp(self, rp) != 0) { | ||
97 | free(rp); | ||
98 | free(dup); | ||
99 | return fname; | ||
100 | } | ||
101 | free(rp); | ||
102 | } | 109 | } |
110 | |||
103 | free(fname); | 111 | free(fname); |
104 | tok = strtok(NULL, ":"); | 112 | tok = strtok(NULL, ":"); |
105 | } | 113 | } |
@@ -178,8 +186,7 @@ void fslib_mount(const char *full_path) { | |||
178 | 186 | ||
179 | if (*full_path == '\0' || | 187 | if (*full_path == '\0' || |
180 | !valid_full_path(full_path) || | 188 | !valid_full_path(full_path) || |
181 | access(full_path, F_OK) != 0 || | 189 | stat_as_user(full_path, &s) != 0 || |
182 | stat(full_path, &s) != 0 || | ||
183 | s.st_uid != 0) | 190 | s.st_uid != 0) |
184 | return; | 191 | return; |
185 | 192 | ||
@@ -196,6 +203,11 @@ void fslib_mount_libs(const char *full_path, unsigned user) { | |||
196 | assert(full_path); | 203 | assert(full_path); |
197 | // if library/executable does not exist or the user does not have read access to it | 204 | // if library/executable does not exist or the user does not have read access to it |
198 | // print a warning and exit the function. | 205 | // print a warning and exit the function. |
206 | if (access(full_path, F_OK)) { | ||
207 | if (arg_debug || arg_debug_private_lib) | ||
208 | printf("Cannot find %s, skipping...\n", full_path); | ||
209 | return; | ||
210 | } | ||
199 | if (user && access(full_path, R_OK)) { | 211 | if (user && access(full_path, R_OK)) { |
200 | if (arg_debug || arg_debug_private_lib) | 212 | if (arg_debug || arg_debug_private_lib) |
201 | printf("Cannot read %s, skipping...\n", full_path); | 213 | printf("Cannot read %s, skipping...\n", full_path); |
@@ -203,7 +215,7 @@ void fslib_mount_libs(const char *full_path, unsigned user) { | |||
203 | } | 215 | } |
204 | 216 | ||
205 | if (arg_debug || arg_debug_private_lib) | 217 | if (arg_debug || arg_debug_private_lib) |
206 | printf(" fslib_mount_libs %s (parse as %s)\n", full_path, user ? "user" : "root"); | 218 | printf(" fslib_mount_libs %s\n", full_path); |
207 | // create an empty RUN_LIB_FILE and allow the user to write to it | 219 | // create an empty RUN_LIB_FILE and allow the user to write to it |
208 | unlink(RUN_LIB_FILE); // in case is there | 220 | unlink(RUN_LIB_FILE); // in case is there |
209 | create_empty_file_as_root(RUN_LIB_FILE, 0644); | 221 | create_empty_file_as_root(RUN_LIB_FILE, 0644); |
@@ -212,7 +224,7 @@ void fslib_mount_libs(const char *full_path, unsigned user) { | |||
212 | 224 | ||
213 | // run fldd to extract the list of files | 225 | // run fldd to extract the list of files |
214 | if (arg_debug || arg_debug_private_lib) | 226 | if (arg_debug || arg_debug_private_lib) |
215 | printf(" running fldd %s\n", full_path); | 227 | printf(" running fldd %s as %s\n", full_path, user ? "user" : "root"); |
216 | unsigned mask; | 228 | unsigned mask; |
217 | if (user) | 229 | if (user) |
218 | mask = SBOX_USER; | 230 | mask = SBOX_USER; |
@@ -221,7 +233,7 @@ void fslib_mount_libs(const char *full_path, unsigned user) { | |||
221 | sbox_run(mask | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE); | 233 | sbox_run(mask | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE); |
222 | 234 | ||
223 | // open the list of libraries and install them on by one | 235 | // open the list of libraries and install them on by one |
224 | FILE *fp = fopen(RUN_LIB_FILE, "r"); | 236 | FILE *fp = fopen(RUN_LIB_FILE, "re"); |
225 | if (!fp) | 237 | if (!fp) |
226 | errExit("fopen"); | 238 | errExit("fopen"); |
227 | 239 | ||
@@ -246,7 +258,7 @@ static void load_library(const char *fname) { | |||
246 | 258 | ||
247 | // existing file owned by root | 259 | // existing file owned by root |
248 | struct stat s; | 260 | struct stat s; |
249 | if (!access(fname, F_OK) && stat(fname, &s) == 0 && s.st_uid == 0) { | 261 | if (stat_as_user(fname, &s) == 0 && s.st_uid == 0) { |
250 | // load directories, regular 64 bit libraries, and 64 bit executables | 262 | // load directories, regular 64 bit libraries, and 64 bit executables |
251 | if (S_ISDIR(s.st_mode)) | 263 | if (S_ISDIR(s.st_mode)) |
252 | fslib_mount(fname); | 264 | fslib_mount(fname); |
@@ -264,9 +276,9 @@ static void install_list_entry(const char *lib) { | |||
264 | assert(lib); | 276 | assert(lib); |
265 | 277 | ||
266 | // filename check | 278 | // filename check |
267 | int len = strlen(lib); | 279 | reject_meta_chars(lib, 1); |
268 | if (strcspn(lib, "\\&!?\"'<>%^(){}[];,") != (size_t)len || | 280 | |
269 | strstr(lib, "..")) { | 281 | if (strstr(lib, "..")) { |
270 | fprintf(stderr, "Error: \"%s\" is an invalid library\n", lib); | 282 | fprintf(stderr, "Error: \"%s\" is an invalid library\n", lib); |
271 | exit(1); | 283 | exit(1); |
272 | } | 284 | } |
@@ -286,19 +298,21 @@ static void install_list_entry(const char *lib) { | |||
286 | #define DO_GLOBBING | 298 | #define DO_GLOBBING |
287 | #ifdef DO_GLOBBING | 299 | #ifdef DO_GLOBBING |
288 | // globbing | 300 | // globbing |
301 | EUID_USER(); | ||
289 | glob_t globbuf; | 302 | glob_t globbuf; |
290 | int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf); | 303 | int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf); |
291 | if (globerr) { | 304 | if (globerr) { |
292 | fprintf(stderr, "Error: failed to glob private-lib pattern %s\n", fname); | 305 | fprintf(stderr, "Error: failed to glob private-lib pattern %s\n", fname); |
293 | exit(1); | 306 | exit(1); |
294 | } | 307 | } |
308 | EUID_ROOT(); | ||
295 | size_t j; | 309 | size_t j; |
296 | for (j = 0; j < globbuf.gl_pathc; j++) { | 310 | for (j = 0; j < globbuf.gl_pathc; j++) { |
297 | assert(globbuf.gl_pathv[j]); | 311 | assert(globbuf.gl_pathv[j]); |
298 | //printf("glob %s\n", globbuf.gl_pathv[j]); | 312 | //printf("glob %s\n", globbuf.gl_pathv[j]); |
299 | // GLOB_NOCHECK - no pattern matched returns the original pattern; try to load it anyway | 313 | // GLOB_NOCHECK - no pattern matched returns the original pattern; try to load it anyway |
300 | 314 | ||
301 | // foobar/* includes foobar/. and foobar/.. | 315 | // foobar/* expands to foobar/. and foobar/.. |
302 | const char *base = gnu_basename(globbuf.gl_pathv[j]); | 316 | const char *base = gnu_basename(globbuf.gl_pathv[j]); |
303 | if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) | 317 | if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) |
304 | continue; | 318 | continue; |
diff --git a/src/firejail/fs_lib2.c b/src/firejail/fs_lib2.c index c69bf7c98..aefd38e3c 100644 --- a/src/firejail/fs_lib2.c +++ b/src/firejail/fs_lib2.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -143,7 +143,7 @@ static void fdir(void) { | |||
143 | NULL, | 143 | NULL, |
144 | }; | 144 | }; |
145 | 145 | ||
146 | // need to parse as root user, unprivileged users have no read permission on executables | 146 | // need to parse as root user, unprivileged users have no read permission on some of these binaries |
147 | int i; | 147 | int i; |
148 | for (i = 0; fbin[i]; i++) | 148 | for (i = 0; fbin[i]; i++) |
149 | fslib_mount_libs(fbin[i], 0); | 149 | fslib_mount_libs(fbin[i], 0); |
@@ -153,7 +153,9 @@ void fslib_install_firejail(void) { | |||
153 | timetrace_start(); | 153 | timetrace_start(); |
154 | // bring in firejail executable libraries, in case we are redirected here | 154 | // bring in firejail executable libraries, in case we are redirected here |
155 | // by a firejail symlink from /usr/local/bin/firejail | 155 | // by a firejail symlink from /usr/local/bin/firejail |
156 | fslib_mount_libs(PATH_FIREJAIL, 1); // parse as user | 156 | // fldd might have no read permission on the firejail executable |
157 | // parse as root in order to support these setups | ||
158 | fslib_mount_libs(PATH_FIREJAIL, 0); | ||
157 | 159 | ||
158 | // bring in firejail directory | 160 | // bring in firejail directory |
159 | fdir(); | 161 | fdir(); |
diff --git a/src/firejail/fs_logger.c b/src/firejail/fs_logger.c index 67ad4b52e..06f03dac5 100644 --- a/src/firejail/fs_logger.c +++ b/src/firejail/fs_logger.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -92,7 +92,7 @@ void fs_logger_print(void) { | |||
92 | if (!head) | 92 | if (!head) |
93 | return; | 93 | return; |
94 | 94 | ||
95 | FILE *fp = fopen(RUN_FSLOGGER_FILE, "a"); | 95 | FILE *fp = fopen(RUN_FSLOGGER_FILE, "ae"); |
96 | if (!fp) { | 96 | if (!fp) { |
97 | perror("fopen"); | 97 | perror("fopen"); |
98 | return; | 98 | return; |
@@ -123,15 +123,8 @@ void fs_logger_print_log(pid_t pid) { | |||
123 | // in case the pid is that of a firejail process, use the pid of the first child process | 123 | // in case the pid is that of a firejail process, use the pid of the first child process |
124 | pid = switch_to_child(pid); | 124 | pid = switch_to_child(pid); |
125 | 125 | ||
126 | // check privileges for non-root users | 126 | // exit if no permission to join the sandbox |
127 | uid_t uid = getuid(); | 127 | check_join_permission(pid); |
128 | if (uid != 0) { | ||
129 | uid_t sandbox_uid = pid_get_uid(pid); | ||
130 | if (uid != sandbox_uid) { | ||
131 | fprintf(stderr, "Error: permission denied\n"); | ||
132 | exit(1); | ||
133 | } | ||
134 | } | ||
135 | 128 | ||
136 | // print RUN_FSLOGGER_FILE | 129 | // print RUN_FSLOGGER_FILE |
137 | char *fname; | 130 | char *fname; |
@@ -139,24 +132,16 @@ void fs_logger_print_log(pid_t pid) { | |||
139 | errExit("asprintf"); | 132 | errExit("asprintf"); |
140 | 133 | ||
141 | EUID_ROOT(); | 134 | EUID_ROOT(); |
142 | struct stat s; | 135 | FILE *fp = fopen(fname, "re"); |
143 | if (stat(fname, &s) == -1 || s.st_uid != 0) { | 136 | free(fname); |
144 | fprintf(stderr, "Error: Cannot access filesystem log\n"); | ||
145 | exit(1); | ||
146 | } | ||
147 | |||
148 | /* coverity[toctou] */ | ||
149 | FILE *fp = fopen(fname, "r"); | ||
150 | if (!fp) { | 137 | if (!fp) { |
151 | fprintf(stderr, "Error: Cannot open filesystem log\n"); | 138 | fprintf(stderr, "Error: Cannot open filesystem log\n"); |
152 | exit(1); | 139 | exit(1); |
153 | } | 140 | } |
154 | |||
155 | char buf[MAXBUF]; | 141 | char buf[MAXBUF]; |
156 | while (fgets(buf, MAXBUF, fp)) | 142 | while (fgets(buf, MAXBUF, fp)) |
157 | printf("%s", buf); | 143 | printf("%s", buf); |
158 | fclose(fp); | 144 | fclose(fp); |
159 | free(fname); | ||
160 | 145 | ||
161 | exit(0); | 146 | exit(0); |
162 | } | 147 | } |
diff --git a/src/firejail/fs_mkdir.c b/src/firejail/fs_mkdir.c index 8cfeea582..30dbd8e9b 100644 --- a/src/firejail/fs_mkdir.c +++ b/src/firejail/fs_mkdir.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,6 +18,7 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include "../include/gcov_wrapper.h" | ||
21 | #include <sys/types.h> | 22 | #include <sys/types.h> |
22 | #include <sys/stat.h> | 23 | #include <sys/stat.h> |
23 | #include <unistd.h> | 24 | #include <unistd.h> |
@@ -25,7 +26,6 @@ | |||
25 | #include <sys/wait.h> | 26 | #include <sys/wait.h> |
26 | #include <string.h> | 27 | #include <string.h> |
27 | 28 | ||
28 | |||
29 | static void check(const char *fname) { | 29 | static void check(const char *fname) { |
30 | // manufacture /run/user directory | 30 | // manufacture /run/user directory |
31 | char *runuser; | 31 | char *runuser; |
@@ -95,9 +95,9 @@ void fs_mkdir(const char *name) { | |||
95 | 95 | ||
96 | // create directory | 96 | // create directory |
97 | mkdir_recursive(expanded); | 97 | mkdir_recursive(expanded); |
98 | #ifdef HAVE_GCOV | 98 | |
99 | __gcov_flush(); | 99 | __gcov_flush(); |
100 | #endif | 100 | |
101 | _exit(0); | 101 | _exit(0); |
102 | } | 102 | } |
103 | // wait for the child to finish | 103 | // wait for the child to finish |
diff --git a/src/firejail/fs_overlayfs.c b/src/firejail/fs_overlayfs.c new file mode 100644 index 000000000..167a7e28b --- /dev/null +++ b/src/firejail/fs_overlayfs.c | |||
@@ -0,0 +1,470 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #ifdef HAVE_OVERLAYFS | ||
22 | #include "firejail.h" | ||
23 | #include "../include/gcov_wrapper.h" | ||
24 | #include <sys/mount.h> | ||
25 | #include <sys/wait.h> | ||
26 | #include <ftw.h> | ||
27 | #include <errno.h> | ||
28 | |||
29 | #include <fcntl.h> | ||
30 | #ifndef O_PATH | ||
31 | #define O_PATH 010000000 | ||
32 | #endif | ||
33 | |||
34 | |||
35 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | ||
36 | assert(subdirname); | ||
37 | EUID_ASSERT(); | ||
38 | struct stat s; | ||
39 | char *dirname; | ||
40 | |||
41 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) | ||
42 | errExit("asprintf"); | ||
43 | // check if ~/.firejail already exists | ||
44 | if (lstat(dirname, &s) == 0) { | ||
45 | if (!S_ISDIR(s.st_mode)) { | ||
46 | if (S_ISLNK(s.st_mode)) | ||
47 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); | ||
48 | else | ||
49 | fprintf(stderr, "Error: %s is not a directory\n", dirname); | ||
50 | exit(1); | ||
51 | } | ||
52 | if (s.st_uid != getuid()) { | ||
53 | fprintf(stderr, "Error: %s is not owned by the current user\n", dirname); | ||
54 | exit(1); | ||
55 | } | ||
56 | } | ||
57 | else { | ||
58 | // create ~/.firejail directory | ||
59 | create_empty_dir_as_user(dirname, 0700); | ||
60 | if (stat(dirname, &s) == -1) { | ||
61 | fprintf(stderr, "Error: cannot create directory %s\n", dirname); | ||
62 | exit(1); | ||
63 | } | ||
64 | } | ||
65 | free(dirname); | ||
66 | |||
67 | // check overlay directory | ||
68 | if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) | ||
69 | errExit("asprintf"); | ||
70 | if (lstat(dirname, &s) == 0) { | ||
71 | if (!S_ISDIR(s.st_mode)) { | ||
72 | if (S_ISLNK(s.st_mode)) | ||
73 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); | ||
74 | else | ||
75 | fprintf(stderr, "Error: %s is not a directory\n", dirname); | ||
76 | exit(1); | ||
77 | } | ||
78 | if (s.st_uid != 0) { | ||
79 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", dirname); | ||
80 | exit(1); | ||
81 | } | ||
82 | if (allow_reuse == 0) { | ||
83 | fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); | ||
84 | exit(1); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | return dirname; | ||
89 | } | ||
90 | |||
91 | |||
92 | // mount overlayfs on top of / directory | ||
93 | // mounting an overlay and chrooting into it: | ||
94 | // | ||
95 | // Old Ubuntu kernel | ||
96 | // # cd ~ | ||
97 | // # mkdir -p overlay/root | ||
98 | // # mkdir -p overlay/diff | ||
99 | // # mount -t overlayfs -o lowerdir=/,upperdir=/root/overlay/diff overlayfs /root/overlay/root | ||
100 | // # chroot /root/overlay/root | ||
101 | // to shutdown, first exit the chroot and then unmount the overlay | ||
102 | // # exit | ||
103 | // # umount /root/overlay/root | ||
104 | // | ||
105 | // Kernels 3.18+ | ||
106 | // # cd ~ | ||
107 | // # mkdir -p overlay/root | ||
108 | // # mkdir -p overlay/diff | ||
109 | // # mkdir -p overlay/work | ||
110 | // # mount -t overlay -o lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work overlay /root/overlay/root | ||
111 | // # cat /etc/mtab | grep overlay | ||
112 | // /root/overlay /root/overlay/root overlay rw,relatime,lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work 0 0 | ||
113 | // # chroot /root/overlay/root | ||
114 | // to shutdown, first exit the chroot and then unmount the overlay | ||
115 | // # exit | ||
116 | // # umount /root/overlay/root | ||
117 | |||
118 | // to do: fix the code below | ||
119 | #include <sys/utsname.h> | ||
120 | void fs_overlayfs(void) { | ||
121 | struct stat s; | ||
122 | |||
123 | // check kernel version | ||
124 | struct utsname u; | ||
125 | int rv = uname(&u); | ||
126 | if (rv != 0) | ||
127 | errExit("uname"); | ||
128 | int major; | ||
129 | int minor; | ||
130 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
131 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
132 | exit(1); | ||
133 | } | ||
134 | |||
135 | if (arg_debug) | ||
136 | printf("Linux kernel version %d.%d\n", major, minor); | ||
137 | int oldkernel = 0; | ||
138 | if (major < 3) { | ||
139 | fprintf(stderr, "Error: minimum kernel version required 3.x\n"); | ||
140 | exit(1); | ||
141 | } | ||
142 | if (major == 3 && minor < 18) | ||
143 | oldkernel = 1; | ||
144 | |||
145 | // mounting an overlayfs on top of / seems to be broken for kernels > 4.19 | ||
146 | // we disable overlayfs for now, pending fixing | ||
147 | if (major >= 4 &&minor >= 19) { | ||
148 | fprintf(stderr, "Error: OverlayFS disabled for Linux kernels 4.19 and newer, pending fixing.\n"); | ||
149 | exit(1); | ||
150 | } | ||
151 | |||
152 | char *oroot = RUN_OVERLAY_ROOT; | ||
153 | mkdir_attr(oroot, 0755, 0, 0); | ||
154 | |||
155 | // set base for working and diff directories | ||
156 | char *basedir = RUN_MNT_DIR; | ||
157 | int basefd = -1; | ||
158 | |||
159 | if (arg_overlay_keep) { | ||
160 | basedir = cfg.overlay_dir; | ||
161 | assert(basedir); | ||
162 | // get a file descriptor for ~/.firejail, fails if there is any symlink | ||
163 | char *firejail; | ||
164 | if (asprintf(&firejail, "%s/.firejail", cfg.homedir) == -1) | ||
165 | errExit("asprintf"); | ||
166 | int fd = safer_openat(-1, firejail, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
167 | if (fd == -1) | ||
168 | errExit("safer_openat"); | ||
169 | free(firejail); | ||
170 | // create basedir if it doesn't exist | ||
171 | // the new directory will be owned by root | ||
172 | const char *dirname = gnu_basename(basedir); | ||
173 | if (mkdirat(fd, dirname, 0755) == -1 && errno != EEXIST) { | ||
174 | perror("mkdir"); | ||
175 | fprintf(stderr, "Error: cannot create overlay directory %s\n", basedir); | ||
176 | exit(1); | ||
177 | } | ||
178 | // open basedir | ||
179 | basefd = openat(fd, dirname, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
180 | close(fd); | ||
181 | } | ||
182 | else { | ||
183 | basefd = open(basedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
184 | } | ||
185 | if (basefd == -1) { | ||
186 | perror("open"); | ||
187 | fprintf(stderr, "Error: cannot open overlay directory %s\n", basedir); | ||
188 | exit(1); | ||
189 | } | ||
190 | |||
191 | // confirm once more base is owned by root | ||
192 | if (fstat(basefd, &s) == -1) | ||
193 | errExit("fstat"); | ||
194 | if (s.st_uid != 0) { | ||
195 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", basedir); | ||
196 | exit(1); | ||
197 | } | ||
198 | // confirm permissions of base are 0755 | ||
199 | if (((S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) & s.st_mode) != (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) { | ||
200 | fprintf(stderr, "Error: invalid permissions on overlay directory %s\n", basedir); | ||
201 | exit(1); | ||
202 | } | ||
203 | |||
204 | // create diff and work directories inside base | ||
205 | // no need to check arg_overlay_reuse | ||
206 | char *odiff; | ||
207 | if (asprintf(&odiff, "%s/odiff", basedir) == -1) | ||
208 | errExit("asprintf"); | ||
209 | // the new directory will be owned by root | ||
210 | if (mkdirat(basefd, "odiff", 0755) == -1 && errno != EEXIST) { | ||
211 | perror("mkdir"); | ||
212 | fprintf(stderr, "Error: cannot create overlay directory %s\n", odiff); | ||
213 | exit(1); | ||
214 | } | ||
215 | ASSERT_PERMS(odiff, 0, 0, 0755); | ||
216 | |||
217 | char *owork; | ||
218 | if (asprintf(&owork, "%s/owork", basedir) == -1) | ||
219 | errExit("asprintf"); | ||
220 | // the new directory will be owned by root | ||
221 | if (mkdirat(basefd, "owork", 0755) == -1 && errno != EEXIST) { | ||
222 | perror("mkdir"); | ||
223 | fprintf(stderr, "Error: cannot create overlay directory %s\n", owork); | ||
224 | exit(1); | ||
225 | } | ||
226 | ASSERT_PERMS(owork, 0, 0, 0755); | ||
227 | |||
228 | // mount overlayfs | ||
229 | if (arg_debug) | ||
230 | printf("Mounting OverlayFS\n"); | ||
231 | char *option; | ||
232 | if (oldkernel) { // old Ubuntu/OpenSUSE kernels | ||
233 | if (arg_overlay_keep) { | ||
234 | fprintf(stderr, "Error: option --overlay= not available for kernels older than 3.18\n"); | ||
235 | exit(1); | ||
236 | } | ||
237 | if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) | ||
238 | errExit("asprintf"); | ||
239 | if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) | ||
240 | errExit("mounting overlayfs"); | ||
241 | } | ||
242 | else { // kernel 3.18 or newer | ||
243 | if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) | ||
244 | errExit("asprintf"); | ||
245 | if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) { | ||
246 | fprintf(stderr, "Debug: running on kernel version %d.%d\n", major, minor); | ||
247 | errExit("mounting overlayfs"); | ||
248 | } | ||
249 | |||
250 | //*************************** | ||
251 | // issue #263 start code | ||
252 | // My setup has a separate mount point for /home. When the overlay is mounted, | ||
253 | // the overlay does not contain the original /home contents. | ||
254 | // I added code to create a second overlay for /home if the overlay home dir is empty and this seems to work | ||
255 | // @dshmgh, Jan 2016 | ||
256 | { | ||
257 | char *overlayhome; | ||
258 | struct stat s; | ||
259 | char *hroot; | ||
260 | char *hdiff; | ||
261 | char *hwork; | ||
262 | |||
263 | // dons add debug | ||
264 | if (arg_debug) printf ("DEBUG: chroot dirs are oroot %s odiff %s owork %s\n",oroot,odiff,owork); | ||
265 | |||
266 | // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it? | ||
267 | // must create var for oroot/cfg.homedir | ||
268 | if (asprintf(&overlayhome, "%s%s", oroot, cfg.homedir) == -1) | ||
269 | errExit("asprintf"); | ||
270 | if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n", overlayhome); | ||
271 | |||
272 | // if no homedir in overlay -- create another overlay for /home | ||
273 | if (stat(cfg.homedir, &s) == 0 && stat(overlayhome, &s) == -1) { | ||
274 | |||
275 | // no need to check arg_overlay_reuse | ||
276 | if (asprintf(&hdiff, "%s/hdiff", basedir) == -1) | ||
277 | errExit("asprintf"); | ||
278 | // the new directory will be owned by root | ||
279 | if (mkdirat(basefd, "hdiff", 0755) == -1 && errno != EEXIST) { | ||
280 | perror("mkdir"); | ||
281 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hdiff); | ||
282 | exit(1); | ||
283 | } | ||
284 | ASSERT_PERMS(hdiff, 0, 0, 0755); | ||
285 | |||
286 | // no need to check arg_overlay_reuse | ||
287 | if (asprintf(&hwork, "%s/hwork", basedir) == -1) | ||
288 | errExit("asprintf"); | ||
289 | // the new directory will be owned by root | ||
290 | if (mkdirat(basefd, "hwork", 0755) == -1 && errno != EEXIST) { | ||
291 | perror("mkdir"); | ||
292 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hwork); | ||
293 | exit(1); | ||
294 | } | ||
295 | ASSERT_PERMS(hwork, 0, 0, 0755); | ||
296 | |||
297 | // no homedir in overlay so now mount another overlay for /home | ||
298 | if (asprintf(&hroot, "%s/home", oroot) == -1) | ||
299 | errExit("asprintf"); | ||
300 | if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) | ||
301 | errExit("asprintf"); | ||
302 | if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) | ||
303 | errExit("mounting overlayfs for mounted home directory"); | ||
304 | |||
305 | printf("OverlayFS for /home configured in %s directory\n", basedir); | ||
306 | free(hroot); | ||
307 | free(hdiff); | ||
308 | free(hwork); | ||
309 | |||
310 | } // stat(overlayhome) | ||
311 | free(overlayhome); | ||
312 | } | ||
313 | // issue #263 end code | ||
314 | //*************************** | ||
315 | } | ||
316 | fmessage("OverlayFS configured in %s directory\n", basedir); | ||
317 | close(basefd); | ||
318 | |||
319 | // /dev, /run and /tmp are not covered by the overlay | ||
320 | // mount-bind dev directory | ||
321 | if (arg_debug) | ||
322 | printf("Mounting /dev\n"); | ||
323 | char *dev; | ||
324 | if (asprintf(&dev, "%s/dev", oroot) == -1) | ||
325 | errExit("asprintf"); | ||
326 | if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
327 | errExit("mounting /dev"); | ||
328 | fs_logger("whitelist /dev"); | ||
329 | |||
330 | // mount-bind run directory | ||
331 | if (arg_debug) | ||
332 | printf("Mounting /run\n"); | ||
333 | char *run; | ||
334 | if (asprintf(&run, "%s/run", oroot) == -1) | ||
335 | errExit("asprintf"); | ||
336 | if (mount("/run", run, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
337 | errExit("mounting /run"); | ||
338 | fs_logger("whitelist /run"); | ||
339 | |||
340 | // mount-bind tmp directory | ||
341 | if (arg_debug) | ||
342 | printf("Mounting /tmp\n"); | ||
343 | char *tmp; | ||
344 | if (asprintf(&tmp, "%s/tmp", oroot) == -1) | ||
345 | errExit("asprintf"); | ||
346 | if (mount("/tmp", tmp, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
347 | errExit("mounting /tmp"); | ||
348 | fs_logger("whitelist /tmp"); | ||
349 | |||
350 | // chroot in the new filesystem | ||
351 | __gcov_flush(); | ||
352 | |||
353 | if (chroot(oroot) == -1) | ||
354 | errExit("chroot"); | ||
355 | |||
356 | // mount a new proc filesystem | ||
357 | if (arg_debug) | ||
358 | printf("Mounting /proc filesystem representing the PID namespace\n"); | ||
359 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) | ||
360 | errExit("mounting /proc"); | ||
361 | |||
362 | // update /var directory in order to support multiple sandboxes running on the same root directory | ||
363 | // if (!arg_private_dev) | ||
364 | // fs_dev_shm(); | ||
365 | fs_var_lock(); | ||
366 | if (!arg_keep_var_tmp) | ||
367 | fs_var_tmp(); | ||
368 | if (!arg_writable_var_log) | ||
369 | fs_var_log(); | ||
370 | fs_var_lib(); | ||
371 | fs_var_cache(); | ||
372 | fs_var_utmp(); | ||
373 | fs_machineid(); | ||
374 | |||
375 | // don't leak user information | ||
376 | restrict_users(); | ||
377 | |||
378 | // when starting as root, firejail config is not disabled; | ||
379 | if (getuid() != 0) | ||
380 | disable_config(); | ||
381 | |||
382 | // cleanup and exit | ||
383 | free(option); | ||
384 | free(odiff); | ||
385 | free(owork); | ||
386 | free(dev); | ||
387 | free(run); | ||
388 | free(tmp); | ||
389 | } | ||
390 | |||
391 | |||
392 | static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { | ||
393 | (void) sb; | ||
394 | (void) typeflag; | ||
395 | (void) ftwbuf; | ||
396 | assert(fpath); | ||
397 | |||
398 | if (strcmp(fpath, ".") == 0) // rmdir would fail with EINVAL | ||
399 | return 0; | ||
400 | |||
401 | if (remove(fpath)) { // removes the link not the actual file | ||
402 | fprintf(stderr, "Error: cannot remove file: %s\n", strerror(errno)); | ||
403 | exit(1); | ||
404 | } | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | int remove_overlay_directory(void) { | ||
410 | EUID_ASSERT(); | ||
411 | sleep(1); | ||
412 | |||
413 | char *path; | ||
414 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) | ||
415 | errExit("asprintf"); | ||
416 | |||
417 | if (access(path, F_OK) == 0) { | ||
418 | pid_t child = fork(); | ||
419 | if (child < 0) | ||
420 | errExit("fork"); | ||
421 | if (child == 0) { | ||
422 | // open ~/.firejail | ||
423 | int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); | ||
424 | if (fd == -1) { | ||
425 | fprintf(stderr, "Error: cannot open %s\n", path); | ||
426 | exit(1); | ||
427 | } | ||
428 | struct stat s; | ||
429 | if (fstat(fd, &s) == -1) | ||
430 | errExit("fstat"); | ||
431 | if (!S_ISDIR(s.st_mode)) { | ||
432 | if (S_ISLNK(s.st_mode)) | ||
433 | fprintf(stderr, "Error: %s is a symbolic link\n", path); | ||
434 | else | ||
435 | fprintf(stderr, "Error: %s is not a directory\n", path); | ||
436 | exit(1); | ||
437 | } | ||
438 | if (s.st_uid != getuid()) { | ||
439 | fprintf(stderr, "Error: %s is not owned by the current user\n", path); | ||
440 | exit(1); | ||
441 | } | ||
442 | // chdir to ~/.firejail | ||
443 | if (fchdir(fd) == -1) | ||
444 | errExit("fchdir"); | ||
445 | close(fd); | ||
446 | |||
447 | EUID_ROOT(); | ||
448 | // FTW_PHYS - do not follow symbolic links | ||
449 | if (nftw(".", remove_callback, 64, FTW_DEPTH | FTW_PHYS) == -1) | ||
450 | errExit("nftw"); | ||
451 | |||
452 | EUID_USER(); | ||
453 | // remove ~/.firejail | ||
454 | if (rmdir(path) == -1) | ||
455 | errExit("rmdir"); | ||
456 | |||
457 | __gcov_flush(); | ||
458 | |||
459 | _exit(0); | ||
460 | } | ||
461 | // wait for the child to finish | ||
462 | waitpid(child, NULL, 0); | ||
463 | // check if ~/.firejail was deleted | ||
464 | if (access(path, F_OK) == 0) | ||
465 | return 1; | ||
466 | } | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | #endif // HAVE_OVERLAYFS | ||
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c index 8f939b5f5..4cecea9ce 100644 --- a/src/firejail/fs_trace.c +++ b/src/firejail/fs_trace.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,26 +20,31 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <glob.h> | 23 | #include <glob.h> |
25 | #include <dirent.h> | 24 | #include <dirent.h> |
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
27 | #include <pwd.h> | 26 | #include <pwd.h> |
28 | 27 | ||
29 | void fs_trace_preload(void) { | 28 | // create an empty /etc/ld.so.preload |
29 | void fs_trace_touch_preload(void) { | ||
30 | create_empty_file_as_root("/etc/ld.so.preload", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
31 | } | ||
32 | |||
33 | void fs_trace_touch_or_store_preload(void) { | ||
30 | struct stat s; | 34 | struct stat s; |
31 | 35 | ||
32 | // create an empty /etc/ld.so.preload | 36 | if (stat("/etc/ld.so.preload", &s) != 0) { |
33 | if (stat("/etc/ld.so.preload", &s)) { | 37 | fs_trace_touch_preload(); |
34 | if (arg_debug) | 38 | return; |
35 | printf("Creating an empty /etc/ld.so.preload file\n"); | 39 | } |
36 | /* coverity[toctou] */ | 40 | |
37 | FILE *fp = fopen("/etc/ld.so.preload", "w"); | 41 | if (s.st_size == 0) |
38 | if (!fp) | 42 | return; |
39 | errExit("fopen"); | 43 | |
40 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 44 | // create a copy of /etc/ld.so.preload |
41 | fclose(fp); | 45 | if (copy_file("/etc/ld.so.preload", RUN_LDPRELOAD_FILE, 0, 0, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { |
42 | fs_logger("touch /etc/ld.so.preload"); | 46 | fprintf(stderr, "Error: cannot copy /etc/ld.so.preload file\n"); |
47 | exit(1); | ||
43 | } | 48 | } |
44 | } | 49 | } |
45 | 50 | ||
@@ -48,7 +53,7 @@ void fs_tracefile(void) { | |||
48 | if (arg_debug) | 53 | if (arg_debug) |
49 | printf("Creating an empty trace log file: %s\n", arg_tracefile); | 54 | printf("Creating an empty trace log file: %s\n", arg_tracefile); |
50 | EUID_USER(); | 55 | EUID_USER(); |
51 | int fd = open(arg_tracefile, O_CREAT|O_WRONLY|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 56 | int fd = open(arg_tracefile, O_CREAT|O_WRONLY|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
52 | if (fd == -1) { | 57 | if (fd == -1) { |
53 | perror("open"); | 58 | perror("open"); |
54 | fprintf(stderr, "Error: cannot open trace log file %s for writing\n", arg_tracefile); | 59 | fprintf(stderr, "Error: cannot open trace log file %s for writing\n", arg_tracefile); |
@@ -64,20 +69,16 @@ void fs_tracefile(void) { | |||
64 | if (ftruncate(fd, 0) == -1) | 69 | if (ftruncate(fd, 0) == -1) |
65 | errExit("ftruncate"); | 70 | errExit("ftruncate"); |
66 | EUID_ROOT(); | 71 | EUID_ROOT(); |
67 | FILE *fp = fopen(RUN_TRACE_FILE, "w"); | 72 | FILE *fp = fopen(RUN_TRACE_FILE, "we"); |
68 | if (!fp) | 73 | if (!fp) |
69 | errExit("fopen " RUN_TRACE_FILE); | 74 | errExit("fopen " RUN_TRACE_FILE); |
70 | fclose(fp); | 75 | fclose(fp); |
71 | fs_logger2("touch ", arg_tracefile); | 76 | fs_logger2("touch", arg_tracefile); |
72 | // mount using the symbolic link in /proc/self/fd | 77 | // mount using the symbolic link in /proc/self/fd |
73 | if (arg_debug) | 78 | if (arg_debug) |
74 | printf("Bind mount %s to %s\n", arg_tracefile, RUN_TRACE_FILE); | 79 | printf("Bind mount %s to %s\n", arg_tracefile, RUN_TRACE_FILE); |
75 | char *proc; | 80 | if (bind_mount_fd_to_path(fd, RUN_TRACE_FILE)) |
76 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
77 | errExit("asprintf"); | ||
78 | if (mount(proc, RUN_TRACE_FILE, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
79 | errExit("mount bind " RUN_TRACE_FILE); | 81 | errExit("mount bind " RUN_TRACE_FILE); |
80 | free(proc); | ||
81 | close(fd); | 82 | close(fd); |
82 | // now that RUN_TRACE_FILE is user-writable, mount it noexec | 83 | // now that RUN_TRACE_FILE is user-writable, mount it noexec |
83 | fs_remount(RUN_TRACE_FILE, MOUNT_NOEXEC, 0); | 84 | fs_remount(RUN_TRACE_FILE, MOUNT_NOEXEC, 0); |
@@ -88,7 +89,7 @@ void fs_trace(void) { | |||
88 | if (arg_debug) | 89 | if (arg_debug) |
89 | printf("Create the new ld.so.preload file\n"); | 90 | printf("Create the new ld.so.preload file\n"); |
90 | 91 | ||
91 | FILE *fp = fopen(RUN_LDPRELOAD_FILE, "w"); | 92 | FILE *fp = fopen(RUN_LDPRELOAD_FILE, "ae"); |
92 | if (!fp) | 93 | if (!fp) |
93 | errExit("fopen"); | 94 | errExit("fopen"); |
94 | const char *prefix = RUN_FIREJAIL_LIB_DIR; | 95 | const char *prefix = RUN_FIREJAIL_LIB_DIR; |
@@ -105,7 +106,7 @@ void fs_trace(void) { | |||
105 | fmessage("Post-exec seccomp protector enabled\n"); | 106 | fmessage("Post-exec seccomp protector enabled\n"); |
106 | } | 107 | } |
107 | 108 | ||
108 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 109 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
109 | fclose(fp); | 110 | fclose(fp); |
110 | 111 | ||
111 | // mount the new preload file | 112 | // mount the new preload file |
diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c index f07581cd8..9523875d7 100644 --- a/src/firejail/fs_var.c +++ b/src/firejail/fs_var.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,7 +20,6 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <glob.h> | 23 | #include <glob.h> |
25 | #include <dirent.h> | 24 | #include <dirent.h> |
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
@@ -127,17 +126,17 @@ void fs_var_log(void) { | |||
127 | 126 | ||
128 | // create an empty /var/log/wtmp file | 127 | // create an empty /var/log/wtmp file |
129 | /* coverity[toctou] */ | 128 | /* coverity[toctou] */ |
130 | FILE *fp = fopen("/var/log/wtmp", "w"); | 129 | FILE *fp = fopen("/var/log/wtmp", "wxe"); |
131 | if (fp) { | 130 | if (fp) { |
132 | SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH); | 131 | SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); |
133 | fclose(fp); | 132 | fclose(fp); |
134 | } | 133 | } |
135 | fs_logger("touch /var/log/wtmp"); | 134 | fs_logger("touch /var/log/wtmp"); |
136 | 135 | ||
137 | // create an empty /var/log/btmp file | 136 | // create an empty /var/log/btmp file |
138 | fp = fopen("/var/log/btmp", "w"); | 137 | fp = fopen("/var/log/btmp", "wxe"); |
139 | if (fp) { | 138 | if (fp) { |
140 | SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP); | 139 | SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); |
141 | fclose(fp); | 140 | fclose(fp); |
142 | } | 141 | } |
143 | fs_logger("touch /var/log/btmp"); | 142 | fs_logger("touch /var/log/btmp"); |
@@ -158,8 +157,7 @@ void fs_var_lib(void) { | |||
158 | fs_logger("tmpfs /var/lib/dhcp"); | 157 | fs_logger("tmpfs /var/lib/dhcp"); |
159 | 158 | ||
160 | // isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file | 159 | // isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file |
161 | FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "w"); | 160 | FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "wxe"); |
162 | |||
163 | if (fp) { | 161 | if (fp) { |
164 | fprintf(fp, "\n"); | 162 | fprintf(fp, "\n"); |
165 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); | 163 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); |
@@ -287,7 +285,7 @@ void fs_var_utmp(void) { | |||
287 | if (stat(UTMP_FILE, &s) == 0) | 285 | if (stat(UTMP_FILE, &s) == 0) |
288 | utmp_group = s.st_gid; | 286 | utmp_group = s.st_gid; |
289 | else { | 287 | else { |
290 | fwarning("cannot find /var/run/utmp\n"); | 288 | fwarning("cannot find %s\n", UTMP_FILE); |
291 | return; | 289 | return; |
292 | } | 290 | } |
293 | 291 | ||
@@ -296,7 +294,7 @@ void fs_var_utmp(void) { | |||
296 | printf("Create the new utmp file\n"); | 294 | printf("Create the new utmp file\n"); |
297 | 295 | ||
298 | /* coverity[toctou] */ | 296 | /* coverity[toctou] */ |
299 | FILE *fp = fopen(RUN_UTMP_FILE, "w"); | 297 | FILE *fp = fopen(RUN_UTMP_FILE, "we"); |
300 | if (!fp) | 298 | if (!fp) |
301 | errExit("fopen"); | 299 | errExit("fopen"); |
302 | 300 | ||
@@ -315,7 +313,7 @@ void fs_var_utmp(void) { | |||
315 | // save new utmp file | 313 | // save new utmp file |
316 | int rv = fwrite(&u_boot, sizeof(u_boot), 1, fp); | 314 | int rv = fwrite(&u_boot, sizeof(u_boot), 1, fp); |
317 | (void) rv; | 315 | (void) rv; |
318 | SET_PERMS_STREAM(fp, 0, utmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH); | 316 | SET_PERMS_STREAM(fp, 0, utmp_group, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); |
319 | fclose(fp); | 317 | fclose(fp); |
320 | 318 | ||
321 | // mount the new utmp file | 319 | // mount the new utmp file |
@@ -323,5 +321,9 @@ void fs_var_utmp(void) { | |||
323 | printf("Mount the new utmp file\n"); | 321 | printf("Mount the new utmp file\n"); |
324 | if (mount(RUN_UTMP_FILE, UTMP_FILE, NULL, MS_BIND|MS_NOSUID|MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) | 322 | if (mount(RUN_UTMP_FILE, UTMP_FILE, NULL, MS_BIND|MS_NOSUID|MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) |
325 | errExit("mount bind utmp"); | 323 | errExit("mount bind utmp"); |
326 | fs_logger("create /var/run/utmp"); | 324 | fs_logger2("create", UTMP_FILE); |
325 | |||
326 | // blacklist RUN_UTMP_FILE | ||
327 | if (mount(RUN_RO_FILE, RUN_UTMP_FILE, NULL, MS_BIND, "mode=400,gid=0") < 0) | ||
328 | errExit("mount bind"); | ||
327 | } | 329 | } |
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index 698d47b69..3377b2592 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -16,63 +16,70 @@ | |||
16 | * You should have received a copy of the GNU General Public License along | 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., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <fnmatch.h> | 23 | #include <fnmatch.h> |
25 | #include <glob.h> | 24 | #include <glob.h> |
26 | #include <dirent.h> | ||
27 | #include <errno.h> | 25 | #include <errno.h> |
28 | 26 | ||
29 | #include <fcntl.h> | 27 | #include <fcntl.h> |
30 | #ifndef O_PATH | 28 | #ifndef O_PATH |
31 | # define O_PATH 010000000 | 29 | #define O_PATH 010000000 |
32 | #endif | 30 | #endif |
33 | 31 | ||
32 | #define TOP_MAX 64 // maximum number of top level directories | ||
33 | |||
34 | // mountinfo functionality test; | 34 | // mountinfo functionality test; |
35 | // 1. enable TEST_MOUNTINFO definition | 35 | // 1. enable TEST_MOUNTINFO definition |
36 | // 2. run firejail --whitelist=/any/directory | 36 | // 2. run firejail --whitelist=/any/directory |
37 | //#define TEST_MOUNTINFO | 37 | //#define TEST_MOUNTINFO |
38 | 38 | ||
39 | #define EMPTY_STRING ("") | 39 | static size_t homedir_len = 0; // cache length of homedir string |
40 | static size_t homedir_len; // cache length of homedir string | 40 | static size_t runuser_len = 0; // cache length of runuser string |
41 | static size_t runuser_len; // cache length of runuser string | 41 | static char *runuser = NULL; |
42 | static char *runuser; | ||
43 | 42 | ||
44 | 43 | ||
45 | static int mkpath(const char* path, mode_t mode) { | ||
46 | assert(path && *path); | ||
47 | mode |= 0111; | ||
48 | 44 | ||
49 | // create directories with uid/gid as root, or as current user if inside home or run/user/$uid directory | 45 | static void whitelist_error(const char *path) { |
50 | int userprivs = 0; | 46 | assert(path); |
51 | if ((strncmp(path, cfg.homedir, homedir_len) == 0 && path[homedir_len] == '/') || | 47 | |
52 | (strncmp(path, runuser, runuser_len) == 0 && path[runuser_len] == '/')) { | 48 | fprintf(stderr, "Error: invalid whitelist path %s\n", path); |
53 | EUID_USER(); | 49 | exit(1); |
54 | userprivs = 1; | 50 | } |
51 | |||
52 | static int whitelist_mkpath(const char *parentdir, const char *relpath, mode_t mode) { | ||
53 | // starting from top level directory | ||
54 | int parentfd = safer_openat(-1, parentdir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
55 | if (parentfd < 0) | ||
56 | errExit("open"); | ||
57 | |||
58 | // top level directory mount id | ||
59 | int mountid = get_mount_id(parentfd); | ||
60 | if (mountid < 0) { | ||
61 | close(parentfd); | ||
62 | return -1; | ||
55 | } | 63 | } |
56 | 64 | ||
57 | // work on a copy of the path | 65 | // work on a copy of the path |
58 | char *dup = strdup(path); | 66 | char *dup = strdup(relpath); |
59 | if (!dup) | 67 | if (!dup) |
60 | errExit("strdup"); | 68 | errExit("strdup"); |
61 | 69 | ||
62 | // don't create the last path element | 70 | // only create leading directories, don't create the file |
63 | char *p = strrchr(dup, '/'); | 71 | char *p = strrchr(dup, '/'); |
64 | assert(p); | 72 | if (!p) { // nothing to do |
73 | free(dup); | ||
74 | return parentfd; | ||
75 | } | ||
65 | *p = '\0'; | 76 | *p = '\0'; |
66 | 77 | ||
67 | int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC); | ||
68 | if (parentfd == -1) | ||
69 | errExit("open"); | ||
70 | |||
71 | // traverse the path, return -1 if a symlink is encountered | 78 | // traverse the path, return -1 if a symlink is encountered |
72 | int done = 0; | ||
73 | int fd = -1; | 79 | int fd = -1; |
80 | int done = 0; | ||
74 | char *tok = strtok(dup, "/"); | 81 | char *tok = strtok(dup, "/"); |
75 | assert(tok); // path is no top level directory | 82 | assert(tok); |
76 | while (tok) { | 83 | while (tok) { |
77 | // create the directory if necessary | 84 | // create the directory if necessary |
78 | if (mkdirat(parentfd, tok, mode) == -1) { | 85 | if (mkdirat(parentfd, tok, mode) == -1) { |
@@ -81,9 +88,6 @@ static int mkpath(const char* path, mode_t mode) { | |||
81 | perror("mkdir"); | 88 | perror("mkdir"); |
82 | close(parentfd); | 89 | close(parentfd); |
83 | free(dup); | 90 | free(dup); |
84 | if (userprivs) { | ||
85 | EUID_ROOT(); | ||
86 | } | ||
87 | return -1; | 91 | return -1; |
88 | } | 92 | } |
89 | } | 93 | } |
@@ -96,9 +100,15 @@ static int mkpath(const char* path, mode_t mode) { | |||
96 | perror("open"); | 100 | perror("open"); |
97 | close(parentfd); | 101 | close(parentfd); |
98 | free(dup); | 102 | free(dup); |
99 | if (userprivs) { | 103 | return -1; |
100 | EUID_ROOT(); | 104 | } |
101 | } | 105 | // different mount id indicates earlier whitelist mount |
106 | if (get_mount_id(fd) != mountid) { | ||
107 | if (arg_debug || arg_debug_whitelists) | ||
108 | printf("Debug %d: whitelisted already\n", __LINE__); | ||
109 | close(parentfd); | ||
110 | close(fd); | ||
111 | free(dup); | ||
102 | return -1; | 112 | return -1; |
103 | } | 113 | } |
104 | // move on to next path segment | 114 | // move on to next path segment |
@@ -107,199 +117,110 @@ static int mkpath(const char* path, mode_t mode) { | |||
107 | tok = strtok(NULL, "/"); | 117 | tok = strtok(NULL, "/"); |
108 | } | 118 | } |
109 | 119 | ||
110 | if (done) | 120 | if (done) { |
111 | fs_logger2("mkpath", path); | 121 | char *abspath; |
122 | if (asprintf(&abspath, "%s/%s", parentdir, relpath) < 0) | ||
123 | errExit("asprintf"); | ||
124 | fs_logger2("mkpath", abspath); | ||
125 | free(abspath); | ||
126 | } | ||
112 | 127 | ||
113 | free(dup); | 128 | free(dup); |
114 | if (userprivs) { | ||
115 | EUID_ROOT(); | ||
116 | } | ||
117 | return fd; | 129 | return fd; |
118 | } | 130 | } |
119 | 131 | ||
120 | static void whitelist_path(ProfileEntry *entry) { | 132 | static void whitelist_file(const TopDir * const top, const char *path) { |
121 | assert(entry); | 133 | EUID_ASSERT(); |
122 | const char *path = entry->data + 10; | 134 | assert(top && path); |
123 | const char *fname; | ||
124 | char *wfile = NULL; | ||
125 | |||
126 | if (entry->wldir == WLDIR_HOME) { | ||
127 | if (strncmp(path, cfg.homedir, homedir_len) != 0 || path[homedir_len] != '/') | ||
128 | // either symlink pointing outside home directory | ||
129 | // or entire home directory, skip the mount | ||
130 | return; | ||
131 | |||
132 | fname = path + homedir_len + 1; // strlen("/home/user/") | ||
133 | |||
134 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_HOME_USER_DIR, fname) == -1) | ||
135 | errExit("asprintf"); | ||
136 | } | ||
137 | else if (entry->wldir == WLDIR_TMP) { | ||
138 | fname = path + 5; // strlen("/tmp/") | ||
139 | |||
140 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_TMP_DIR, fname) == -1) | ||
141 | errExit("asprintf"); | ||
142 | } | ||
143 | else if (entry->wldir == WLDIR_MEDIA) { | ||
144 | fname = path + 7; // strlen("/media/") | ||
145 | 135 | ||
146 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_MEDIA_DIR, fname) == -1) | 136 | // check if path is inside top level directory |
147 | errExit("asprintf"); | 137 | size_t top_pathlen = strlen(top->path); |
148 | } | 138 | if (strncmp(top->path, path, top_pathlen) != 0 || path[top_pathlen] != '/') |
149 | else if (entry->wldir == WLDIR_MNT) { | 139 | return; |
150 | fname = path + 5; // strlen("/mnt/") | 140 | const char *relpath = path + top_pathlen + 1; |
151 | 141 | ||
152 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_MNT_DIR, fname) == -1) | 142 | // open mount source, using a file descriptor that refers to the |
153 | errExit("asprintf"); | 143 | // top level directory |
154 | } | 144 | // as the top level directory was opened before mounting the tmpfs |
155 | else if (entry->wldir == WLDIR_VAR) { | 145 | // we still have full access to all directory contents |
156 | if (strncmp(path, "/var/", 5) != 0) | 146 | // take care to not follow symbolic links (top->fd was obtained without |
157 | // symlink pointing outside /var, skip the mount | 147 | // following a link, too) |
158 | return; | 148 | int fd = safer_openat(top->fd, relpath, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
159 | |||
160 | fname = path + 5; // strlen("/var/") | ||
161 | |||
162 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_VAR_DIR, fname) == -1) | ||
163 | errExit("asprintf"); | ||
164 | } | ||
165 | else if (entry->wldir == WLDIR_DEV) { | ||
166 | if (strncmp(path, "/dev/", 5) != 0) | ||
167 | // symlink pointing outside /dev, skip the mount | ||
168 | return; | ||
169 | |||
170 | fname = path + 5; // strlen("/dev/") | ||
171 | |||
172 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_DEV_DIR, fname) == -1) | ||
173 | errExit("asprintf"); | ||
174 | } | ||
175 | else if (entry->wldir == WLDIR_OPT) { | ||
176 | fname = path + 5; // strlen("/opt/") | ||
177 | |||
178 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_OPT_DIR, fname) == -1) | ||
179 | errExit("asprintf"); | ||
180 | } | ||
181 | else if (entry->wldir == WLDIR_SRV) { | ||
182 | fname = path + 5; // strlen("/srv/") | ||
183 | |||
184 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_SRV_DIR, fname) == -1) | ||
185 | errExit("asprintf"); | ||
186 | } | ||
187 | else if (entry->wldir == WLDIR_ETC) { | ||
188 | if (strncmp(path, "/etc/", 5) != 0) | ||
189 | // symlink pointing outside /etc, skip the mount | ||
190 | return; | ||
191 | |||
192 | fname = path + 5; // strlen("/etc/") | ||
193 | |||
194 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_ETC_DIR, fname) == -1) | ||
195 | errExit("asprintf"); | ||
196 | } | ||
197 | else if (entry->wldir == WLDIR_SHARE) { | ||
198 | fname = path + 11; // strlen("/usr/share/") | ||
199 | |||
200 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_SHARE_DIR, fname) == -1) | ||
201 | errExit("asprintf"); | ||
202 | } | ||
203 | else if (entry->wldir == WLDIR_MODULE) { | ||
204 | fname = path + 12; // strlen("/sys/module/") | ||
205 | |||
206 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_MODULE_DIR, fname) == -1) | ||
207 | errExit("asprintf"); | ||
208 | } | ||
209 | else if (entry->wldir == WLDIR_RUN) { | ||
210 | fname = path + runuser_len + 1; // strlen("/run/user/$uid/") | ||
211 | |||
212 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_RUN_USER_DIR, fname) == -1) | ||
213 | errExit("asprintf"); | ||
214 | } | ||
215 | assert(wfile); | ||
216 | |||
217 | if (arg_debug || arg_debug_whitelists) | ||
218 | printf("Whitelisting %s\n", path); | ||
219 | |||
220 | // confirm again the mount source exists and there is no symlink | ||
221 | struct stat wfilestat; | ||
222 | EUID_USER(); | ||
223 | int fd = safe_fd(wfile, O_PATH|O_NOFOLLOW|O_CLOEXEC); | ||
224 | EUID_ROOT(); | ||
225 | if (fd == -1) { | 149 | if (fd == -1) { |
226 | if (arg_debug || arg_debug_whitelists) | 150 | if (arg_debug || arg_debug_whitelists) |
227 | printf("Debug %d: skip whitelisting of %s\n", __LINE__, path); | 151 | printf("Debug %d: skip whitelist %s\n", __LINE__, path); |
228 | free(wfile); | ||
229 | return; | 152 | return; |
230 | } | 153 | } |
231 | if (fstat(fd, &wfilestat) == -1) | 154 | struct stat s; |
155 | if (fstat(fd, &s) == -1) | ||
232 | errExit("fstat"); | 156 | errExit("fstat"); |
233 | close(fd); | 157 | if (S_ISLNK(s.st_mode)) { |
234 | if (S_ISLNK(wfilestat.st_mode)) { | ||
235 | if (arg_debug || arg_debug_whitelists) | 158 | if (arg_debug || arg_debug_whitelists) |
236 | printf("Debug %d: skip whitelisting of %s\n", __LINE__, path); | 159 | printf("Debug %d: skip whitelist %s\n", __LINE__, path); |
237 | free(wfile); | 160 | close(fd); |
238 | return; | 161 | return; |
239 | } | 162 | } |
240 | 163 | ||
241 | // create path of the mount target if necessary | 164 | // now modify the tmpfs: |
242 | int fd2 = mkpath(path, 0755); | 165 | // create mount target as root, except if inside home or run/user/$UID directory |
166 | if (strcmp(top->path, cfg.homedir) != 0 && | ||
167 | strcmp(top->path, runuser) != 0) | ||
168 | EUID_ROOT(); | ||
169 | |||
170 | // create path of the mount target | ||
171 | int fd2 = whitelist_mkpath(top->path, relpath, 0755); | ||
243 | if (fd2 == -1) { | 172 | if (fd2 == -1) { |
244 | // something went wrong during path creation or a symlink was found; | ||
245 | // if there is a symlink somewhere in the path of the mount target, | ||
246 | // assume the file is whitelisted already | ||
247 | if (arg_debug || arg_debug_whitelists) | 173 | if (arg_debug || arg_debug_whitelists) |
248 | printf("Debug %d: skip whitelisting of %s\n", __LINE__, path); | 174 | printf("Debug %d: skip whitelist %s\n", __LINE__, path); |
249 | free(wfile); | 175 | close(fd); |
176 | EUID_USER(); | ||
250 | return; | 177 | return; |
251 | } | 178 | } |
252 | 179 | ||
253 | // get file name of the mount target | 180 | // get file name of the mount target |
254 | const char *file = gnu_basename(path); | 181 | const char *file = gnu_basename(relpath); |
255 | 182 | ||
256 | // create the mount target if necessary and open it, a symlink is rejected | 183 | // create mount target itself if necessary |
184 | // and open it, a symlink is not allowed | ||
257 | int fd3 = -1; | 185 | int fd3 = -1; |
258 | if (S_ISDIR(wfilestat.st_mode)) { | 186 | if (S_ISDIR(s.st_mode)) { |
259 | // directory foo can exist already: | 187 | // directory bar can exist already: |
260 | // firejail --whitelist=/foo/bar --whitelist=/foo | 188 | // firejail --whitelist=/foo/bar/baz --whitelist=/foo/bar |
261 | if (mkdirat(fd2, file, 0755) == -1 && errno != EEXIST) { | 189 | if (mkdirat(fd2, file, 0755) == -1 && errno != EEXIST) { |
262 | if (arg_debug || arg_debug_whitelists) { | 190 | if (arg_debug || arg_debug_whitelists) { |
263 | perror("mkdir"); | 191 | perror("mkdir"); |
264 | printf("Debug %d: skip whitelisting of %s\n", __LINE__, path); | 192 | printf("Debug %d: skip whitelist %s\n", __LINE__, path); |
265 | } | 193 | } |
194 | close(fd); | ||
266 | close(fd2); | 195 | close(fd2); |
267 | free(wfile); | 196 | EUID_USER(); |
268 | return; | 197 | return; |
269 | } | 198 | } |
270 | fd3 = openat(fd2, file, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 199 | fd3 = openat(fd2, file, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
271 | } | 200 | } |
272 | else { | 201 | else |
273 | // create an empty file, fails with EEXIST if it is whitelisted already: | 202 | // create an empty file |
274 | // firejail --whitelist=/foo --whitelist=/foo/bar | 203 | // fails with EEXIST if it is whitelisted already |
275 | fd3 = openat(fd2, file, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR|S_IWUSR); | 204 | fd3 = openat(fd2, file, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR|S_IWUSR); |
276 | } | ||
277 | 205 | ||
278 | if (fd3 == -1) { | 206 | if (fd3 == -1) { |
279 | if (arg_debug || arg_debug_whitelists) { | 207 | if (errno != EEXIST && (arg_debug || arg_debug_whitelists)) { |
280 | if (errno != EEXIST) { | 208 | perror("open"); |
281 | perror("open"); | 209 | printf("Debug %d: skip whitelist %s\n", __LINE__, path); |
282 | printf("Debug %d: skip whitelisting of %s\n", __LINE__, path); | ||
283 | } | ||
284 | } | 210 | } |
211 | close(fd); | ||
285 | close(fd2); | 212 | close(fd2); |
286 | free(wfile); | 213 | EUID_USER(); |
287 | return; | 214 | return; |
288 | } | 215 | } |
289 | close(fd2); | 216 | close(fd2); |
290 | 217 | ||
291 | fs_logger2("whitelist", path); | 218 | if (arg_debug || arg_debug_whitelists) |
292 | 219 | printf("Whitelisting %s\n", path); | |
293 | // in order to make this mount resilient against symlink attacks, use | 220 | EUID_ROOT(); |
294 | // a magic link in /proc/self/fd instead of mounting on path directly | 221 | if (bind_mount_by_fd(fd, fd3)) |
295 | char *proc; | ||
296 | if (asprintf(&proc, "/proc/self/fd/%d", fd3) == -1) | ||
297 | errExit("asprintf"); | ||
298 | if (mount(wfile, proc, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
299 | errExit("mount bind"); | 222 | errExit("mount bind"); |
300 | free(proc); | 223 | EUID_USER(); |
301 | close(fd3); | ||
302 | |||
303 | // check the last mount operation | 224 | // check the last mount operation |
304 | MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found | 225 | MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found |
305 | #ifdef TEST_MOUNTINFO | 226 | #ifdef TEST_MOUNTINFO |
@@ -316,37 +237,54 @@ static void whitelist_path(ProfileEntry *entry) { | |||
316 | // - there should be more than one '/' char in dest string | 237 | // - there should be more than one '/' char in dest string |
317 | if (mptr->dir == strrchr(mptr->dir, '/')) | 238 | if (mptr->dir == strrchr(mptr->dir, '/')) |
318 | errLogExit("invalid whitelist mount"); | 239 | errLogExit("invalid whitelist mount"); |
319 | // confirm the right file was mounted by comparing device and inode numbers | 240 | close(fd); |
320 | int fd4 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); | 241 | close(fd3); |
321 | if (fd4 == -1) | 242 | fs_logger2("whitelist", path); |
322 | errExit("safe_fd"); | ||
323 | struct stat s; | ||
324 | if (fstat(fd4, &s) == -1) | ||
325 | errExit("fstat"); | ||
326 | if (s.st_dev != wfilestat.st_dev || s.st_ino != wfilestat.st_ino) | ||
327 | errLogExit("invalid whitelist mount"); | ||
328 | close(fd4); | ||
329 | |||
330 | free(wfile); | ||
331 | return; | ||
332 | } | 243 | } |
333 | 244 | ||
334 | static void whitelist_home(int topdir) { | 245 | static void whitelist_symlink(const TopDir * const top, const char *link, const char *target) { |
335 | ProfileEntry entry; | 246 | EUID_ASSERT(); |
336 | memset(&entry, 0, sizeof(entry)); | 247 | assert(top && link && target); |
337 | char *cmd; | 248 | |
338 | if (asprintf(&cmd, "whitelist %s", cfg.homedir) == -1) | 249 | // confirm link is inside top level directory |
339 | errExit("asprintf"); | 250 | // this should never fail |
340 | entry.data = cmd; | 251 | size_t top_pathlen = strlen(top->path); |
341 | entry.wldir = topdir; | 252 | assert(strncmp(top->path, link, top_pathlen) == 0 && link[top_pathlen] == '/'); |
342 | // creates path owned by root, except homedir is inside /run/user/$uid | 253 | |
343 | // does nothing if homedir does not exist | 254 | const char *relpath = link + top_pathlen + 1; |
344 | whitelist_path(&entry); | 255 | |
345 | free(cmd); | 256 | // create link as root, except if inside home or run/user/$UID directory |
346 | } | 257 | if (strcmp(top->path, cfg.homedir) != 0 && |
258 | strcmp(top->path, runuser) != 0) | ||
259 | EUID_ROOT(); | ||
347 | 260 | ||
261 | int fd = whitelist_mkpath(top->path, relpath, 0755); | ||
262 | if (fd == -1) { | ||
263 | if (arg_debug || arg_debug_whitelists) | ||
264 | printf("Debug %d: cannot create symbolic link %s\n", __LINE__, link); | ||
265 | EUID_USER(); | ||
266 | return; | ||
267 | } | ||
268 | |||
269 | // get file name of symlink | ||
270 | const char *file = gnu_basename(relpath); | ||
271 | |||
272 | // create the link | ||
273 | if (symlinkat(target, fd, file) == -1) { | ||
274 | if (arg_debug || arg_debug_whitelists) { | ||
275 | perror("symlink"); | ||
276 | printf("Debug %d: cannot create symbolic link %s\n", __LINE__, link); | ||
277 | } | ||
278 | } | ||
279 | else if (arg_debug || arg_debug_whitelists) | ||
280 | printf("Created symbolic link %s -> %s\n", link, target); | ||
281 | |||
282 | close(fd); | ||
283 | EUID_USER(); | ||
284 | } | ||
348 | 285 | ||
349 | static void globbing(const char *pattern) { | 286 | static void globbing(const char *pattern) { |
287 | EUID_ASSERT(); | ||
350 | assert(pattern); | 288 | assert(pattern); |
351 | 289 | ||
352 | // globbing | 290 | // globbing |
@@ -363,6 +301,11 @@ static void globbing(const char *pattern) { | |||
363 | // testing for GLOB_NOCHECK - no pattern matched returns the original pattern | 301 | // testing for GLOB_NOCHECK - no pattern matched returns the original pattern |
364 | if (strcmp(globbuf.gl_pathv[i], pattern) == 0) | 302 | if (strcmp(globbuf.gl_pathv[i], pattern) == 0) |
365 | continue; | 303 | continue; |
304 | // foo/* expands to foo/. and foo/.. | ||
305 | const char *base = gnu_basename(globbuf.gl_pathv[i]); | ||
306 | if (strcmp(base, ".") == 0 || | ||
307 | strcmp(base, "..") == 0) | ||
308 | continue; | ||
366 | 309 | ||
367 | // build the new profile command | 310 | // build the new profile command |
368 | char *newcmd; | 311 | char *newcmd; |
@@ -378,8 +321,237 @@ static void globbing(const char *pattern) { | |||
378 | globfree(&globbuf); | 321 | globfree(&globbuf); |
379 | } | 322 | } |
380 | 323 | ||
324 | // mount tmpfs on all top level directories | ||
325 | static void tmpfs_topdirs(const TopDir * const topdirs) { | ||
326 | int tmpfs_home = 0; | ||
327 | int tmpfs_runuser = 0; | ||
328 | |||
329 | int i; | ||
330 | for (i = 0; i < TOP_MAX && topdirs[i].path; i++) { | ||
331 | // do nested top level directories last | ||
332 | // this way '--whitelist=nested_top_level_dir' | ||
333 | // yields the full, unmodified directory | ||
334 | // instead of the tmpfs | ||
335 | if (strcmp(topdirs[i].path, cfg.homedir) == 0) { | ||
336 | tmpfs_home = 1; | ||
337 | continue; | ||
338 | } | ||
339 | if (strcmp(topdirs[i].path, runuser) == 0) { | ||
340 | tmpfs_runuser = 1; | ||
341 | continue; | ||
342 | } | ||
343 | |||
344 | // special case /run | ||
345 | // open /run/firejail, so it can be restored right after mounting the tmpfs | ||
346 | int fd = -1; | ||
347 | if (strcmp(topdirs[i].path, "/run") == 0) { | ||
348 | fd = open(RUN_FIREJAIL_DIR, O_PATH|O_CLOEXEC); | ||
349 | if (fd == -1) | ||
350 | errExit("open"); | ||
351 | } | ||
352 | |||
353 | // mount tmpfs | ||
354 | fs_tmpfs(topdirs[i].path, 0); | ||
355 | selinux_relabel_path(topdirs[i].path, topdirs[i].path); | ||
356 | |||
357 | // init tmpfs | ||
358 | if (strcmp(topdirs[i].path, "/run") == 0) { | ||
359 | // restore /run/firejail directory | ||
360 | EUID_ROOT(); | ||
361 | mkdir_attr(RUN_FIREJAIL_DIR, 0755, 0, 0); | ||
362 | if (bind_mount_fd_to_path(fd, RUN_FIREJAIL_DIR)) | ||
363 | errExit("mount bind"); | ||
364 | EUID_USER(); | ||
365 | close(fd); | ||
366 | fs_logger2("whitelist", RUN_FIREJAIL_DIR); | ||
367 | |||
368 | // restore /run/user/$UID directory | ||
369 | whitelist_file(&topdirs[i], runuser); | ||
370 | } | ||
371 | else if (strcmp(topdirs[i].path, "/tmp") == 0) { | ||
372 | // fix pam-tmpdir (#2685) | ||
373 | const char *env = env_get("TMP"); | ||
374 | if (env) { | ||
375 | // we allow TMP env set as /tmp/user/$UID and /tmp/$UID - see #4151 | ||
376 | char *pamtmpdir1; | ||
377 | if (asprintf(&pamtmpdir1, "/tmp/user/%u", getuid()) == -1) | ||
378 | errExit("asprintf"); | ||
379 | char *pamtmpdir2; | ||
380 | if (asprintf(&pamtmpdir2, "/tmp/%u", getuid()) == -1) | ||
381 | errExit("asprintf"); | ||
382 | if (strcmp(env, pamtmpdir1) == 0) { | ||
383 | // create empty user-owned /tmp/user/$UID directory | ||
384 | EUID_ROOT(); | ||
385 | mkdir_attr("/tmp/user", 0755, 0, 0); | ||
386 | selinux_relabel_path("/tmp/user", "/tmp/user"); | ||
387 | fs_logger("mkdir /tmp/user"); | ||
388 | mkdir_attr(pamtmpdir1, 0700, getuid(), 0); | ||
389 | selinux_relabel_path(pamtmpdir1, pamtmpdir1); | ||
390 | fs_logger2("mkdir", pamtmpdir1); | ||
391 | EUID_USER(); | ||
392 | } | ||
393 | else if (strcmp(env, pamtmpdir2) == 0) { | ||
394 | // create empty user-owned /tmp/$UID directory | ||
395 | EUID_ROOT(); | ||
396 | mkdir_attr(pamtmpdir2, 0700, getuid(), 0); | ||
397 | selinux_relabel_path(pamtmpdir2, pamtmpdir2); | ||
398 | fs_logger2("mkdir", pamtmpdir2); | ||
399 | EUID_USER(); | ||
400 | } | ||
401 | free(pamtmpdir1); | ||
402 | free(pamtmpdir2); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | // restore user home directory if it is masked by the tmpfs | ||
407 | // creates path owned by root | ||
408 | // does nothing if user home directory doesn't exist | ||
409 | whitelist_file(&topdirs[i], cfg.homedir); | ||
410 | } | ||
411 | |||
412 | // user home directory | ||
413 | if (tmpfs_home) | ||
414 | fs_private(); // checks owner if outside /home | ||
415 | |||
416 | // /run/user/$UID directory | ||
417 | if (tmpfs_runuser) { | ||
418 | fs_tmpfs(runuser, 0); | ||
419 | selinux_relabel_path(runuser, runuser); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | static int reject_topdir(const char *dir) { | ||
424 | if (!whitelist_reject_topdirs) | ||
425 | return 0; | ||
426 | |||
427 | size_t i; | ||
428 | for (i = 0; whitelist_reject_topdirs[i]; i++) { | ||
429 | if (strcmp(dir, whitelist_reject_topdirs[i]) == 0) | ||
430 | return 1; | ||
431 | } | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | // keep track of whitelist top level directories by adding them to an array | ||
436 | // open each directory | ||
437 | static TopDir *add_topdir(const char *dir, TopDir *topdirs, const char *path) { | ||
438 | EUID_ASSERT(); | ||
439 | assert(dir && path); | ||
440 | |||
441 | // /proc and /sys are not allowed | ||
442 | if (strcmp(dir, "/") == 0 || | ||
443 | strcmp(dir, "/proc") == 0 || | ||
444 | strcmp(dir, "/sys") == 0) | ||
445 | whitelist_error(path); | ||
446 | |||
447 | // whitelisting home directory is disabled if --private option is present | ||
448 | if (arg_private && strcmp(dir, cfg.homedir) == 0) { | ||
449 | if (arg_debug || arg_debug_whitelists) | ||
450 | printf("Debug %d: skip %s - a private home dir is configured!\n", __LINE__, path); | ||
451 | return NULL; | ||
452 | } | ||
453 | |||
454 | // do nothing if directory doesn't exist | ||
455 | struct stat s; | ||
456 | if (lstat(dir, &s) != 0) { | ||
457 | if (arg_debug || arg_debug_whitelists) | ||
458 | printf("Cannot access whitelist top level directory %s: %s\n", dir, strerror(errno)); | ||
459 | return NULL; | ||
460 | } | ||
461 | // do nothing if directory is a link | ||
462 | if (!S_ISDIR(s.st_mode)) { | ||
463 | if (S_ISLNK(s.st_mode)) { | ||
464 | fwarning("skipping whitelist %s because %s is a symbolic link\n", path, dir); | ||
465 | return NULL; | ||
466 | } | ||
467 | whitelist_error(path); | ||
468 | } | ||
469 | // do nothing if directory is disabled by administrator | ||
470 | if (reject_topdir(dir)) { | ||
471 | fmessage("Whitelist top level directory %s is disabled in Firejail configuration file\n", dir); | ||
472 | return NULL; | ||
473 | } | ||
474 | |||
475 | // add directory to array | ||
476 | if (arg_debug || arg_debug_whitelists) | ||
477 | printf("Adding whitelist top level directory %s\n", dir); | ||
478 | static int cnt = 0; | ||
479 | if (cnt >= TOP_MAX) { | ||
480 | fprintf(stderr, "Error: too many whitelist top level directories\n"); | ||
481 | exit(1); | ||
482 | } | ||
483 | TopDir *rv = topdirs + cnt; | ||
484 | cnt++; | ||
485 | |||
486 | rv->path = strdup(dir); | ||
487 | if (!rv->path) | ||
488 | errExit("strdup"); | ||
489 | |||
490 | // open the directory, don't follow symbolic links | ||
491 | rv->fd = safer_openat(-1, dir, O_PATH|O_NOFOLLOW|O_DIRECTORY|O_CLOEXEC); | ||
492 | if (rv->fd == -1) { | ||
493 | fprintf(stderr, "Error: cannot open %s\n", dir); | ||
494 | exit(1); | ||
495 | } | ||
496 | |||
497 | return rv; | ||
498 | } | ||
499 | |||
500 | static TopDir *have_topdir(const char *dir, TopDir *topdirs) { | ||
501 | assert(dir); | ||
502 | |||
503 | int i; | ||
504 | for (i = 0; i < TOP_MAX; i++) { | ||
505 | TopDir *rv = topdirs + i; | ||
506 | if (!rv->path) | ||
507 | break; | ||
508 | if (strcmp(dir, rv->path) == 0) | ||
509 | return rv; | ||
510 | } | ||
511 | return NULL; | ||
512 | } | ||
513 | |||
514 | static char *extract_topdir(const char *path) { | ||
515 | assert(path); | ||
516 | |||
517 | char *dup = strdup(path); | ||
518 | if (!dup) | ||
519 | errExit("strdup"); | ||
520 | |||
521 | // user home directory can be anywhere; disconnect user home | ||
522 | // whitelisting from top level directory whitelisting | ||
523 | // by treating user home as separate whitelist top level directory | ||
524 | if (strncmp(dup, cfg.homedir, homedir_len) == 0 && dup[homedir_len] == '/') | ||
525 | dup[homedir_len] = '\0'; | ||
526 | // /run/user/$UID is treated as top level directory | ||
527 | else if (strncmp(dup, runuser, runuser_len) == 0 && dup[runuser_len] == '/') | ||
528 | dup[runuser_len] = '\0'; | ||
529 | // whitelisting in /sys is not allowed, but /sys/module is an exception | ||
530 | // and is treated as top level directory here | ||
531 | else if (strncmp(dup, "/sys/module", 11) == 0 && dup[11] == '/') | ||
532 | dup[11] = '\0'; | ||
533 | // treat /usr subdirectories as top level directories | ||
534 | else if (strncmp(dup, "/usr/", 5) == 0) { | ||
535 | char *p = strchr(dup+5, '/'); | ||
536 | if (!p) | ||
537 | whitelist_error(path); | ||
538 | *p = '\0'; | ||
539 | } | ||
540 | // all other top level directories | ||
541 | else { | ||
542 | assert(dup[0] == '/'); | ||
543 | char *p = strchr(dup+1, '/'); | ||
544 | if (!p) | ||
545 | whitelist_error(path); | ||
546 | *p = '\0'; | ||
547 | } | ||
548 | |||
549 | return dup; | ||
550 | } | ||
381 | 551 | ||
382 | void fs_whitelist(void) { | 552 | void fs_whitelist(void) { |
553 | EUID_ASSERT(); | ||
554 | |||
383 | ProfileEntry *entry = cfg.profile; | 555 | ProfileEntry *entry = cfg.profile; |
384 | if (!entry) | 556 | if (!entry) |
385 | return; | 557 | return; |
@@ -389,29 +561,17 @@ void fs_whitelist(void) { | |||
389 | runuser_len = strlen(runuser); | 561 | runuser_len = strlen(runuser); |
390 | homedir_len = strlen(cfg.homedir); | 562 | homedir_len = strlen(cfg.homedir); |
391 | 563 | ||
392 | char *new_name = NULL; | ||
393 | int home_dir = 0; // /home/user directory flag | ||
394 | int tmp_dir = 0; // /tmp directory flag | ||
395 | int media_dir = 0; // /media directory flag | ||
396 | int mnt_dir = 0; // /mnt directory flag | ||
397 | int var_dir = 0; // /var directory flag | ||
398 | int dev_dir = 0; // /dev directory flag | ||
399 | int opt_dir = 0; // /opt directory flag | ||
400 | int srv_dir = 0; // /srv directory flag | ||
401 | int etc_dir = 0; // /etc directory flag | ||
402 | int share_dir = 0; // /usr/share directory flag | ||
403 | int module_dir = 0; // /sys/module directory flag | ||
404 | int run_dir = 0; // /run/user/$uid directory flag | ||
405 | |||
406 | size_t nowhitelist_c = 0; | 564 | size_t nowhitelist_c = 0; |
407 | size_t nowhitelist_m = 32; | 565 | size_t nowhitelist_m = 32; |
408 | char **nowhitelist = calloc(nowhitelist_m, sizeof(*nowhitelist)); | 566 | char **nowhitelist = calloc(nowhitelist_m, sizeof(*nowhitelist)); |
409 | if (nowhitelist == NULL) | 567 | if (nowhitelist == NULL) |
410 | errExit("failed allocating memory for nowhitelist entries"); | 568 | errExit("calloc"); |
569 | |||
570 | TopDir *topdirs = calloc(TOP_MAX, sizeof(*topdirs)); | ||
571 | if (topdirs == NULL) | ||
572 | errExit("calloc"); | ||
411 | 573 | ||
412 | // verify whitelist files, extract symbolic links, etc. | 574 | // verify whitelist files, extract symbolic links, etc. |
413 | EUID_USER(); | ||
414 | struct stat s; | ||
415 | while (entry) { | 575 | while (entry) { |
416 | int nowhitelist_flag = 0; | 576 | int nowhitelist_flag = 0; |
417 | 577 | ||
@@ -424,48 +584,76 @@ void fs_whitelist(void) { | |||
424 | entry = entry->next; | 584 | entry = entry->next; |
425 | continue; | 585 | continue; |
426 | } | 586 | } |
427 | char *dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | 587 | if (arg_debug || arg_debug_whitelists) |
428 | 588 | printf("Debug %d: %s\n", __LINE__, entry->data); | |
429 | // replace ~/ or ${HOME} into /home/username or resolve macro | 589 | |
430 | new_name = expand_macros(dataptr); | 590 | const char *dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; |
431 | assert(new_name); | 591 | |
432 | 592 | // replace ~ into /home/username or resolve macro | |
433 | // mount empty home directory if resolving the macro was not successful | 593 | char *expanded = expand_macros(dataptr); |
434 | if (is_macro(new_name) && macro_id(new_name) > -1) { | 594 | |
435 | // no warning if home does not exist (e.g. in a chroot) | 595 | // check if respolving the macro was successful |
436 | if (stat(cfg.homedir, &s) == 0 && !nowhitelist_flag && !arg_private) { | 596 | if (is_macro(expanded) && macro_id(expanded) > -1) { |
437 | home_dir = 1; | 597 | if (!nowhitelist_flag && (have_topdir(cfg.homedir, topdirs) || add_topdir(cfg.homedir, topdirs, expanded)) && !arg_quiet) { |
438 | if (!arg_quiet) { | 598 | fprintf(stderr, "***\n"); |
439 | fprintf(stderr, "***\n"); | 599 | fprintf(stderr, "*** Warning: cannot whitelist %s directory\n", expanded); |
440 | fprintf(stderr, "*** Warning: cannot whitelist %s directory\n", new_name); | 600 | fprintf(stderr, "*** Any file saved in this directory will be lost when the sandbox is closed.\n"); |
441 | fprintf(stderr, "*** Any file saved in this directory will be lost when the sandbox is closed.\n"); | 601 | fprintf(stderr, "***\n"); |
442 | fprintf(stderr, "***\n"); | ||
443 | } | ||
444 | } | 602 | } |
445 | entry->data = EMPTY_STRING; | ||
446 | entry = entry->next; | 603 | entry = entry->next; |
447 | free(new_name); | 604 | free(expanded); |
448 | continue; | 605 | continue; |
449 | } | 606 | } |
450 | 607 | ||
451 | // remove trailing slashes and single dots | 608 | if (arg_debug || arg_debug_whitelists) |
452 | if (!nowhitelist_flag) | 609 | printf("Debug %d: expanded: %s\n", __LINE__, expanded); |
453 | trim_trailing_slash_or_dot(new_name); | 610 | |
611 | // path should be absolute at this point | ||
612 | if (expanded[0] != '/') | ||
613 | whitelist_error(expanded); | ||
614 | |||
615 | // sane pathname | ||
616 | char *new_name = clean_pathname(expanded); | ||
617 | free(expanded); | ||
454 | 618 | ||
455 | if (arg_debug || arg_debug_whitelists) | 619 | if (arg_debug || arg_debug_whitelists) |
456 | fprintf(stderr, "Debug %d: new_name #%s#, %s\n", __LINE__, new_name, (nowhitelist_flag)? "nowhitelist": "whitelist"); | 620 | printf("Debug %d: new_name: %s\n", __LINE__, new_name); |
621 | |||
622 | if (strstr(new_name, "..")) | ||
623 | whitelist_error(new_name); | ||
457 | 624 | ||
458 | // valid path referenced to filesystem root | 625 | TopDir *current_top = NULL; |
459 | if (*new_name != '/') { | 626 | if (!nowhitelist_flag) { |
627 | // extract whitelist top level directory | ||
628 | char *dir = extract_topdir(new_name); | ||
460 | if (arg_debug || arg_debug_whitelists) | 629 | if (arg_debug || arg_debug_whitelists) |
461 | fprintf(stderr, "Debug %d: \n", __LINE__); | 630 | printf("Debug %d: dir: %s\n", __LINE__, dir); |
462 | goto errexit; | 631 | |
632 | // check if this top level directory has been processed already | ||
633 | current_top = have_topdir(dir, topdirs); | ||
634 | if (!current_top) { // got new top level directory | ||
635 | current_top = add_topdir(dir, topdirs, new_name); | ||
636 | if (!current_top) { // skip this command, top level directory not valid | ||
637 | entry = entry->next; | ||
638 | free(new_name); | ||
639 | free(dir); | ||
640 | continue; | ||
641 | } | ||
642 | } | ||
643 | free(dir); | ||
644 | } | ||
645 | |||
646 | // /run/firejail directory is internal and not allowed | ||
647 | if (strncmp(new_name, RUN_FIREJAIL_DIR, strlen(RUN_FIREJAIL_DIR)) == 0) { | ||
648 | entry = entry->next; | ||
649 | free(new_name); | ||
650 | continue; | ||
463 | } | 651 | } |
464 | 652 | ||
465 | // extract the absolute path of the file | 653 | // extract resolved path of the file |
466 | // realpath function will fail with ENOENT if the file is not found or with EACCES if user has no permission | 654 | // realpath function will fail with ENOENT if the file is not found or with EACCES if user has no permission |
467 | // special processing for /dev/fd, /dev/stdin, /dev/stdout and /dev/stderr | 655 | // special processing for /dev/fd, /dev/stdin, /dev/stdout and /dev/stderr |
468 | char *fname; | 656 | char *fname = NULL; |
469 | if (strcmp(new_name, "/dev/fd") == 0) | 657 | if (strcmp(new_name, "/dev/fd") == 0) |
470 | fname = strdup("/proc/self/fd"); | 658 | fname = strdup("/proc/self/fd"); |
471 | else if (strcmp(new_name, "/dev/stdin") == 0) | 659 | else if (strcmp(new_name, "/dev/stdin") == 0) |
@@ -477,60 +665,34 @@ void fs_whitelist(void) { | |||
477 | else | 665 | else |
478 | fname = realpath(new_name, NULL); | 666 | fname = realpath(new_name, NULL); |
479 | 667 | ||
480 | // if this is not a real path, let's try globbing | ||
481 | // mark this entry as EMPTY_STRING and push the new paths at the end of profile entry list | ||
482 | // the new profile entries will be processed in this loop | ||
483 | // currently there is no globbing support for nowhitelist | ||
484 | if (!fname && !nowhitelist_flag) | ||
485 | globbing(new_name); | ||
486 | |||
487 | if (!fname) { | 668 | if (!fname) { |
488 | // file not found, blank the entry in the list and continue | ||
489 | if (arg_debug || arg_debug_whitelists) { | 669 | if (arg_debug || arg_debug_whitelists) { |
490 | printf("Removed whitelist/nowhitelist path: %s\n", entry->data); | 670 | printf("Removed path: %s\n", entry->data); |
491 | printf("\texpanded: %s\n", new_name); | 671 | printf("\tnew_name: %s\n", new_name); |
492 | printf("\treal path: (null)\n"); | 672 | printf("\trealpath: (null)\n"); |
493 | printf("\t");fflush(0); | 673 | printf("\t%s\n", strerror(errno)); |
494 | perror("realpath"); | ||
495 | } | 674 | } |
496 | 675 | ||
497 | // if 1 the file was not found; mount an empty directory | ||
498 | if (!nowhitelist_flag) { | 676 | if (!nowhitelist_flag) { |
499 | if (strncmp(new_name, cfg.homedir, homedir_len) == 0 && new_name[homedir_len] == '/') { | 677 | // if this is not a real path, let's try globbing |
500 | if(!arg_private) | 678 | // push the new paths at the end of profile entry list |
501 | home_dir = 1; | 679 | // the new profile entries will be processed in this loop |
502 | } | 680 | // currently there is no globbing support for nowhitelist |
503 | else if (strncmp(new_name, "/tmp/", 5) == 0) | 681 | globbing(new_name); |
504 | tmp_dir = 1; | ||
505 | else if (strncmp(new_name, "/media/", 7) == 0) | ||
506 | media_dir = 1; | ||
507 | else if (strncmp(new_name, "/mnt/", 5) == 0) | ||
508 | mnt_dir = 1; | ||
509 | else if (strncmp(new_name, "/var/", 5) == 0) | ||
510 | var_dir = 1; | ||
511 | else if (strncmp(new_name, "/dev/", 5) == 0) | ||
512 | dev_dir = 1; | ||
513 | else if (strncmp(new_name, "/opt/", 5) == 0) | ||
514 | opt_dir = 1; | ||
515 | else if (strncmp(new_name, "/srv/", 5) == 0) | ||
516 | srv_dir = 1; | ||
517 | else if (strncmp(new_name, "/etc/", 5) == 0) | ||
518 | etc_dir = 1; | ||
519 | else if (strncmp(new_name, "/usr/share/", 11) == 0) | ||
520 | share_dir = 1; | ||
521 | else if (strncmp(new_name, "/sys/module/", 12) == 0) | ||
522 | module_dir = 1; | ||
523 | else if (strncmp(new_name, runuser, runuser_len) == 0 && new_name[runuser_len] == '/') | ||
524 | run_dir = 1; | ||
525 | } | 682 | } |
526 | 683 | ||
527 | entry->data = EMPTY_STRING; | ||
528 | entry = entry->next; | 684 | entry = entry->next; |
529 | free(new_name); | 685 | free(new_name); |
530 | continue; | 686 | continue; |
531 | } | 687 | } |
532 | else if (arg_debug_whitelists) | 688 | |
533 | printf("real path %s\n", fname); | 689 | // /run/firejail directory is internal and not allowed |
690 | if (strncmp(fname, RUN_FIREJAIL_DIR, strlen(RUN_FIREJAIL_DIR)) == 0) { | ||
691 | entry = entry->next; | ||
692 | free(new_name); | ||
693 | free(fname); | ||
694 | continue; | ||
695 | } | ||
534 | 696 | ||
535 | if (nowhitelist_flag) { | 697 | if (nowhitelist_flag) { |
536 | // store the path in nowhitelist array | 698 | // store the path in nowhitelist array |
@@ -544,175 +706,12 @@ void fs_whitelist(void) { | |||
544 | errExit("failed increasing memory for nowhitelist entries"); | 706 | errExit("failed increasing memory for nowhitelist entries"); |
545 | } | 707 | } |
546 | nowhitelist[nowhitelist_c++] = fname; | 708 | nowhitelist[nowhitelist_c++] = fname; |
547 | entry->data = EMPTY_STRING; | ||
548 | entry = entry->next; | 709 | entry = entry->next; |
549 | free(new_name); | 710 | free(new_name); |
550 | continue; | 711 | continue; |
551 | } | 712 | } |
552 | |||
553 | // check for supported directories | ||
554 | if (strncmp(new_name, cfg.homedir, homedir_len) == 0 && new_name[homedir_len] == '/') { | ||
555 | // whitelisting home directory is disabled if --private option is present | ||
556 | if (arg_private) { | ||
557 | if (arg_debug || arg_debug_whitelists) | ||
558 | printf("\"%s\" disabled by --private\n", entry->data); | ||
559 | |||
560 | entry->data = EMPTY_STRING; | ||
561 | entry = entry->next; | ||
562 | free(fname); | ||
563 | free(new_name); | ||
564 | continue; | ||
565 | } | ||
566 | |||
567 | entry->wldir = WLDIR_HOME; | ||
568 | home_dir = 1; | ||
569 | if (arg_debug || arg_debug_whitelists) | ||
570 | fprintf(stderr, "Debug %d: fname #%s#, cfg.homedir #%s#\n", | ||
571 | __LINE__, fname, cfg.homedir); | ||
572 | |||
573 | // both path and absolute path are in user home, | ||
574 | // if not check if the symlink destination is owned by the user | ||
575 | if (strncmp(fname, cfg.homedir, homedir_len) != 0 || fname[homedir_len] != '/') { | ||
576 | if (checkcfg(CFG_FOLLOW_SYMLINK_AS_USER)) { | ||
577 | if (stat(fname, &s) == 0 && s.st_uid != getuid()) { | ||
578 | free(fname); | ||
579 | goto errexit; | ||
580 | } | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | else if (strncmp(new_name, "/tmp/", 5) == 0) { | ||
585 | entry->wldir = WLDIR_TMP; | ||
586 | tmp_dir = 1; | ||
587 | |||
588 | // both path and absolute path are under /tmp | ||
589 | if (strncmp(fname, "/tmp/", 5) != 0) { | ||
590 | free(fname); | ||
591 | goto errexit; | ||
592 | } | ||
593 | } | ||
594 | else if (strncmp(new_name, "/media/", 7) == 0) { | ||
595 | entry->wldir = WLDIR_MEDIA; | ||
596 | media_dir = 1; | ||
597 | // both path and absolute path are under /media | ||
598 | if (strncmp(fname, "/media/", 7) != 0) { | ||
599 | free(fname); | ||
600 | goto errexit; | ||
601 | } | ||
602 | } | ||
603 | else if (strncmp(new_name, "/mnt/", 5) == 0) { | ||
604 | entry->wldir = WLDIR_MNT; | ||
605 | mnt_dir = 1; | ||
606 | // both path and absolute path are under /mnt | ||
607 | if (strncmp(fname, "/mnt/", 5) != 0) { | ||
608 | free(fname); | ||
609 | goto errexit; | ||
610 | } | ||
611 | } | ||
612 | else if (strncmp(new_name, "/var/", 5) == 0) { | ||
613 | entry->wldir = WLDIR_VAR; | ||
614 | var_dir = 1; | ||
615 | // both path and absolute path are under /var | ||
616 | // exceptions: /var/tmp, /var/run and /var/lock | ||
617 | if (strcmp(new_name, "/var/run")== 0 && strcmp(fname, "/run") == 0); | ||
618 | else if (strcmp(new_name, "/var/lock")== 0 && strcmp(fname, "/run/lock") == 0); | ||
619 | else if (strcmp(new_name, "/var/tmp")== 0 && strcmp(fname, "/tmp") == 0); | ||
620 | else { | ||
621 | // both path and absolute path are under /var | ||
622 | if (strncmp(fname, "/var/", 5) != 0) { | ||
623 | free(fname); | ||
624 | goto errexit; | ||
625 | } | ||
626 | } | ||
627 | } | ||
628 | else if (strncmp(new_name, "/dev/", 5) == 0) { | ||
629 | entry->wldir = WLDIR_DEV; | ||
630 | dev_dir = 1; | ||
631 | // special handling for /dev/shm | ||
632 | // on some platforms (Debian wheezy, Ubuntu 14.04), it is a symlink to /run/shm | ||
633 | if (strcmp(new_name, "/dev/shm") == 0 && strcmp(fname, "/run/shm") == 0); | ||
634 | // special handling for /dev/log, which can be a symlink to /run/systemd/journal/dev-log | ||
635 | else if (strcmp(new_name, "/dev/log") == 0 && strcmp(fname, "/run/systemd/journal/dev-log") == 0); | ||
636 | // special processing for /proc/self/fd files | ||
637 | else if (strcmp(new_name, "/dev/fd") == 0 && strcmp(fname, "/proc/self/fd") == 0); | ||
638 | else if (strcmp(new_name, "/dev/stdin") == 0 && strcmp(fname, "/proc/self/fd/0") == 0); | ||
639 | else if (strcmp(new_name, "/dev/stdout") == 0 && strcmp(fname, "/proc/self/fd/1") == 0); | ||
640 | else if (strcmp(new_name, "/dev/stderr") == 0 && strcmp(fname, "/proc/self/fd/2") == 0); | ||
641 | else { | ||
642 | // both path and absolute path are under /dev | ||
643 | if (strncmp(fname, "/dev/", 5) != 0) { | ||
644 | free(fname); | ||
645 | goto errexit; | ||
646 | } | ||
647 | } | ||
648 | } | ||
649 | else if (strncmp(new_name, "/opt/", 5) == 0) { | ||
650 | entry->wldir = WLDIR_OPT; | ||
651 | opt_dir = 1; | ||
652 | // both path and absolute path are under /dev | ||
653 | if (strncmp(fname, "/opt/", 5) != 0) { | ||
654 | free(fname); | ||
655 | goto errexit; | ||
656 | } | ||
657 | } | ||
658 | else if (strncmp(new_name, "/srv/", 5) == 0) { | ||
659 | entry->wldir = WLDIR_SRV; | ||
660 | srv_dir = 1; | ||
661 | // both path and absolute path are under /srv | ||
662 | if (strncmp(fname, "/srv/", 5) != 0) { | ||
663 | free(fname); | ||
664 | goto errexit; | ||
665 | } | ||
666 | } | ||
667 | else if (strncmp(new_name, "/etc/", 5) == 0) { | ||
668 | entry->wldir = WLDIR_ETC; | ||
669 | etc_dir = 1; | ||
670 | // special handling for some of the symlinks | ||
671 | if (strcmp(new_name, "/etc/localtime") == 0); | ||
672 | else if (strcmp(new_name, "/etc/mtab") == 0); | ||
673 | else if (strcmp(new_name, "/etc/os-release") == 0); | ||
674 | // both path and absolute path are under /etc | ||
675 | else { | ||
676 | if (strncmp(fname, "/etc/", 5) != 0) { | ||
677 | free(fname); | ||
678 | goto errexit; | ||
679 | } | ||
680 | } | ||
681 | } | ||
682 | else if (strncmp(new_name, "/usr/share/", 11) == 0) { | ||
683 | entry->wldir = WLDIR_SHARE; | ||
684 | share_dir = 1; | ||
685 | // both path and absolute path are under /etc | ||
686 | if (strncmp(fname, "/usr/share/", 11) != 0) { | ||
687 | free(fname); | ||
688 | goto errexit; | ||
689 | } | ||
690 | } | ||
691 | else if (strncmp(new_name, "/sys/module/", 12) == 0) { | ||
692 | entry->wldir = WLDIR_MODULE; | ||
693 | module_dir = 1; | ||
694 | // both path and absolute path are under /sys/module | ||
695 | if (strncmp(fname, "/sys/module/", 12) != 0) { | ||
696 | free(fname); | ||
697 | goto errexit; | ||
698 | } | ||
699 | } | ||
700 | else if (strncmp(new_name, runuser, runuser_len) == 0 && new_name[runuser_len] == '/') { | ||
701 | entry->wldir = WLDIR_RUN; | ||
702 | run_dir = 1; | ||
703 | // both path and absolute path are under /run/user/$uid | ||
704 | if (strncmp(fname, runuser, runuser_len) != 0 || fname[runuser_len] != '/') { | ||
705 | free(fname); | ||
706 | goto errexit; | ||
707 | } | ||
708 | } | ||
709 | else { | 713 | else { |
710 | free(fname); | 714 | // check if the path is in nowhitelist array |
711 | goto errexit; | ||
712 | } | ||
713 | |||
714 | // check if the path is in nowhitelist array | ||
715 | if (nowhitelist_flag == 0) { | ||
716 | size_t i; | 715 | size_t i; |
717 | int found = 0; | 716 | int found = 0; |
718 | for (i = 0; i < nowhitelist_c; i++) { | 717 | for (i = 0; i < nowhitelist_c; i++) { |
@@ -726,494 +725,70 @@ void fs_whitelist(void) { | |||
726 | if (found) { | 725 | if (found) { |
727 | if (arg_debug || arg_debug_whitelists) | 726 | if (arg_debug || arg_debug_whitelists) |
728 | printf("Skip nowhitelisted path %s\n", fname); | 727 | printf("Skip nowhitelisted path %s\n", fname); |
729 | entry->data = EMPTY_STRING; | ||
730 | entry = entry->next; | 728 | entry = entry->next; |
731 | free(fname); | ||
732 | free(new_name); | 729 | free(new_name); |
730 | free(fname); | ||
733 | continue; | 731 | continue; |
734 | } | 732 | } |
735 | } | 733 | } |
736 | 734 | ||
737 | // mark symbolic links | 735 | // attach whitelist parameters to profile entry |
738 | if (is_link(new_name)) | 736 | entry->wparam = calloc(1, sizeof(struct wparam_t)); |
739 | entry->link = new_name; | 737 | if (!entry->wparam) |
740 | else { | 738 | errExit("calloc"); |
741 | free(new_name); | ||
742 | entry->link = NULL; | ||
743 | } | ||
744 | |||
745 | // change file name in entry->data | ||
746 | if (strcmp(fname, entry->data + 10) != 0) { | ||
747 | char *newdata; | ||
748 | if (asprintf(&newdata, "whitelist %s", fname) == -1) | ||
749 | errExit("asprintf"); | ||
750 | entry->data = newdata; | ||
751 | if (arg_debug || arg_debug_whitelists) | ||
752 | printf("Replaced whitelist path: %s\n", entry->data); | ||
753 | } | ||
754 | free(fname); | ||
755 | entry = entry->next; | ||
756 | } | ||
757 | |||
758 | // release nowhitelist memory | ||
759 | assert(nowhitelist); | ||
760 | free(nowhitelist); | ||
761 | |||
762 | EUID_ROOT(); | ||
763 | // /tmp mountpoint | ||
764 | if (tmp_dir) { | ||
765 | // check if /tmp directory exists | ||
766 | if (stat("/tmp", &s) == 0) { | ||
767 | // keep a copy of real /tmp directory in RUN_WHITELIST_TMP_DIR | ||
768 | mkdir_attr(RUN_WHITELIST_TMP_DIR, 1777, 0, 0); | ||
769 | if (mount("/tmp", RUN_WHITELIST_TMP_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
770 | errExit("mount bind"); | ||
771 | |||
772 | // mount tmpfs on /tmp | ||
773 | if (arg_debug || arg_debug_whitelists) | ||
774 | printf("Mounting tmpfs on /tmp directory\n"); | ||
775 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=1777,gid=0") < 0) | ||
776 | errExit("mounting tmpfs on /tmp"); | ||
777 | selinux_relabel_path("/tmp", "/tmp"); | ||
778 | fs_logger("tmpfs /tmp"); | ||
779 | |||
780 | // pam-tmpdir - issue #2685 | ||
781 | const char *env = env_get("TMP"); | ||
782 | if (env) { | ||
783 | char *pamtmpdir; | ||
784 | if (asprintf(&pamtmpdir, "/tmp/user/%u", getuid()) == -1) | ||
785 | errExit("asprintf"); | ||
786 | if (strcmp(env, pamtmpdir) == 0) { | ||
787 | // create empty user-owned /tmp/user/$uid directory | ||
788 | mkdir_attr("/tmp/user", 0711, 0, 0); | ||
789 | selinux_relabel_path("/tmp/user", "/tmp/user"); | ||
790 | fs_logger("mkdir /tmp/user"); | ||
791 | mkdir_attr(pamtmpdir, 0700, getuid(), 0); | ||
792 | selinux_relabel_path(pamtmpdir, pamtmpdir); | ||
793 | fs_logger2("mkdir", pamtmpdir); | ||
794 | } | ||
795 | free(pamtmpdir); | ||
796 | } | ||
797 | |||
798 | // autowhitelist home directory if it is masked by the tmpfs | ||
799 | if (strncmp(cfg.homedir, "/tmp/", 5) == 0) | ||
800 | whitelist_home(WLDIR_TMP); | ||
801 | } | ||
802 | else | ||
803 | tmp_dir = 0; | ||
804 | } | ||
805 | |||
806 | // /media mountpoint | ||
807 | if (media_dir) { | ||
808 | // some distros don't have a /media directory | ||
809 | if (stat("/media", &s) == 0) { | ||
810 | // keep a copy of real /media directory in RUN_WHITELIST_MEDIA_DIR | ||
811 | mkdir_attr(RUN_WHITELIST_MEDIA_DIR, 0755, 0, 0); | ||
812 | if (mount("/media", RUN_WHITELIST_MEDIA_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
813 | errExit("mount bind"); | ||
814 | |||
815 | // mount tmpfs on /media | ||
816 | if (arg_debug || arg_debug_whitelists) | ||
817 | printf("Mounting tmpfs on /media directory\n"); | ||
818 | if (mount("tmpfs", "/media", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
819 | errExit("mounting tmpfs on /media"); | ||
820 | selinux_relabel_path("/media", "/media"); | ||
821 | fs_logger("tmpfs /media"); | ||
822 | |||
823 | // autowhitelist home directory if it is masked by the tmpfs | ||
824 | if (strncmp(cfg.homedir, "/media/", 7) == 0) | ||
825 | whitelist_home(WLDIR_MEDIA); | ||
826 | } | ||
827 | else | ||
828 | media_dir = 0; | ||
829 | } | ||
830 | |||
831 | // /mnt mountpoint | ||
832 | if (mnt_dir) { | ||
833 | // check if /mnt directory exists | ||
834 | if (stat("/mnt", &s) == 0) { | ||
835 | // keep a copy of real /mnt directory in RUN_WHITELIST_MNT_DIR | ||
836 | mkdir_attr(RUN_WHITELIST_MNT_DIR, 0755, 0, 0); | ||
837 | if (mount("/mnt", RUN_WHITELIST_MNT_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
838 | errExit("mount bind"); | ||
839 | |||
840 | // mount tmpfs on /mnt | ||
841 | if (arg_debug || arg_debug_whitelists) | ||
842 | printf("Mounting tmpfs on /mnt directory\n"); | ||
843 | if (mount("tmpfs", "/mnt", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
844 | errExit("mounting tmpfs on /mnt"); | ||
845 | selinux_relabel_path("/mnt", "/mnt"); | ||
846 | fs_logger("tmpfs /mnt"); | ||
847 | |||
848 | // autowhitelist home directory if it is masked by the tmpfs | ||
849 | if (strncmp(cfg.homedir, "/mnt/", 5) == 0) | ||
850 | whitelist_home(WLDIR_MNT); | ||
851 | } | ||
852 | else | ||
853 | mnt_dir = 0; | ||
854 | } | ||
855 | |||
856 | // /var mountpoint | ||
857 | if (var_dir) { | ||
858 | // check if /var directory exists | ||
859 | if (stat("/var", &s) == 0) { | ||
860 | // keep a copy of real /var directory in RUN_WHITELIST_VAR_DIR | ||
861 | mkdir_attr(RUN_WHITELIST_VAR_DIR, 0755, 0, 0); | ||
862 | if (mount("/var", RUN_WHITELIST_VAR_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
863 | errExit("mount bind"); | ||
864 | 739 | ||
865 | // mount tmpfs on /var | 740 | assert(current_top); |
866 | if (arg_debug || arg_debug_whitelists) | 741 | entry->wparam->top = current_top; |
867 | printf("Mounting tmpfs on /var directory\n"); | 742 | entry->wparam->file = fname; |
868 | if (mount("tmpfs", "/var", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
869 | errExit("mounting tmpfs on /var"); | ||
870 | selinux_relabel_path("/var", "/var"); | ||
871 | fs_logger("tmpfs /var"); | ||
872 | |||
873 | // autowhitelist home directory if it is masked by the tmpfs | ||
874 | if (strncmp(cfg.homedir, "/var/", 5) == 0) | ||
875 | whitelist_home(WLDIR_VAR); | ||
876 | } | ||
877 | else | ||
878 | var_dir = 0; | ||
879 | } | ||
880 | |||
881 | // /dev mountpoint | ||
882 | if (dev_dir) { | ||
883 | // check if /dev directory exists | ||
884 | if (stat("/dev", &s) == 0) { | ||
885 | // keep a copy of real /dev directory in RUN_WHITELIST_DEV_DIR | ||
886 | mkdir_attr(RUN_WHITELIST_DEV_DIR, 0755, 0, 0); | ||
887 | if (mount("/dev", RUN_WHITELIST_DEV_DIR, NULL, MS_BIND|MS_REC, "mode=755,gid=0") < 0) | ||
888 | errExit("mount bind"); | ||
889 | |||
890 | // mount tmpfs on /dev | ||
891 | if (arg_debug || arg_debug_whitelists) | ||
892 | printf("Mounting tmpfs on /dev directory\n"); | ||
893 | if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
894 | errExit("mounting tmpfs on /dev"); | ||
895 | selinux_relabel_path("/dev", "/dev"); | ||
896 | fs_logger("tmpfs /dev"); | ||
897 | |||
898 | // autowhitelist home directory if it is masked by the tmpfs | ||
899 | if (strncmp(cfg.homedir, "/dev/", 5) == 0) | ||
900 | whitelist_home(WLDIR_DEV); | ||
901 | } | ||
902 | else | ||
903 | dev_dir = 0; | ||
904 | } | ||
905 | |||
906 | // /opt mountpoint | ||
907 | if (opt_dir) { | ||
908 | // check if /opt directory exists | ||
909 | if (stat("/opt", &s) == 0) { | ||
910 | // keep a copy of real /opt directory in RUN_WHITELIST_OPT_DIR | ||
911 | mkdir_attr(RUN_WHITELIST_OPT_DIR, 0755, 0, 0); | ||
912 | if (mount("/opt", RUN_WHITELIST_OPT_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
913 | errExit("mount bind"); | ||
914 | |||
915 | // mount tmpfs on /opt | ||
916 | if (arg_debug || arg_debug_whitelists) | ||
917 | printf("Mounting tmpfs on /opt directory\n"); | ||
918 | if (mount("tmpfs", "/opt", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
919 | errExit("mounting tmpfs on /opt"); | ||
920 | selinux_relabel_path("/opt", "/opt"); | ||
921 | fs_logger("tmpfs /opt"); | ||
922 | |||
923 | // autowhitelist home directory if it is masked by the tmpfs | ||
924 | if (strncmp(cfg.homedir, "/opt/", 5) == 0) | ||
925 | whitelist_home(WLDIR_OPT); | ||
926 | } | ||
927 | else | ||
928 | opt_dir = 0; | ||
929 | } | ||
930 | |||
931 | // /srv mountpoint | ||
932 | if (srv_dir) { | ||
933 | // check if /srv directory exists | ||
934 | if (stat("/srv", &s) == 0) { | ||
935 | // keep a copy of real /srv directory in RUN_WHITELIST_SRV_DIR | ||
936 | mkdir_attr(RUN_WHITELIST_SRV_DIR, 0755, 0, 0); | ||
937 | if (mount("/srv", RUN_WHITELIST_SRV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
938 | errExit("mount bind"); | ||
939 | |||
940 | // mount tmpfs on /srv | ||
941 | if (arg_debug || arg_debug_whitelists) | ||
942 | printf("Mounting tmpfs on /srv directory\n"); | ||
943 | if (mount("tmpfs", "/srv", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
944 | errExit("mounting tmpfs on /srv"); | ||
945 | selinux_relabel_path("/srv", "/srv"); | ||
946 | fs_logger("tmpfs /srv"); | ||
947 | |||
948 | // autowhitelist home directory if it is masked by the tmpfs | ||
949 | if (strncmp(cfg.homedir, "/srv/", 5) == 0) | ||
950 | whitelist_home(WLDIR_SRV); | ||
951 | } | ||
952 | else | ||
953 | srv_dir = 0; | ||
954 | } | ||
955 | |||
956 | // /etc mountpoint | ||
957 | if (etc_dir) { | ||
958 | // check if /etc directory exists | ||
959 | if (stat("/etc", &s) == 0) { | ||
960 | // keep a copy of real /etc directory in RUN_WHITELIST_ETC_DIR | ||
961 | mkdir_attr(RUN_WHITELIST_ETC_DIR, 0755, 0, 0); | ||
962 | if (mount("/etc", RUN_WHITELIST_ETC_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
963 | errExit("mount bind"); | ||
964 | |||
965 | // mount tmpfs on /etc | ||
966 | if (arg_debug || arg_debug_whitelists) | ||
967 | printf("Mounting tmpfs on /etc directory\n"); | ||
968 | if (mount("tmpfs", "/etc", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
969 | errExit("mounting tmpfs on /etc"); | ||
970 | selinux_relabel_path("/etc", "/etc"); | ||
971 | fs_logger("tmpfs /etc"); | ||
972 | |||
973 | // autowhitelist home directory if it is masked by the tmpfs | ||
974 | if (strncmp(cfg.homedir, "/etc/", 5) == 0) | ||
975 | whitelist_home(WLDIR_ETC); | ||
976 | } | ||
977 | else | ||
978 | etc_dir = 0; | ||
979 | } | ||
980 | |||
981 | // /usr/share mountpoint | ||
982 | if (share_dir) { | ||
983 | // check if /usr/share directory exists | ||
984 | if (stat("/usr/share", &s) == 0) { | ||
985 | // keep a copy of real /usr/share directory in RUN_WHITELIST_ETC_DIR | ||
986 | mkdir_attr(RUN_WHITELIST_SHARE_DIR, 0755, 0, 0); | ||
987 | if (mount("/usr/share", RUN_WHITELIST_SHARE_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
988 | errExit("mount bind"); | ||
989 | |||
990 | // mount tmpfs on /srv | ||
991 | if (arg_debug || arg_debug_whitelists) | ||
992 | printf("Mounting tmpfs on /usr/share directory\n"); | ||
993 | if (mount("tmpfs", "/usr/share", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
994 | errExit("mounting tmpfs on /usr/share"); | ||
995 | selinux_relabel_path("/usr/share", "/usr/share"); | ||
996 | fs_logger("tmpfs /usr/share"); | ||
997 | |||
998 | // autowhitelist home directory if it is masked by the tmpfs | ||
999 | if (strncmp(cfg.homedir, "/usr/share/", 11) == 0) | ||
1000 | whitelist_home(WLDIR_SHARE); | ||
1001 | } | ||
1002 | else | ||
1003 | share_dir = 0; | ||
1004 | } | ||
1005 | |||
1006 | // /sys/module mountpoint | ||
1007 | if (module_dir) { | ||
1008 | // check if /sys/module directory exists | ||
1009 | if (stat("/sys/module", &s) == 0) { | ||
1010 | // keep a copy of real /sys/module directory in RUN_WHITELIST_MODULE_DIR | ||
1011 | mkdir_attr(RUN_WHITELIST_MODULE_DIR, 0755, 0, 0); | ||
1012 | if (mount("/sys/module", RUN_WHITELIST_MODULE_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1013 | errExit("mount bind"); | ||
1014 | 743 | ||
1015 | // mount tmpfs on /sys/module | 744 | // mark link |
1016 | if (arg_debug || arg_debug_whitelists) | 745 | if (is_link(new_name)) |
1017 | printf("Mounting tmpfs on /sys/module directory\n"); | 746 | entry->wparam->link = new_name; |
1018 | if (mount("tmpfs", "/sys/module", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1019 | errExit("mounting tmpfs on /sys/module"); | ||
1020 | selinux_relabel_path("/sys/module", "/sys/module"); | ||
1021 | fs_logger("tmpfs /sys/module"); | ||
1022 | } | ||
1023 | else | 747 | else |
1024 | module_dir = 0; | 748 | free(new_name); |
1025 | } | ||
1026 | |||
1027 | // /run/user/$uid mountpoint | ||
1028 | if (run_dir) { | ||
1029 | // check if /run/user/$uid directory exists | ||
1030 | if (stat(runuser, &s) == 0) { | ||
1031 | // keep a copy of real /run/user/$uid directory in RUN_WHITELIST_RUN_USER_DIR | ||
1032 | mkdir_attr(RUN_WHITELIST_RUN_USER_DIR, 0700, getuid(), getgid()); | ||
1033 | if (mount(runuser, RUN_WHITELIST_RUN_USER_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1034 | errExit("mount bind"); | ||
1035 | 749 | ||
1036 | // mount tmpfs on /run/user/$uid | 750 | entry = entry->next; |
1037 | if (arg_debug || arg_debug_whitelists) | ||
1038 | printf("Mounting tmpfs on %s directory\n", runuser); | ||
1039 | char *options; | ||
1040 | if (asprintf(&options, "mode=700,uid=%u,gid=%u", getuid(), getgid()) == -1) | ||
1041 | errExit("asprintf"); | ||
1042 | if (mount("tmpfs", runuser, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, options) < 0) | ||
1043 | errExit("mounting tmpfs on /run/user/<uid>"); | ||
1044 | selinux_relabel_path(runuser, runuser); | ||
1045 | free(options); | ||
1046 | fs_logger2("tmpfs", runuser); | ||
1047 | |||
1048 | // autowhitelist home directory if it is masked by the tmpfs | ||
1049 | if (strncmp(cfg.homedir, runuser, runuser_len) == 0 && cfg.homedir[runuser_len] == '/') | ||
1050 | whitelist_home(WLDIR_RUN); | ||
1051 | } | ||
1052 | else | ||
1053 | run_dir = 0; | ||
1054 | } | 751 | } |
1055 | 752 | ||
1056 | // home mountpoint | 753 | // mount tmpfs on all top level directories |
1057 | if (home_dir) { | 754 | tmpfs_topdirs(topdirs); |
1058 | // check if home directory exists | ||
1059 | if (stat(cfg.homedir, &s) == 0) { | ||
1060 | // keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR | ||
1061 | mkdir_attr(RUN_WHITELIST_HOME_USER_DIR, 0755, getuid(), getgid()); | ||
1062 | int fd = safe_fd(cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
1063 | if (fd == -1) | ||
1064 | errExit("safe_fd"); | ||
1065 | char *proc; | ||
1066 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
1067 | errExit("asprintf"); | ||
1068 | if (mount(proc, RUN_WHITELIST_HOME_USER_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1069 | errExit("mount bind"); | ||
1070 | free(proc); | ||
1071 | close(fd); | ||
1072 | |||
1073 | // mount a tmpfs and initialize home directory | ||
1074 | fs_private(); | ||
1075 | } | ||
1076 | else | ||
1077 | home_dir = 0; | ||
1078 | } | ||
1079 | 755 | ||
1080 | // go through profile rules again, and interpret whitelist commands | 756 | // go through profile rules again, and interpret whitelist commands |
1081 | entry = cfg.profile; | 757 | entry = cfg.profile; |
1082 | while (entry) { | 758 | while (entry) { |
1083 | // handle only whitelist commands | 759 | if (entry->wparam) { |
1084 | if (strncmp(entry->data, "whitelist ", 10)) { | 760 | char *file = entry->wparam->file; |
1085 | entry = entry->next; | 761 | char *link = entry->wparam->link; |
1086 | continue; | 762 | const TopDir * const current_top = entry->wparam->top; |
1087 | } | 763 | |
1088 | 764 | // top level directories of link and file can differ | |
1089 | //printf("here %d#%s#\n", __LINE__, entry->data); | 765 | // will whitelist the file only if it is in same top level directory |
1090 | // whitelist the real file | 766 | whitelist_file(current_top, file); |
1091 | whitelist_path(entry); | 767 | |
1092 | 768 | // create the link if any | |
1093 | // create the link if any | 769 | if (link) { |
1094 | if (entry->link) { | 770 | whitelist_symlink(current_top, link, file); |
1095 | // if the link is already there, do not bother | 771 | free(link); |
1096 | if (lstat(entry->link, &s) != 0) { | ||
1097 | // create the path if necessary | ||
1098 | // entry->link has no trailing slashes or single dots | ||
1099 | int fd = mkpath(entry->link, 0755); | ||
1100 | if (fd == -1) { | ||
1101 | if (arg_debug || arg_debug_whitelists) | ||
1102 | printf("Debug %d: cannot create symbolic link %s\n", __LINE__, entry->link); | ||
1103 | free(entry->link); | ||
1104 | entry->link = NULL; | ||
1105 | entry = entry->next; | ||
1106 | continue; | ||
1107 | } | ||
1108 | // get file name of symlink | ||
1109 | const char *file = gnu_basename(entry->link); | ||
1110 | // create the link | ||
1111 | int rv = symlinkat(entry->data + 10, fd, file); | ||
1112 | if (rv) { | ||
1113 | if (arg_debug || arg_debug_whitelists) { | ||
1114 | perror("symlink"); | ||
1115 | printf("Debug %d: cannot create symbolic link %s\n", __LINE__, entry->link); | ||
1116 | } | ||
1117 | } | ||
1118 | else if (arg_debug || arg_debug_whitelists) | ||
1119 | printf("Created symbolic link %s -> %s\n", entry->link, entry->data + 10); | ||
1120 | close(fd); | ||
1121 | } | 772 | } |
1122 | free(entry->link); | 773 | |
1123 | entry->link = NULL; | 774 | free(file); |
775 | free(entry->wparam); | ||
776 | entry->wparam = NULL; | ||
1124 | } | 777 | } |
1125 | 778 | ||
1126 | entry = entry->next; | 779 | entry = entry->next; |
1127 | } | 780 | } |
1128 | 781 | ||
1129 | // mask the real home directory, currently mounted on RUN_WHITELIST_HOME_DIR | 782 | // release resources |
1130 | if (home_dir) { | 783 | size_t i; |
1131 | if (mount("tmpfs", RUN_WHITELIST_HOME_USER_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | 784 | for (i = 0; i < nowhitelist_c; i++) |
1132 | errExit("mount tmpfs"); | 785 | free(nowhitelist[i]); |
1133 | fs_logger2("tmpfs", RUN_WHITELIST_HOME_USER_DIR); | 786 | free(nowhitelist); |
1134 | } | ||
1135 | |||
1136 | // mask the real /tmp directory, currently mounted on RUN_WHITELIST_TMP_DIR | ||
1137 | if (tmp_dir) { | ||
1138 | if (mount("tmpfs", RUN_WHITELIST_TMP_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1139 | errExit("mount tmpfs"); | ||
1140 | fs_logger2("tmpfs", RUN_WHITELIST_TMP_DIR); | ||
1141 | } | ||
1142 | |||
1143 | // mask the real /var directory, currently mounted on RUN_WHITELIST_VAR_DIR | ||
1144 | if (var_dir) { | ||
1145 | if (mount("tmpfs", RUN_WHITELIST_VAR_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1146 | errExit("mount tmpfs"); | ||
1147 | fs_logger2("tmpfs", RUN_WHITELIST_VAR_DIR); | ||
1148 | } | ||
1149 | |||
1150 | // mask the real /opt directory, currently mounted on RUN_WHITELIST_OPT_DIR | ||
1151 | if (opt_dir) { | ||
1152 | if (mount("tmpfs", RUN_WHITELIST_OPT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1153 | errExit("mount tmpfs"); | ||
1154 | fs_logger2("tmpfs", RUN_WHITELIST_OPT_DIR); | ||
1155 | } | ||
1156 | |||
1157 | // mask the real /dev directory, currently mounted on RUN_WHITELIST_DEV_DIR | ||
1158 | if (dev_dir) { | ||
1159 | if (mount("tmpfs", RUN_WHITELIST_DEV_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1160 | errExit("mount tmpfs"); | ||
1161 | fs_logger2("tmpfs", RUN_WHITELIST_DEV_DIR); | ||
1162 | } | ||
1163 | |||
1164 | // mask the real /media directory, currently mounted on RUN_WHITELIST_MEDIA_DIR | ||
1165 | if (media_dir) { | ||
1166 | if (mount("tmpfs", RUN_WHITELIST_MEDIA_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1167 | errExit("mount tmpfs"); | ||
1168 | fs_logger2("tmpfs", RUN_WHITELIST_MEDIA_DIR); | ||
1169 | } | ||
1170 | |||
1171 | // mask the real /mnt directory, currently mounted on RUN_WHITELIST_MNT_DIR | ||
1172 | if (mnt_dir) { | ||
1173 | if (mount("tmpfs", RUN_WHITELIST_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1174 | errExit("mount tmpfs"); | ||
1175 | fs_logger2("tmpfs", RUN_WHITELIST_MNT_DIR); | ||
1176 | } | ||
1177 | |||
1178 | // mask the real /srv directory, currently mounted on RUN_WHITELIST_SRV_DIR | ||
1179 | if (srv_dir) { | ||
1180 | if (mount("tmpfs", RUN_WHITELIST_SRV_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1181 | errExit("mount tmpfs"); | ||
1182 | fs_logger2("tmpfs", RUN_WHITELIST_SRV_DIR); | ||
1183 | } | ||
1184 | |||
1185 | // mask the real /etc directory, currently mounted on RUN_WHITELIST_ETC_DIR | ||
1186 | if (etc_dir) { | ||
1187 | if (mount("tmpfs", RUN_WHITELIST_ETC_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1188 | errExit("mount tmpfs"); | ||
1189 | fs_logger2("tmpfs", RUN_WHITELIST_ETC_DIR); | ||
1190 | } | ||
1191 | |||
1192 | // mask the real /usr/share directory, currently mounted on RUN_WHITELIST_SHARE_DIR | ||
1193 | if (share_dir) { | ||
1194 | if (mount("tmpfs", RUN_WHITELIST_SHARE_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1195 | errExit("mount tmpfs"); | ||
1196 | fs_logger2("tmpfs", RUN_WHITELIST_SHARE_DIR); | ||
1197 | } | ||
1198 | |||
1199 | // mask the real /sys/module directory, currently mounted on RUN_WHITELIST_MODULE_DIR | ||
1200 | if (module_dir) { | ||
1201 | if (mount("tmpfs", RUN_WHITELIST_MODULE_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | ||
1202 | errExit("mount tmpfs"); | ||
1203 | fs_logger2("tmpfs", RUN_WHITELIST_MODULE_DIR); | ||
1204 | } | ||
1205 | 787 | ||
1206 | // mask the real /run/user/$uid directory, currently mounted on RUN_WHITELIST_RUN_USER_DIR | 788 | for (i = 0; i < TOP_MAX && topdirs[i].path; i++) { |
1207 | if (run_dir) { | 789 | free(topdirs[i].path); |
1208 | if (mount("tmpfs", RUN_WHITELIST_RUN_USER_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,gid=0") < 0) | 790 | close(topdirs[i].fd); |
1209 | errExit("mount tmpfs"); | ||
1210 | fs_logger2("tmpfs", RUN_WHITELIST_RUN_USER_DIR); | ||
1211 | } | 791 | } |
1212 | 792 | free(topdirs); | |
1213 | free(runuser); | 793 | free(runuser); |
1214 | return; | ||
1215 | |||
1216 | errexit: | ||
1217 | fprintf(stderr, "Error: invalid whitelist path %s\n", new_name); | ||
1218 | exit(1); | ||
1219 | } | 794 | } |
diff --git a/src/firejail/ids.c b/src/firejail/ids.c new file mode 100644 index 000000000..fdb78d6e6 --- /dev/null +++ b/src/firejail/ids.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include "firejail.h" | ||
21 | #include <sys/types.h> | ||
22 | #include <sys/stat.h> | ||
23 | #include <fcntl.h> | ||
24 | |||
25 | |||
26 | static void ids_init(void) { | ||
27 | // store checksums as root in /var/lib/firejail/${USERNAME}.ids | ||
28 | char *fname; | ||
29 | if (asprintf(&fname, VARDIR"/%s.ids", cfg.username) == -1) | ||
30 | errExit("asprintf"); | ||
31 | |||
32 | int rv = unlink(fname); | ||
33 | (void) rv; | ||
34 | int fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0600); | ||
35 | if (fd < 0) { | ||
36 | fprintf(stderr, "Error: cannot create %s\n", fname); | ||
37 | exit(1); | ||
38 | } | ||
39 | |||
40 | // redirect output | ||
41 | close(STDOUT_FILENO); | ||
42 | if (dup(fd) != STDOUT_FILENO) | ||
43 | errExit("dup"); | ||
44 | close(fd); | ||
45 | |||
46 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FIDS, "--init", cfg.homedir); | ||
47 | } | ||
48 | |||
49 | static void ids_check(void) { | ||
50 | // store checksums as root in /var/lib/firejail/${USERNAME}.ids | ||
51 | char *fname; | ||
52 | if (asprintf(&fname, VARDIR"/%s.ids", cfg.username) == -1) | ||
53 | errExit("asprintf"); | ||
54 | |||
55 | int fd = open(fname, O_RDONLY); | ||
56 | if (fd < 0) { | ||
57 | fprintf(stderr, "Error: cannot open %s\n", fname); | ||
58 | exit(1); | ||
59 | } | ||
60 | |||
61 | // redirect input | ||
62 | close(STDIN_FILENO); | ||
63 | if (dup(fd) != STDIN_FILENO) | ||
64 | errExit("dup"); | ||
65 | close(fd); | ||
66 | |||
67 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP| SBOX_ALLOW_STDIN, 3, PATH_FIDS, "--check", cfg.homedir); | ||
68 | } | ||
69 | |||
70 | void run_ids(int argc, char **argv) { | ||
71 | if (argc != 2) { | ||
72 | fprintf(stderr, "Error: only one IDS command expected\n"); | ||
73 | exit(1); | ||
74 | } | ||
75 | |||
76 | EUID_ROOT(); | ||
77 | struct stat s; | ||
78 | if (stat(VARDIR, &s)) // /var/lib/firejail | ||
79 | create_empty_dir_as_root(VARDIR, 0700); | ||
80 | |||
81 | if (strcmp(argv[1], "--ids-init") == 0) | ||
82 | ids_init(); | ||
83 | else if (strcmp(argv[1], "--ids-check") == 0) | ||
84 | ids_check(); | ||
85 | else | ||
86 | fprintf(stderr, "Error: unrecognized IDS command\n"); | ||
87 | |||
88 | exit(0); | ||
89 | } | ||
diff --git a/src/firejail/join.c b/src/firejail/join.c index 1575a7469..5d73f71be 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -45,7 +45,7 @@ static unsigned display = 0; | |||
45 | static void signal_handler(int sig){ | 45 | static void signal_handler(int sig){ |
46 | flush_stdin(); | 46 | flush_stdin(); |
47 | 47 | ||
48 | exit(sig); | 48 | exit(128 + sig); |
49 | } | 49 | } |
50 | 50 | ||
51 | static void install_handler(void) { | 51 | static void install_handler(void) { |
@@ -103,7 +103,7 @@ static void extract_x11_display(pid_t pid) { | |||
103 | if (asprintf(&fname, "%s/%d", RUN_FIREJAIL_X11_DIR, pid) == -1) | 103 | if (asprintf(&fname, "%s/%d", RUN_FIREJAIL_X11_DIR, pid) == -1) |
104 | errExit("asprintf"); | 104 | errExit("asprintf"); |
105 | 105 | ||
106 | FILE *fp = fopen(fname, "r"); | 106 | FILE *fp = fopen(fname, "re"); |
107 | free(fname); | 107 | free(fname); |
108 | if (!fp) | 108 | if (!fp) |
109 | return; | 109 | return; |
@@ -147,7 +147,7 @@ static void extract_command(int argc, char **argv, int index) { | |||
147 | } | 147 | } |
148 | 148 | ||
149 | // build command | 149 | // build command |
150 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, index); | 150 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, index, true); |
151 | } | 151 | } |
152 | 152 | ||
153 | static void extract_nogroups(pid_t pid) { | 153 | static void extract_nogroups(pid_t pid) { |
@@ -219,7 +219,7 @@ static void extract_caps(pid_t pid) { | |||
219 | perror("asprintf"); | 219 | perror("asprintf"); |
220 | exit(1); | 220 | exit(1); |
221 | } | 221 | } |
222 | FILE *fp = fopen(file, "r"); | 222 | FILE *fp = fopen(file, "re"); |
223 | if (!fp) | 223 | if (!fp) |
224 | goto errexit; | 224 | goto errexit; |
225 | 225 | ||
@@ -266,7 +266,7 @@ static void extract_user_namespace(pid_t pid) { | |||
266 | char *uidmap; | 266 | char *uidmap; |
267 | if (asprintf(&uidmap, "/proc/%u/uid_map", pid) == -1) | 267 | if (asprintf(&uidmap, "/proc/%u/uid_map", pid) == -1) |
268 | errExit("asprintf"); | 268 | errExit("asprintf"); |
269 | FILE *fp = fopen(uidmap, "r"); | 269 | FILE *fp = fopen(uidmap, "re"); |
270 | if (!fp) { | 270 | if (!fp) { |
271 | free(uidmap); | 271 | free(uidmap); |
272 | return; | 272 | return; |
@@ -315,6 +315,11 @@ static int open_shell(void) { | |||
315 | fprintf(stderr, "Error: cannot open shell %s\n", cfg.shell); | 315 | fprintf(stderr, "Error: cannot open shell %s\n", cfg.shell); |
316 | exit(1); | 316 | exit(1); |
317 | } | 317 | } |
318 | |||
319 | // pass file descriptor through to the final fexecve | ||
320 | if (asprintf(&cfg.keep_fd, "%s,%d", cfg.keep_fd ? cfg.keep_fd : "", fd) == -1) | ||
321 | errExit("asprintf"); | ||
322 | |||
318 | return fd; | 323 | return fd; |
319 | } | 324 | } |
320 | 325 | ||
@@ -431,7 +436,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
431 | 436 | ||
432 | // set cgroup | 437 | // set cgroup |
433 | if (cfg.cgroup) // not available for uid 0 | 438 | if (cfg.cgroup) // not available for uid 0 |
434 | set_cgroup(cfg.cgroup); | 439 | set_cgroup(cfg.cgroup, getpid()); |
435 | 440 | ||
436 | // join namespaces | 441 | // join namespaces |
437 | if (arg_join_network) { | 442 | if (arg_join_network) { |
@@ -536,7 +541,6 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
536 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); | 541 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); |
537 | 542 | ||
538 | #ifdef HAVE_APPARMOR | 543 | #ifdef HAVE_APPARMOR |
539 | // add apparmor confinement after the execve | ||
540 | set_apparmor(); | 544 | set_apparmor(); |
541 | #endif | 545 | #endif |
542 | 546 | ||
@@ -552,10 +556,6 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
552 | if (cfg.cpus) // not available for uid 0 | 556 | if (cfg.cpus) // not available for uid 0 |
553 | set_cpu_affinity(); | 557 | set_cpu_affinity(); |
554 | 558 | ||
555 | // set nice value | ||
556 | if (arg_nice) | ||
557 | set_nice(cfg.nice); | ||
558 | |||
559 | // add x11 display | 559 | // add x11 display |
560 | if (display) { | 560 | if (display) { |
561 | char *display_str; | 561 | char *display_str; |
@@ -596,15 +596,17 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
596 | 596 | ||
597 | // end of signal-safe code | 597 | // end of signal-safe code |
598 | //***************************** | 598 | //***************************** |
599 | flush_stdin(); | ||
600 | 599 | ||
601 | if (WIFEXITED(status)) { | 600 | if (WIFEXITED(status)) { |
601 | // if we had a proper exit, return that exit status | ||
602 | status = WEXITSTATUS(status); | 602 | status = WEXITSTATUS(status); |
603 | } else if (WIFSIGNALED(status)) { | 603 | } else if (WIFSIGNALED(status)) { |
604 | status = WTERMSIG(status); | 604 | // distinguish fatal signals by adding 128 |
605 | status = 128 + WTERMSIG(status); | ||
605 | } else { | 606 | } else { |
606 | status = 0; | 607 | status = -1; |
607 | } | 608 | } |
608 | 609 | ||
610 | flush_stdin(); | ||
609 | exit(status); | 611 | exit(status); |
610 | } | 612 | } |
diff --git a/src/firejail/ls.c b/src/firejail/ls.c index 63ef2309b..4156a7b25 100644 --- a/src/firejail/ls.c +++ b/src/firejail/ls.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -19,6 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include "firejail.h" | 21 | #include "firejail.h" |
22 | #include "../include/gcov_wrapper.h" | ||
22 | #include <sys/types.h> | 23 | #include <sys/types.h> |
23 | #include <sys/stat.h> | 24 | #include <sys/stat.h> |
24 | #include <sys/wait.h> | 25 | #include <sys/wait.h> |
@@ -45,7 +46,8 @@ static void print_file_or_dir(const char *path, const char *fname) { | |||
45 | struct stat s; | 46 | struct stat s; |
46 | if (stat(name, &s) == -1) { | 47 | if (stat(name, &s) == -1) { |
47 | if (lstat(name, &s) == -1) { | 48 | if (lstat(name, &s) == -1) { |
48 | printf("Error: cannot access %s\n", name); | 49 | printf("Error: cannot access %s\n", do_replace_cntrl_chars(name, '?')); |
50 | free(name); | ||
49 | return; | 51 | return; |
50 | } | 52 | } |
51 | } | 53 | } |
@@ -150,12 +152,17 @@ static void print_file_or_dir(const char *path, const char *fname) { | |||
150 | if (allocated) | 152 | if (allocated) |
151 | free(groupname); | 153 | free(groupname); |
152 | 154 | ||
155 | // file size | ||
153 | char *sz; | 156 | char *sz; |
154 | if (asprintf(&sz, "%d", (int) s.st_size) == -1) | 157 | if (asprintf(&sz, "%d", (int) s.st_size) == -1) |
155 | errExit("asprintf"); | 158 | errExit("asprintf"); |
156 | printf("%11.10s %s\n", sz, fname); | ||
157 | free(sz); | ||
158 | 159 | ||
160 | // file name | ||
161 | char *fname_print = replace_cntrl_chars(fname, '?'); | ||
162 | |||
163 | printf("%11.10s %s\n", sz, fname_print); | ||
164 | free(sz); | ||
165 | free(fname_print); | ||
159 | } | 166 | } |
160 | 167 | ||
161 | static void print_directory(const char *path) { | 168 | static void print_directory(const char *path) { |
@@ -191,13 +198,15 @@ void ls(const char *path) { | |||
191 | fprintf(stderr, "Error: cannot access %s\n", path); | 198 | fprintf(stderr, "Error: cannot access %s\n", path); |
192 | exit(1); | 199 | exit(1); |
193 | } | 200 | } |
201 | |||
202 | // debug doesn't filter control characters currently | ||
194 | if (arg_debug) | 203 | if (arg_debug) |
195 | printf("ls %s\n", rp); | 204 | printf("ls %s\n", rp); |
196 | 205 | ||
197 | // list directory contents | 206 | // list directory contents |
198 | struct stat s; | 207 | struct stat s; |
199 | if (stat(rp, &s) == -1) { | 208 | if (stat(rp, &s) == -1) { |
200 | fprintf(stderr, "Error: cannot access %s\n", rp); | 209 | fprintf(stderr, "Error: cannot access %s\n", do_replace_cntrl_chars(rp, '?')); |
201 | exit(1); | 210 | exit(1); |
202 | } | 211 | } |
203 | if (S_ISDIR(s.st_mode)) | 212 | if (S_ISDIR(s.st_mode)) |
@@ -221,7 +230,7 @@ void cat(const char *path) { | |||
221 | 230 | ||
222 | if (arg_debug) | 231 | if (arg_debug) |
223 | printf("cat %s\n", path); | 232 | printf("cat %s\n", path); |
224 | FILE *fp = fopen(path, "r"); | 233 | FILE *fp = fopen(path, "re"); |
225 | if (!fp) { | 234 | if (!fp) { |
226 | fprintf(stderr, "Error: cannot read %s\n", path); | 235 | fprintf(stderr, "Error: cannot read %s\n", path); |
227 | exit(1); | 236 | exit(1); |
@@ -236,13 +245,13 @@ void cat(const char *path) { | |||
236 | fprintf(stderr, "Error: %s is not a regular file\n", path); | 245 | fprintf(stderr, "Error: %s is not a regular file\n", path); |
237 | exit(1); | 246 | exit(1); |
238 | } | 247 | } |
239 | bool tty = isatty(STDOUT_FILENO); | 248 | int tty = isatty(STDOUT_FILENO); |
240 | 249 | ||
241 | int c; | 250 | int c; |
242 | while ((c = fgetc(fp)) != EOF) { | 251 | while ((c = fgetc(fp)) != EOF) { |
243 | // file is untrusted | 252 | // file is untrusted |
244 | // replace control characters when printing to a terminal | 253 | // replace control characters when printing to a terminal |
245 | if (tty && c != '\t' && c != '\n' && iscntrl((unsigned char) c)) | 254 | if (tty && iscntrl((unsigned char) c) && c != '\t' && c != '\n') |
246 | c = '?'; | 255 | c = '?'; |
247 | fputc(c, stdout); | 256 | fputc(c, stdout); |
248 | } | 257 | } |
@@ -304,7 +313,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
304 | } | 313 | } |
305 | // create destination file if necessary | 314 | // create destination file if necessary |
306 | EUID_ASSERT(); | 315 | EUID_ASSERT(); |
307 | int fd = open(dest_fname, O_WRONLY|O_CREAT|O_CLOEXEC, S_IRUSR | S_IWRITE); | 316 | int fd = open(dest_fname, O_WRONLY|O_CREAT|O_CLOEXEC, S_IRUSR | S_IWUSR); |
308 | if (fd == -1) { | 317 | if (fd == -1) { |
309 | fprintf(stderr, "Error: cannot open %s for writing\n", dest_fname); | 318 | fprintf(stderr, "Error: cannot open %s for writing\n", dest_fname); |
310 | exit(1); | 319 | exit(1); |
@@ -324,7 +333,6 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
324 | // redirection | 333 | // redirection |
325 | if (dup2(fd, STDOUT_FILENO) == -1) | 334 | if (dup2(fd, STDOUT_FILENO) == -1) |
326 | errExit("dup2"); | 335 | errExit("dup2"); |
327 | assert(fd != STDOUT_FILENO); | ||
328 | close(fd); | 336 | close(fd); |
329 | op = SANDBOX_FS_CAT; | 337 | op = SANDBOX_FS_CAT; |
330 | } | 338 | } |
@@ -349,9 +357,8 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
349 | ls(fname1); | 357 | ls(fname1); |
350 | else | 358 | else |
351 | cat(fname1); | 359 | cat(fname1); |
352 | #ifdef HAVE_GCOV | 360 | |
353 | __gcov_flush(); | 361 | __gcov_flush(); |
354 | #endif | ||
355 | } | 362 | } |
356 | // get file from host and store it in the sandbox | 363 | // get file from host and store it in the sandbox |
357 | else if (op == SANDBOX_FS_PUT && path2) { | 364 | else if (op == SANDBOX_FS_PUT && path2) { |
@@ -383,9 +390,9 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
383 | // copy the file | 390 | // copy the file |
384 | if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) // already a regular user | 391 | if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) // already a regular user |
385 | _exit(1); | 392 | _exit(1); |
386 | #ifdef HAVE_GCOV | 393 | |
387 | __gcov_flush(); | 394 | __gcov_flush(); |
388 | #endif | 395 | |
389 | _exit(0); | 396 | _exit(0); |
390 | } | 397 | } |
391 | 398 | ||
@@ -415,9 +422,9 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
415 | // copy the file | 422 | // copy the file |
416 | if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) // already a regular user | 423 | if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) // already a regular user |
417 | _exit(1); | 424 | _exit(1); |
418 | #ifdef HAVE_GCOV | 425 | |
419 | __gcov_flush(); | 426 | __gcov_flush(); |
420 | #endif | 427 | |
421 | _exit(0); | 428 | _exit(0); |
422 | } | 429 | } |
423 | 430 | ||
diff --git a/src/firejail/macros.c b/src/firejail/macros.c index 7f2f6dbf3..3f9460041 100644 --- a/src/firejail/macros.c +++ b/src/firejail/macros.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -22,9 +22,11 @@ | |||
22 | #define MAXBUF 4098 | 22 | #define MAXBUF 4098 |
23 | 23 | ||
24 | typedef struct macro_t { | 24 | typedef struct macro_t { |
25 | char *name; // macro name | 25 | char *name; // macro name |
26 | char *xdg; // xdg line in ~/.config/user-dirs.dirs | 26 | char *xdg; // xdg line in ~/.config/user-dirs.dirs |
27 | #define MAX_TRANSLATIONS 3 // several translations in case ~/.config/user-dirs.dirs not found | 27 | // several translations in case ~/.config/user-dirs.dirs not found |
28 | // covered currently: English, Russian, French, Italian, Spanish, Portuguese, German | ||
29 | #define MAX_TRANSLATIONS 7 | ||
28 | char *translation[MAX_TRANSLATIONS]; | 30 | char *translation[MAX_TRANSLATIONS]; |
29 | } Macro; | 31 | } Macro; |
30 | 32 | ||
@@ -32,37 +34,37 @@ Macro macro[] = { | |||
32 | { | 34 | { |
33 | "${DOWNLOADS}", | 35 | "${DOWNLOADS}", |
34 | "XDG_DOWNLOAD_DIR=\"$HOME/", | 36 | "XDG_DOWNLOAD_DIR=\"$HOME/", |
35 | { "Downloads", "Загрузки", "Téléchargement" } | 37 | {"Downloads", "Загрузки", "Téléchargement", "Scaricati", "Descargas"} |
36 | }, | 38 | }, |
37 | 39 | ||
38 | { | 40 | { |
39 | "${MUSIC}", | 41 | "${MUSIC}", |
40 | "XDG_MUSIC_DIR=\"$HOME/", | 42 | "XDG_MUSIC_DIR=\"$HOME/", |
41 | {"Music", "Музыка", "Musique"} | 43 | {"Music", "Музыка", "Musique", "Musica", "Música", "Musik"} |
42 | }, | 44 | }, |
43 | 45 | ||
44 | { | 46 | { |
45 | "${VIDEOS}", | 47 | "${VIDEOS}", |
46 | "XDG_VIDEOS_DIR=\"$HOME/", | 48 | "XDG_VIDEOS_DIR=\"$HOME/", |
47 | {"Videos", "Видео", "Vidéos"} | 49 | {"Videos", "Видео", "Vidéos", "Video", "Vídeos"} |
48 | }, | 50 | }, |
49 | 51 | ||
50 | { | 52 | { |
51 | "${PICTURES}", | 53 | "${PICTURES}", |
52 | "XDG_PICTURES_DIR=\"$HOME/", | 54 | "XDG_PICTURES_DIR=\"$HOME/", |
53 | {"Pictures", "Изображения", "Photos"} | 55 | {"Pictures", "Изображения", "Photos", "Immagini", "Imágenes", "Imagens", "Bilder"} |
54 | }, | 56 | }, |
55 | 57 | ||
56 | { | 58 | { |
57 | "${DESKTOP}", | 59 | "${DESKTOP}", |
58 | "XDG_DESKTOP_DIR=\"$HOME/", | 60 | "XDG_DESKTOP_DIR=\"$HOME/", |
59 | {"Desktop", "Рабочий стол", "Bureau"} | 61 | {"Desktop", "Рабочий стол", "Bureau", "Scrivania", "Escritorio", "Área de trabalho", "Schreibtisch"} |
60 | }, | 62 | }, |
61 | 63 | ||
62 | { | 64 | { |
63 | "${DOCUMENTS}", | 65 | "${DOCUMENTS}", |
64 | "XDG_DOCUMENTS_DIR=\"$HOME/", | 66 | "XDG_DOCUMENTS_DIR=\"$HOME/", |
65 | {"Documents", "Документы", "Documents"} | 67 | {"Documents", "Документы", "Documenti", "Documentos", "Dokumente"} |
66 | }, | 68 | }, |
67 | 69 | ||
68 | { 0 } | 70 | { 0 } |
@@ -99,7 +101,7 @@ static char *resolve_xdg(const char *var) { | |||
99 | 101 | ||
100 | if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1) | 102 | if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1) |
101 | errExit("asprintf"); | 103 | errExit("asprintf"); |
102 | FILE *fp = fopen(fname, "r"); | 104 | FILE *fp = fopen(fname, "re"); |
103 | if (!fp) { | 105 | if (!fp) { |
104 | free(fname); | 106 | free(fname); |
105 | return NULL; | 107 | return NULL; |
@@ -149,11 +151,12 @@ static char *resolve_xdg(const char *var) { | |||
149 | 151 | ||
150 | // returns mallocated memory | 152 | // returns mallocated memory |
151 | static char *resolve_hardcoded(char *entries[]) { | 153 | static char *resolve_hardcoded(char *entries[]) { |
154 | EUID_ASSERT(); | ||
152 | char *fname; | 155 | char *fname; |
153 | struct stat s; | 156 | struct stat s; |
154 | 157 | ||
155 | int i = 0; | 158 | int i = 0; |
156 | while (entries[i] != NULL) { | 159 | while (i < MAX_TRANSLATIONS && entries[i] != NULL) { |
157 | if (asprintf(&fname, "%s/%s", cfg.homedir, entries[i]) == -1) | 160 | if (asprintf(&fname, "%s/%s", cfg.homedir, entries[i]) == -1) |
158 | errExit("asprintf"); | 161 | errExit("asprintf"); |
159 | 162 | ||
@@ -262,28 +265,6 @@ char *expand_macros(const char *path) { | |||
262 | return rv; | 265 | return rv; |
263 | } | 266 | } |
264 | 267 | ||
265 | // replace control characters with a '?' | ||
266 | static char *fix_control_chars(const char *fname) { | ||
267 | assert(fname); | ||
268 | |||
269 | size_t len = strlen(fname); | ||
270 | char *rv = malloc(len + 1); | ||
271 | if (!rv) | ||
272 | errExit("malloc"); | ||
273 | |||
274 | size_t i = 0; | ||
275 | while (fname[i] != '\0') { | ||
276 | if (iscntrl((unsigned char) fname[i])) | ||
277 | rv[i] = '?'; | ||
278 | else | ||
279 | rv[i] = fname[i]; | ||
280 | i++; | ||
281 | } | ||
282 | rv[i] = '\0'; | ||
283 | |||
284 | return rv; | ||
285 | } | ||
286 | |||
287 | void invalid_filename(const char *fname, int globbing) { | 268 | void invalid_filename(const char *fname, int globbing) { |
288 | // EUID_ASSERT(); | 269 | // EUID_ASSERT(); |
289 | assert(fname); | 270 | assert(fname); |
@@ -301,24 +282,5 @@ void invalid_filename(const char *fname, int globbing) { | |||
301 | return; | 282 | return; |
302 | } | 283 | } |
303 | 284 | ||
304 | size_t i = 0; | 285 | reject_meta_chars(ptr, globbing); |
305 | while (ptr[i] != '\0') { | ||
306 | if (iscntrl((unsigned char) ptr[i])) { | ||
307 | char *new = fix_control_chars(fname); | ||
308 | fprintf(stderr, "Error: \"%s\" is an invalid filename: no control characters allowed\n", new); | ||
309 | exit(1); | ||
310 | } | ||
311 | i++; | ||
312 | } | ||
313 | |||
314 | char *reject; | ||
315 | if (globbing) | ||
316 | reject = "\\&!\"'<>%^{};,"; // file globbing ('*?[]') is allowed | ||
317 | else | ||
318 | reject = "\\&!?\"'<>%^{};,*[]"; | ||
319 | char *c = strpbrk(ptr, reject); | ||
320 | if (c) { | ||
321 | fprintf(stderr, "Error: \"%s\" is an invalid filename: rejected character: \"%c\"\n", fname, *c); | ||
322 | exit(1); | ||
323 | } | ||
324 | } | 286 | } |
diff --git a/src/firejail/main.c b/src/firejail/main.c index d6de6d997..4b01ea0a5 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,6 +20,7 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include "../include/pid.h" | 21 | #include "../include/pid.h" |
22 | #include "../include/firejail_user.h" | 22 | #include "../include/firejail_user.h" |
23 | #include "../include/gcov_wrapper.h" | ||
23 | #include "../include/syscall.h" | 24 | #include "../include/syscall.h" |
24 | #include "../include/seccomp.h" | 25 | #include "../include/seccomp.h" |
25 | #define _GNU_SOURCE | 26 | #define _GNU_SOURCE |
@@ -31,7 +32,8 @@ | |||
31 | #include <dirent.h> | 32 | #include <dirent.h> |
32 | #include <pwd.h> | 33 | #include <pwd.h> |
33 | #include <errno.h> | 34 | #include <errno.h> |
34 | //#include <limits.h> | 35 | |
36 | #include <limits.h> | ||
35 | #include <sys/file.h> | 37 | #include <sys/file.h> |
36 | #include <sys/prctl.h> | 38 | #include <sys/prctl.h> |
37 | #include <signal.h> | 39 | #include <signal.h> |
@@ -116,15 +118,16 @@ int arg_private_cwd = 0; // private working directory | |||
116 | int arg_scan = 0; // arp-scan all interfaces | 118 | int arg_scan = 0; // arp-scan all interfaces |
117 | int arg_whitelist = 0; // whitelist command | 119 | int arg_whitelist = 0; // whitelist command |
118 | int arg_nosound = 0; // disable sound | 120 | int arg_nosound = 0; // disable sound |
119 | int arg_noautopulse = 0; // disable automatic ~/.config/pulse init | ||
120 | int arg_novideo = 0; //disable video devices in /dev | 121 | int arg_novideo = 0; //disable video devices in /dev |
121 | int arg_no3d; // disable 3d hardware acceleration | 122 | int arg_no3d; // disable 3d hardware acceleration |
123 | int arg_noprinters = 0; // disable printers | ||
122 | int arg_quiet = 0; // no output for scripting | 124 | int arg_quiet = 0; // no output for scripting |
123 | int arg_join_network = 0; // join only the network namespace | 125 | int arg_join_network = 0; // join only the network namespace |
124 | int arg_join_filesystem = 0; // join only the mount namespace | 126 | int arg_join_filesystem = 0; // join only the mount namespace |
125 | int arg_nice = 0; // nice value configured | 127 | int arg_nice = 0; // nice value configured |
126 | int arg_ipc = 0; // enable ipc namespace | 128 | int arg_ipc = 0; // enable ipc namespace |
127 | int arg_writable_etc = 0; // writable etc | 129 | int arg_writable_etc = 0; // writable etc |
130 | int arg_keep_config_pulse = 0; // disable automatic ~/.config/pulse init | ||
128 | int arg_writable_var = 0; // writable var | 131 | int arg_writable_var = 0; // writable var |
129 | int arg_keep_var_tmp = 0; // don't overwrite /var/tmp | 132 | int arg_keep_var_tmp = 0; // don't overwrite /var/tmp |
130 | int arg_writable_run_user = 0; // writable /run/user | 133 | int arg_writable_run_user = 0; // writable /run/user |
@@ -135,7 +138,7 @@ int arg_allow_debuggers = 0; // allow debuggers | |||
135 | int arg_x11_block = 0; // block X11 | 138 | int arg_x11_block = 0; // block X11 |
136 | int arg_x11_xorg = 0; // use X11 security extension | 139 | int arg_x11_xorg = 0; // use X11 security extension |
137 | int arg_allusers = 0; // all user home directories visible | 140 | int arg_allusers = 0; // all user home directories visible |
138 | int arg_machineid = 0; // preserve /etc/machine-id | 141 | int arg_machineid = 0; // spoof /etc/machine-id |
139 | int arg_allow_private_blacklist = 0; // blacklist things in private directories | 142 | int arg_allow_private_blacklist = 0; // blacklist things in private directories |
140 | int arg_disable_mnt = 0; // disable /mnt and /media | 143 | int arg_disable_mnt = 0; // disable /mnt and /media |
141 | int arg_noprofile = 0; // use default.profile if none other found/specified | 144 | int arg_noprofile = 0; // use default.profile if none other found/specified |
@@ -145,11 +148,14 @@ int arg_nodvd = 0; // --nodvd | |||
145 | int arg_nou2f = 0; // --nou2f | 148 | int arg_nou2f = 0; // --nou2f |
146 | int arg_noinput = 0; // --noinput | 149 | int arg_noinput = 0; // --noinput |
147 | int arg_deterministic_exit_code = 0; // always exit with first child's exit status | 150 | int arg_deterministic_exit_code = 0; // always exit with first child's exit status |
151 | int arg_deterministic_shutdown = 0; // shut down the sandbox if first child dies | ||
152 | int arg_keep_fd_all = 0; // inherit all file descriptors to sandbox | ||
148 | DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user | 153 | DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user |
149 | DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system | 154 | DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system |
150 | const char *arg_dbus_log_file = NULL; | 155 | const char *arg_dbus_log_file = NULL; |
151 | int arg_dbus_log_user = 0; | 156 | int arg_dbus_log_user = 0; |
152 | int arg_dbus_log_system = 0; | 157 | int arg_dbus_log_system = 0; |
158 | int arg_tab = 0; | ||
153 | int login_shell = 0; | 159 | int login_shell = 0; |
154 | 160 | ||
155 | int parent_to_child_fds[2]; | 161 | int parent_to_child_fds[2]; |
@@ -188,13 +194,15 @@ static void my_handler(int s) { | |||
188 | logsignal(s); | 194 | logsignal(s); |
189 | 195 | ||
190 | if (waitpid(child, NULL, WNOHANG) == 0) { | 196 | if (waitpid(child, NULL, WNOHANG) == 0) { |
191 | if (has_handler(child, s)) // signals are not delivered if there is no handler yet | 197 | // child is pid 1 of a pid namespace: |
198 | // signals are not delivered if there is no handler yet | ||
199 | if (has_handler(child, s)) | ||
192 | kill(child, s); | 200 | kill(child, s); |
193 | else | 201 | else |
194 | kill(child, SIGKILL); | 202 | kill(child, SIGKILL); |
195 | waitpid(child, NULL, 0); | 203 | waitpid(child, NULL, 0); |
196 | } | 204 | } |
197 | myexit(s); | 205 | myexit(128 + s); |
198 | } | 206 | } |
199 | 207 | ||
200 | static void install_handler(void) { | 208 | static void install_handler(void) { |
@@ -259,8 +267,8 @@ static void init_cfg(int argc, char **argv) { | |||
259 | fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); | 267 | fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); |
260 | exit(1); | 268 | exit(1); |
261 | } | 269 | } |
270 | check_homedir(pw->pw_dir); | ||
262 | cfg.homedir = clean_pathname(pw->pw_dir); | 271 | cfg.homedir = clean_pathname(pw->pw_dir); |
263 | check_homedir(); | ||
264 | 272 | ||
265 | // initialize random number generator | 273 | // initialize random number generator |
266 | sandbox_pid = getpid(); | 274 | sandbox_pid = getpid(); |
@@ -402,6 +410,23 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
402 | } | 410 | } |
403 | #endif | 411 | #endif |
404 | #ifdef HAVE_NETWORK | 412 | #ifdef HAVE_NETWORK |
413 | else if (strcmp(argv[i], "--nettrace") == 0) { | ||
414 | if (checkcfg(CFG_NETWORK)) { | ||
415 | netfilter_trace(0); | ||
416 | } | ||
417 | else | ||
418 | exit_err_feature("networking"); | ||
419 | exit(0); | ||
420 | } | ||
421 | else if (strncmp(argv[i], "--nettrace=", 11) == 0) { | ||
422 | if (checkcfg(CFG_NETWORK)) { | ||
423 | pid_t pid = require_pid(argv[i] + 11); | ||
424 | netfilter_trace(pid); | ||
425 | } | ||
426 | else | ||
427 | exit_err_feature("networking"); | ||
428 | exit(0); | ||
429 | } | ||
405 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { | 430 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { |
406 | if (checkcfg(CFG_NETWORK)) { | 431 | if (checkcfg(CFG_NETWORK)) { |
407 | logargs(argc, argv); | 432 | logargs(argc, argv); |
@@ -535,7 +560,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
535 | char *fname; | 560 | char *fname; |
536 | if (asprintf(&fname, RUN_FIREJAIL_PROFILE_DIR "/%d", pid) == -1) | 561 | if (asprintf(&fname, RUN_FIREJAIL_PROFILE_DIR "/%d", pid) == -1) |
537 | errExit("asprintf"); | 562 | errExit("asprintf"); |
538 | FILE *fp = fopen(fname, "r"); | 563 | FILE *fp = fopen(fname, "re"); |
539 | if (!fp) { | 564 | if (!fp) { |
540 | fprintf(stderr, "Error: sandbox %s not found\n", argv[i] + 16); | 565 | fprintf(stderr, "Error: sandbox %s not found\n", argv[i] + 16); |
541 | exit(1); | 566 | exit(1); |
@@ -862,13 +887,12 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
862 | char *guess_shell(void) { | 887 | char *guess_shell(void) { |
863 | const char *shell; | 888 | const char *shell; |
864 | char *retval; | 889 | char *retval; |
865 | struct stat s; | ||
866 | 890 | ||
867 | shell = env_get("SHELL"); | 891 | shell = env_get("SHELL"); |
868 | if (shell) { | 892 | if (shell) { |
869 | invalid_filename(shell, 0); // no globbing | 893 | invalid_filename(shell, 0); // no globbing |
870 | if (!is_dir(shell) && strstr(shell, "..") == NULL && stat(shell, &s) == 0 && access(shell, X_OK) == 0 && | 894 | if (access(shell, X_OK) == 0 && !is_dir(shell) && strstr(shell, "..") == NULL && |
871 | strcmp(shell, PATH_FIREJAIL) != 0) | 895 | strcmp(gnu_basename(shell), "firejail") != 0) |
872 | goto found; | 896 | goto found; |
873 | } | 897 | } |
874 | 898 | ||
@@ -878,12 +902,15 @@ char *guess_shell(void) { | |||
878 | int i = 0; | 902 | int i = 0; |
879 | while (shells[i] != NULL) { | 903 | while (shells[i] != NULL) { |
880 | // access call checks as real UID/GID, not as effective UID/GID | 904 | // access call checks as real UID/GID, not as effective UID/GID |
881 | if (stat(shells[i], &s) == 0 && access(shells[i], X_OK) == 0) { | 905 | if (access(shells[i], X_OK) == 0) { |
882 | shell = shells[i]; | 906 | shell = shells[i]; |
883 | break; | 907 | goto found; |
884 | } | 908 | } |
885 | i++; | 909 | i++; |
886 | } | 910 | } |
911 | |||
912 | return NULL; | ||
913 | |||
887 | found: | 914 | found: |
888 | retval = strdup(shell); | 915 | retval = strdup(shell); |
889 | if (!retval) | 916 | if (!retval) |
@@ -929,12 +956,14 @@ static void run_builder(int argc, char **argv) { | |||
929 | if (setresuid(-1, getuid(), getuid()) != 0) | 956 | if (setresuid(-1, getuid(), getuid()) != 0) |
930 | errExit("setresuid"); | 957 | errExit("setresuid"); |
931 | 958 | ||
959 | if (env_get("LD_PRELOAD") != NULL) | ||
960 | fprintf(stderr, "run_builder: LD_PRELOAD is: '%s'\n", env_get("LD_PRELOAD")); | ||
932 | assert(env_get("LD_PRELOAD") == NULL); | 961 | assert(env_get("LD_PRELOAD") == NULL); |
933 | assert(getenv("LD_PRELOAD") == NULL); | 962 | assert(getenv("LD_PRELOAD") == NULL); |
934 | umask(orig_umask); | 963 | umask(orig_umask); |
935 | 964 | ||
936 | // restore some environment variables | 965 | // restore original environment variables |
937 | env_apply_whitelist_sbox(); | 966 | env_apply_all(); |
938 | 967 | ||
939 | argv[0] = LIBDIR "/firejail/fbuilder"; | 968 | argv[0] = LIBDIR "/firejail/fbuilder"; |
940 | execvp(argv[0], argv); | 969 | execvp(argv[0], argv); |
@@ -961,7 +990,7 @@ void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, b | |||
961 | static int check_postexec(const char *list) { | 990 | static int check_postexec(const char *list) { |
962 | char *prelist, *postlist; | 991 | char *prelist, *postlist; |
963 | 992 | ||
964 | if (list) { | 993 | if (list && list[0]) { |
965 | syscalls_in_list(list, "@default-keep", -1, &prelist, &postlist, true); | 994 | syscalls_in_list(list, "@default-keep", -1, &prelist, &postlist, true); |
966 | if (postlist) | 995 | if (postlist) |
967 | return 1; | 996 | return 1; |
@@ -980,125 +1009,64 @@ int main(int argc, char **argv, char **envp) { | |||
980 | int option_cgroup = 0; | 1009 | int option_cgroup = 0; |
981 | int custom_profile = 0; // custom profile loaded | 1010 | int custom_profile = 0; // custom profile loaded |
982 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) | 1011 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) |
1012 | int arg_netlock = 0; | ||
983 | char **ptr; | 1013 | char **ptr; |
984 | 1014 | ||
1015 | |||
985 | // sanitize the umask | 1016 | // sanitize the umask |
986 | orig_umask = umask(022); | 1017 | orig_umask = umask(022); |
987 | 1018 | ||
988 | // check standard streams before printing anything | ||
989 | fix_std_streams(); | ||
990 | |||
991 | // drop permissions by default and rise them when required | 1019 | // drop permissions by default and rise them when required |
992 | EUID_INIT(); | 1020 | EUID_INIT(); |
993 | EUID_USER(); | 1021 | EUID_USER(); |
994 | 1022 | ||
1023 | // check standard streams before opening any file | ||
1024 | fix_std_streams(); | ||
1025 | |||
995 | // argument count should be larger than 0 | 1026 | // argument count should be larger than 0 |
996 | if (argc == 0 || !argv || strlen(argv[0]) == 0) { | 1027 | if (argc == 0 || !argv || strlen(argv[0]) == 0) { |
997 | fprintf(stderr, "Error: argv is invalid\n"); | 1028 | fprintf(stderr, "Error: argv is invalid\n"); |
998 | exit(1); | 1029 | exit(1); |
999 | } else if (argc >= MAX_ARGS) { | 1030 | } else if (argc >= MAX_ARGS) { |
1000 | fprintf(stderr, "Error: too many arguments\n"); | 1031 | fprintf(stderr, "Error: too many arguments: argc (%d) >= MAX_ARGS (%d)\n", argc, MAX_ARGS); |
1001 | exit(1); | 1032 | exit(1); |
1002 | } | 1033 | } |
1003 | 1034 | ||
1035 | // sanity check for arguments | ||
1036 | for (i = 0; i < argc; i++) { | ||
1037 | // if (*argv[i] == 0) { // see #4395 - bug reported by Debian | ||
1038 | // fprintf(stderr, "Error: too short arguments: argv[%d] is empty\n", i); | ||
1039 | // exit(1); | ||
1040 | // } | ||
1041 | if (strlen(argv[i]) >= MAX_ARG_LEN) { | ||
1042 | fprintf(stderr, "Error: too long arguments: argv[%d] len (%zu) >= MAX_ARG_LEN (%d)\n", i, strlen(argv[i]), MAX_ARG_LEN); | ||
1043 | exit(1); | ||
1044 | } | ||
1045 | } | ||
1046 | |||
1004 | // Stash environment variables | 1047 | // Stash environment variables |
1005 | for (i = 0, ptr = envp; ptr && *ptr && i < MAX_ENVS; i++, ptr++) | 1048 | for (i = 0, ptr = envp; ptr && *ptr && i < MAX_ENVS; i++, ptr++) |
1006 | env_store(*ptr, SETENV); | 1049 | env_store(*ptr, SETENV); |
1007 | 1050 | ||
1008 | // sanity check for environment variables | 1051 | // sanity check for environment variables |
1009 | if (i >= MAX_ENVS) { | 1052 | if (i >= MAX_ENVS) { |
1010 | fprintf(stderr, "Error: too many environment variables\n"); | 1053 | fprintf(stderr, "Error: too many environment variables: >= MAX_ENVS (%d)\n", MAX_ENVS); |
1011 | exit(1); | 1054 | exit(1); |
1012 | } | 1055 | } |
1013 | 1056 | ||
1014 | // sanity check for arguments | ||
1015 | for (i = 0; i < argc; i++) { | ||
1016 | if (*argv[i] == 0) { | ||
1017 | fprintf(stderr, "Error: too short arguments\n"); | ||
1018 | exit(1); | ||
1019 | } | ||
1020 | if (strlen(argv[i]) >= MAX_ARG_LEN) { | ||
1021 | fprintf(stderr, "Error: too long arguments\n"); | ||
1022 | exit(1); | ||
1023 | } | ||
1024 | } | ||
1025 | |||
1026 | // Reapply a minimal set of environment variables | 1057 | // Reapply a minimal set of environment variables |
1027 | env_apply_whitelist(); | 1058 | env_apply_whitelist(); |
1028 | 1059 | ||
1029 | // check if the user is allowed to use firejail | 1060 | // process --quiet |
1030 | init_cfg(argc, argv); | ||
1031 | |||
1032 | // get starting timestamp, process --quiet | ||
1033 | timetrace_start(); | ||
1034 | const char *env_quiet = env_get("FIREJAIL_QUIET"); | 1061 | const char *env_quiet = env_get("FIREJAIL_QUIET"); |
1035 | if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0)) | 1062 | if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0)) |
1036 | arg_quiet = 1; | 1063 | arg_quiet = 1; |
1037 | 1064 | ||
1038 | // cleanup at exit | 1065 | // check if the user is allowed to use firejail |
1039 | EUID_ROOT(); | 1066 | init_cfg(argc, argv); |
1040 | atexit(clear_atexit); | ||
1041 | |||
1042 | // build /run/firejail directory structure | ||
1043 | preproc_build_firejail_dir(); | ||
1044 | const char *container_name = env_get("container"); | ||
1045 | if (!container_name || strcmp(container_name, "firejail")) { | ||
1046 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); | ||
1047 | if (lockfd_directory != -1) { | ||
1048 | int rv = fchown(lockfd_directory, 0, 0); | ||
1049 | (void) rv; | ||
1050 | flock(lockfd_directory, LOCK_EX); | ||
1051 | } | ||
1052 | preproc_clean_run(); | ||
1053 | flock(lockfd_directory, LOCK_UN); | ||
1054 | close(lockfd_directory); | ||
1055 | } | ||
1056 | EUID_USER(); | ||
1057 | |||
1058 | // --ip=dhcp - we need access to /sbin and /usr/sbin directories in order to run ISC DHCP client (dhclient) | ||
1059 | // these paths are disabled in disable-common.inc | ||
1060 | if ((i = check_arg(argc, argv, "--ip", 0)) != 0) { | ||
1061 | if (strncmp(argv[i] + 4, "=dhcp", 5) == 0) { | ||
1062 | profile_add("noblacklist /sbin"); | ||
1063 | profile_add("noblacklist /usr/sbin"); | ||
1064 | } | ||
1065 | } | ||
1066 | |||
1067 | // for appimages we need to remove "include disable-shell.inc from the profile | ||
1068 | // a --profile command can show up before --appimage | ||
1069 | if (check_arg(argc, argv, "--appimage", 1)) | ||
1070 | arg_appimage = 1; | ||
1071 | |||
1072 | // process allow-debuggers | ||
1073 | if (check_arg(argc, argv, "--allow-debuggers", 1)) { | ||
1074 | // check kernel version | ||
1075 | struct utsname u; | ||
1076 | int rv = uname(&u); | ||
1077 | if (rv != 0) | ||
1078 | errExit("uname"); | ||
1079 | int major; | ||
1080 | int minor; | ||
1081 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
1082 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
1083 | exit(1); | ||
1084 | } | ||
1085 | if (major < 4 || (major == 4 && minor < 8)) { | ||
1086 | fprintf(stderr, "Error: --allow-debuggers is disabled on Linux kernels prior to 4.8. " | ||
1087 | "A bug in ptrace call allows a full bypass of the seccomp filter. " | ||
1088 | "Your current kernel version is %d.%d.\n", major, minor); | ||
1089 | exit(1); | ||
1090 | } | ||
1091 | |||
1092 | arg_allow_debuggers = 1; | ||
1093 | char *cmd = strdup("noblacklist ${PATH}/strace"); | ||
1094 | if (!cmd) | ||
1095 | errExit("strdup"); | ||
1096 | profile_add(cmd); | ||
1097 | } | ||
1098 | 1067 | ||
1099 | // profile builder | 1068 | // get starting timestamp |
1100 | if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename | 1069 | timetrace_start(); |
1101 | run_builder(argc, argv); // this function will not return | ||
1102 | 1070 | ||
1103 | // check argv[0] symlink wrapper if this is not a login shell | 1071 | // check argv[0] symlink wrapper if this is not a login shell |
1104 | if (*argv[0] != '-') | 1072 | if (*argv[0] != '-') |
@@ -1123,15 +1091,44 @@ int main(int argc, char **argv, char **envp) { | |||
1123 | __builtin_unreachable(); | 1091 | __builtin_unreachable(); |
1124 | } | 1092 | } |
1125 | } | 1093 | } |
1126 | EUID_ASSERT(); | ||
1127 | 1094 | ||
1095 | // profile builder | ||
1096 | if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename | ||
1097 | run_builder(argc, argv); // this function will not return | ||
1098 | |||
1099 | // intrusion detection system | ||
1100 | if (check_arg(argc, argv, "--ids-", 0)) // supports both --ids-init and --ids-check | ||
1101 | run_ids(argc, argv); // this function will not return | ||
1128 | 1102 | ||
1129 | // check firejail directories | ||
1130 | EUID_ROOT(); | 1103 | EUID_ROOT(); |
1131 | delete_run_files(sandbox_pid); | 1104 | #ifndef HAVE_SUID |
1105 | if (geteuid() != 0) { | ||
1106 | fprintf(stderr, "Error: Firejail needs to be SUID.\n"); | ||
1107 | fprintf(stderr, "Assuming firejail is installed in /usr/bin, execute the following command as root:\n"); | ||
1108 | fprintf(stderr, " chmod u+s /usr/bin/firejail\n"); | ||
1109 | } | ||
1110 | #endif | ||
1111 | |||
1112 | // build /run/firejail directory structure | ||
1113 | preproc_build_firejail_dir(); | ||
1114 | const char *container_name = env_get("container"); | ||
1115 | if (!container_name || strcmp(container_name, "firejail")) { | ||
1116 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); | ||
1117 | if (lockfd_directory != -1) { | ||
1118 | int rv = fchown(lockfd_directory, 0, 0); | ||
1119 | (void) rv; | ||
1120 | flock(lockfd_directory, LOCK_EX); | ||
1121 | } | ||
1122 | preproc_clean_run(); | ||
1123 | flock(lockfd_directory, LOCK_UN); | ||
1124 | close(lockfd_directory); | ||
1125 | } | ||
1126 | |||
1127 | delete_run_files(getpid()); | ||
1128 | atexit(clear_atexit); | ||
1132 | EUID_USER(); | 1129 | EUID_USER(); |
1133 | 1130 | ||
1134 | //check if the parent is sshd daemon | 1131 | // check if the parent is sshd daemon |
1135 | int parent_sshd = 0; | 1132 | int parent_sshd = 0; |
1136 | { | 1133 | { |
1137 | pid_t ppid = getppid(); | 1134 | pid_t ppid = getppid(); |
@@ -1145,7 +1142,7 @@ int main(int argc, char **argv, char **envp) { | |||
1145 | 1142 | ||
1146 | #ifdef DEBUG_RESTRICTED_SHELL | 1143 | #ifdef DEBUG_RESTRICTED_SHELL |
1147 | {EUID_ROOT(); | 1144 | {EUID_ROOT(); |
1148 | FILE *fp = fopen("/firelog", "w"); | 1145 | FILE *fp = fopen("/firelog", "we"); |
1149 | if (fp) { | 1146 | if (fp) { |
1150 | int i; | 1147 | int i; |
1151 | fprintf(fp, "argc %d: ", argc); | 1148 | fprintf(fp, "argc %d: ", argc); |
@@ -1164,7 +1161,7 @@ int main(int argc, char **argv, char **envp) { | |||
1164 | strncmp(argv[2], "scp ", 4) == 0) { | 1161 | strncmp(argv[2], "scp ", 4) == 0) { |
1165 | #ifdef DEBUG_RESTRICTED_SHELL | 1162 | #ifdef DEBUG_RESTRICTED_SHELL |
1166 | {EUID_ROOT(); | 1163 | {EUID_ROOT(); |
1167 | FILE *fp = fopen("/firelog", "a"); | 1164 | FILE *fp = fopen("/firelog", "ae"); |
1168 | if (fp) { | 1165 | if (fp) { |
1169 | fprintf(fp, "run without a sandbox\n"); | 1166 | fprintf(fp, "run without a sandbox\n"); |
1170 | fclose(fp); | 1167 | fclose(fp); |
@@ -1188,7 +1185,8 @@ int main(int argc, char **argv, char **envp) { | |||
1188 | } | 1185 | } |
1189 | EUID_ASSERT(); | 1186 | EUID_ASSERT(); |
1190 | 1187 | ||
1191 | // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users | 1188 | // is this a login shell, or a command passed by sshd, |
1189 | // insert command line options from /etc/firejail/login.users | ||
1192 | if (*argv[0] == '-' || parent_sshd) { | 1190 | if (*argv[0] == '-' || parent_sshd) { |
1193 | if (argc == 1) | 1191 | if (argc == 1) |
1194 | login_shell = 1; | 1192 | login_shell = 1; |
@@ -1197,7 +1195,7 @@ int main(int argc, char **argv, char **envp) { | |||
1197 | 1195 | ||
1198 | #ifdef DEBUG_RESTRICTED_SHELL | 1196 | #ifdef DEBUG_RESTRICTED_SHELL |
1199 | {EUID_ROOT(); | 1197 | {EUID_ROOT(); |
1200 | FILE *fp = fopen("/firelog", "a"); | 1198 | FILE *fp = fopen("/firelog", "ae"); |
1201 | if (fp) { | 1199 | if (fp) { |
1202 | fprintf(fp, "fullargc %d: ", fullargc); | 1200 | fprintf(fp, "fullargc %d: ", fullargc); |
1203 | int i; | 1201 | int i; |
@@ -1219,7 +1217,7 @@ int main(int argc, char **argv, char **envp) { | |||
1219 | 1217 | ||
1220 | #ifdef DEBUG_RESTRICTED_SHELL | 1218 | #ifdef DEBUG_RESTRICTED_SHELL |
1221 | {EUID_ROOT(); | 1219 | {EUID_ROOT(); |
1222 | FILE *fp = fopen("/firelog", "a"); | 1220 | FILE *fp = fopen("/firelog", "ae"); |
1223 | if (fp) { | 1221 | if (fp) { |
1224 | fprintf(fp, "argc %d: ", argc); | 1222 | fprintf(fp, "argc %d: ", argc); |
1225 | int i; | 1223 | int i; |
@@ -1240,6 +1238,47 @@ int main(int argc, char **argv, char **envp) { | |||
1240 | #endif | 1238 | #endif |
1241 | EUID_ASSERT(); | 1239 | EUID_ASSERT(); |
1242 | 1240 | ||
1241 | // --ip=dhcp - we need access to /sbin and /usr/sbin directories in order to run ISC DHCP client (dhclient) | ||
1242 | // these paths are disabled in disable-common.inc | ||
1243 | if ((i = check_arg(argc, argv, "--ip", 0)) != 0) { | ||
1244 | if (strncmp(argv[i] + 4, "=dhcp", 5) == 0) { | ||
1245 | profile_add("noblacklist /sbin"); | ||
1246 | profile_add("noblacklist /usr/sbin"); | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | // process allow-debuggers | ||
1251 | if (check_arg(argc, argv, "--allow-debuggers", 1)) { | ||
1252 | // check kernel version | ||
1253 | struct utsname u; | ||
1254 | int rv = uname(&u); | ||
1255 | if (rv != 0) | ||
1256 | errExit("uname"); | ||
1257 | int major; | ||
1258 | int minor; | ||
1259 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
1260 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
1261 | exit(1); | ||
1262 | } | ||
1263 | if (major < 4 || (major == 4 && minor < 8)) { | ||
1264 | fprintf(stderr, "Error: --allow-debuggers is disabled on Linux kernels prior to 4.8. " | ||
1265 | "A bug in ptrace call allows a full bypass of the seccomp filter. " | ||
1266 | "Your current kernel version is %d.%d.\n", major, minor); | ||
1267 | exit(1); | ||
1268 | } | ||
1269 | |||
1270 | arg_allow_debuggers = 1; | ||
1271 | char *cmd = strdup("noblacklist ${PATH}/strace"); | ||
1272 | if (!cmd) | ||
1273 | errExit("strdup"); | ||
1274 | profile_add(cmd); | ||
1275 | } | ||
1276 | |||
1277 | // for appimages we need to remove "include disable-shell.inc from the profile | ||
1278 | // a --profile command can show up before --appimage | ||
1279 | if (check_arg(argc, argv, "--appimage", 1)) | ||
1280 | arg_appimage = 1; | ||
1281 | |||
1243 | // check for force-nonewprivs in /etc/firejail/firejail.config file | 1282 | // check for force-nonewprivs in /etc/firejail/firejail.config file |
1244 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) | 1283 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) |
1245 | arg_nonewprivs = 1; | 1284 | arg_nonewprivs = 1; |
@@ -1248,8 +1287,10 @@ int main(int argc, char **argv, char **envp) { | |||
1248 | for (i = 1; i < argc; i++) { | 1287 | for (i = 1; i < argc; i++) { |
1249 | run_cmd_and_exit(i, argc, argv); // will exit if the command is recognized | 1288 | run_cmd_and_exit(i, argc, argv); // will exit if the command is recognized |
1250 | 1289 | ||
1251 | if (strcmp(argv[i], "--debug") == 0 && !arg_quiet) | 1290 | if (strcmp(argv[i], "--debug") == 0) { |
1252 | arg_debug = 1; | 1291 | arg_debug = 1; |
1292 | arg_quiet = 0; | ||
1293 | } | ||
1253 | else if (strcmp(argv[i], "--debug-blacklists") == 0) | 1294 | else if (strcmp(argv[i], "--debug-blacklists") == 0) |
1254 | arg_debug_blacklists = 1; | 1295 | arg_debug_blacklists = 1; |
1255 | else if (strcmp(argv[i], "--debug-whitelists") == 0) | 1296 | else if (strcmp(argv[i], "--debug-whitelists") == 0) |
@@ -1257,8 +1298,8 @@ int main(int argc, char **argv, char **envp) { | |||
1257 | else if (strcmp(argv[i], "--debug-private-lib") == 0) | 1298 | else if (strcmp(argv[i], "--debug-private-lib") == 0) |
1258 | arg_debug_private_lib = 1; | 1299 | arg_debug_private_lib = 1; |
1259 | else if (strcmp(argv[i], "--quiet") == 0) { | 1300 | else if (strcmp(argv[i], "--quiet") == 0) { |
1260 | arg_quiet = 1; | 1301 | if (!arg_debug) |
1261 | arg_debug = 0; | 1302 | arg_quiet = 1; |
1262 | } | 1303 | } |
1263 | else if (strcmp(argv[i], "--allow-debuggers") == 0) { | 1304 | else if (strcmp(argv[i], "--allow-debuggers") == 0) { |
1264 | // already handled | 1305 | // already handled |
@@ -1480,8 +1521,11 @@ int main(int argc, char **argv, char **envp) { | |||
1480 | arg_rlimit_nproc = 1; | 1521 | arg_rlimit_nproc = 1; |
1481 | } | 1522 | } |
1482 | else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) { | 1523 | else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) { |
1483 | check_unsigned(argv[i] + 15, "Error: invalid rlimit"); | 1524 | cfg.rlimit_fsize = parse_arg_size(argv[i] + 15); |
1484 | sscanf(argv[i] + 15, "%llu", &cfg.rlimit_fsize); | 1525 | if (cfg.rlimit_fsize == 0) { |
1526 | perror("Error: invalid rlimit-fsize. Only use positive numbers and k, m or g suffix."); | ||
1527 | exit(1); | ||
1528 | } | ||
1485 | arg_rlimit_fsize = 1; | 1529 | arg_rlimit_fsize = 1; |
1486 | } | 1530 | } |
1487 | else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) { | 1531 | else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) { |
@@ -1490,8 +1534,11 @@ int main(int argc, char **argv, char **envp) { | |||
1490 | arg_rlimit_sigpending = 1; | 1534 | arg_rlimit_sigpending = 1; |
1491 | } | 1535 | } |
1492 | else if (strncmp(argv[i], "--rlimit-as=", 12) == 0) { | 1536 | else if (strncmp(argv[i], "--rlimit-as=", 12) == 0) { |
1493 | check_unsigned(argv[i] + 12, "Error: invalid rlimit"); | 1537 | cfg.rlimit_as = parse_arg_size(argv[i] + 12); |
1494 | sscanf(argv[i] + 12, "%llu", &cfg.rlimit_as); | 1538 | if (cfg.rlimit_as == 0) { |
1539 | perror("Error: invalid rlimit-as. Only use positive numbers and k, m or g suffix."); | ||
1540 | exit(1); | ||
1541 | } | ||
1495 | arg_rlimit_as = 1; | 1542 | arg_rlimit_as = 1; |
1496 | } | 1543 | } |
1497 | else if (strncmp(argv[i], "--ipc-namespace", 15) == 0) | 1544 | else if (strncmp(argv[i], "--ipc-namespace", 15) == 0) |
@@ -1507,15 +1554,16 @@ int main(int argc, char **argv, char **envp) { | |||
1507 | else if (strncmp(argv[i], "--cgroup=", 9) == 0) { | 1554 | else if (strncmp(argv[i], "--cgroup=", 9) == 0) { |
1508 | if (checkcfg(CFG_CGROUP)) { | 1555 | if (checkcfg(CFG_CGROUP)) { |
1509 | if (option_cgroup) { | 1556 | if (option_cgroup) { |
1510 | fprintf(stderr, "Error: only a cgroup can be defined\n"); | 1557 | fprintf(stderr, "Error: only one cgroup can be defined\n"); |
1511 | exit(1); | 1558 | exit(1); |
1512 | } | 1559 | } |
1513 | |||
1514 | option_cgroup = 1; | ||
1515 | cfg.cgroup = strdup(argv[i] + 9); | 1560 | cfg.cgroup = strdup(argv[i] + 9); |
1516 | if (!cfg.cgroup) | 1561 | if (!cfg.cgroup) |
1517 | errExit("strdup"); | 1562 | errExit("strdup"); |
1518 | set_cgroup(cfg.cgroup); | 1563 | |
1564 | check_cgroup_file(cfg.cgroup); | ||
1565 | set_cgroup(cfg.cgroup, getpid()); | ||
1566 | option_cgroup = 1; | ||
1519 | } | 1567 | } |
1520 | else | 1568 | else |
1521 | exit_err_feature("cgroup"); | 1569 | exit_err_feature("cgroup"); |
@@ -1546,6 +1594,7 @@ int main(int argc, char **argv, char **envp) { | |||
1546 | profile_check_line(line, 0, NULL); // will exit if something wrong | 1594 | profile_check_line(line, 0, NULL); // will exit if something wrong |
1547 | profile_add(line); | 1595 | profile_add(line); |
1548 | } | 1596 | } |
1597 | |||
1549 | else if (strncmp(argv[i], "--blacklist=", 12) == 0) { | 1598 | else if (strncmp(argv[i], "--blacklist=", 12) == 0) { |
1550 | char *line; | 1599 | char *line; |
1551 | if (asprintf(&line, "blacklist %s", argv[i] + 12) == -1) | 1600 | if (asprintf(&line, "blacklist %s", argv[i] + 12) == -1) |
@@ -1562,19 +1611,13 @@ int main(int argc, char **argv, char **envp) { | |||
1562 | profile_check_line(line, 0, NULL); // will exit if something wrong | 1611 | profile_check_line(line, 0, NULL); // will exit if something wrong |
1563 | profile_add(line); | 1612 | profile_add(line); |
1564 | } | 1613 | } |
1565 | |||
1566 | #ifdef HAVE_WHITELIST | ||
1567 | else if (strncmp(argv[i], "--whitelist=", 12) == 0) { | 1614 | else if (strncmp(argv[i], "--whitelist=", 12) == 0) { |
1568 | if (checkcfg(CFG_WHITELIST)) { | 1615 | char *line; |
1569 | char *line; | 1616 | if (asprintf(&line, "whitelist %s", argv[i] + 12) == -1) |
1570 | if (asprintf(&line, "whitelist %s", argv[i] + 12) == -1) | 1617 | errExit("asprintf"); |
1571 | errExit("asprintf"); | ||
1572 | 1618 | ||
1573 | profile_check_line(line, 0, NULL); // will exit if something wrong | 1619 | profile_check_line(line, 0, NULL); // will exit if something wrong |
1574 | profile_add(line); | 1620 | profile_add(line); |
1575 | } | ||
1576 | else | ||
1577 | exit_err_feature("whitelist"); | ||
1578 | } | 1621 | } |
1579 | else if (strncmp(argv[i], "--nowhitelist=", 14) == 0) { | 1622 | else if (strncmp(argv[i], "--nowhitelist=", 14) == 0) { |
1580 | char *line; | 1623 | char *line; |
@@ -1584,7 +1627,7 @@ int main(int argc, char **argv, char **envp) { | |||
1584 | profile_check_line(line, 0, NULL); // will exit if something wrong | 1627 | profile_check_line(line, 0, NULL); // will exit if something wrong |
1585 | profile_add(line); | 1628 | profile_add(line); |
1586 | } | 1629 | } |
1587 | #endif | 1630 | |
1588 | else if (strncmp(argv[i], "--mkdir=", 8) == 0) { | 1631 | else if (strncmp(argv[i], "--mkdir=", 8) == 0) { |
1589 | char *line; | 1632 | char *line; |
1590 | if (asprintf(&line, "mkdir %s", argv[i] + 8) == -1) | 1633 | if (asprintf(&line, "mkdir %s", argv[i] + 8) == -1) |
@@ -1824,6 +1867,8 @@ int main(int argc, char **argv, char **envp) { | |||
1824 | exit(1); | 1867 | exit(1); |
1825 | } | 1868 | } |
1826 | arg_noprofile = 1; | 1869 | arg_noprofile = 1; |
1870 | // force keep-config-pulse in order to keep ~/.config/pulse as is | ||
1871 | arg_keep_config_pulse = 1; | ||
1827 | } | 1872 | } |
1828 | else if (strncmp(argv[i], "--ignore=", 9) == 0) { | 1873 | else if (strncmp(argv[i], "--ignore=", 9) == 0) { |
1829 | if (custom_profile) { | 1874 | if (custom_profile) { |
@@ -1832,6 +1877,14 @@ int main(int argc, char **argv, char **envp) { | |||
1832 | } | 1877 | } |
1833 | profile_add_ignore(argv[i] + 9); | 1878 | profile_add_ignore(argv[i] + 9); |
1834 | } | 1879 | } |
1880 | else if (strncmp(argv[i], "--keep-fd=", 10) == 0) { | ||
1881 | if (strcmp(argv[i] + 10, "all") == 0) | ||
1882 | arg_keep_fd_all = 1; | ||
1883 | else { | ||
1884 | const char *add = argv[i] + 10; | ||
1885 | profile_list_augment(&cfg.keep_fd, add); | ||
1886 | } | ||
1887 | } | ||
1835 | #ifdef HAVE_CHROOT | 1888 | #ifdef HAVE_CHROOT |
1836 | else if (strncmp(argv[i], "--chroot=", 9) == 0) { | 1889 | else if (strncmp(argv[i], "--chroot=", 9) == 0) { |
1837 | if (checkcfg(CFG_CHROOT)) { | 1890 | if (checkcfg(CFG_CHROOT)) { |
@@ -1874,6 +1927,9 @@ int main(int argc, char **argv, char **envp) { | |||
1874 | } | 1927 | } |
1875 | arg_writable_etc = 1; | 1928 | arg_writable_etc = 1; |
1876 | } | 1929 | } |
1930 | else if (strcmp(argv[i], "--keep-config-pulse") == 0) { | ||
1931 | arg_keep_config_pulse = 1; | ||
1932 | } | ||
1877 | else if (strcmp(argv[i], "--writable-var") == 0) { | 1933 | else if (strcmp(argv[i], "--writable-var") == 0) { |
1878 | arg_writable_var = 1; | 1934 | arg_writable_var = 1; |
1879 | } | 1935 | } |
@@ -1944,61 +2000,77 @@ int main(int argc, char **argv, char **envp) { | |||
1944 | arg_keep_dev_shm = 1; | 2000 | arg_keep_dev_shm = 1; |
1945 | } | 2001 | } |
1946 | else if (strncmp(argv[i], "--private-etc=", 14) == 0) { | 2002 | else if (strncmp(argv[i], "--private-etc=", 14) == 0) { |
1947 | if (arg_writable_etc) { | 2003 | if (checkcfg(CFG_PRIVATE_ETC)) { |
1948 | fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n"); | 2004 | if (arg_writable_etc) { |
1949 | exit(1); | 2005 | fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n"); |
1950 | } | 2006 | exit(1); |
2007 | } | ||
1951 | 2008 | ||
1952 | // extract private etc list | 2009 | // extract private etc list |
1953 | if (*(argv[i] + 14) == '\0') { | 2010 | if (*(argv[i] + 14) == '\0') { |
1954 | fprintf(stderr, "Error: invalid private-etc option\n"); | 2011 | fprintf(stderr, "Error: invalid private-etc option\n"); |
1955 | exit(1); | 2012 | exit(1); |
2013 | } | ||
2014 | if (cfg.etc_private_keep) { | ||
2015 | if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, argv[i] + 14) < 0 ) | ||
2016 | errExit("asprintf"); | ||
2017 | } else | ||
2018 | cfg.etc_private_keep = argv[i] + 14; | ||
2019 | arg_private_etc = 1; | ||
1956 | } | 2020 | } |
1957 | if (cfg.etc_private_keep) { | 2021 | else |
1958 | if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, argv[i] + 14) < 0 ) | 2022 | exit_err_feature("private-etc"); |
1959 | errExit("asprintf"); | ||
1960 | } else | ||
1961 | cfg.etc_private_keep = argv[i] + 14; | ||
1962 | arg_private_etc = 1; | ||
1963 | } | 2023 | } |
1964 | else if (strncmp(argv[i], "--private-opt=", 14) == 0) { | 2024 | else if (strncmp(argv[i], "--private-opt=", 14) == 0) { |
1965 | // extract private opt list | 2025 | if (checkcfg(CFG_PRIVATE_OPT)) { |
1966 | if (*(argv[i] + 14) == '\0') { | 2026 | // extract private opt list |
1967 | fprintf(stderr, "Error: invalid private-opt option\n"); | 2027 | if (*(argv[i] + 14) == '\0') { |
1968 | exit(1); | 2028 | fprintf(stderr, "Error: invalid private-opt option\n"); |
2029 | exit(1); | ||
2030 | } | ||
2031 | if (cfg.opt_private_keep) { | ||
2032 | if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, argv[i] + 14) < 0 ) | ||
2033 | errExit("asprintf"); | ||
2034 | } else | ||
2035 | cfg.opt_private_keep = argv[i] + 14; | ||
2036 | arg_private_opt = 1; | ||
1969 | } | 2037 | } |
1970 | if (cfg.opt_private_keep) { | 2038 | else |
1971 | if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, argv[i] + 14) < 0 ) | 2039 | exit_err_feature("private-opt"); |
1972 | errExit("asprintf"); | ||
1973 | } else | ||
1974 | cfg.opt_private_keep = argv[i] + 14; | ||
1975 | arg_private_opt = 1; | ||
1976 | } | 2040 | } |
1977 | else if (strncmp(argv[i], "--private-srv=", 14) == 0) { | 2041 | else if (strncmp(argv[i], "--private-srv=", 14) == 0) { |
1978 | // extract private srv list | 2042 | if (checkcfg(CFG_PRIVATE_SRV)) { |
1979 | if (*(argv[i] + 14) == '\0') { | 2043 | // extract private srv list |
1980 | fprintf(stderr, "Error: invalid private-srv option\n"); | 2044 | if (*(argv[i] + 14) == '\0') { |
1981 | exit(1); | 2045 | fprintf(stderr, "Error: invalid private-srv option\n"); |
2046 | exit(1); | ||
2047 | } | ||
2048 | if (cfg.srv_private_keep) { | ||
2049 | if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, argv[i] + 14) < 0 ) | ||
2050 | errExit("asprintf"); | ||
2051 | } else | ||
2052 | cfg.srv_private_keep = argv[i] + 14; | ||
2053 | arg_private_srv = 1; | ||
1982 | } | 2054 | } |
1983 | if (cfg.srv_private_keep) { | 2055 | else |
1984 | if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, argv[i] + 14) < 0 ) | 2056 | exit_err_feature("private-srv"); |
1985 | errExit("asprintf"); | ||
1986 | } else | ||
1987 | cfg.srv_private_keep = argv[i] + 14; | ||
1988 | arg_private_srv = 1; | ||
1989 | } | 2057 | } |
1990 | else if (strncmp(argv[i], "--private-bin=", 14) == 0) { | 2058 | else if (strncmp(argv[i], "--private-bin=", 14) == 0) { |
1991 | // extract private bin list | 2059 | if (checkcfg(CFG_PRIVATE_BIN)) { |
1992 | if (*(argv[i] + 14) == '\0') { | 2060 | // extract private bin list |
1993 | fprintf(stderr, "Error: invalid private-bin option\n"); | 2061 | if (*(argv[i] + 14) == '\0') { |
1994 | exit(1); | 2062 | fprintf(stderr, "Error: invalid private-bin option\n"); |
2063 | exit(1); | ||
2064 | } | ||
2065 | if (cfg.bin_private_keep) { | ||
2066 | if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, argv[i] + 14) < 0 ) | ||
2067 | errExit("asprintf"); | ||
2068 | } else | ||
2069 | cfg.bin_private_keep = argv[i] + 14; | ||
2070 | arg_private_bin = 1; | ||
1995 | } | 2071 | } |
1996 | if (cfg.bin_private_keep) { | 2072 | else |
1997 | if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, argv[i] + 14) < 0 ) | 2073 | exit_err_feature("private-bin"); |
1998 | errExit("asprintf"); | ||
1999 | } else | ||
2000 | cfg.bin_private_keep = argv[i] + 14; | ||
2001 | arg_private_bin = 1; | ||
2002 | } | 2074 | } |
2003 | else if (strncmp(argv[i], "--private-lib", 13) == 0) { | 2075 | else if (strncmp(argv[i], "--private-lib", 13) == 0) { |
2004 | if (checkcfg(CFG_PRIVATE_LIB)) { | 2076 | if (checkcfg(CFG_PRIVATE_LIB)) { |
@@ -2076,11 +2148,16 @@ int main(int argc, char **argv, char **envp) { | |||
2076 | else if (strcmp(argv[i], "--nosound") == 0) | 2148 | else if (strcmp(argv[i], "--nosound") == 0) |
2077 | arg_nosound = 1; | 2149 | arg_nosound = 1; |
2078 | else if (strcmp(argv[i], "--noautopulse") == 0) | 2150 | else if (strcmp(argv[i], "--noautopulse") == 0) |
2079 | arg_noautopulse = 1; | 2151 | arg_keep_config_pulse = 1; |
2080 | else if (strcmp(argv[i], "--novideo") == 0) | 2152 | else if (strcmp(argv[i], "--novideo") == 0) |
2081 | arg_novideo = 1; | 2153 | arg_novideo = 1; |
2082 | else if (strcmp(argv[i], "--no3d") == 0) | 2154 | else if (strcmp(argv[i], "--no3d") == 0) |
2083 | arg_no3d = 1; | 2155 | arg_no3d = 1; |
2156 | else if (strcmp(argv[i], "--noprinters") == 0) { | ||
2157 | arg_noprinters = 1; | ||
2158 | profile_add("blacklist /dev/lp*"); | ||
2159 | profile_add("blacklist /run/cups/cups.sock"); | ||
2160 | } | ||
2084 | else if (strcmp(argv[i], "--notv") == 0) | 2161 | else if (strcmp(argv[i], "--notv") == 0) |
2085 | arg_notv = 1; | 2162 | arg_notv = 1; |
2086 | else if (strcmp(argv[i], "--nodvd") == 0) | 2163 | else if (strcmp(argv[i], "--nodvd") == 0) |
@@ -2253,6 +2330,21 @@ int main(int argc, char **argv, char **envp) { | |||
2253 | continue; | 2330 | continue; |
2254 | } | 2331 | } |
2255 | #ifdef HAVE_NETWORK | 2332 | #ifdef HAVE_NETWORK |
2333 | else if (strcmp(argv[i], "--netlock") == 0) { | ||
2334 | if (checkcfg(CFG_NETWORK)) | ||
2335 | arg_netlock = 1; | ||
2336 | else | ||
2337 | exit_err_feature("networking"); | ||
2338 | } | ||
2339 | else if (strncmp(argv[i], "--netlock=", 10) == 0) { | ||
2340 | if (checkcfg(CFG_NETWORK)) { | ||
2341 | pid_t pid = require_pid(argv[i] + 10); | ||
2342 | netfilter_netlock(pid); | ||
2343 | } | ||
2344 | else | ||
2345 | exit_err_feature("networking"); | ||
2346 | exit(0); | ||
2347 | } | ||
2256 | else if (strncmp(argv[i], "--interface=", 12) == 0) { | 2348 | else if (strncmp(argv[i], "--interface=", 12) == 0) { |
2257 | if (checkcfg(CFG_NETWORK)) { | 2349 | if (checkcfg(CFG_NETWORK)) { |
2258 | // checks | 2350 | // checks |
@@ -2558,7 +2650,7 @@ int main(int argc, char **argv, char **envp) { | |||
2558 | else if (cfg.dns4 == NULL) | 2650 | else if (cfg.dns4 == NULL) |
2559 | cfg.dns4 = dns; | 2651 | cfg.dns4 = dns; |
2560 | else { | 2652 | else { |
2561 | fwarning("Warning: up to 4 DNS servers can be specified, %s ignored\n", dns); | 2653 | fwarning("up to 4 DNS servers can be specified, %s ignored\n", dns); |
2562 | free(dns); | 2654 | free(dns); |
2563 | } | 2655 | } |
2564 | } | 2656 | } |
@@ -2579,6 +2671,15 @@ int main(int argc, char **argv, char **envp) { | |||
2579 | if (checkcfg(CFG_NETWORK)) { | 2671 | if (checkcfg(CFG_NETWORK)) { |
2580 | arg_netfilter = 1; | 2672 | arg_netfilter = 1; |
2581 | arg_netfilter_file = argv[i] + 12; | 2673 | arg_netfilter_file = argv[i] + 12; |
2674 | |||
2675 | // expand tilde | ||
2676 | if (*arg_netfilter_file == '~') { | ||
2677 | char *tmp; | ||
2678 | if (asprintf(&tmp, "%s%s", cfg.homedir, arg_netfilter_file + 1) == -1) | ||
2679 | errExit("asprintf"); | ||
2680 | arg_netfilter_file = tmp; | ||
2681 | } | ||
2682 | |||
2582 | check_netfilter_file(arg_netfilter_file); | 2683 | check_netfilter_file(arg_netfilter_file); |
2583 | } | 2684 | } |
2584 | else | 2685 | else |
@@ -2589,6 +2690,15 @@ int main(int argc, char **argv, char **envp) { | |||
2589 | if (checkcfg(CFG_NETWORK)) { | 2690 | if (checkcfg(CFG_NETWORK)) { |
2590 | arg_netfilter6 = 1; | 2691 | arg_netfilter6 = 1; |
2591 | arg_netfilter6_file = argv[i] + 13; | 2692 | arg_netfilter6_file = argv[i] + 13; |
2693 | |||
2694 | // expand tilde | ||
2695 | if (*arg_netfilter6_file == '~') { | ||
2696 | char *tmp; | ||
2697 | if (asprintf(&tmp, "%s%s", cfg.homedir, arg_netfilter6_file + 1) == -1) | ||
2698 | errExit("asprintf"); | ||
2699 | arg_netfilter6_file = tmp; | ||
2700 | } | ||
2701 | |||
2592 | check_netfilter_file(arg_netfilter6_file); | 2702 | check_netfilter_file(arg_netfilter6_file); |
2593 | } | 2703 | } |
2594 | else | 2704 | else |
@@ -2609,8 +2719,9 @@ int main(int argc, char **argv, char **envp) { | |||
2609 | //************************************* | 2719 | //************************************* |
2610 | else if (strncmp(argv[i], "--timeout=", 10) == 0) | 2720 | else if (strncmp(argv[i], "--timeout=", 10) == 0) |
2611 | cfg.timeout = extract_timeout(argv[i] + 10); | 2721 | cfg.timeout = extract_timeout(argv[i] + 10); |
2612 | else if (strcmp(argv[i], "--appimage") == 0) | 2722 | else if (strcmp(argv[i], "--appimage") == 0) { |
2613 | arg_appimage = 1; | 2723 | // already handled |
2724 | } | ||
2614 | else if (strcmp(argv[i], "--shell=none") == 0) { | 2725 | else if (strcmp(argv[i], "--shell=none") == 0) { |
2615 | arg_shell_none = 1; | 2726 | arg_shell_none = 1; |
2616 | if (cfg.shell) { | 2727 | if (cfg.shell) { |
@@ -2685,6 +2796,11 @@ int main(int argc, char **argv, char **envp) { | |||
2685 | else if (strcmp(argv[i], "--deterministic-exit-code") == 0) { | 2796 | else if (strcmp(argv[i], "--deterministic-exit-code") == 0) { |
2686 | arg_deterministic_exit_code = 1; | 2797 | arg_deterministic_exit_code = 1; |
2687 | } | 2798 | } |
2799 | else if (strcmp(argv[i], "--deterministic-shutdown") == 0) { | ||
2800 | arg_deterministic_shutdown = 1; | ||
2801 | } | ||
2802 | else if (strcmp(argv[i], "--tab") == 0) | ||
2803 | arg_tab = 1; | ||
2688 | else { | 2804 | else { |
2689 | // double dash - positional params to follow | 2805 | // double dash - positional params to follow |
2690 | if (strcmp(argv[i], "--") == 0) { | 2806 | if (strcmp(argv[i], "--") == 0) { |
@@ -2786,6 +2902,11 @@ int main(int argc, char **argv, char **envp) { | |||
2786 | // build the sandbox command | 2902 | // build the sandbox command |
2787 | if (prog_index == -1 && cfg.shell) { | 2903 | if (prog_index == -1 && cfg.shell) { |
2788 | assert(cfg.command_line == NULL); // runs cfg.shell | 2904 | assert(cfg.command_line == NULL); // runs cfg.shell |
2905 | if (arg_appimage) { | ||
2906 | fprintf(stderr, "Error: no appimage archive specified\n"); | ||
2907 | exit(1); | ||
2908 | } | ||
2909 | |||
2789 | cfg.window_title = cfg.shell; | 2910 | cfg.window_title = cfg.shell; |
2790 | cfg.command_name = cfg.shell; | 2911 | cfg.command_name = cfg.shell; |
2791 | } | 2912 | } |
@@ -2793,10 +2914,11 @@ int main(int argc, char **argv, char **envp) { | |||
2793 | if (arg_debug) | 2914 | if (arg_debug) |
2794 | printf("Configuring appimage environment\n"); | 2915 | printf("Configuring appimage environment\n"); |
2795 | appimage_set(cfg.command_name); | 2916 | appimage_set(cfg.command_name); |
2796 | build_appimage_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); | 2917 | build_appimage_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index, true); |
2797 | } | 2918 | } |
2798 | else { | 2919 | else { |
2799 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); | 2920 | // Only add extra quotes if we were not launched by sshd. |
2921 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index, !parent_sshd); | ||
2800 | } | 2922 | } |
2801 | /* else { | 2923 | /* else { |
2802 | fprintf(stderr, "Error: command must be specified when --shell=none used.\n"); | 2924 | fprintf(stderr, "Error: command must be specified when --shell=none used.\n"); |
@@ -2810,7 +2932,13 @@ int main(int argc, char **argv, char **envp) { | |||
2810 | 2932 | ||
2811 | // load the profile | 2933 | // load the profile |
2812 | if (!arg_noprofile && !custom_profile) { | 2934 | if (!arg_noprofile && !custom_profile) { |
2813 | custom_profile = profile_find_firejail(cfg.command_name, 1); | 2935 | if (arg_appimage) { |
2936 | custom_profile = appimage_find_profile(cfg.command_name); | ||
2937 | // disable shell=* for appimages | ||
2938 | arg_shell_none = 0; | ||
2939 | } | ||
2940 | else | ||
2941 | custom_profile = profile_find_firejail(cfg.command_name, 1); | ||
2814 | } | 2942 | } |
2815 | 2943 | ||
2816 | // use default.profile as the default | 2944 | // use default.profile as the default |
@@ -2824,7 +2952,7 @@ int main(int argc, char **argv, char **envp) { | |||
2824 | custom_profile = profile_find_firejail(profile_name, 1); | 2952 | custom_profile = profile_find_firejail(profile_name, 1); |
2825 | 2953 | ||
2826 | if (!custom_profile) { | 2954 | if (!custom_profile) { |
2827 | fprintf(stderr, "Error: no default.profile installed\n"); | 2955 | fprintf(stderr, "Error: no %s installed\n", profile_name); |
2828 | exit(1); | 2956 | exit(1); |
2829 | } | 2957 | } |
2830 | 2958 | ||
@@ -2840,6 +2968,15 @@ int main(int argc, char **argv, char **envp) { | |||
2840 | // check network configuration options - it will exit if anything went wrong | 2968 | // check network configuration options - it will exit if anything went wrong |
2841 | net_check_cfg(); | 2969 | net_check_cfg(); |
2842 | 2970 | ||
2971 | // customization of default seccomp filter | ||
2972 | if (config_seccomp_filter_add) { | ||
2973 | if (arg_seccomp && !cfg.seccomp_list_keep && !cfg.seccomp_list_drop) | ||
2974 | profile_list_augment(&cfg.seccomp_list, config_seccomp_filter_add); | ||
2975 | |||
2976 | if (arg_seccomp32 && !cfg.seccomp_list_keep32 && !cfg.seccomp_list_drop32) | ||
2977 | profile_list_augment(&cfg.seccomp_list32, config_seccomp_filter_add); | ||
2978 | } | ||
2979 | |||
2843 | if (arg_seccomp) | 2980 | if (arg_seccomp) |
2844 | arg_seccomp_postexec = check_postexec(cfg.seccomp_list) || check_postexec(cfg.seccomp_list_drop); | 2981 | arg_seccomp_postexec = check_postexec(cfg.seccomp_list) || check_postexec(cfg.seccomp_list_drop); |
2845 | 2982 | ||
@@ -2850,7 +2987,7 @@ int main(int argc, char **argv, char **envp) { | |||
2850 | // check and assign an IP address - for macvlan it will be done again in the sandbox! | 2987 | // check and assign an IP address - for macvlan it will be done again in the sandbox! |
2851 | if (any_bridge_configured()) { | 2988 | if (any_bridge_configured()) { |
2852 | EUID_ROOT(); | 2989 | EUID_ROOT(); |
2853 | lockfd_network = open(RUN_NETWORK_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); | 2990 | lockfd_network = open(RUN_NETWORK_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); |
2854 | if (lockfd_network != -1) { | 2991 | if (lockfd_network != -1) { |
2855 | int rv = fchown(lockfd_network, 0, 0); | 2992 | int rv = fchown(lockfd_network, 0, 0); |
2856 | (void) rv; | 2993 | (void) rv; |
@@ -2872,12 +3009,6 @@ int main(int argc, char **argv, char **envp) { | |||
2872 | } | 3009 | } |
2873 | EUID_ASSERT(); | 3010 | EUID_ASSERT(); |
2874 | 3011 | ||
2875 | // create the parent-child communication pipe | ||
2876 | if (pipe(parent_to_child_fds) < 0) | ||
2877 | errExit("pipe"); | ||
2878 | if (pipe(child_to_parent_fds) < 0) | ||
2879 | errExit("pipe"); | ||
2880 | |||
2881 | if (arg_noroot && arg_overlay) { | 3012 | if (arg_noroot && arg_overlay) { |
2882 | fwarning("--overlay and --noroot are mutually exclusive, noroot disabled\n"); | 3013 | fwarning("--overlay and --noroot are mutually exclusive, noroot disabled\n"); |
2883 | arg_noroot = 0; | 3014 | arg_noroot = 0; |
@@ -2890,7 +3021,7 @@ int main(int argc, char **argv, char **envp) { | |||
2890 | 3021 | ||
2891 | // set name and x11 run files | 3022 | // set name and x11 run files |
2892 | EUID_ROOT(); | 3023 | EUID_ROOT(); |
2893 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); | 3024 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); |
2894 | if (lockfd_directory != -1) { | 3025 | if (lockfd_directory != -1) { |
2895 | int rv = fchown(lockfd_directory, 0, 0); | 3026 | int rv = fchown(lockfd_directory, 0, 0); |
2896 | (void) rv; | 3027 | (void) rv; |
@@ -2919,6 +3050,12 @@ int main(int argc, char **argv, char **envp) { | |||
2919 | } | 3050 | } |
2920 | #endif | 3051 | #endif |
2921 | 3052 | ||
3053 | // create the parent-child communication pipe | ||
3054 | if (pipe2(parent_to_child_fds, O_CLOEXEC) < 0) | ||
3055 | errExit("pipe"); | ||
3056 | if (pipe2(child_to_parent_fds, O_CLOEXEC) < 0) | ||
3057 | errExit("pipe"); | ||
3058 | |||
2922 | // clone environment | 3059 | // clone environment |
2923 | int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD; | 3060 | int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD; |
2924 | 3061 | ||
@@ -2975,9 +3112,9 @@ int main(int argc, char **argv, char **envp) { | |||
2975 | network_main(child); | 3112 | network_main(child); |
2976 | if (arg_debug) | 3113 | if (arg_debug) |
2977 | printf("Host network configured\n"); | 3114 | printf("Host network configured\n"); |
2978 | #ifdef HAVE_GCOV | 3115 | |
2979 | __gcov_flush(); | 3116 | __gcov_flush(); |
2980 | #endif | 3117 | |
2981 | _exit(0); | 3118 | _exit(0); |
2982 | } | 3119 | } |
2983 | 3120 | ||
@@ -2987,100 +3124,163 @@ int main(int argc, char **argv, char **envp) { | |||
2987 | } | 3124 | } |
2988 | EUID_ASSERT(); | 3125 | EUID_ASSERT(); |
2989 | 3126 | ||
2990 | // close each end of the unused pipes | 3127 | // close each end of the unused pipes |
2991 | close(parent_to_child_fds[0]); | 3128 | close(parent_to_child_fds[0]); |
2992 | close(child_to_parent_fds[1]); | 3129 | close(child_to_parent_fds[1]); |
2993 | 3130 | ||
2994 | // notify child that base setup is complete | 3131 | // notify child that base setup is complete |
2995 | notify_other(parent_to_child_fds[1]); | 3132 | notify_other(parent_to_child_fds[1]); |
2996 | 3133 | ||
2997 | // wait for child to create new user namespace with CLONE_NEWUSER | 3134 | // wait for child to create new user namespace with CLONE_NEWUSER |
2998 | wait_for_other(child_to_parent_fds[0]); | 3135 | wait_for_other(child_to_parent_fds[0]); |
2999 | close(child_to_parent_fds[0]); | 3136 | close(child_to_parent_fds[0]); |
3000 | 3137 | ||
3001 | if (arg_noroot) { | 3138 | if (arg_noroot) { |
3002 | // update the UID and GID maps in the new child user namespace | 3139 | // update the UID and GID maps in the new child user namespace |
3003 | // uid | 3140 | // uid |
3004 | char *map_path; | 3141 | char *map_path; |
3005 | if (asprintf(&map_path, "/proc/%d/uid_map", child) == -1) | 3142 | if (asprintf(&map_path, "/proc/%d/uid_map", child) == -1) |
3006 | errExit("asprintf"); | 3143 | errExit("asprintf"); |
3007 | 3144 | ||
3008 | char *map; | 3145 | char *map; |
3009 | uid_t uid = getuid(); | 3146 | uid_t uid = getuid(); |
3010 | if (asprintf(&map, "%d %d 1", uid, uid) == -1) | 3147 | if (asprintf(&map, "%d %d 1", uid, uid) == -1) |
3011 | errExit("asprintf"); | 3148 | errExit("asprintf"); |
3012 | EUID_ROOT(); | 3149 | EUID_ROOT(); |
3013 | update_map(map, map_path); | 3150 | update_map(map, map_path); |
3014 | EUID_USER(); | 3151 | EUID_USER(); |
3015 | free(map); | 3152 | free(map); |
3016 | free(map_path); | 3153 | free(map_path); |
3017 | 3154 | ||
3018 | // gid file | 3155 | // gid file |
3019 | if (asprintf(&map_path, "/proc/%d/gid_map", child) == -1) | 3156 | if (asprintf(&map_path, "/proc/%d/gid_map", child) == -1) |
3020 | errExit("asprintf"); | 3157 | errExit("asprintf"); |
3021 | char gidmap[1024]; | 3158 | char gidmap[1024]; |
3022 | char *ptr = gidmap; | 3159 | char *ptr = gidmap; |
3023 | *ptr = '\0'; | 3160 | *ptr = '\0'; |
3024 | 3161 | ||
3025 | // add user group | 3162 | // add user group |
3026 | gid_t gid = getgid(); | 3163 | gid_t gid = getgid(); |
3027 | sprintf(ptr, "%d %d 1\n", gid, gid); | 3164 | sprintf(ptr, "%d %d 1\n", gid, gid); |
3028 | ptr += strlen(ptr); | 3165 | ptr += strlen(ptr); |
3029 | 3166 | ||
3030 | if (!arg_nogroups) { | 3167 | gid_t g; |
3031 | // add firejail group | 3168 | if (!arg_nogroups || !check_can_drop_all_groups()) { |
3032 | gid_t g = get_group_id("firejail"); | 3169 | // add audio group |
3033 | if (g) { | 3170 | if (!arg_nosound) { |
3034 | sprintf(ptr, "%d %d 1\n", g, g); | 3171 | g = get_group_id("audio"); |
3035 | ptr += strlen(ptr); | 3172 | if (g) { |
3036 | } | 3173 | sprintf(ptr, "%d %d 1\n", g, g); |
3037 | 3174 | ptr += strlen(ptr); | |
3038 | // add tty group | 3175 | } |
3039 | g = get_group_id("tty"); | 3176 | } |
3040 | if (g) { | 3177 | |
3041 | sprintf(ptr, "%d %d 1\n", g, g); | 3178 | // add video group |
3042 | ptr += strlen(ptr); | 3179 | if (!arg_novideo) { |
3043 | } | 3180 | g = get_group_id("video"); |
3044 | 3181 | if (g) { | |
3045 | // add audio group | 3182 | sprintf(ptr, "%d %d 1\n", g, g); |
3046 | g = get_group_id("audio"); | 3183 | ptr += strlen(ptr); |
3047 | if (g) { | 3184 | } |
3048 | sprintf(ptr, "%d %d 1\n", g, g); | 3185 | } |
3049 | ptr += strlen(ptr); | 3186 | |
3050 | } | 3187 | // add render/vglusers group |
3051 | 3188 | if (!arg_no3d) { | |
3052 | // add video group | 3189 | g = get_group_id("render"); |
3053 | g = get_group_id("video"); | 3190 | if (g) { |
3054 | if (g) { | 3191 | sprintf(ptr, "%d %d 1\n", g, g); |
3055 | sprintf(ptr, "%d %d 1\n", g, g); | 3192 | ptr += strlen(ptr); |
3056 | ptr += strlen(ptr); | 3193 | } |
3057 | } | 3194 | g = get_group_id("vglusers"); |
3058 | 3195 | if (g) { | |
3059 | // add games group | 3196 | sprintf(ptr, "%d %d 1\n", g, g); |
3060 | g = get_group_id("games"); | 3197 | ptr += strlen(ptr); |
3061 | if (g) { | 3198 | } |
3062 | sprintf(ptr, "%d %d 1\n", g, g); | 3199 | } |
3063 | } | 3200 | |
3064 | } | 3201 | // add lp group |
3065 | 3202 | if (!arg_noprinters) { | |
3066 | EUID_ROOT(); | 3203 | g = get_group_id("lp"); |
3067 | update_map(gidmap, map_path); | 3204 | if (g) { |
3068 | EUID_USER(); | 3205 | sprintf(ptr, "%d %d 1\n", g, g); |
3069 | free(map_path); | 3206 | ptr += strlen(ptr); |
3070 | } | 3207 | } |
3208 | } | ||
3209 | |||
3210 | // add cdrom/optical groups | ||
3211 | if (!arg_nodvd) { | ||
3212 | g = get_group_id("cdrom"); | ||
3213 | if (g) { | ||
3214 | sprintf(ptr, "%d %d 1\n", g, g); | ||
3215 | ptr += strlen(ptr); | ||
3216 | } | ||
3217 | g = get_group_id("optical"); | ||
3218 | if (g) { | ||
3219 | sprintf(ptr, "%d %d 1\n", g, g); | ||
3220 | ptr += strlen(ptr); | ||
3221 | } | ||
3222 | } | ||
3223 | |||
3224 | // add input group | ||
3225 | if (!arg_noinput) { | ||
3226 | g = get_group_id("input"); | ||
3227 | if (g) { | ||
3228 | sprintf(ptr, "%d %d 1\n", g, g); | ||
3229 | ptr += strlen(ptr); | ||
3230 | } | ||
3231 | } | ||
3232 | } | ||
3233 | |||
3234 | if (!arg_nogroups) { | ||
3235 | // add firejail group | ||
3236 | g = get_group_id("firejail"); | ||
3237 | if (g) { | ||
3238 | sprintf(ptr, "%d %d 1\n", g, g); | ||
3239 | ptr += strlen(ptr); | ||
3240 | } | ||
3241 | |||
3242 | // add tty group | ||
3243 | g = get_group_id("tty"); | ||
3244 | if (g) { | ||
3245 | sprintf(ptr, "%d %d 1\n", g, g); | ||
3246 | ptr += strlen(ptr); | ||
3247 | } | ||
3248 | |||
3249 | // add games group | ||
3250 | g = get_group_id("games"); | ||
3251 | if (g) { | ||
3252 | sprintf(ptr, "%d %d 1\n", g, g); | ||
3253 | } | ||
3254 | } | ||
3255 | |||
3256 | EUID_ROOT(); | ||
3257 | update_map(gidmap, map_path); | ||
3258 | EUID_USER(); | ||
3259 | free(map_path); | ||
3260 | } | ||
3071 | EUID_ASSERT(); | 3261 | EUID_ASSERT(); |
3072 | 3262 | ||
3073 | // notify child that UID/GID mapping is complete | 3263 | // notify child that UID/GID mapping is complete |
3074 | notify_other(parent_to_child_fds[1]); | 3264 | notify_other(parent_to_child_fds[1]); |
3075 | close(parent_to_child_fds[1]); | 3265 | close(parent_to_child_fds[1]); |
3076 | 3266 | ||
3077 | EUID_ROOT(); | 3267 | EUID_ROOT(); |
3078 | if (lockfd_network != -1) { | 3268 | if (lockfd_network != -1) { |
3079 | flock(lockfd_network, LOCK_UN); | 3269 | flock(lockfd_network, LOCK_UN); |
3080 | close(lockfd_network); | 3270 | close(lockfd_network); |
3081 | } | 3271 | } |
3082 | EUID_USER(); | 3272 | EUID_USER(); |
3083 | 3273 | ||
3274 | // lock netfilter firewall | ||
3275 | if (arg_netlock) { | ||
3276 | char *cmd; | ||
3277 | if (asprintf(&cmd, "firejail --netlock=%d&", getpid()) == -1) | ||
3278 | errExit("asprintf"); | ||
3279 | int rv = system(cmd); | ||
3280 | (void) rv; | ||
3281 | free(cmd); | ||
3282 | } | ||
3283 | |||
3084 | int status = 0; | 3284 | int status = 0; |
3085 | //***************************** | 3285 | //***************************** |
3086 | // following code is signal-safe | 3286 | // following code is signal-safe |
@@ -3098,35 +3298,16 @@ int main(int argc, char **argv, char **envp) { | |||
3098 | // end of signal-safe code | 3298 | // end of signal-safe code |
3099 | //***************************** | 3299 | //***************************** |
3100 | 3300 | ||
3101 | #if 0 | ||
3102 | // at this point the sandbox was closed and we are on our way out | ||
3103 | // it would make sense to move this before waitpid above to free some memory | ||
3104 | // crash for now as of issue #3662 from dhcp code | ||
3105 | // free globals | ||
3106 | if (cfg.profile) { | ||
3107 | ProfileEntry *prf = cfg.profile; | ||
3108 | while (prf != NULL) { | ||
3109 | ProfileEntry *next = prf->next; | ||
3110 | printf("data #%s#\n", prf->data); | ||
3111 | if (prf->data) | ||
3112 | free(prf->data); | ||
3113 | printf("link #%s#\n", prf->link); | ||
3114 | if (prf->link) | ||
3115 | free(prf->link); | ||
3116 | free(prf); | ||
3117 | prf = next; | ||
3118 | } | ||
3119 | } | ||
3120 | #endif | ||
3121 | 3301 | ||
3122 | 3302 | ||
3123 | if (WIFEXITED(status)){ | 3303 | if (WIFEXITED(status)){ |
3124 | myexit(WEXITSTATUS(status)); | 3304 | myexit(WEXITSTATUS(status)); |
3125 | } else if (WIFSIGNALED(status)) { | 3305 | } else if (WIFSIGNALED(status)) { |
3126 | myexit(WTERMSIG(status)); | 3306 | // distinguish fatal signals by adding 128 |
3307 | myexit(128 + WTERMSIG(status)); | ||
3127 | } else { | 3308 | } else { |
3128 | myexit(0); | 3309 | myexit(1); |
3129 | } | 3310 | } |
3130 | 3311 | ||
3131 | return 0; | 3312 | return 1; |
3132 | } | 3313 | } |
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c index a700729d3..56c0bda30 100644 --- a/src/firejail/mountinfo.c +++ b/src/firejail/mountinfo.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -19,10 +19,11 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include "firejail.h" | 21 | #include "firejail.h" |
22 | #include <errno.h> | ||
22 | 23 | ||
23 | #include <fcntl.h> | 24 | #include <fcntl.h> |
24 | #ifndef O_PATH | 25 | #ifndef O_PATH |
25 | # define O_PATH 010000000 | 26 | #define O_PATH 010000000 |
26 | #endif | 27 | #endif |
27 | 28 | ||
28 | #define MAX_BUF 4096 | 29 | #define MAX_BUF 4096 |
@@ -32,43 +33,38 @@ static MountData mdata; | |||
32 | 33 | ||
33 | 34 | ||
34 | // Convert octal escape sequence to decimal value | 35 | // Convert octal escape sequence to decimal value |
35 | static int read_oct(const char *path) { | 36 | static unsigned read_oct(char *s) { |
36 | int dec = 0; | 37 | assert(s[0] == '\\'); |
37 | int digit, i; | 38 | s++; |
38 | // there are always exactly three octal digits | 39 | |
39 | for (i = 1; i < 4; i++) { | 40 | int i; |
40 | digit = *(path + i); | 41 | for (i = 0; i < 3; i++) |
41 | if (digit < '0' || digit > '7') { | 42 | assert(s[i] >= '0' && s[i] <= '7'); |
42 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 43 | |
43 | exit(1); | 44 | return ((s[0] - '0') << 6 | |
44 | } | 45 | (s[1] - '0') << 3 | |
45 | dec = (dec << 3) + (digit - '0'); | 46 | (s[2] - '0') << 0); |
46 | } | ||
47 | return dec; | ||
48 | } | 47 | } |
49 | 48 | ||
50 | // Restore empty spaces in pathnames extracted from /proc/self/mountinfo | 49 | // Restore empty spaces in pathnames extracted from /proc/self/mountinfo |
51 | static void unmangle_path(char *path) { | 50 | static void unmangle_path(char *path) { |
52 | char *p = strchr(path, '\\'); | 51 | char *r = strchr(path, '\\'); |
53 | if (p && read_oct(p) == ' ') { | 52 | if (!r) |
54 | *p = ' '; | 53 | return; |
55 | int i = 3; | 54 | |
56 | do { | 55 | char *w = r; |
57 | p++; | 56 | do { |
58 | if (*(p + i) == '\\' && read_oct(p + i) == ' ') { | 57 | while (*r == '\\') { |
59 | *p = ' '; | 58 | *w++ = read_oct(r); |
60 | i += 3; | 59 | r += 4; |
61 | } | 60 | } |
62 | else | 61 | *w++ = *r; |
63 | *p = *(p + i); | 62 | } while (*r++); |
64 | } while (*p); | ||
65 | } | ||
66 | } | 63 | } |
67 | 64 | ||
68 | // Parse a line from /proc/self/mountinfo, | 65 | // Parse a line from /proc/self/mountinfo, |
69 | // the function does an exit(1) if anything goes wrong. | 66 | // the function does an exit(1) if anything goes wrong. |
70 | static void parse_line(char *line, MountData *output) { | 67 | static void parse_line(char *line, MountData *output) { |
71 | assert(line && output); | ||
72 | memset(output, 0, sizeof(*output)); | 68 | memset(output, 0, sizeof(*output)); |
73 | // extract mount id, filesystem name, directory and filesystem types | 69 | // extract mount id, filesystem name, directory and filesystem types |
74 | // examples: | 70 | // examples: |
@@ -86,8 +82,6 @@ static void parse_line(char *line, MountData *output) { | |||
86 | char *ptr = strtok(line, " "); | 82 | char *ptr = strtok(line, " "); |
87 | if (!ptr) | 83 | if (!ptr) |
88 | goto errexit; | 84 | goto errexit; |
89 | if (ptr != line) | ||
90 | goto errexit; | ||
91 | output->mountid = atoi(ptr); | 85 | output->mountid = atoi(ptr); |
92 | int cnt = 1; | 86 | int cnt = 1; |
93 | 87 | ||
@@ -108,10 +102,9 @@ static void parse_line(char *line, MountData *output) { | |||
108 | ptr = strtok(NULL, " "); | 102 | ptr = strtok(NULL, " "); |
109 | if (!ptr) | 103 | if (!ptr) |
110 | goto errexit; | 104 | goto errexit; |
111 | output->fstype = ptr++; | 105 | output->fstype = ptr; |
112 | 106 | ||
113 | 107 | if (output->mountid < 0 || | |
114 | if (output->mountid == 0 || | ||
115 | output->fsname == NULL || | 108 | output->fsname == NULL || |
116 | output->dir == NULL || | 109 | output->dir == NULL || |
117 | output->fstype == NULL) | 110 | output->fstype == NULL) |
@@ -151,108 +144,118 @@ MountData *get_last_mount(void) { | |||
151 | return &mdata; | 144 | return &mdata; |
152 | } | 145 | } |
153 | 146 | ||
154 | // Extract the mount id from /proc/self/fdinfo and return it. | 147 | // Returns mount id, or -1 if fd refers to a procfs or sysfs file |
155 | int get_mount_id(const char *path) { | 148 | static int get_mount_id_from_handle(int fd) { |
156 | assert(path); | 149 | char *proc; |
150 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
151 | errExit("asprintf"); | ||
152 | |||
153 | struct file_handle *fh = malloc(sizeof *fh); | ||
154 | if (!fh) | ||
155 | errExit("malloc"); | ||
156 | fh->handle_bytes = 0; | ||
157 | |||
158 | int rv = -1; | ||
159 | int tmp; | ||
160 | if (name_to_handle_at(-1, proc, fh, &tmp, AT_SYMLINK_FOLLOW) != -1) { | ||
161 | fprintf(stderr, "Error: unexpected result from name_to_handle_at\n"); | ||
162 | exit(1); | ||
163 | } | ||
164 | if (errno == EOVERFLOW && fh->handle_bytes) | ||
165 | rv = tmp; | ||
157 | 166 | ||
158 | int fd = open(path, O_PATH|O_CLOEXEC); | 167 | free(proc); |
159 | if (fd == -1) | 168 | free(fh); |
160 | return -1; | 169 | return rv; |
170 | } | ||
161 | 171 | ||
162 | char *fdinfo; | 172 | // Returns mount id, or -1 on kernels < 3.15 |
163 | if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) | 173 | static int get_mount_id_from_fdinfo(int fd) { |
174 | char *proc; | ||
175 | if (asprintf(&proc, "/proc/self/fdinfo/%d", fd) == -1) | ||
164 | errExit("asprintf"); | 176 | errExit("asprintf"); |
165 | FILE *fp = fopen(fdinfo, "re"); | ||
166 | free(fdinfo); | ||
167 | if (!fp) | ||
168 | goto errexit; | ||
169 | 177 | ||
170 | // read the file | 178 | int called_as_root = 0; |
179 | if (geteuid() == 0) | ||
180 | called_as_root = 1; | ||
181 | |||
182 | if (called_as_root == 0) | ||
183 | EUID_ROOT(); | ||
184 | |||
185 | FILE *fp = fopen(proc, "re"); | ||
186 | if (!fp) { | ||
187 | fprintf(stderr, "Error: cannot read proc file\n"); | ||
188 | exit(1); | ||
189 | } | ||
190 | |||
191 | if (called_as_root == 0) | ||
192 | EUID_USER(); | ||
193 | |||
194 | int rv = -1; | ||
171 | char buf[MAX_BUF]; | 195 | char buf[MAX_BUF]; |
172 | if (fgets(buf, MAX_BUF, fp) == NULL) | 196 | while (fgets(buf, MAX_BUF, fp)) { |
173 | goto errexit; | 197 | if (sscanf(buf, "mnt_id: %d", &rv) == 1) |
174 | do { | 198 | break; |
175 | if (strncmp(buf, "mnt_id:", 7) == 0) { | 199 | } |
176 | char *ptr = buf + 7; | ||
177 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { | ||
178 | ptr++; | ||
179 | } | ||
180 | if (*ptr == '\0') | ||
181 | goto errexit; | ||
182 | fclose(fp); | ||
183 | close(fd); | ||
184 | return atoi(ptr); | ||
185 | } | ||
186 | } while (fgets(buf, MAX_BUF, fp)); | ||
187 | 200 | ||
188 | // fallback, kernels older than 3.15 don't expose the mount id in this place | 201 | free(proc); |
189 | fclose(fp); | 202 | fclose(fp); |
190 | close(fd); | 203 | return rv; |
191 | return -2; | 204 | } |
192 | 205 | ||
193 | errexit: | 206 | int get_mount_id(int fd) { |
194 | fprintf(stderr, "Error: cannot read proc file\n"); | 207 | int rv = get_mount_id_from_handle(fd); |
195 | exit(1); | 208 | if (rv < 0) |
209 | rv = get_mount_id_from_fdinfo(fd); | ||
210 | return rv; | ||
196 | } | 211 | } |
197 | 212 | ||
198 | // Check /proc/self/mountinfo if path contains any mounts points. | 213 | // Check /proc/self/mountinfo if path contains any mounts points. |
199 | // Returns an array that can be iterated over for recursive remounting. | 214 | // Returns an array that can be iterated over for recursive remounting. |
200 | char **build_mount_array(const int mount_id, const char *path) { | 215 | char **build_mount_array(const int mountid, const char *path) { |
201 | assert(path); | 216 | assert(path); |
202 | 217 | ||
203 | // open /proc/self/mountinfo | ||
204 | FILE *fp = fopen("/proc/self/mountinfo", "re"); | 218 | FILE *fp = fopen("/proc/self/mountinfo", "re"); |
205 | if (!fp) { | 219 | if (!fp) { |
206 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 220 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); |
207 | exit(1); | 221 | exit(1); |
208 | } | 222 | } |
209 | 223 | ||
210 | // array to be returned | 224 | // try to find line with mount id |
211 | size_t cnt = 0; | 225 | int found = 0; |
226 | MountData mntp; | ||
227 | char line[MAX_BUF]; | ||
228 | while (fgets(line, MAX_BUF, fp)) { | ||
229 | parse_line(line, &mntp); | ||
230 | if (mntp.mountid == mountid) { | ||
231 | found = 1; | ||
232 | break; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | if (!found) { | ||
237 | fclose(fp); | ||
238 | return NULL; | ||
239 | } | ||
240 | |||
241 | // allocate array | ||
212 | size_t size = 32; | 242 | size_t size = 32; |
213 | char **rv = malloc(size * sizeof(*rv)); | 243 | char **rv = malloc(size * sizeof(*rv)); |
214 | if (!rv) | 244 | if (!rv) |
215 | errExit("malloc"); | 245 | errExit("malloc"); |
216 | 246 | ||
217 | // read /proc/self/mountinfo | 247 | // add directory itself |
218 | size_t pathlen = strlen(path); | 248 | size_t cnt = 0; |
219 | char buf[MAX_BUF]; | 249 | rv[cnt] = strdup(path); |
220 | MountData mntp; | 250 | if (rv[cnt] == NULL) |
221 | int found = 0; | 251 | errExit("strdup"); |
222 | 252 | ||
223 | if (fgets(buf, MAX_BUF, fp) == NULL) { | 253 | // and add all following mountpoints contained in this directory |
224 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 254 | size_t pathlen = strlen(path); |
225 | exit(1); | 255 | while (fgets(line, MAX_BUF, fp)) { |
226 | } | 256 | parse_line(line, &mntp); |
227 | do { | 257 | if (strncmp(mntp.dir, path, pathlen) == 0 && mntp.dir[pathlen] == '/') { |
228 | parse_line(buf, &mntp); | 258 | if (++cnt == size) { |
229 | // find mount point with mount id | ||
230 | if (!found) { | ||
231 | if (mntp.mountid == mount_id) { | ||
232 | // give up if mount id has been reassigned, | ||
233 | // don't remount blacklisted path | ||
234 | if (strncmp(mntp.dir, path, strlen(mntp.dir)) || | ||
235 | strstr(mntp.fsname, "firejail.ro.dir") || | ||
236 | strstr(mntp.fsname, "firejail.ro.file")) | ||
237 | break; | ||
238 | |||
239 | rv[cnt] = strdup(path); | ||
240 | if (rv[cnt] == NULL) | ||
241 | errExit("strdup"); | ||
242 | cnt++; | ||
243 | found = 1; | ||
244 | continue; | ||
245 | } | ||
246 | continue; | ||
247 | } | ||
248 | // from here on add all mount points below path, | ||
249 | // don't remount blacklisted paths | ||
250 | if (strncmp(mntp.dir, path, pathlen) == 0 && | ||
251 | mntp.dir[pathlen] == '/' && | ||
252 | strstr(mntp.fsname, "firejail.ro.dir") == NULL && | ||
253 | strstr(mntp.fsname, "firejail.ro.file") == NULL) { | ||
254 | |||
255 | if (cnt == size) { | ||
256 | size *= 2; | 259 | size *= 2; |
257 | rv = realloc(rv, size * sizeof(*rv)); | 260 | rv = realloc(rv, size * sizeof(*rv)); |
258 | if (!rv) | 261 | if (!rv) |
@@ -261,18 +264,17 @@ char **build_mount_array(const int mount_id, const char *path) { | |||
261 | rv[cnt] = strdup(mntp.dir); | 264 | rv[cnt] = strdup(mntp.dir); |
262 | if (rv[cnt] == NULL) | 265 | if (rv[cnt] == NULL) |
263 | errExit("strdup"); | 266 | errExit("strdup"); |
264 | cnt++; | ||
265 | } | 267 | } |
266 | } while (fgets(buf, MAX_BUF, fp)); | 268 | } |
269 | fclose(fp); | ||
267 | 270 | ||
268 | if (cnt == size) { | 271 | // end of array |
269 | size++; | 272 | if (++cnt == size) { |
273 | ++size; | ||
270 | rv = realloc(rv, size * sizeof(*rv)); | 274 | rv = realloc(rv, size * sizeof(*rv)); |
271 | if (!rv) | 275 | if (!rv) |
272 | errExit("realloc"); | 276 | errExit("realloc"); |
273 | } | 277 | } |
274 | rv[cnt] = NULL; // end of the array | 278 | rv[cnt] = NULL; |
275 | |||
276 | fclose(fp); | ||
277 | return rv; | 279 | return rv; |
278 | } | 280 | } |
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c index fc79dddec..5b49fe19a 100644 --- a/src/firejail/netfilter.c +++ b/src/firejail/netfilter.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -24,6 +24,96 @@ | |||
24 | #include <sys/wait.h> | 24 | #include <sys/wait.h> |
25 | #include <fcntl.h> | 25 | #include <fcntl.h> |
26 | 26 | ||
27 | void netfilter_netlock(pid_t pid) { | ||
28 | EUID_ASSERT(); | ||
29 | |||
30 | // give the sandbox a chance to start up before entering the network namespace | ||
31 | sleep(1); | ||
32 | enter_network_namespace(pid); | ||
33 | |||
34 | char *flog; | ||
35 | if (asprintf(&flog, "/run/firejail/network/%d-netlock", getpid()) == -1) | ||
36 | errExit("asprintf"); | ||
37 | FILE *fp = fopen(flog, "w"); | ||
38 | if (!fp) | ||
39 | errExit("fopen"); | ||
40 | fclose(fp); | ||
41 | |||
42 | // try to find a X terminal | ||
43 | char *terminal = NULL; | ||
44 | if (access("/usr/bin/xterm", X_OK) == 0) | ||
45 | terminal = "/usr/bin/xterm"; | ||
46 | else if (access("/usr/bin/lxterminal", X_OK) == 0) | ||
47 | terminal = "/usr/bin/lxterminal"; | ||
48 | else if (access("/usr/bin/xfce4-terminal", X_OK) == 0) | ||
49 | terminal = "/usr/bin/xfce4-terminal"; | ||
50 | else if (access("/usr/bin/konsole", X_OK) == 0) | ||
51 | terminal = "/usr/bin/konsole"; | ||
52 | // problem: newer gnome-terminal versions don't support -e command line option??? | ||
53 | // same for mate-terminal | ||
54 | |||
55 | if (isatty(STDIN_FILENO)) | ||
56 | terminal = NULL; | ||
57 | |||
58 | if (terminal) { | ||
59 | pid_t p = fork(); | ||
60 | if (p == -1) | ||
61 | ; // run without terminal logger | ||
62 | else if (p == 0) { // child | ||
63 | drop_privs(0); | ||
64 | |||
65 | char *cmd; | ||
66 | if (asprintf(&cmd, "%s -e \"%s/firejail/fnettrace --tail --log=%s\"", terminal, LIBDIR, flog) == -1) | ||
67 | errExit("asprintf"); | ||
68 | int rv = system(cmd); | ||
69 | (void) rv; | ||
70 | exit(0); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | char *cmd; | ||
75 | if (asprintf(&cmd, "%s/firejail/fnettrace --netfilter --log=%s", LIBDIR, flog) == -1) | ||
76 | errExit("asprintf"); | ||
77 | free(flog); | ||
78 | |||
79 | //************************ | ||
80 | // build command | ||
81 | //************************ | ||
82 | char *arg[4]; | ||
83 | arg[0] = "/bin/sh"; | ||
84 | arg[1] = "-c"; | ||
85 | arg[2] = cmd; | ||
86 | arg[3] = NULL; | ||
87 | clearenv(); | ||
88 | sbox_exec_v(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, arg); | ||
89 | // it will never get here!! | ||
90 | } | ||
91 | |||
92 | void netfilter_trace(pid_t pid) { | ||
93 | EUID_ASSERT(); | ||
94 | |||
95 | // a pid of 0 means the main system network namespace | ||
96 | if (pid) | ||
97 | enter_network_namespace(pid); | ||
98 | |||
99 | char *cmd; | ||
100 | if (asprintf(&cmd, "%s/firejail/fnettrace", LIBDIR) == -1) | ||
101 | errExit("asprintf"); | ||
102 | |||
103 | //************************ | ||
104 | // build command | ||
105 | //************************ | ||
106 | char *arg[4]; | ||
107 | arg[0] = "/bin/sh"; | ||
108 | arg[1] = "-c"; | ||
109 | arg[2] = cmd; | ||
110 | arg[3] = NULL; | ||
111 | |||
112 | clearenv(); | ||
113 | sbox_exec_v(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, arg); | ||
114 | // it will never get here!! | ||
115 | } | ||
116 | |||
27 | void check_netfilter_file(const char *fname) { | 117 | void check_netfilter_file(const char *fname) { |
28 | EUID_ASSERT(); | 118 | EUID_ASSERT(); |
29 | 119 | ||
diff --git a/src/firejail/netns.c b/src/firejail/netns.c index b5d6fb636..c72c009ae 100644 --- a/src/firejail/netns.c +++ b/src/firejail/netns.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2020-2021 Firejail Authors | 2 | * Copyright (C) 2020-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firejail/network.c b/src/firejail/network.c index f7142cefd..e631745fb 100644 --- a/src/firejail/network.c +++ b/src/firejail/network.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -217,7 +217,7 @@ int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) { | |||
217 | 217 | ||
218 | #define BUFSIZE 1024 | 218 | #define BUFSIZE 1024 |
219 | uint32_t network_get_defaultgw(void) { | 219 | uint32_t network_get_defaultgw(void) { |
220 | FILE *fp = fopen("/proc/self/net/route", "r"); | 220 | FILE *fp = fopen("/proc/self/net/route", "re"); |
221 | if (!fp) | 221 | if (!fp) |
222 | errExit("fopen"); | 222 | errExit("fopen"); |
223 | 223 | ||
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c index ee3c00872..dd66ecc55 100644 --- a/src/firejail/network_main.c +++ b/src/firejail/network_main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -292,7 +292,7 @@ void net_dns_print(pid_t pid) { | |||
292 | errExit("chdir"); | 292 | errExit("chdir"); |
293 | 293 | ||
294 | // access /etc/resolv.conf | 294 | // access /etc/resolv.conf |
295 | FILE *fp = fopen("/etc/resolv.conf", "r"); | 295 | FILE *fp = fopen("/etc/resolv.conf", "re"); |
296 | if (!fp) { | 296 | if (!fp) { |
297 | fprintf(stderr, "Error: cannot access /etc/resolv.conf\n"); | 297 | fprintf(stderr, "Error: cannot access /etc/resolv.conf\n"); |
298 | exit(1); | 298 | exit(1); |
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c index 60a82821e..c57d397ef 100644 --- a/src/firejail/no_sandbox.c +++ b/src/firejail/no_sandbox.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -20,6 +20,7 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <errno.h> | ||
23 | #include <unistd.h> | 24 | #include <unistd.h> |
24 | #include <grp.h> | 25 | #include <grp.h> |
25 | 26 | ||
@@ -47,7 +48,8 @@ int check_namespace_virt(void) { | |||
47 | 48 | ||
48 | // check PID 1 container environment variable | 49 | // check PID 1 container environment variable |
49 | EUID_ROOT(); | 50 | EUID_ROOT(); |
50 | FILE *fp = fopen("/proc/1/environ", "r"); | 51 | FILE *fp = fopen("/proc/1/environ", "re"); |
52 | EUID_USER(); | ||
51 | if (fp) { | 53 | if (fp) { |
52 | int c = 0; | 54 | int c = 0; |
53 | while (c != EOF) { | 55 | while (c != EOF) { |
@@ -68,7 +70,6 @@ int check_namespace_virt(void) { | |||
68 | // found it | 70 | // found it |
69 | if (is_container(buf + 10)) { | 71 | if (is_container(buf + 10)) { |
70 | fclose(fp); | 72 | fclose(fp); |
71 | EUID_USER(); | ||
72 | return 1; | 73 | return 1; |
73 | } | 74 | } |
74 | } | 75 | } |
@@ -78,7 +79,6 @@ int check_namespace_virt(void) { | |||
78 | fclose(fp); | 79 | fclose(fp); |
79 | } | 80 | } |
80 | 81 | ||
81 | EUID_USER(); | ||
82 | return 0; | 82 | return 0; |
83 | } | 83 | } |
84 | 84 | ||
@@ -105,20 +105,15 @@ int check_kernel_procs(void) { | |||
105 | // look at the first 10 processes | 105 | // look at the first 10 processes |
106 | // if a kernel process is found, return 1 | 106 | // if a kernel process is found, return 1 |
107 | for (i = 1; i <= 10; i++) { | 107 | for (i = 1; i <= 10; i++) { |
108 | struct stat s; | ||
109 | char *fname; | 108 | char *fname; |
110 | if (asprintf(&fname, "/proc/%d/comm", i) == -1) | 109 | if (asprintf(&fname, "/proc/%d/comm", i) == -1) |
111 | errExit("asprintf"); | 110 | errExit("asprintf"); |
112 | if (stat(fname, &s) == -1) { | ||
113 | free(fname); | ||
114 | continue; | ||
115 | } | ||
116 | 111 | ||
117 | // open file | 112 | // open file |
118 | /* coverity[toctou] */ | 113 | FILE *fp = fopen(fname, "re"); |
119 | FILE *fp = fopen(fname, "r"); | ||
120 | if (!fp) { | 114 | if (!fp) { |
121 | fwarning("cannot open %s\n", fname); | 115 | if (errno != ENOENT) |
116 | fwarning("cannot open %s\n", fname); | ||
122 | free(fname); | 117 | free(fname); |
123 | continue; | 118 | continue; |
124 | } | 119 | } |
@@ -208,7 +203,7 @@ void run_no_sandbox(int argc, char **argv) { | |||
208 | // force --shell=none in order to not break firecfg symbolic links | 203 | // force --shell=none in order to not break firecfg symbolic links |
209 | arg_shell_none = 1; | 204 | arg_shell_none = 1; |
210 | 205 | ||
211 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); | 206 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index, true); |
212 | } | 207 | } |
213 | 208 | ||
214 | fwarning("an existing sandbox was detected. " | 209 | fwarning("an existing sandbox was detected. " |
diff --git a/src/firejail/output.c b/src/firejail/output.c index 835dff2db..f9df9f3d4 100644 --- a/src/firejail/output.c +++ b/src/firejail/output.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -50,13 +50,21 @@ void check_output(int argc, char **argv) { | |||
50 | if (!outindex) | 50 | if (!outindex) |
51 | return; | 51 | return; |
52 | 52 | ||
53 | |||
54 | // check filename | ||
55 | drop_privs(0); | 53 | drop_privs(0); |
56 | char *outfile = argv[outindex]; | 54 | char *outfile = argv[outindex]; |
57 | outfile += (enable_stderr)? 16:9; | 55 | outfile += (enable_stderr)? 16:9; |
56 | |||
57 | // check filename | ||
58 | invalid_filename(outfile, 0); // no globbing | 58 | invalid_filename(outfile, 0); // no globbing |
59 | 59 | ||
60 | // expand user home directory | ||
61 | if (outfile[0] == '~') { | ||
62 | char *full; | ||
63 | if (asprintf(&full, "%s%s", cfg.homedir, outfile + 1) == -1) | ||
64 | errExit("asprintf"); | ||
65 | outfile = full; | ||
66 | } | ||
67 | |||
60 | // do not accept directories, links, and files with ".." | 68 | // do not accept directories, links, and files with ".." |
61 | if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) { | 69 | if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) { |
62 | fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n"); | 70 | fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n"); |
diff --git a/src/firejail/paths.c b/src/firejail/paths.c index b800fa944..6d62c9004 100644 --- a/src/firejail/paths.c +++ b/src/firejail/paths.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -136,7 +136,7 @@ int program_in_path(const char *program) { | |||
136 | // ('x' permission means something different for directories). | 136 | // ('x' permission means something different for directories). |
137 | // exec follows symlinks, so use stat, not lstat. | 137 | // exec follows symlinks, so use stat, not lstat. |
138 | struct stat st; | 138 | struct stat st; |
139 | if (stat(scratch, &st)) { | 139 | if (stat_as_user(scratch, &st)) { |
140 | perror(scratch); | 140 | perror(scratch); |
141 | exit(1); | 141 | exit(1); |
142 | } | 142 | } |
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c index 7f602545d..da50e9a82 100644 --- a/src/firejail/preproc.c +++ b/src/firejail/preproc.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -164,7 +164,7 @@ void preproc_clean_run(void) { | |||
164 | int max_pids=32769; | 164 | int max_pids=32769; |
165 | int start_pid = 100; | 165 | int start_pid = 100; |
166 | // extract real max_pids | 166 | // extract real max_pids |
167 | FILE *fp = fopen("/proc/sys/kernel/pid_max", "r"); | 167 | FILE *fp = fopen("/proc/sys/kernel/pid_max", "re"); |
168 | if (fp) { | 168 | if (fp) { |
169 | int val; | 169 | int val; |
170 | if (fscanf(fp, "%d", &val) == 1) { | 170 | if (fscanf(fp, "%d", &val) == 1) { |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 2ea32b665..5bc77263a 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,10 +18,12 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include "../include/gcov_wrapper.h" | ||
21 | #include "../include/seccomp.h" | 22 | #include "../include/seccomp.h" |
22 | #include "../include/syscall.h" | 23 | #include "../include/syscall.h" |
23 | #include <dirent.h> | 24 | #include <dirent.h> |
24 | #include <sys/stat.h> | 25 | #include <sys/stat.h> |
26 | |||
25 | extern char *xephyr_screen; | 27 | extern char *xephyr_screen; |
26 | 28 | ||
27 | #define MAX_READ 8192 // line buffer for profile files | 29 | #define MAX_READ 8192 // line buffer for profile files |
@@ -70,6 +72,7 @@ static int profile_find(const char *name, const char *dir, int add_ext) { | |||
70 | // search and read the profile specified by name from firejail directories | 72 | // search and read the profile specified by name from firejail directories |
71 | // return 1 if a profile was found | 73 | // return 1 if a profile was found |
72 | int profile_find_firejail(const char *name, int add_ext) { | 74 | int profile_find_firejail(const char *name, int add_ext) { |
75 | #ifndef HAVE_ONLY_SYSCFG_PROFILES | ||
73 | // look for a profile in ~/.config/firejail directory | 76 | // look for a profile in ~/.config/firejail directory |
74 | char *usercfgdir; | 77 | char *usercfgdir; |
75 | if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) | 78 | if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) |
@@ -82,6 +85,9 @@ int profile_find_firejail(const char *name, int add_ext) { | |||
82 | rv = profile_find(name, SYSCONFDIR, add_ext); | 85 | rv = profile_find(name, SYSCONFDIR, add_ext); |
83 | 86 | ||
84 | return rv; | 87 | return rv; |
88 | #else | ||
89 | return profile_find(name, SYSCONFDIR, add_ext); | ||
90 | #endif | ||
85 | } | 91 | } |
86 | 92 | ||
87 | //*************************************************** | 93 | //*************************************************** |
@@ -173,6 +179,10 @@ static int check_allow_drm(void) { | |||
173 | return checkcfg(CFG_BROWSER_ALLOW_DRM) != 0; | 179 | return checkcfg(CFG_BROWSER_ALLOW_DRM) != 0; |
174 | } | 180 | } |
175 | 181 | ||
182 | static int check_allow_tray(void) { | ||
183 | return checkcfg(CFG_ALLOW_TRAY) != 0; | ||
184 | } | ||
185 | |||
176 | Cond conditionals[] = { | 186 | Cond conditionals[] = { |
177 | {"HAS_APPIMAGE", check_appimage}, | 187 | {"HAS_APPIMAGE", check_appimage}, |
178 | {"HAS_NET", check_netoptions}, | 188 | {"HAS_NET", check_netoptions}, |
@@ -182,6 +192,7 @@ Cond conditionals[] = { | |||
182 | {"HAS_X11", check_x11}, | 192 | {"HAS_X11", check_x11}, |
183 | {"BROWSER_DISABLE_U2F", check_disable_u2f}, | 193 | {"BROWSER_DISABLE_U2F", check_disable_u2f}, |
184 | {"BROWSER_ALLOW_DRM", check_allow_drm}, | 194 | {"BROWSER_ALLOW_DRM", check_allow_drm}, |
195 | {"ALLOW_TRAY", check_allow_tray}, | ||
185 | { NULL, NULL } | 196 | { NULL, NULL } |
186 | }; | 197 | }; |
187 | 198 | ||
@@ -283,6 +294,15 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
283 | return 0; | 294 | return 0; |
284 | } | 295 | } |
285 | 296 | ||
297 | if (strncmp(ptr, "keep-fd ", 8) == 0) { | ||
298 | if (strcmp(ptr + 8, "all") == 0) | ||
299 | arg_keep_fd_all = 1; | ||
300 | else { | ||
301 | const char *add = ptr + 8; | ||
302 | profile_list_augment(&cfg.keep_fd, add); | ||
303 | } | ||
304 | return 0; | ||
305 | } | ||
286 | if (strncmp(ptr, "xephyr-screen ", 14) == 0) { | 306 | if (strncmp(ptr, "xephyr-screen ", 14) == 0) { |
287 | #ifdef HAVE_X11 | 307 | #ifdef HAVE_X11 |
288 | if (checkcfg(CFG_X11)) { | 308 | if (checkcfg(CFG_X11)) { |
@@ -373,6 +393,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
373 | #endif | 393 | #endif |
374 | return 0; | 394 | return 0; |
375 | } | 395 | } |
396 | else if (strcmp(ptr, "tab") == 0) { | ||
397 | arg_tab = 1; | ||
398 | return 0; | ||
399 | } | ||
376 | else if (strcmp(ptr, "private-cwd") == 0) { | 400 | else if (strcmp(ptr, "private-cwd") == 0) { |
377 | cfg.cwd = NULL; | 401 | cfg.cwd = NULL; |
378 | arg_private_cwd = 1; | 402 | arg_private_cwd = 1; |
@@ -409,13 +433,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
409 | return 0; | 433 | return 0; |
410 | } | 434 | } |
411 | else if (strcmp(ptr, "nogroups") == 0) { | 435 | else if (strcmp(ptr, "nogroups") == 0) { |
412 | // nvidia cards require video group; disable nogroups | 436 | arg_nogroups = 1; |
413 | if (access("/dev/nvidiactl", R_OK) == 0 && arg_no3d == 0) { | ||
414 | fwarning("Warning: NVIDIA card detected, nogroups command disabled\n"); | ||
415 | arg_nogroups = 0; | ||
416 | } | ||
417 | else | ||
418 | arg_nogroups = 1; | ||
419 | return 0; | 437 | return 0; |
420 | } | 438 | } |
421 | else if (strcmp(ptr, "nosound") == 0) { | 439 | else if (strcmp(ptr, "nosound") == 0) { |
@@ -423,7 +441,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
423 | return 0; | 441 | return 0; |
424 | } | 442 | } |
425 | else if (strcmp(ptr, "noautopulse") == 0) { | 443 | else if (strcmp(ptr, "noautopulse") == 0) { |
426 | arg_noautopulse = 1; | 444 | arg_keep_config_pulse = 1; |
427 | return 0; | 445 | return 0; |
428 | } | 446 | } |
429 | else if (strcmp(ptr, "notv") == 0) { | 447 | else if (strcmp(ptr, "notv") == 0) { |
@@ -442,6 +460,12 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
442 | arg_no3d = 1; | 460 | arg_no3d = 1; |
443 | return 0; | 461 | return 0; |
444 | } | 462 | } |
463 | else if (strcmp(ptr, "noprinters") == 0) { | ||
464 | arg_noprinters = 1; | ||
465 | profile_add("blacklist /dev/lp*"); | ||
466 | profile_add("blacklist /run/cups/cups.sock"); | ||
467 | return 0; | ||
468 | } | ||
445 | else if (strcmp(ptr, "noinput") == 0) { | 469 | else if (strcmp(ptr, "noinput") == 0) { |
446 | arg_noinput = 1; | 470 | arg_noinput = 1; |
447 | return 0; | 471 | return 0; |
@@ -628,7 +652,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
628 | #endif | 652 | #endif |
629 | return 0; | 653 | return 0; |
630 | } | 654 | } |
631 | else if (strncmp(ptr, "netns ", 6) == 0) { | 655 | else if (strncmp(ptr, "netns ", 6) == 0) { |
632 | #ifdef HAVE_NETWORK | 656 | #ifdef HAVE_NETWORK |
633 | if (checkcfg(CFG_NETWORK)) { | 657 | if (checkcfg(CFG_NETWORK)) { |
634 | arg_netns = ptr + 6; | 658 | arg_netns = ptr + 6; |
@@ -979,10 +1003,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
979 | warning_feature_disabled("seccomp"); | 1003 | warning_feature_disabled("seccomp"); |
980 | return 0; | 1004 | return 0; |
981 | } | 1005 | } |
982 | if (strncmp(ptr, "seccomp.32.drop ", 13) == 0) { | 1006 | if (strncmp(ptr, "seccomp.32.drop ", 16) == 0) { |
983 | if (checkcfg(CFG_SECCOMP)) { | 1007 | if (checkcfg(CFG_SECCOMP)) { |
984 | arg_seccomp32 = 1; | 1008 | arg_seccomp32 = 1; |
985 | cfg.seccomp_list_drop32 = seccomp_check_list(ptr + 13); | 1009 | cfg.seccomp_list_drop32 = seccomp_check_list(ptr + 16); |
986 | } | 1010 | } |
987 | else | 1011 | else |
988 | warning_feature_disabled("seccomp"); | 1012 | warning_feature_disabled("seccomp"); |
@@ -999,10 +1023,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
999 | warning_feature_disabled("seccomp"); | 1023 | warning_feature_disabled("seccomp"); |
1000 | return 0; | 1024 | return 0; |
1001 | } | 1025 | } |
1002 | if (strncmp(ptr, "seccomp.32.keep ", 13) == 0) { | 1026 | if (strncmp(ptr, "seccomp.32.keep ", 16) == 0) { |
1003 | if (checkcfg(CFG_SECCOMP)) { | 1027 | if (checkcfg(CFG_SECCOMP)) { |
1004 | arg_seccomp32 = 1; | 1028 | arg_seccomp32 = 1; |
1005 | cfg.seccomp_list_keep32 = seccomp_check_list(ptr + 13); | 1029 | cfg.seccomp_list_keep32 = seccomp_check_list(ptr + 16); |
1006 | } | 1030 | } |
1007 | else | 1031 | else |
1008 | warning_feature_disabled("seccomp"); | 1032 | warning_feature_disabled("seccomp"); |
@@ -1099,7 +1123,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1099 | else if (cfg.dns4 == NULL) | 1123 | else if (cfg.dns4 == NULL) |
1100 | cfg.dns4 = dns; | 1124 | cfg.dns4 = dns; |
1101 | else { | 1125 | else { |
1102 | fwarning("Warning: up to 4 DNS servers can be specified, %s ignored\n", dns); | 1126 | fwarning("up to 4 DNS servers can be specified, %s ignored\n", dns); |
1103 | free(dns); | 1127 | free(dns); |
1104 | } | 1128 | } |
1105 | return 0; | 1129 | return 0; |
@@ -1122,8 +1146,14 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1122 | 1146 | ||
1123 | // cgroup | 1147 | // cgroup |
1124 | if (strncmp(ptr, "cgroup ", 7) == 0) { | 1148 | if (strncmp(ptr, "cgroup ", 7) == 0) { |
1125 | if (checkcfg(CFG_CGROUP)) | 1149 | if (checkcfg(CFG_CGROUP)) { |
1126 | set_cgroup(ptr + 7); | 1150 | cfg.cgroup = strdup(ptr + 7); |
1151 | if (!cfg.cgroup) | ||
1152 | errExit("strdup"); | ||
1153 | |||
1154 | check_cgroup_file(cfg.cgroup); | ||
1155 | set_cgroup(cfg.cgroup, getpid()); | ||
1156 | } | ||
1127 | else | 1157 | else |
1128 | warning_feature_disabled("cgroup"); | 1158 | warning_feature_disabled("cgroup"); |
1129 | return 0; | 1159 | return 0; |
@@ -1143,6 +1173,12 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1143 | arg_machineid = 1; | 1173 | arg_machineid = 1; |
1144 | return 0; | 1174 | return 0; |
1145 | } | 1175 | } |
1176 | |||
1177 | if (strcmp(ptr, "keep-config-pulse") == 0) { | ||
1178 | arg_keep_config_pulse = 1; | ||
1179 | return 0; | ||
1180 | } | ||
1181 | |||
1146 | // writable-var | 1182 | // writable-var |
1147 | if (strcmp(ptr, "writable-var") == 0) { | 1183 | if (strcmp(ptr, "writable-var") == 0) { |
1148 | arg_writable_var = 1; | 1184 | arg_writable_var = 1; |
@@ -1269,56 +1305,69 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1269 | 1305 | ||
1270 | // private /etc list of files and directories | 1306 | // private /etc list of files and directories |
1271 | if (strncmp(ptr, "private-etc ", 12) == 0) { | 1307 | if (strncmp(ptr, "private-etc ", 12) == 0) { |
1272 | if (arg_writable_etc) { | 1308 | if (checkcfg(CFG_PRIVATE_ETC)) { |
1273 | fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n"); | 1309 | if (arg_writable_etc) { |
1274 | exit(1); | 1310 | fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n"); |
1275 | } | 1311 | exit(1); |
1276 | if (cfg.etc_private_keep) { | 1312 | } |
1277 | if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, ptr + 12) < 0 ) | 1313 | if (cfg.etc_private_keep) { |
1278 | errExit("asprintf"); | 1314 | if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, ptr + 12) < 0 ) |
1279 | } else { | 1315 | errExit("asprintf"); |
1280 | cfg.etc_private_keep = ptr + 12; | 1316 | } else { |
1317 | cfg.etc_private_keep = ptr + 12; | ||
1318 | } | ||
1319 | arg_private_etc = 1; | ||
1281 | } | 1320 | } |
1282 | arg_private_etc = 1; | 1321 | else |
1283 | 1322 | warning_feature_disabled("private-etc"); | |
1284 | return 0; | 1323 | return 0; |
1285 | } | 1324 | } |
1286 | 1325 | ||
1287 | // private /opt list of files and directories | 1326 | // private /opt list of files and directories |
1288 | if (strncmp(ptr, "private-opt ", 12) == 0) { | 1327 | if (strncmp(ptr, "private-opt ", 12) == 0) { |
1289 | if (cfg.opt_private_keep) { | 1328 | if (checkcfg(CFG_PRIVATE_OPT)) { |
1290 | if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, ptr + 12) < 0 ) | 1329 | if (cfg.opt_private_keep) { |
1291 | errExit("asprintf"); | 1330 | if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, ptr + 12) < 0 ) |
1292 | } else { | 1331 | errExit("asprintf"); |
1293 | cfg.opt_private_keep = ptr + 12; | 1332 | } else { |
1333 | cfg.opt_private_keep = ptr + 12; | ||
1334 | } | ||
1335 | arg_private_opt = 1; | ||
1294 | } | 1336 | } |
1295 | arg_private_opt = 1; | 1337 | else |
1296 | 1338 | warning_feature_disabled("private-opt"); | |
1297 | return 0; | 1339 | return 0; |
1298 | } | 1340 | } |
1299 | 1341 | ||
1300 | // private /srv list of files and directories | 1342 | // private /srv list of files and directories |
1301 | if (strncmp(ptr, "private-srv ", 12) == 0) { | 1343 | if (strncmp(ptr, "private-srv ", 12) == 0) { |
1302 | if (cfg.srv_private_keep) { | 1344 | if (checkcfg(CFG_PRIVATE_SRV)) { |
1303 | if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, ptr + 12) < 0 ) | 1345 | if (cfg.srv_private_keep) { |
1304 | errExit("asprintf"); | 1346 | if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, ptr + 12) < 0 ) |
1305 | } else { | 1347 | errExit("asprintf"); |
1306 | cfg.srv_private_keep = ptr + 12; | 1348 | } else { |
1349 | cfg.srv_private_keep = ptr + 12; | ||
1350 | } | ||
1351 | arg_private_srv = 1; | ||
1307 | } | 1352 | } |
1308 | arg_private_srv = 1; | 1353 | else |
1309 | 1354 | warning_feature_disabled("private-srv"); | |
1310 | return 0; | 1355 | return 0; |
1311 | } | 1356 | } |
1312 | 1357 | ||
1313 | // private /bin list of files | 1358 | // private /bin list of files |
1314 | if (strncmp(ptr, "private-bin ", 12) == 0) { | 1359 | if (strncmp(ptr, "private-bin ", 12) == 0) { |
1315 | if (cfg.bin_private_keep) { | 1360 | if (checkcfg(CFG_PRIVATE_BIN)) { |
1316 | if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, ptr + 12) < 0 ) | 1361 | if (cfg.bin_private_keep) { |
1317 | errExit("asprintf"); | 1362 | if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, ptr + 12) < 0 ) |
1318 | } else { | 1363 | errExit("asprintf"); |
1319 | cfg.bin_private_keep = ptr + 12; | 1364 | } else { |
1365 | cfg.bin_private_keep = ptr + 12; | ||
1366 | } | ||
1367 | arg_private_bin = 1; | ||
1320 | } | 1368 | } |
1321 | arg_private_bin = 1; | 1369 | else |
1370 | warning_feature_disabled("private-bin"); | ||
1322 | return 0; | 1371 | return 0; |
1323 | } | 1372 | } |
1324 | 1373 | ||
@@ -1486,8 +1535,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1486 | arg_rlimit_nproc = 1; | 1535 | arg_rlimit_nproc = 1; |
1487 | } | 1536 | } |
1488 | else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) { | 1537 | else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) { |
1489 | check_unsigned(ptr + 13, "Error: invalid rlimit in profile file: "); | 1538 | cfg.rlimit_fsize = parse_arg_size(ptr + 13); |
1490 | sscanf(ptr + 13, "%llu", &cfg.rlimit_fsize); | 1539 | if (cfg.rlimit_fsize == 0) { |
1540 | perror("Error: invalid rlimit-fsize in profile file. Only use positive numbers and k, m or g suffix."); | ||
1541 | exit(1); | ||
1542 | } | ||
1491 | arg_rlimit_fsize = 1; | 1543 | arg_rlimit_fsize = 1; |
1492 | } | 1544 | } |
1493 | else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) { | 1545 | else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) { |
@@ -1496,8 +1548,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1496 | arg_rlimit_sigpending = 1; | 1548 | arg_rlimit_sigpending = 1; |
1497 | } | 1549 | } |
1498 | else if (strncmp(ptr, "rlimit-as ", 10) == 0) { | 1550 | else if (strncmp(ptr, "rlimit-as ", 10) == 0) { |
1499 | check_unsigned(ptr + 10, "Error: invalid rlimit in profile file: "); | 1551 | cfg.rlimit_as = parse_arg_size(ptr + 10); |
1500 | sscanf(ptr + 10, "%llu", &cfg.rlimit_as); | 1552 | if (cfg.rlimit_as == 0) { |
1553 | perror("Error: invalid rlimit-as in profile file. Only use positive numbers and k, m or g suffix."); | ||
1554 | exit(1); | ||
1555 | } | ||
1501 | arg_rlimit_as = 1; | 1556 | arg_rlimit_as = 1; |
1502 | } | 1557 | } |
1503 | else { | 1558 | else { |
@@ -1554,6 +1609,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1554 | return 0; | 1609 | return 0; |
1555 | } | 1610 | } |
1556 | 1611 | ||
1612 | if (strcmp(ptr, "deterministic-shutdown") == 0) { | ||
1613 | arg_deterministic_shutdown = 1; | ||
1614 | return 0; | ||
1615 | } | ||
1616 | |||
1557 | // rest of filesystem | 1617 | // rest of filesystem |
1558 | if (strncmp(ptr, "blacklist ", 10) == 0) | 1618 | if (strncmp(ptr, "blacklist ", 10) == 0) |
1559 | ptr += 10; | 1619 | ptr += 10; |
@@ -1562,22 +1622,8 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1562 | else if (strncmp(ptr, "noblacklist ", 12) == 0) | 1622 | else if (strncmp(ptr, "noblacklist ", 12) == 0) |
1563 | ptr += 12; | 1623 | ptr += 12; |
1564 | else if (strncmp(ptr, "whitelist ", 10) == 0) { | 1624 | else if (strncmp(ptr, "whitelist ", 10) == 0) { |
1565 | #ifdef HAVE_WHITELIST | 1625 | arg_whitelist = 1; |
1566 | if (checkcfg(CFG_WHITELIST)) { | 1626 | ptr += 10; |
1567 | arg_whitelist = 1; | ||
1568 | ptr += 10; | ||
1569 | } | ||
1570 | else { | ||
1571 | static int whitelist_warning_printed = 0; | ||
1572 | if (!whitelist_warning_printed) { | ||
1573 | warning_feature_disabled("whitelist"); | ||
1574 | whitelist_warning_printed = 1; | ||
1575 | } | ||
1576 | return 0; | ||
1577 | } | ||
1578 | #else | ||
1579 | return 0; | ||
1580 | #endif | ||
1581 | } | 1627 | } |
1582 | else if (strncmp(ptr, "nowhitelist ", 12) == 0) | 1628 | else if (strncmp(ptr, "nowhitelist ", 12) == 0) |
1583 | ptr += 12; | 1629 | ptr += 12; |
@@ -1691,7 +1737,7 @@ void profile_read(const char *fname) { | |||
1691 | } | 1737 | } |
1692 | 1738 | ||
1693 | // open profile file: | 1739 | // open profile file: |
1694 | FILE *fp = fopen(fname, "r"); | 1740 | FILE *fp = fopen(fname, "re"); |
1695 | if (fp == NULL) { | 1741 | if (fp == NULL) { |
1696 | fprintf(stderr, "Error: cannot open profile file %s\n", fname); | 1742 | fprintf(stderr, "Error: cannot open profile file %s\n", fname); |
1697 | exit(1); | 1743 | exit(1); |
@@ -1708,13 +1754,29 @@ void profile_read(const char *fname) { | |||
1708 | int lineno = 0; | 1754 | int lineno = 0; |
1709 | while (fgets(buf, MAX_READ, fp)) { | 1755 | while (fgets(buf, MAX_READ, fp)) { |
1710 | ++lineno; | 1756 | ++lineno; |
1757 | |||
1758 | // remove comments | ||
1759 | char *ptr = strchr(buf, '#'); | ||
1760 | if (ptr) | ||
1761 | *ptr = '\0'; | ||
1762 | |||
1711 | // remove empty space - ptr in allocated memory | 1763 | // remove empty space - ptr in allocated memory |
1712 | char *ptr = line_remove_spaces(buf); | 1764 | ptr = line_remove_spaces(buf); |
1713 | if (ptr == NULL) | 1765 | if (ptr == NULL) |
1714 | continue; | 1766 | continue; |
1767 | if (*ptr == '\0') { | ||
1768 | free(ptr); | ||
1769 | continue; | ||
1770 | } | ||
1715 | 1771 | ||
1716 | // comments | 1772 | if (strncmp(ptr, "whitelist-ro ", 13) == 0) { |
1717 | if (*ptr == '#' || *ptr == '\0') { | 1773 | char *whitelist, *readonly; |
1774 | if (asprintf(&whitelist, "whitelist %s", ptr + 13) == -1) | ||
1775 | errExit("asprintf"); | ||
1776 | profile_add(whitelist); | ||
1777 | if (asprintf(&readonly, "read-only %s", ptr + 13) == -1) | ||
1778 | errExit("asprintf"); | ||
1779 | profile_add(readonly); | ||
1718 | free(ptr); | 1780 | free(ptr); |
1719 | continue; | 1781 | continue; |
1720 | } | 1782 | } |
@@ -1724,7 +1786,7 @@ void profile_read(const char *fname) { | |||
1724 | if (strcmp(ptr, "quiet") == 0) { | 1786 | if (strcmp(ptr, "quiet") == 0) { |
1725 | if (is_in_ignore_list(ptr)) | 1787 | if (is_in_ignore_list(ptr)) |
1726 | arg_quiet = 0; | 1788 | arg_quiet = 0; |
1727 | else | 1789 | else if (!arg_debug) |
1728 | arg_quiet = 1; | 1790 | arg_quiet = 1; |
1729 | free(ptr); | 1791 | free(ptr); |
1730 | continue; | 1792 | continue; |
@@ -1771,9 +1833,8 @@ void profile_read(const char *fname) { | |||
1771 | // else { | 1833 | // else { |
1772 | // free(ptr); | 1834 | // free(ptr); |
1773 | // } | 1835 | // } |
1774 | #ifdef HAVE_GCOV | 1836 | |
1775 | __gcov_flush(); | 1837 | __gcov_flush(); |
1776 | #endif | ||
1777 | } | 1838 | } |
1778 | fclose(fp); | 1839 | fclose(fp); |
1779 | } | 1840 | } |
@@ -1884,7 +1945,7 @@ char *profile_list_compress(char *list) | |||
1884 | /* Include non-empty item */ | 1945 | /* Include non-empty item */ |
1885 | if (!*item) | 1946 | if (!*item) |
1886 | in[i] = 0; | 1947 | in[i] = 0; |
1887 | /* Remove all allready included items */ | 1948 | /* Remove all already included items */ |
1888 | for (k = 0; k < i; ++k) | 1949 | for (k = 0; k < i; ++k) |
1889 | in[k] = 0; | 1950 | in[k] = 0; |
1890 | break; | 1951 | break; |
diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c index 926af7967..37e541f50 100644 --- a/src/firejail/protocol.c +++ b/src/firejail/protocol.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -23,7 +23,7 @@ | |||
23 | 23 | ||
24 | void protocol_filter_save(void) { | 24 | void protocol_filter_save(void) { |
25 | // save protocol filter configuration in PROTOCOL_CFG | 25 | // save protocol filter configuration in PROTOCOL_CFG |
26 | FILE *fp = fopen(RUN_PROTOCOL_CFG, "w"); | 26 | FILE *fp = fopen(RUN_PROTOCOL_CFG, "wxe"); |
27 | if (!fp) | 27 | if (!fp) |
28 | errExit("fopen"); | 28 | errExit("fopen"); |
29 | fprintf(fp, "%s\n", cfg.protocol); | 29 | fprintf(fp, "%s\n", cfg.protocol); |
@@ -35,7 +35,7 @@ void protocol_filter_load(const char *fname) { | |||
35 | assert(fname); | 35 | assert(fname); |
36 | 36 | ||
37 | // read protocol filter configuration from PROTOCOL_CFG | 37 | // read protocol filter configuration from PROTOCOL_CFG |
38 | FILE *fp = fopen(fname, "r"); | 38 | FILE *fp = fopen(fname, "re"); |
39 | if (!fp) | 39 | if (!fp) |
40 | return; | 40 | return; |
41 | 41 | ||
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c index 4b9203c36..320668bf9 100644 --- a/src/firejail/pulseaudio.c +++ b/src/firejail/pulseaudio.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -25,6 +25,7 @@ | |||
25 | #include <dirent.h> | 25 | #include <dirent.h> |
26 | #include <errno.h> | 26 | #include <errno.h> |
27 | #include <sys/wait.h> | 27 | #include <sys/wait.h> |
28 | #include <glob.h> | ||
28 | 29 | ||
29 | #include <fcntl.h> | 30 | #include <fcntl.h> |
30 | #ifndef O_PATH | 31 | #ifndef O_PATH |
@@ -33,6 +34,59 @@ | |||
33 | 34 | ||
34 | #define PULSE_CLIENT_SYSCONF "/etc/pulse/client.conf" | 35 | #define PULSE_CLIENT_SYSCONF "/etc/pulse/client.conf" |
35 | 36 | ||
37 | |||
38 | |||
39 | static void disable_rundir_pipewire(const char *path) { | ||
40 | assert(path); | ||
41 | |||
42 | // globbing for path/pipewire-* | ||
43 | char *pattern; | ||
44 | if (asprintf(&pattern, "%s/pipewire-*", path) == -1) | ||
45 | errExit("asprintf"); | ||
46 | |||
47 | glob_t globbuf; | ||
48 | int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT, NULL, &globbuf); | ||
49 | if (globerr) { | ||
50 | fprintf(stderr, "Error: failed to glob pattern %s\n", pattern); | ||
51 | exit(1); | ||
52 | } | ||
53 | |||
54 | size_t i; | ||
55 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
56 | char *dir = globbuf.gl_pathv[i]; | ||
57 | assert(dir); | ||
58 | |||
59 | // don't disable symlinks - disable_file_or_dir will bind-mount an empty directory on top of it! | ||
60 | if (is_link(dir)) | ||
61 | continue; | ||
62 | disable_file_or_dir(dir); | ||
63 | } | ||
64 | globfree(&globbuf); | ||
65 | free(pattern); | ||
66 | } | ||
67 | |||
68 | |||
69 | |||
70 | // disable pipewire socket | ||
71 | void pipewire_disable(void) { | ||
72 | if (arg_debug) | ||
73 | printf("disable pipewire\n"); | ||
74 | // blacklist user config directory | ||
75 | disable_file_path(cfg.homedir, ".config/pipewire"); | ||
76 | |||
77 | // blacklist pipewire in XDG_RUNTIME_DIR | ||
78 | const char *name = env_get("XDG_RUNTIME_DIR"); | ||
79 | if (name) | ||
80 | disable_rundir_pipewire(name); | ||
81 | |||
82 | // try the default location anyway | ||
83 | char *path; | ||
84 | if (asprintf(&path, "/run/user/%d", getuid()) == -1) | ||
85 | errExit("asprintf"); | ||
86 | disable_rundir_pipewire(path); | ||
87 | free(path); | ||
88 | } | ||
89 | |||
36 | // disable pulseaudio socket | 90 | // disable pulseaudio socket |
37 | void pulseaudio_disable(void) { | 91 | void pulseaudio_disable(void) { |
38 | if (arg_debug) | 92 | if (arg_debug) |
@@ -75,38 +129,41 @@ void pulseaudio_disable(void) { | |||
75 | closedir(dir); | 129 | closedir(dir); |
76 | } | 130 | } |
77 | 131 | ||
78 | static void pulseaudio_fallback(const char *path) { | ||
79 | assert(path); | ||
80 | |||
81 | fmessage("Cannot mount tmpfs on %s/.config/pulse\n", cfg.homedir); | ||
82 | env_store_name_val("PULSE_CLIENTCONFIG", path, SETENV); | ||
83 | } | ||
84 | |||
85 | // disable shm in pulseaudio (issue #69) | 132 | // disable shm in pulseaudio (issue #69) |
86 | void pulseaudio_init(void) { | 133 | void pulseaudio_init(void) { |
87 | struct stat s; | ||
88 | |||
89 | // do we have pulseaudio in the system? | 134 | // do we have pulseaudio in the system? |
90 | if (stat(PULSE_CLIENT_SYSCONF, &s) == -1) { | 135 | if (access(PULSE_CLIENT_SYSCONF, R_OK)) { |
91 | if (arg_debug) | 136 | if (arg_debug) |
92 | printf("%s not found\n", PULSE_CLIENT_SYSCONF); | 137 | printf("Cannot read %s\n", PULSE_CLIENT_SYSCONF); |
93 | return; | 138 | return; |
94 | } | 139 | } |
95 | 140 | ||
141 | // create ~/.config/pulse directory if not present | ||
142 | char *homeusercfg = NULL; | ||
143 | if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1) | ||
144 | errExit("asprintf"); | ||
145 | if (create_empty_dir_as_user(homeusercfg, 0700)) | ||
146 | fs_logger2("create", homeusercfg); | ||
147 | |||
148 | free(homeusercfg); | ||
149 | if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1) | ||
150 | errExit("asprintf"); | ||
151 | if (create_empty_dir_as_user(homeusercfg, 0700)) | ||
152 | fs_logger2("create", homeusercfg); | ||
153 | |||
96 | // create the new user pulseaudio directory | 154 | // create the new user pulseaudio directory |
155 | // that will be mounted over ~/.config/pulse | ||
97 | if (mkdir(RUN_PULSE_DIR, 0700) == -1) | 156 | if (mkdir(RUN_PULSE_DIR, 0700) == -1) |
98 | errExit("mkdir"); | 157 | errExit("mkdir"); |
99 | selinux_relabel_path(RUN_PULSE_DIR, RUN_PULSE_DIR); | 158 | selinux_relabel_path(RUN_PULSE_DIR, homeusercfg); |
100 | // mount it nosuid, noexec, nodev | ||
101 | fs_remount(RUN_PULSE_DIR, MOUNT_NOEXEC, 0); | 159 | fs_remount(RUN_PULSE_DIR, MOUNT_NOEXEC, 0); |
102 | |||
103 | // create the new client.conf file | 160 | // create the new client.conf file |
104 | char *pulsecfg = NULL; | 161 | char *pulsecfg = NULL; |
105 | if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1) | 162 | if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1) |
106 | errExit("asprintf"); | 163 | errExit("asprintf"); |
107 | if (copy_file(PULSE_CLIENT_SYSCONF, pulsecfg, -1, -1, 0644)) // root needed | 164 | if (copy_file(PULSE_CLIENT_SYSCONF, pulsecfg, -1, -1, 0644)) // root needed |
108 | errExit("copy_file"); | 165 | errExit("copy_file"); |
109 | FILE *fp = fopen(pulsecfg, "a"); | 166 | FILE *fp = fopen(pulsecfg, "ae"); |
110 | if (!fp) | 167 | if (!fp) |
111 | errExit("fopen"); | 168 | errExit("fopen"); |
112 | fprintf(fp, "%s", "\nenable-shm = no\n"); | 169 | fprintf(fp, "%s", "\nenable-shm = no\n"); |
@@ -116,37 +173,14 @@ void pulseaudio_init(void) { | |||
116 | if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700)) | 173 | if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700)) |
117 | errExit("set_perms"); | 174 | errExit("set_perms"); |
118 | 175 | ||
119 | // create ~/.config/pulse directory if not present | ||
120 | char *homeusercfg = NULL; | ||
121 | if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1) | ||
122 | errExit("asprintf"); | ||
123 | if (create_empty_dir_as_user(homeusercfg, 0700)) | ||
124 | fs_logger2("create", homeusercfg); | ||
125 | |||
126 | free(homeusercfg); | ||
127 | if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1) | ||
128 | errExit("asprintf"); | ||
129 | if (create_empty_dir_as_user(homeusercfg, 0700)) | ||
130 | fs_logger2("create", homeusercfg); | ||
131 | |||
132 | // if ~/.config/pulse exists and there are no symbolic links, mount the new directory | 176 | // if ~/.config/pulse exists and there are no symbolic links, mount the new directory |
133 | // else set environment variable | 177 | // else set environment variable |
134 | int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 178 | EUID_USER(); |
179 | int fd = safer_openat(-1, homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
180 | EUID_ROOT(); | ||
135 | if (fd == -1) { | 181 | if (fd == -1) { |
136 | pulseaudio_fallback(pulsecfg); | 182 | fwarning("not mounting tmpfs on %s\n", homeusercfg); |
137 | goto out; | 183 | env_store_name_val("PULSE_CLIENTCONFIG", pulsecfg, SETENV); |
138 | } | ||
139 | // confirm the actual mount destination is owned by the user | ||
140 | if (fstat(fd, &s) == -1) { // FUSE | ||
141 | if (errno != EACCES) | ||
142 | errExit("fstat"); | ||
143 | close(fd); | ||
144 | pulseaudio_fallback(pulsecfg); | ||
145 | goto out; | ||
146 | } | ||
147 | if (s.st_uid != getuid()) { | ||
148 | close(fd); | ||
149 | pulseaudio_fallback(pulsecfg); | ||
150 | goto out; | 184 | goto out; |
151 | } | 185 | } |
152 | // preserve a read-only mount | 186 | // preserve a read-only mount |
@@ -158,17 +192,13 @@ void pulseaudio_init(void) { | |||
158 | // mount via the link in /proc/self/fd | 192 | // mount via the link in /proc/self/fd |
159 | if (arg_debug) | 193 | if (arg_debug) |
160 | printf("Mounting %s on %s\n", RUN_PULSE_DIR, homeusercfg); | 194 | printf("Mounting %s on %s\n", RUN_PULSE_DIR, homeusercfg); |
161 | char *proc; | 195 | if (bind_mount_path_to_fd(RUN_PULSE_DIR, fd)) |
162 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
163 | errExit("asprintf"); | ||
164 | if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0) | ||
165 | errExit("mount pulseaudio"); | 196 | errExit("mount pulseaudio"); |
166 | // check /proc/self/mountinfo to confirm the mount is ok | 197 | // check /proc/self/mountinfo to confirm the mount is ok |
167 | MountData *mptr = get_last_mount(); | 198 | MountData *mptr = get_last_mount(); |
168 | if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) | 199 | if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) |
169 | errLogExit("invalid pulseaudio mount"); | 200 | errLogExit("invalid pulseaudio mount"); |
170 | fs_logger2("tmpfs", homeusercfg); | 201 | fs_logger2("tmpfs", homeusercfg); |
171 | free(proc); | ||
172 | close(fd); | 202 | close(fd); |
173 | 203 | ||
174 | char *p; | 204 | char *p; |
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c index a0ca4c02c..447d7b663 100644 --- a/src/firejail/restrict_users.c +++ b/src/firejail/restrict_users.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -21,7 +21,6 @@ | |||
21 | #include "../include/firejail_user.h" | 21 | #include "../include/firejail_user.h" |
22 | #include <sys/mount.h> | 22 | #include <sys/mount.h> |
23 | #include <sys/stat.h> | 23 | #include <sys/stat.h> |
24 | #include <linux/limits.h> | ||
25 | #include <fnmatch.h> | 24 | #include <fnmatch.h> |
26 | #include <glob.h> | 25 | #include <glob.h> |
27 | #include <dirent.h> | 26 | #include <dirent.h> |
@@ -73,7 +72,7 @@ static void sanitize_home(void) { | |||
73 | if (arg_debug) | 72 | if (arg_debug) |
74 | printf("Cleaning /home directory\n"); | 73 | printf("Cleaning /home directory\n"); |
75 | // open user home directory in order to keep it around | 74 | // open user home directory in order to keep it around |
76 | int fd = safe_fd(cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 75 | int fd = safer_openat(-1, cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
77 | if (fd == -1) | 76 | if (fd == -1) |
78 | goto errout; | 77 | goto errout; |
79 | if (fstat(fd, &s) == -1) { // FUSE | 78 | if (fstat(fd, &s) == -1) { // FUSE |
@@ -104,12 +103,8 @@ static void sanitize_home(void) { | |||
104 | selinux_relabel_path(cfg.homedir, cfg.homedir); | 103 | selinux_relabel_path(cfg.homedir, cfg.homedir); |
105 | 104 | ||
106 | // bring back real user home directory | 105 | // bring back real user home directory |
107 | char *proc; | 106 | if (bind_mount_fd_to_path(fd, cfg.homedir)) |
108 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
109 | errExit("asprintf"); | ||
110 | if (mount(proc, cfg.homedir, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
111 | errExit("mount bind"); | 107 | errExit("mount bind"); |
112 | free(proc); | ||
113 | close(fd); | 108 | close(fd); |
114 | 109 | ||
115 | if (!arg_private) | 110 | if (!arg_private) |
@@ -154,12 +149,8 @@ static void sanitize_run(void) { | |||
154 | selinux_relabel_path(runuser, runuser); | 149 | selinux_relabel_path(runuser, runuser); |
155 | 150 | ||
156 | // bring back real run/user/$UID directory | 151 | // bring back real run/user/$UID directory |
157 | char *proc; | 152 | if (bind_mount_fd_to_path(fd, runuser)) |
158 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
159 | errExit("asprintf"); | ||
160 | if (mount(proc, runuser, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
161 | errExit("mount bind"); | 153 | errExit("mount bind"); |
162 | free(proc); | ||
163 | close(fd); | 154 | close(fd); |
164 | 155 | ||
165 | fs_logger2("whitelist", runuser); | 156 | fs_logger2("whitelist", runuser); |
@@ -183,10 +174,10 @@ static void sanitize_passwd(void) { | |||
183 | 174 | ||
184 | // open files | 175 | // open files |
185 | /* coverity[toctou] */ | 176 | /* coverity[toctou] */ |
186 | fpin = fopen("/etc/passwd", "r"); | 177 | fpin = fopen("/etc/passwd", "re"); |
187 | if (!fpin) | 178 | if (!fpin) |
188 | goto errout; | 179 | goto errout; |
189 | fpout = fopen(RUN_PASSWD_FILE, "w"); | 180 | fpout = fopen(RUN_PASSWD_FILE, "we"); |
190 | if (!fpout) | 181 | if (!fpout) |
191 | goto errout; | 182 | goto errout; |
192 | 183 | ||
@@ -246,6 +237,11 @@ static void sanitize_passwd(void) { | |||
246 | // mount-bind tne new password file | 237 | // mount-bind tne new password file |
247 | if (mount(RUN_PASSWD_FILE, "/etc/passwd", "none", MS_BIND, "mode=400,gid=0") < 0) | 238 | if (mount(RUN_PASSWD_FILE, "/etc/passwd", "none", MS_BIND, "mode=400,gid=0") < 0) |
248 | errExit("mount"); | 239 | errExit("mount"); |
240 | |||
241 | // blacklist RUN_PASSWD_FILE | ||
242 | if (mount(RUN_RO_FILE, RUN_PASSWD_FILE, "none", MS_BIND, "mode=400,gid=0") < 0) | ||
243 | errExit("mount"); | ||
244 | |||
249 | fs_logger("create /etc/passwd"); | 245 | fs_logger("create /etc/passwd"); |
250 | 246 | ||
251 | return; | 247 | return; |
@@ -318,10 +314,10 @@ static void sanitize_group(void) { | |||
318 | 314 | ||
319 | // open files | 315 | // open files |
320 | /* coverity[toctou] */ | 316 | /* coverity[toctou] */ |
321 | fpin = fopen("/etc/group", "r"); | 317 | fpin = fopen("/etc/group", "re"); |
322 | if (!fpin) | 318 | if (!fpin) |
323 | goto errout; | 319 | goto errout; |
324 | fpout = fopen(RUN_GROUP_FILE, "w"); | 320 | fpout = fopen(RUN_GROUP_FILE, "we"); |
325 | if (!fpout) | 321 | if (!fpout) |
326 | goto errout; | 322 | goto errout; |
327 | 323 | ||
@@ -376,6 +372,11 @@ static void sanitize_group(void) { | |||
376 | // mount-bind tne new group file | 372 | // mount-bind tne new group file |
377 | if (mount(RUN_GROUP_FILE, "/etc/group", "none", MS_BIND, "mode=400,gid=0") < 0) | 373 | if (mount(RUN_GROUP_FILE, "/etc/group", "none", MS_BIND, "mode=400,gid=0") < 0) |
378 | errExit("mount"); | 374 | errExit("mount"); |
375 | |||
376 | // blacklist RUN_GROUP_FILE | ||
377 | if (mount(RUN_RO_FILE, RUN_GROUP_FILE, "none", MS_BIND, "mode=400,gid=0") < 0) | ||
378 | errExit("mount"); | ||
379 | |||
379 | fs_logger("create /etc/group"); | 380 | fs_logger("create /etc/group"); |
380 | 381 | ||
381 | return; | 382 | return; |
diff --git a/src/firejail/restricted_shell.c b/src/firejail/restricted_shell.c index ae453f4f1..c1340cae1 100644 --- a/src/firejail/restricted_shell.c +++ b/src/firejail/restricted_shell.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -32,7 +32,7 @@ int restricted_shell(const char *user) { | |||
32 | char *fname; | 32 | char *fname; |
33 | if (asprintf(&fname, "%s/login.users", SYSCONFDIR) == -1) | 33 | if (asprintf(&fname, "%s/login.users", SYSCONFDIR) == -1) |
34 | errExit("asprintf"); | 34 | errExit("asprintf"); |
35 | FILE *fp = fopen(fname, "r"); | 35 | FILE *fp = fopen(fname, "re"); |
36 | free(fname); | 36 | free(fname); |
37 | if (fp == NULL) | 37 | if (fp == NULL) |
38 | return 0; | 38 | return 0; |
@@ -96,7 +96,7 @@ int restricted_shell(const char *user) { | |||
96 | fullargv[i] = ptr; | 96 | fullargv[i] = ptr; |
97 | #ifdef DEBUG_RESTRICTED_SHELL | 97 | #ifdef DEBUG_RESTRICTED_SHELL |
98 | {EUID_ROOT(); | 98 | {EUID_ROOT(); |
99 | FILE *fp = fopen("/firelog", "a"); | 99 | FILE *fp = fopen("/firelog", "ae"); |
100 | if (fp) { | 100 | if (fp) { |
101 | fprintf(fp, "i %d ptr #%s#\n", i, fullargv[i]); | 101 | fprintf(fp, "i %d ptr #%s#\n", i, fullargv[i]); |
102 | fclose(fp); | 102 | fclose(fp); |
diff --git a/src/firejail/rlimit.c b/src/firejail/rlimit.c index 78f00bc63..b10d2c528 100644 --- a/src/firejail/rlimit.c +++ b/src/firejail/rlimit.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,6 +18,7 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include "../include/gcov_wrapper.h" | ||
21 | #include <sys/time.h> | 22 | #include <sys/time.h> |
22 | #include <sys/resource.h> | 23 | #include <sys/resource.h> |
23 | 24 | ||
@@ -33,9 +34,9 @@ void set_rlimits(void) { | |||
33 | // set the new limit | 34 | // set the new limit |
34 | rl.rlim_cur = (rlim_t) cfg.rlimit_cpu; | 35 | rl.rlim_cur = (rlim_t) cfg.rlimit_cpu; |
35 | rl.rlim_max = (rlim_t) cfg.rlimit_cpu; | 36 | rl.rlim_max = (rlim_t) cfg.rlimit_cpu; |
36 | #ifdef HAVE_GCOV | 37 | |
37 | __gcov_dump(); | 38 | __gcov_dump(); |
38 | #endif | 39 | |
39 | if (setrlimit(RLIMIT_CPU, &rl) == -1) | 40 | if (setrlimit(RLIMIT_CPU, &rl) == -1) |
40 | errExit("setrlimit"); | 41 | errExit("setrlimit"); |
41 | if (arg_debug) | 42 | if (arg_debug) |
@@ -50,9 +51,10 @@ void set_rlimits(void) { | |||
50 | // set the new limit | 51 | // set the new limit |
51 | rl.rlim_cur = (rlim_t) cfg.rlimit_nofile; | 52 | rl.rlim_cur = (rlim_t) cfg.rlimit_nofile; |
52 | rl.rlim_max = (rlim_t) cfg.rlimit_nofile; | 53 | rl.rlim_max = (rlim_t) cfg.rlimit_nofile; |
53 | #ifdef HAVE_GCOV // gcov-instrumented programs might crash at this point | 54 | |
55 | // gcov-instrumented programs might crash at this point | ||
54 | __gcov_dump(); | 56 | __gcov_dump(); |
55 | #endif | 57 | |
56 | if (setrlimit(RLIMIT_NOFILE, &rl) == -1) | 58 | if (setrlimit(RLIMIT_NOFILE, &rl) == -1) |
57 | errExit("setrlimit"); | 59 | errExit("setrlimit"); |
58 | if (arg_debug) | 60 | if (arg_debug) |
@@ -67,9 +69,9 @@ void set_rlimits(void) { | |||
67 | // set the new limit | 69 | // set the new limit |
68 | rl.rlim_cur = (rlim_t) cfg.rlimit_nproc; | 70 | rl.rlim_cur = (rlim_t) cfg.rlimit_nproc; |
69 | rl.rlim_max = (rlim_t) cfg.rlimit_nproc; | 71 | rl.rlim_max = (rlim_t) cfg.rlimit_nproc; |
70 | #ifdef HAVE_GCOV | 72 | |
71 | __gcov_dump(); | 73 | __gcov_dump(); |
72 | #endif | 74 | |
73 | if (setrlimit(RLIMIT_NPROC, &rl) == -1) | 75 | if (setrlimit(RLIMIT_NPROC, &rl) == -1) |
74 | errExit("setrlimit"); | 76 | errExit("setrlimit"); |
75 | if (arg_debug) | 77 | if (arg_debug) |
@@ -84,9 +86,9 @@ void set_rlimits(void) { | |||
84 | // set the new limit | 86 | // set the new limit |
85 | rl.rlim_cur = (rlim_t) cfg.rlimit_fsize; | 87 | rl.rlim_cur = (rlim_t) cfg.rlimit_fsize; |
86 | rl.rlim_max = (rlim_t) cfg.rlimit_fsize; | 88 | rl.rlim_max = (rlim_t) cfg.rlimit_fsize; |
87 | #ifdef HAVE_GCOV | 89 | |
88 | __gcov_dump(); | 90 | __gcov_dump(); |
89 | #endif | 91 | |
90 | if (setrlimit(RLIMIT_FSIZE, &rl) == -1) | 92 | if (setrlimit(RLIMIT_FSIZE, &rl) == -1) |
91 | errExit("setrlimit"); | 93 | errExit("setrlimit"); |
92 | if (arg_debug) | 94 | if (arg_debug) |
@@ -101,9 +103,9 @@ void set_rlimits(void) { | |||
101 | // set the new limit | 103 | // set the new limit |
102 | rl.rlim_cur = (rlim_t) cfg.rlimit_sigpending; | 104 | rl.rlim_cur = (rlim_t) cfg.rlimit_sigpending; |
103 | rl.rlim_max = (rlim_t) cfg.rlimit_sigpending; | 105 | rl.rlim_max = (rlim_t) cfg.rlimit_sigpending; |
104 | #ifdef HAVE_GCOV | 106 | |
105 | __gcov_dump(); | 107 | __gcov_dump(); |
106 | #endif | 108 | |
107 | if (setrlimit(RLIMIT_SIGPENDING, &rl) == -1) | 109 | if (setrlimit(RLIMIT_SIGPENDING, &rl) == -1) |
108 | errExit("setrlimit"); | 110 | errExit("setrlimit"); |
109 | if (arg_debug) | 111 | if (arg_debug) |
@@ -118,9 +120,9 @@ void set_rlimits(void) { | |||
118 | // set the new limit | 120 | // set the new limit |
119 | rl.rlim_cur = (rlim_t) cfg.rlimit_as; | 121 | rl.rlim_cur = (rlim_t) cfg.rlimit_as; |
120 | rl.rlim_max = (rlim_t) cfg.rlimit_as; | 122 | rl.rlim_max = (rlim_t) cfg.rlimit_as; |
121 | #ifdef HAVE_GCOV | 123 | |
122 | __gcov_dump(); | 124 | __gcov_dump(); |
123 | #endif | 125 | |
124 | if (setrlimit(RLIMIT_AS, &rl) == -1) | 126 | if (setrlimit(RLIMIT_AS, &rl) == -1) |
125 | errExit("setrlimit"); | 127 | errExit("setrlimit"); |
126 | if (arg_debug) | 128 | if (arg_debug) |
diff --git a/src/firejail/run_files.c b/src/firejail/run_files.c index cd44f745f..c971a4f53 100644 --- a/src/firejail/run_files.c +++ b/src/firejail/run_files.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -101,7 +101,7 @@ void set_name_run_file(pid_t pid) { | |||
101 | errExit("asprintf"); | 101 | errExit("asprintf"); |
102 | 102 | ||
103 | // the file is deleted first | 103 | // the file is deleted first |
104 | FILE *fp = fopen(fname, "w"); | 104 | FILE *fp = fopen(fname, "we"); |
105 | if (!fp) { | 105 | if (!fp) { |
106 | fprintf(stderr, "Error: cannot create %s\n", fname); | 106 | fprintf(stderr, "Error: cannot create %s\n", fname); |
107 | exit(1); | 107 | exit(1); |
@@ -120,7 +120,7 @@ void set_x11_run_file(pid_t pid, int display) { | |||
120 | errExit("asprintf"); | 120 | errExit("asprintf"); |
121 | 121 | ||
122 | // the file is deleted first | 122 | // the file is deleted first |
123 | FILE *fp = fopen(fname, "w"); | 123 | FILE *fp = fopen(fname, "we"); |
124 | if (!fp) { | 124 | if (!fp) { |
125 | fprintf(stderr, "Error: cannot create %s\n", fname); | 125 | fprintf(stderr, "Error: cannot create %s\n", fname); |
126 | exit(1); | 126 | exit(1); |
@@ -139,7 +139,7 @@ void set_profile_run_file(pid_t pid, const char *fname) { | |||
139 | 139 | ||
140 | EUID_ROOT(); | 140 | EUID_ROOT(); |
141 | // the file is deleted first | 141 | // the file is deleted first |
142 | FILE *fp = fopen(runfile, "w"); | 142 | FILE *fp = fopen(runfile, "we"); |
143 | if (!fp) { | 143 | if (!fp) { |
144 | fprintf(stderr, "Error: cannot create %s\n", runfile); | 144 | fprintf(stderr, "Error: cannot create %s\n", runfile); |
145 | exit(1); | 145 | exit(1); |
diff --git a/src/firejail/run_symlink.c b/src/firejail/run_symlink.c index 77fac5438..e2847aea6 100644 --- a/src/firejail/run_symlink.c +++ b/src/firejail/run_symlink.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -22,7 +22,6 @@ | |||
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <unistd.h> | 23 | #include <unistd.h> |
24 | 24 | ||
25 | extern char *find_in_path(const char *program); | ||
26 | 25 | ||
27 | void run_symlink(int argc, char **argv, int run_as_is) { | 26 | void run_symlink(int argc, char **argv, int run_as_is) { |
28 | EUID_ASSERT(); | 27 | EUID_ASSERT(); |
@@ -77,6 +76,8 @@ void run_symlink(int argc, char **argv, int run_as_is) { | |||
77 | a[i + 2] = argv[i + 1]; | 76 | a[i + 2] = argv[i + 1]; |
78 | } | 77 | } |
79 | a[i + 2] = NULL; | 78 | a[i + 2] = NULL; |
79 | if (env_get("LD_PRELOAD") != NULL) | ||
80 | fprintf(stderr, "run_symlink: LD_PRELOAD is: '%s'\n", env_get("LD_PRELOAD")); | ||
80 | assert(env_get("LD_PRELOAD") == NULL); | 81 | assert(env_get("LD_PRELOAD") == NULL); |
81 | assert(getenv("LD_PRELOAD") == NULL); | 82 | assert(getenv("LD_PRELOAD") == NULL); |
82 | execvp(a[0], a); | 83 | execvp(a[0], a); |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 3af828ede..96407d081 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -19,6 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include "firejail.h" | 21 | #include "firejail.h" |
22 | #include "../include/gcov_wrapper.h" | ||
22 | #include "../include/seccomp.h" | 23 | #include "../include/seccomp.h" |
23 | #include <sys/mman.h> | 24 | #include <sys/mman.h> |
24 | #include <sys/mount.h> | 25 | #include <sys/mount.h> |
@@ -49,7 +50,6 @@ | |||
49 | #include <sys/apparmor.h> | 50 | #include <sys/apparmor.h> |
50 | #endif | 51 | #endif |
51 | 52 | ||
52 | |||
53 | static int force_nonewprivs = 0; | 53 | static int force_nonewprivs = 0; |
54 | 54 | ||
55 | static int monitored_pid = 0; | 55 | static int monitored_pid = 0; |
@@ -67,7 +67,7 @@ static void sandbox_handler(int sig){ | |||
67 | if (asprintf(&monfile, "/proc/%d/cmdline", monitored_pid) == -1) | 67 | if (asprintf(&monfile, "/proc/%d/cmdline", monitored_pid) == -1) |
68 | errExit("asprintf"); | 68 | errExit("asprintf"); |
69 | while (monsec) { | 69 | while (monsec) { |
70 | FILE *fp = fopen(monfile, "r"); | 70 | FILE *fp = fopen(monfile, "re"); |
71 | if (!fp) | 71 | if (!fp) |
72 | break; | 72 | break; |
73 | 73 | ||
@@ -87,9 +87,9 @@ static void sandbox_handler(int sig){ | |||
87 | 87 | ||
88 | // broadcast a SIGKILL | 88 | // broadcast a SIGKILL |
89 | kill(-1, SIGKILL); | 89 | kill(-1, SIGKILL); |
90 | flush_stdin(); | ||
91 | 90 | ||
92 | exit(sig); | 91 | flush_stdin(); |
92 | exit(128 + sig); | ||
93 | } | 93 | } |
94 | 94 | ||
95 | static void install_handler(void) { | 95 | static void install_handler(void) { |
@@ -162,7 +162,7 @@ static void save_nogroups(void) { | |||
162 | if (arg_nogroups == 0) | 162 | if (arg_nogroups == 0) |
163 | return; | 163 | return; |
164 | 164 | ||
165 | FILE *fp = fopen(RUN_GROUPS_CFG, "w"); | 165 | FILE *fp = fopen(RUN_GROUPS_CFG, "wxe"); |
166 | if (fp) { | 166 | if (fp) { |
167 | fprintf(fp, "\n"); | 167 | fprintf(fp, "\n"); |
168 | SET_PERMS_STREAM(fp, 0, 0, 0644); // assume mode 0644 | 168 | SET_PERMS_STREAM(fp, 0, 0, 0644); // assume mode 0644 |
@@ -204,7 +204,7 @@ static void save_umask(void) { | |||
204 | } | 204 | } |
205 | 205 | ||
206 | static char *create_join_file(void) { | 206 | static char *create_join_file(void) { |
207 | int fd = open(RUN_JOIN_FILE, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 207 | int fd = open(RUN_JOIN_FILE, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
208 | if (fd == -1) | 208 | if (fd == -1) |
209 | errExit("open"); | 209 | errExit("open"); |
210 | if (ftruncate(fd, 1) == -1) | 210 | if (ftruncate(fd, 1) == -1) |
@@ -227,7 +227,7 @@ static void sandbox_if_up(Bridge *br) { | |||
227 | if (br->arg_ip_none == 1); // do nothing | 227 | if (br->arg_ip_none == 1); // do nothing |
228 | else if (br->arg_ip_none == 0 && br->macvlan == 0) { | 228 | else if (br->arg_ip_none == 0 && br->macvlan == 0) { |
229 | if (br->ipsandbox == br->ip) { | 229 | if (br->ipsandbox == br->ip) { |
230 | fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev); | 230 | fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address, exiting...\n", PRINT_IP(br->ipsandbox), br->dev); |
231 | exit(1); | 231 | exit(1); |
232 | } | 232 | } |
233 | 233 | ||
@@ -245,13 +245,17 @@ static void sandbox_if_up(Bridge *br) { | |||
245 | br->ipsandbox = arp_assign(dev, br); //br->ip, br->mask); | 245 | br->ipsandbox = arp_assign(dev, br); //br->ip, br->mask); |
246 | else { | 246 | else { |
247 | if (br->ipsandbox == br->ip) { | 247 | if (br->ipsandbox == br->ip) { |
248 | fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev); | 248 | fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address, exiting...\n", PRINT_IP(br->ipsandbox), br->dev); |
249 | exit(1); | ||
250 | } | ||
251 | if (br->ipsandbox == cfg.defaultgw) { | ||
252 | fprintf(stderr, "Error: %d.%d.%d.%d is the default gateway, exiting...\n", PRINT_IP(br->ipsandbox)); | ||
249 | exit(1); | 253 | exit(1); |
250 | } | 254 | } |
251 | 255 | ||
252 | uint32_t rv = arp_check(dev, br->ipsandbox); | 256 | uint32_t rv = arp_check(dev, br->ipsandbox); |
253 | if (rv) { | 257 | if (rv) { |
254 | fprintf(stderr, "Error: the address %d.%d.%d.%d is already in use.\n", PRINT_IP(br->ipsandbox)); | 258 | fprintf(stderr, "Error: the address %d.%d.%d.%d is already in use, exiting...\n", PRINT_IP(br->ipsandbox)); |
255 | exit(1); | 259 | exit(1); |
256 | } | 260 | } |
257 | } | 261 | } |
@@ -352,6 +356,15 @@ static int monitor_application(pid_t app_pid) { | |||
352 | if (arg_debug) | 356 | if (arg_debug) |
353 | printf("Sandbox monitor: waitpid %d retval %d status %d\n", monitored_pid, rv, status); | 357 | printf("Sandbox monitor: waitpid %d retval %d status %d\n", monitored_pid, rv, status); |
354 | 358 | ||
359 | if (arg_deterministic_shutdown) { | ||
360 | if (arg_debug) | ||
361 | printf("Sandbox monitor: monitored process died, shut down the sandbox\n"); | ||
362 | kill(-1, SIGTERM); | ||
363 | usleep(100000); | ||
364 | kill(-1, SIGKILL); | ||
365 | break; | ||
366 | } | ||
367 | |||
355 | DIR *dir; | 368 | DIR *dir; |
356 | if (!(dir = opendir("/proc"))) { | 369 | if (!(dir = opendir("/proc"))) { |
357 | // sleep 2 seconds and try again | 370 | // sleep 2 seconds and try again |
@@ -373,18 +386,6 @@ static int monitor_application(pid_t app_pid) { | |||
373 | if ((pid_t) pid == dhclient4_pid || (pid_t) pid == dhclient6_pid) | 386 | if ((pid_t) pid == dhclient4_pid || (pid_t) pid == dhclient6_pid) |
374 | continue; | 387 | continue; |
375 | 388 | ||
376 | // todo: make this generic | ||
377 | // Dillo browser leaves a dpid process running, we need to shut it down | ||
378 | int found = 0; | ||
379 | if (strcmp(cfg.command_name, "dillo") == 0) { | ||
380 | char *pidname = pid_proc_comm(pid); | ||
381 | if (pidname && strcmp(pidname, "dpid") == 0) | ||
382 | found = 1; | ||
383 | free(pidname); | ||
384 | } | ||
385 | if (found) | ||
386 | break; | ||
387 | |||
388 | monitored_pid = pid; | 389 | monitored_pid = pid; |
389 | break; | 390 | break; |
390 | } | 391 | } |
@@ -403,7 +404,6 @@ static void print_time(void) { | |||
403 | fmessage("Child process initialized in %.02f ms\n", delta); | 404 | fmessage("Child process initialized in %.02f ms\n", delta); |
404 | } | 405 | } |
405 | 406 | ||
406 | |||
407 | // check execute permissions for the program | 407 | // check execute permissions for the program |
408 | // this is done typically by the shell | 408 | // this is done typically by the shell |
409 | // we are here because of --shell=none | 409 | // we are here because of --shell=none |
@@ -460,10 +460,42 @@ static int ok_to_run(const char *program) { | |||
460 | return 0; | 460 | return 0; |
461 | } | 461 | } |
462 | 462 | ||
463 | static void close_file_descriptors(void) { | ||
464 | if (arg_keep_fd_all) | ||
465 | return; | ||
466 | |||
467 | if (arg_debug) | ||
468 | printf("Closing non-standard file descriptors\n"); | ||
469 | |||
470 | if (!cfg.keep_fd) { | ||
471 | close_all(NULL, 0); | ||
472 | return; | ||
473 | } | ||
474 | |||
475 | size_t sz = 0; | ||
476 | int *keep = str_to_int_array(cfg.keep_fd, &sz); | ||
477 | if (!keep) { | ||
478 | fprintf(stderr, "Error: invalid keep-fd option\n"); | ||
479 | exit(1); | ||
480 | } | ||
481 | close_all(keep, sz); | ||
482 | free(keep); | ||
483 | } | ||
484 | |||
485 | |||
463 | void start_application(int no_sandbox, int fd, char *set_sandbox_status) { | 486 | void start_application(int no_sandbox, int fd, char *set_sandbox_status) { |
464 | // set environment | 487 | if (no_sandbox == 0) { |
465 | if (no_sandbox == 0) | 488 | close_file_descriptors(); |
489 | |||
490 | // set nice and rlimits | ||
491 | if (arg_nice) | ||
492 | set_nice(cfg.nice); | ||
493 | set_rlimits(); | ||
494 | |||
466 | env_defaults(); | 495 | env_defaults(); |
496 | } | ||
497 | |||
498 | // set environment | ||
467 | env_apply_all(); | 499 | env_apply_all(); |
468 | 500 | ||
469 | // restore original umask | 501 | // restore original umask |
@@ -500,9 +532,8 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) { | |||
500 | exit(1); | 532 | exit(1); |
501 | } | 533 | } |
502 | 534 | ||
503 | #ifdef HAVE_GCOV | ||
504 | __gcov_dump(); | 535 | __gcov_dump(); |
505 | #endif | 536 | |
506 | seccomp_install_filters(); | 537 | seccomp_install_filters(); |
507 | 538 | ||
508 | if (set_sandbox_status) | 539 | if (set_sandbox_status) |
@@ -556,9 +587,8 @@ void start_application(int no_sandbox, int fd, char *set_sandbox_status) { | |||
556 | if (!arg_command && !arg_quiet) | 587 | if (!arg_command && !arg_quiet) |
557 | print_time(); | 588 | print_time(); |
558 | 589 | ||
559 | #ifdef HAVE_GCOV | ||
560 | __gcov_dump(); | 590 | __gcov_dump(); |
561 | #endif | 591 | |
562 | seccomp_install_filters(); | 592 | seccomp_install_filters(); |
563 | 593 | ||
564 | if (set_sandbox_status) | 594 | if (set_sandbox_status) |
@@ -796,7 +826,7 @@ int sandbox(void* sandbox_arg) { | |||
796 | 826 | ||
797 | // trace pre-install | 827 | // trace pre-install |
798 | if (need_preload) | 828 | if (need_preload) |
799 | fs_trace_preload(); | 829 | fs_trace_touch_or_store_preload(); |
800 | 830 | ||
801 | // store hosts file | 831 | // store hosts file |
802 | if (cfg.hosts_file) | 832 | if (cfg.hosts_file) |
@@ -812,8 +842,11 @@ int sandbox(void* sandbox_arg) { | |||
812 | //**************************** | 842 | //**************************** |
813 | // trace pre-install, this time inside chroot | 843 | // trace pre-install, this time inside chroot |
814 | //**************************** | 844 | //**************************** |
815 | if (need_preload) | 845 | if (need_preload) { |
816 | fs_trace_preload(); | 846 | int rv = unlink(RUN_LDPRELOAD_FILE); |
847 | (void) rv; | ||
848 | fs_trace_touch_or_store_preload(); | ||
849 | } | ||
817 | } | 850 | } |
818 | else | 851 | else |
819 | #endif | 852 | #endif |
@@ -833,6 +866,7 @@ int sandbox(void* sandbox_arg) { | |||
833 | // private mode | 866 | // private mode |
834 | //**************************** | 867 | //**************************** |
835 | if (arg_private) { | 868 | if (arg_private) { |
869 | EUID_USER(); | ||
836 | if (cfg.home_private) { // --private= | 870 | if (cfg.home_private) { // --private= |
837 | if (cfg.chrootdir) | 871 | if (cfg.chrootdir) |
838 | fwarning("private=directory feature is disabled in chroot\n"); | 872 | fwarning("private=directory feature is disabled in chroot\n"); |
@@ -851,6 +885,7 @@ int sandbox(void* sandbox_arg) { | |||
851 | } | 885 | } |
852 | else // --private | 886 | else // --private |
853 | fs_private(); | 887 | fs_private(); |
888 | EUID_ROOT(); | ||
854 | } | 889 | } |
855 | 890 | ||
856 | if (arg_private_dev) | 891 | if (arg_private_dev) |
@@ -883,16 +918,16 @@ int sandbox(void* sandbox_arg) { | |||
883 | else if (arg_overlay) | 918 | else if (arg_overlay) |
884 | fwarning("private-bin feature is disabled in overlay\n"); | 919 | fwarning("private-bin feature is disabled in overlay\n"); |
885 | else { | 920 | else { |
921 | EUID_USER(); | ||
886 | // for --x11=xorg we need to add xauth command | 922 | // for --x11=xorg we need to add xauth command |
887 | if (arg_x11_xorg) { | 923 | if (arg_x11_xorg) { |
888 | EUID_USER(); | ||
889 | char *tmp; | 924 | char *tmp; |
890 | if (asprintf(&tmp, "%s,xauth", cfg.bin_private_keep) == -1) | 925 | if (asprintf(&tmp, "%s,xauth", cfg.bin_private_keep) == -1) |
891 | errExit("asprintf"); | 926 | errExit("asprintf"); |
892 | cfg.bin_private_keep = tmp; | 927 | cfg.bin_private_keep = tmp; |
893 | EUID_ROOT(); | ||
894 | } | 928 | } |
895 | fs_private_bin_list(); | 929 | fs_private_bin_list(); |
930 | EUID_ROOT(); | ||
896 | } | 931 | } |
897 | } | 932 | } |
898 | 933 | ||
@@ -988,7 +1023,7 @@ int sandbox(void* sandbox_arg) { | |||
988 | 1023 | ||
989 | // create /etc/ld.so.preload file again | 1024 | // create /etc/ld.so.preload file again |
990 | if (need_preload) | 1025 | if (need_preload) |
991 | fs_trace_preload(); | 1026 | fs_trace_touch_preload(); |
992 | 1027 | ||
993 | // openSUSE configuration is split between /etc and /usr/etc | 1028 | // openSUSE configuration is split between /etc and /usr/etc |
994 | // process private-etc a second time | 1029 | // process private-etc a second time |
@@ -1000,10 +1035,12 @@ int sandbox(void* sandbox_arg) { | |||
1000 | // apply the profile file | 1035 | // apply the profile file |
1001 | //**************************** | 1036 | //**************************** |
1002 | // apply all whitelist commands ... | 1037 | // apply all whitelist commands ... |
1038 | EUID_USER(); | ||
1003 | fs_whitelist(); | 1039 | fs_whitelist(); |
1004 | 1040 | ||
1005 | // ... followed by blacklist commands | 1041 | // ... followed by blacklist commands |
1006 | fs_blacklist(); // mkdir and mkfile are processed all over again | 1042 | fs_blacklist(); // mkdir and mkfile are processed all over again |
1043 | EUID_ROOT(); | ||
1007 | 1044 | ||
1008 | //**************************** | 1045 | //**************************** |
1009 | // nosound/no3d/notv/novideo and fix for pulseaudio 7.0 | 1046 | // nosound/no3d/notv/novideo and fix for pulseaudio 7.0 |
@@ -1012,10 +1049,13 @@ int sandbox(void* sandbox_arg) { | |||
1012 | // disable pulseaudio | 1049 | // disable pulseaudio |
1013 | pulseaudio_disable(); | 1050 | pulseaudio_disable(); |
1014 | 1051 | ||
1052 | // disable pipewire | ||
1053 | pipewire_disable(); | ||
1054 | |||
1015 | // disable /dev/snd | 1055 | // disable /dev/snd |
1016 | fs_dev_disable_sound(); | 1056 | fs_dev_disable_sound(); |
1017 | } | 1057 | } |
1018 | else if (!arg_noautopulse) | 1058 | else if (!arg_keep_config_pulse) |
1019 | pulseaudio_init(); | 1059 | pulseaudio_init(); |
1020 | 1060 | ||
1021 | if (arg_no3d) | 1061 | if (arg_no3d) |
@@ -1039,7 +1079,7 @@ int sandbox(void* sandbox_arg) { | |||
1039 | //**************************** | 1079 | //**************************** |
1040 | // set dns | 1080 | // set dns |
1041 | //**************************** | 1081 | //**************************** |
1042 | fs_resolvconf(); | 1082 | fs_rebuild_etc(); |
1043 | 1083 | ||
1044 | //**************************** | 1084 | //**************************** |
1045 | // start dhcp client | 1085 | // start dhcp client |
@@ -1052,6 +1092,11 @@ int sandbox(void* sandbox_arg) { | |||
1052 | EUID_USER(); | 1092 | EUID_USER(); |
1053 | int cwd = 0; | 1093 | int cwd = 0; |
1054 | if (cfg.cwd) { | 1094 | if (cfg.cwd) { |
1095 | if (is_link(cfg.cwd)) { | ||
1096 | fprintf(stderr, "Error: unable to enter private working directory: %s\n", cfg.cwd); | ||
1097 | exit(1); | ||
1098 | } | ||
1099 | |||
1055 | if (chdir(cfg.cwd) == 0) | 1100 | if (chdir(cfg.cwd) == 0) |
1056 | cwd = 1; | 1101 | cwd = 1; |
1057 | else if (arg_private_cwd) { | 1102 | else if (arg_private_cwd) { |
@@ -1219,7 +1264,7 @@ int sandbox(void* sandbox_arg) { | |||
1219 | //**************************************** | 1264 | //**************************************** |
1220 | // drop privileges | 1265 | // drop privileges |
1221 | //**************************************** | 1266 | //**************************************** |
1222 | drop_privs(arg_nogroups); | 1267 | drop_privs(0); |
1223 | 1268 | ||
1224 | // kill the sandbox in case the parent died | 1269 | // kill the sandbox in case the parent died |
1225 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); | 1270 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); |
@@ -1239,28 +1284,25 @@ int sandbox(void* sandbox_arg) { | |||
1239 | 1284 | ||
1240 | if (app_pid == 0) { | 1285 | if (app_pid == 0) { |
1241 | #ifdef HAVE_APPARMOR | 1286 | #ifdef HAVE_APPARMOR |
1242 | // add apparmor confinement after the execve | ||
1243 | set_apparmor(); | 1287 | set_apparmor(); |
1244 | #endif | 1288 | #endif |
1245 | |||
1246 | // set nice and rlimits | ||
1247 | if (arg_nice) | ||
1248 | set_nice(cfg.nice); | ||
1249 | set_rlimits(); | ||
1250 | |||
1251 | start_application(0, -1, set_sandbox_status); | 1289 | start_application(0, -1, set_sandbox_status); |
1252 | } | 1290 | } |
1253 | 1291 | ||
1254 | munmap(set_sandbox_status, 1); | 1292 | munmap(set_sandbox_status, 1); |
1255 | 1293 | ||
1256 | int status = monitor_application(app_pid); // monitor application | 1294 | int status = monitor_application(app_pid); // monitor application |
1257 | flush_stdin(); | ||
1258 | 1295 | ||
1259 | if (WIFEXITED(status)) { | 1296 | if (WIFEXITED(status)) { |
1260 | // if we had a proper exit, return that exit status | 1297 | // if we had a proper exit, return that exit status |
1261 | return WEXITSTATUS(status); | 1298 | status = WEXITSTATUS(status); |
1299 | } else if (WIFSIGNALED(status)) { | ||
1300 | // distinguish fatal signals by adding 128 | ||
1301 | status = 128 + WTERMSIG(status); | ||
1262 | } else { | 1302 | } else { |
1263 | // something else went wrong! | 1303 | status = -1; |
1264 | return -1; | ||
1265 | } | 1304 | } |
1305 | |||
1306 | flush_stdin(); | ||
1307 | return status; | ||
1266 | } | 1308 | } |
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index f9c41f661..a37943940 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -23,6 +23,7 @@ | |||
23 | #include <unistd.h> | 23 | #include <unistd.h> |
24 | #include <net/if.h> | 24 | #include <net/if.h> |
25 | #include <stdarg.h> | 25 | #include <stdarg.h> |
26 | #include <sys/resource.h> | ||
26 | #include <sys/wait.h> | 27 | #include <sys/wait.h> |
27 | #include "../include/seccomp.h" | 28 | #include "../include/seccomp.h" |
28 | 29 | ||
@@ -72,11 +73,8 @@ static int __attribute__((noreturn)) sbox_do_exec_v(unsigned filtermask, char * | |||
72 | } | 73 | } |
73 | 74 | ||
74 | // close all other file descriptors | 75 | // close all other file descriptors |
75 | if ((filtermask & SBOX_KEEP_FDS) == 0) { | 76 | if ((filtermask & SBOX_KEEP_FDS) == 0) |
76 | int i; | 77 | close_all(NULL, 0); |
77 | for (i = 3; i < FIREJAIL_MAX_FD; i++) | ||
78 | close(i); // close open files | ||
79 | } | ||
80 | 78 | ||
81 | umask(027); | 79 | umask(027); |
82 | 80 | ||
@@ -206,6 +204,11 @@ static int __attribute__((noreturn)) sbox_do_exec_v(unsigned filtermask, char * | |||
206 | if (filtermask & SBOX_USER) | 204 | if (filtermask & SBOX_USER) |
207 | drop_privs(1); | 205 | drop_privs(1); |
208 | else if (filtermask & SBOX_ROOT) { | 206 | else if (filtermask & SBOX_ROOT) { |
207 | // https://seclists.org/oss-sec/2021/q4/43 | ||
208 | struct rlimit tozero = { .rlim_cur = 0, .rlim_max = 0 }; | ||
209 | if (setrlimit(RLIMIT_CORE, &tozero)) | ||
210 | errExit("setrlimit"); | ||
211 | |||
209 | // elevate privileges in order to get grsecurity working | 212 | // elevate privileges in order to get grsecurity working |
210 | if (setreuid(0, 0)) | 213 | if (setreuid(0, 0)) |
211 | errExit("setreuid"); | 214 | errExit("setreuid"); |
@@ -248,7 +251,9 @@ int sbox_run(unsigned filtermask, int num, ...) { | |||
248 | va_start(valist, num); | 251 | va_start(valist, num); |
249 | 252 | ||
250 | // build argument list | 253 | // build argument list |
251 | char **arg = malloc((num + 1) * sizeof(char *)); | 254 | char **arg = calloc(num + 1, sizeof(char *)); |
255 | if (!arg) | ||
256 | errExit("calloc"); | ||
252 | int i; | 257 | int i; |
253 | for (i = 0; i < num; i++) | 258 | for (i = 0; i < num; i++) |
254 | arg[i] = va_arg(valist, char *); | 259 | arg[i] = va_arg(valist, char *); |
@@ -263,7 +268,6 @@ int sbox_run(unsigned filtermask, int num, ...) { | |||
263 | } | 268 | } |
264 | 269 | ||
265 | int sbox_run_v(unsigned filtermask, char * const arg[]) { | 270 | int sbox_run_v(unsigned filtermask, char * const arg[]) { |
266 | EUID_ROOT(); | ||
267 | assert(arg); | 271 | assert(arg); |
268 | 272 | ||
269 | if (arg_debug) { | 273 | if (arg_debug) { |
@@ -283,6 +287,7 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) { | |||
283 | if (child < 0) | 287 | if (child < 0) |
284 | errExit("fork"); | 288 | errExit("fork"); |
285 | if (child == 0) { | 289 | if (child == 0) { |
290 | EUID_ROOT(); | ||
286 | sbox_do_exec_v(filtermask, arg); | 291 | sbox_do_exec_v(filtermask, arg); |
287 | } | 292 | } |
288 | 293 | ||
@@ -290,8 +295,9 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) { | |||
290 | if (waitpid(child, &status, 0) == -1 ) { | 295 | if (waitpid(child, &status, 0) == -1 ) { |
291 | errExit("waitpid"); | 296 | errExit("waitpid"); |
292 | } | 297 | } |
293 | if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { | 298 | if (WIFSIGNALED(status) || |
294 | fprintf(stderr, "Error: failed to run %s\n", arg[0]); | 299 | (WIFEXITED(status) && WEXITSTATUS(status) != 0)) { |
300 | fprintf(stderr, "Error: failed to run %s, exiting...\n", arg[0]); | ||
295 | exit(1); | 301 | exit(1); |
296 | } | 302 | } |
297 | 303 | ||
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 785c29517..0cd6ac7ec 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -86,7 +86,7 @@ int seccomp_install_filters(void) { | |||
86 | static void seccomp_save_file_list(const char *fname) { | 86 | static void seccomp_save_file_list(const char *fname) { |
87 | assert(fname); | 87 | assert(fname); |
88 | 88 | ||
89 | FILE *fp = fopen(RUN_SECCOMP_LIST, "a+"); | 89 | FILE *fp = fopen(RUN_SECCOMP_LIST, "ae"); |
90 | if (!fp) | 90 | if (!fp) |
91 | errExit("fopen"); | 91 | errExit("fopen"); |
92 | 92 | ||
@@ -99,7 +99,7 @@ static void seccomp_save_file_list(const char *fname) { | |||
99 | #define MAXBUF 4096 | 99 | #define MAXBUF 4096 |
100 | static int load_file_list_flag = 0; | 100 | static int load_file_list_flag = 0; |
101 | void seccomp_load_file_list(void) { | 101 | void seccomp_load_file_list(void) { |
102 | FILE *fp = fopen(RUN_SECCOMP_LIST, "r"); | 102 | FILE *fp = fopen(RUN_SECCOMP_LIST, "re"); |
103 | if (!fp) | 103 | if (!fp) |
104 | return; // no seccomp configuration whatsoever | 104 | return; // no seccomp configuration whatsoever |
105 | 105 | ||
@@ -122,7 +122,7 @@ int seccomp_load(const char *fname) { | |||
122 | assert(fname); | 122 | assert(fname); |
123 | 123 | ||
124 | // open filter file | 124 | // open filter file |
125 | int fd = open(fname, O_RDONLY); | 125 | int fd = open(fname, O_RDONLY|O_CLOEXEC); |
126 | if (fd == -1) | 126 | if (fd == -1) |
127 | goto errexit; | 127 | goto errexit; |
128 | 128 | ||
@@ -208,7 +208,8 @@ int seccomp_filter_drop(bool native) { | |||
208 | // - seccomp | 208 | // - seccomp |
209 | if (cfg.seccomp_list_drop == NULL) { | 209 | if (cfg.seccomp_list_drop == NULL) { |
210 | // default seccomp if error action is not changed | 210 | // default seccomp if error action is not changed |
211 | if (cfg.seccomp_list == NULL && arg_seccomp_error_action == DEFAULT_SECCOMP_ERROR_ACTION) { | 211 | if ((cfg.seccomp_list == NULL || cfg.seccomp_list[0] == '\0') |
212 | && arg_seccomp_error_action == DEFAULT_SECCOMP_ERROR_ACTION) { | ||
212 | if (arg_seccomp_block_secondary) | 213 | if (arg_seccomp_block_secondary) |
213 | seccomp_filter_block_secondary(); | 214 | seccomp_filter_block_secondary(); |
214 | else { | 215 | else { |
@@ -261,7 +262,7 @@ int seccomp_filter_drop(bool native) { | |||
261 | } | 262 | } |
262 | 263 | ||
263 | // build the seccomp filter as a regular user | 264 | // build the seccomp filter as a regular user |
264 | if (list) | 265 | if (list && list[0]) |
265 | if (arg_allow_debuggers) | 266 | if (arg_allow_debuggers) |
266 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, | 267 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, |
267 | PATH_FSECCOMP, command, "drop", filter, postexec_filter, list, "allow-debuggers"); | 268 | PATH_FSECCOMP, command, "drop", filter, postexec_filter, list, "allow-debuggers"); |
@@ -434,11 +435,11 @@ void seccomp_print_filter(pid_t pid) { | |||
434 | if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_SECCOMP_LIST) == -1) | 435 | if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_SECCOMP_LIST) == -1) |
435 | errExit("asprintf"); | 436 | errExit("asprintf"); |
436 | 437 | ||
437 | struct stat s; | 438 | int fd = open(fname, O_RDONLY|O_CLOEXEC); |
438 | if (stat(fname, &s) == -1) | 439 | if (fd < 0) |
439 | goto errexit; | 440 | goto errexit; |
440 | 441 | ||
441 | FILE *fp = fopen(fname, "r"); | 442 | FILE *fp = fdopen(fd, "r"); |
442 | if (!fp) | 443 | if (!fp) |
443 | goto errexit; | 444 | goto errexit; |
444 | free(fname); | 445 | free(fname); |
diff --git a/src/firejail/selinux.c b/src/firejail/selinux.c index 06189d7f6..0348cef4b 100644 --- a/src/firejail/selinux.c +++ b/src/firejail/selinux.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2020-2021 Firejail and systemd authors | 2 | * Copyright (C) 2020-2022 Firejail and systemd authors |
3 | * | 3 | * |
4 | * This file is part of firejail project, from systemd selinux-util.c | 4 | * This file is part of firejail project, from systemd selinux-util.c |
5 | * | 5 | * |
@@ -19,10 +19,14 @@ | |||
19 | */ | 19 | */ |
20 | #if HAVE_SELINUX | 20 | #if HAVE_SELINUX |
21 | #include "firejail.h" | 21 | #include "firejail.h" |
22 | |||
23 | #include <sys/types.h> | 22 | #include <sys/types.h> |
24 | #include <sys/stat.h> | 23 | #include <sys/stat.h> |
24 | #include <errno.h> | ||
25 | |||
25 | #include <fcntl.h> | 26 | #include <fcntl.h> |
27 | #ifndef O_PATH | ||
28 | #define O_PATH 010000000 | ||
29 | #endif | ||
26 | 30 | ||
27 | #include <selinux/context.h> | 31 | #include <selinux/context.h> |
28 | #include <selinux/label.h> | 32 | #include <selinux/label.h> |
@@ -52,8 +56,19 @@ void selinux_relabel_path(const char *path, const char *inside_path) | |||
52 | if (!label_hnd) | 56 | if (!label_hnd) |
53 | errExit("selabel_open"); | 57 | errExit("selabel_open"); |
54 | 58 | ||
55 | /* Open the file as O_PATH, to pin it while we determine and adjust the label */ | 59 | /* Open the file as O_PATH, to pin it while we determine and adjust the label |
56 | fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); | 60 | * Defeat symlink races by not allowing symbolic links */ |
61 | int called_as_root = 0; | ||
62 | if (geteuid() == 0) | ||
63 | called_as_root = 1; | ||
64 | if (called_as_root) | ||
65 | EUID_USER(); | ||
66 | |||
67 | fd = safer_openat(-1, path, O_NOFOLLOW|O_CLOEXEC|O_PATH); | ||
68 | |||
69 | if (called_as_root) | ||
70 | EUID_ROOT(); | ||
71 | |||
57 | if (fd < 0) | 72 | if (fd < 0) |
58 | return; | 73 | return; |
59 | if (fstat(fd, &st) < 0) | 74 | if (fstat(fd, &st) < 0) |
@@ -64,8 +79,16 @@ void selinux_relabel_path(const char *path, const char *inside_path) | |||
64 | if (arg_debug) | 79 | if (arg_debug) |
65 | printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); | 80 | printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); |
66 | 81 | ||
67 | setfilecon_raw(procfs_path, fcon); | 82 | if (!called_as_root) |
83 | EUID_ROOT(); | ||
84 | |||
85 | if (setfilecon_raw(procfs_path, fcon) != 0 && arg_debug) | ||
86 | printf("Cannot relabel %s: %s\n", path, strerror(errno)); | ||
87 | |||
88 | if (!called_as_root) | ||
89 | EUID_USER(); | ||
68 | } | 90 | } |
91 | |||
69 | freecon(fcon); | 92 | freecon(fcon); |
70 | close: | 93 | close: |
71 | close(fd); | 94 | close(fd); |
diff --git a/src/firejail/shutdown.c b/src/firejail/shutdown.c index 8fb03d0a6..44fdd58ab 100644 --- a/src/firejail/shutdown.c +++ b/src/firejail/shutdown.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -36,8 +36,10 @@ void shut(pid_t pid) { | |||
36 | } | 36 | } |
37 | free(comm); | 37 | free(comm); |
38 | } | 38 | } |
39 | else | 39 | else { |
40 | errExit("/proc/PID/comm"); | 40 | fprintf(stderr, "Error: cannot find process %d\n", pid); |
41 | exit(1); | ||
42 | } | ||
41 | 43 | ||
42 | // check privileges for non-root users | 44 | // check privileges for non-root users |
43 | uid_t uid = getuid(); | 45 | uid_t uid = getuid(); |
@@ -64,7 +66,7 @@ void shut(pid_t pid) { | |||
64 | monsec--; | 66 | monsec--; |
65 | 67 | ||
66 | EUID_ROOT(); | 68 | EUID_ROOT(); |
67 | FILE *fp = fopen(monfile, "r"); | 69 | FILE *fp = fopen(monfile, "re"); |
68 | EUID_USER(); | 70 | EUID_USER(); |
69 | if (!fp) { | 71 | if (!fp) { |
70 | killdone = 1; | 72 | killdone = 1; |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 397150158..2dd913b5e 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -58,16 +58,18 @@ static char *usage_str = | |||
58 | #ifdef HAVE_DBUSPROXY | 58 | #ifdef HAVE_DBUSPROXY |
59 | " --dbus-log=file - set DBus log file location.\n" | 59 | " --dbus-log=file - set DBus log file location.\n" |
60 | " --dbus-system=filter|none - set system DBus access policy.\n" | 60 | " --dbus-system=filter|none - set system DBus access policy.\n" |
61 | " --dbus-system.broadcast=rule - allow signals on the system DBus according to rule.\n" | 61 | " --dbus-system.broadcast=rule - allow signals on the system DBus according\n" |
62 | "\tto rule.\n" | ||
62 | " --dbus-system.call=rule - allow calls on the system DBus according to rule.\n" | 63 | " --dbus-system.call=rule - allow calls on the system DBus according to rule.\n" |
63 | " --dbus-system.log - turn on logging for the system DBus." | 64 | " --dbus-system.log - turn on logging for the system DBus.\n" |
64 | " --dbus-system.own=name - allow ownership of name on the system DBus.\n" | 65 | " --dbus-system.own=name - allow ownership of name on the system DBus.\n" |
65 | " --dbus-system.see=name - allow seeing name on the system DBus.\n" | 66 | " --dbus-system.see=name - allow seeing name on the system DBus.\n" |
66 | " --dbus-system.talk=name - allow talking to name on the system DBus.\n" | 67 | " --dbus-system.talk=name - allow talking to name on the system DBus.\n" |
67 | " --dbus-user=filter|none - set session DBus access policy.\n" | 68 | " --dbus-user=filter|none - set session DBus access policy.\n" |
68 | " --dbus-user.broadcast=rule - allow signals on the session DBus according to rule.\n" | 69 | " --dbus-user.broadcast=rule - allow signals on the session DBus according\n" |
70 | "\tto rule.\n" | ||
69 | " --dbus-user.call=rule - allow calls on the session DBus according to rule.\n" | 71 | " --dbus-user.call=rule - allow calls on the session DBus according to rule.\n" |
70 | " --dbus-user.log - turn on logging for the user DBus." | 72 | " --dbus-user.log - turn on logging for the user DBus.\n" |
71 | " --dbus-user.own=name - allow ownership of name on the session DBus.\n" | 73 | " --dbus-user.own=name - allow ownership of name on the session DBus.\n" |
72 | " --dbus-user.see=name - allow seeing name on the session DBus.\n" | 74 | " --dbus-user.see=name - allow seeing name on the session DBus.\n" |
73 | " --dbus-user.talk=name - allow talking to name on the session DBus.\n" | 75 | " --dbus-user.talk=name - allow talking to name on the session DBus.\n" |
@@ -80,13 +82,12 @@ static char *usage_str = | |||
80 | " --debug-protocols - print all recognized protocols.\n" | 82 | " --debug-protocols - print all recognized protocols.\n" |
81 | " --debug-syscalls - print all recognized system calls.\n" | 83 | " --debug-syscalls - print all recognized system calls.\n" |
82 | " --debug-syscalls32 - print all recognized 32 bit system calls.\n" | 84 | " --debug-syscalls32 - print all recognized 32 bit system calls.\n" |
83 | #ifdef HAVE_WHITELIST | ||
84 | " --debug-whitelists - debug whitelisting.\n" | 85 | " --debug-whitelists - debug whitelisting.\n" |
85 | #endif | ||
86 | #ifdef HAVE_NETWORK | 86 | #ifdef HAVE_NETWORK |
87 | " --defaultgw=address - configure default gateway.\n" | 87 | " --defaultgw=address - configure default gateway.\n" |
88 | #endif | 88 | #endif |
89 | " --deterministic-exit-code - always exit with first child's status code.\n" | 89 | " --deterministic-exit-code - always exit with first child's status code.\n" |
90 | " --deterministic-shutdown - terminate orphan processes.\n" | ||
90 | " --dns=address - set DNS server.\n" | 91 | " --dns=address - set DNS server.\n" |
91 | " --dns.print=name|pid - print DNS configuration.\n" | 92 | " --dns.print=name|pid - print DNS configuration.\n" |
92 | " --env=name=value - set environment variable.\n" | 93 | " --env=name=value - set environment variable.\n" |
@@ -97,6 +98,8 @@ static char *usage_str = | |||
97 | " --help, -? - this help screen.\n" | 98 | " --help, -? - this help screen.\n" |
98 | " --hostname=name - set sandbox hostname.\n" | 99 | " --hostname=name - set sandbox hostname.\n" |
99 | " --hosts-file=file - use file as /etc/hosts.\n" | 100 | " --hosts-file=file - use file as /etc/hosts.\n" |
101 | " --ids-check - verify file system.\n" | ||
102 | " --ids-init - initialize IDS database.\n" | ||
100 | " --ignore=command - ignore command in profile files.\n" | 103 | " --ignore=command - ignore command in profile files.\n" |
101 | #ifdef HAVE_NETWORK | 104 | #ifdef HAVE_NETWORK |
102 | " --interface=name - move interface in sandbox.\n" | 105 | " --interface=name - move interface in sandbox.\n" |
@@ -114,7 +117,9 @@ static char *usage_str = | |||
114 | " --join-network=name|pid - join the network namespace.\n" | 117 | " --join-network=name|pid - join the network namespace.\n" |
115 | #endif | 118 | #endif |
116 | " --join-or-start=name|pid - join the sandbox or start a new one.\n" | 119 | " --join-or-start=name|pid - join the sandbox or start a new one.\n" |
117 | " --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n" | 120 | " --keep-config-pulse - disable automatic ~/.config/pulse init.\n" |
121 | " --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n" | ||
122 | " --keep-fd - inherit open file descriptors to sandbox.\n" | ||
118 | " --keep-var-tmp - /var/tmp directory is untouched.\n" | 123 | " --keep-var-tmp - /var/tmp directory is untouched.\n" |
119 | " --list - list all sandboxes.\n" | 124 | " --list - list all sandboxes.\n" |
120 | #ifdef HAVE_FILE_TRANSFER | 125 | #ifdef HAVE_FILE_TRANSFER |
@@ -123,7 +128,7 @@ static char *usage_str = | |||
123 | #ifdef HAVE_NETWORK | 128 | #ifdef HAVE_NETWORK |
124 | " --mac=xx:xx:xx:xx:xx:xx - set interface MAC address.\n" | 129 | " --mac=xx:xx:xx:xx:xx:xx - set interface MAC address.\n" |
125 | #endif | 130 | #endif |
126 | " --machine-id - preserve /etc/machine-id\n" | 131 | " --machine-id - spoof /etc/machine-id with a random id\n" |
127 | " --memory-deny-write-execute - seccomp filter to block attempts to create\n" | 132 | " --memory-deny-write-execute - seccomp filter to block attempts to create\n" |
128 | "\tmemory mappings that are both writable and executable.\n" | 133 | "\tmemory mappings that are both writable and executable.\n" |
129 | " --mkdir=dirname - create a directory.\n" | 134 | " --mkdir=dirname - create a directory.\n" |
@@ -142,10 +147,12 @@ static char *usage_str = | |||
142 | " --netfilter.print=name|pid - print the firewall.\n" | 147 | " --netfilter.print=name|pid - print the firewall.\n" |
143 | " --netfilter6=filename - enable IPv6 firewall.\n" | 148 | " --netfilter6=filename - enable IPv6 firewall.\n" |
144 | " --netfilter6.print=name|pid - print the IPv6 firewall.\n" | 149 | " --netfilter6.print=name|pid - print the IPv6 firewall.\n" |
145 | " --netmask=address - define a network mask when dealing with unconfigured" | 150 | " --netlock - enable the network locking feature\n" |
146 | "\tparrent interfaces.\n" | 151 | " --netmask=address - define a network mask when dealing with unconfigured\n" |
152 | "\tparent interfaces.\n" | ||
147 | " --netns=name - Run the program in a named, persistent network namespace.\n" | 153 | " --netns=name - Run the program in a named, persistent network namespace.\n" |
148 | " --netstats - monitor network statistics.\n" | 154 | " --netstats - monitor network statistics.\n" |
155 | " --nettrace - monitor TCP and UDP traffic coming into the sandbox.\n" | ||
149 | #endif | 156 | #endif |
150 | " --nice=value - set nice value.\n" | 157 | " --nice=value - set nice value.\n" |
151 | " --no3d - disable 3D hardware acceleration.\n" | 158 | " --no3d - disable 3D hardware acceleration.\n" |
@@ -154,7 +161,9 @@ static char *usage_str = | |||
154 | " --nodvd - disable DVD and audio CD devices.\n" | 161 | " --nodvd - disable DVD and audio CD devices.\n" |
155 | " --noexec=filename - remount the file or directory noexec nosuid and nodev.\n" | 162 | " --noexec=filename - remount the file or directory noexec nosuid and nodev.\n" |
156 | " --nogroups - disable supplementary groups.\n" | 163 | " --nogroups - disable supplementary groups.\n" |
164 | " --noinput - disable input devices.\n" | ||
157 | " --nonewprivs - sets the NO_NEW_PRIVS prctl.\n" | 165 | " --nonewprivs - sets the NO_NEW_PRIVS prctl.\n" |
166 | " --noprinters - disable printers.\n" | ||
158 | " --noprofile - do not use a security profile.\n" | 167 | " --noprofile - do not use a security profile.\n" |
159 | #ifdef HAVE_USERNS | 168 | #ifdef HAVE_USERNS |
160 | " --noroot - install a user namespace with only the current user.\n" | 169 | " --noroot - install a user namespace with only the current user.\n" |
@@ -236,6 +245,8 @@ static char *usage_str = | |||
236 | " --shell=none - run the program directly without a user shell.\n" | 245 | " --shell=none - run the program directly without a user shell.\n" |
237 | " --shell=program - set default user shell.\n" | 246 | " --shell=program - set default user shell.\n" |
238 | " --shutdown=name|pid - shutdown the sandbox identified by name or PID.\n" | 247 | " --shutdown=name|pid - shutdown the sandbox identified by name or PID.\n" |
248 | " --tab - enable shell tab completion in sandboxes using private or\n" | ||
249 | "\twhitelisted home directories.\n" | ||
239 | " --timeout=hh:mm:ss - kill the sandbox automatically after the time\n" | 250 | " --timeout=hh:mm:ss - kill the sandbox automatically after the time\n" |
240 | "\thas elapsed.\n" | 251 | "\thas elapsed.\n" |
241 | " --tmpfs=dirname - mount a tmpfs filesystem on directory dirname.\n" | 252 | " --tmpfs=dirname - mount a tmpfs filesystem on directory dirname.\n" |
@@ -250,9 +261,7 @@ static char *usage_str = | |||
250 | #ifdef HAVE_NETWORK | 261 | #ifdef HAVE_NETWORK |
251 | " --veth-name=name - use this name for the interface connected to the bridge.\n" | 262 | " --veth-name=name - use this name for the interface connected to the bridge.\n" |
252 | #endif | 263 | #endif |
253 | #ifdef HAVE_WHITELIST | ||
254 | " --whitelist=filename - whitelist directory or file.\n" | 264 | " --whitelist=filename - whitelist directory or file.\n" |
255 | #endif | ||
256 | " --writable-etc - /etc directory is mounted read-write.\n" | 265 | " --writable-etc - /etc directory is mounted read-write.\n" |
257 | " --writable-run-user - allow access to /run/user/$UID/systemd and\n" | 266 | " --writable-run-user - allow access to /run/user/$UID/systemd and\n" |
258 | "\t/run/user/$UID/gnupg.\n" | 267 | "\t/run/user/$UID/gnupg.\n" |
diff --git a/src/firejail/util.c b/src/firejail/util.c index 2ad85acd6..109105630 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -19,8 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | #define _XOPEN_SOURCE 500 | 20 | #define _XOPEN_SOURCE 500 |
21 | #include "firejail.h" | 21 | #include "firejail.h" |
22 | #include <ftw.h> | 22 | #include "../include/gcov_wrapper.h" |
23 | #include <sys/stat.h> | ||
24 | #include <sys/mount.h> | 23 | #include <sys/mount.h> |
25 | #include <syslog.h> | 24 | #include <syslog.h> |
26 | #include <errno.h> | 25 | #include <errno.h> |
@@ -46,6 +45,44 @@ | |||
46 | #define EMPTY_STRING ("") | 45 | #define EMPTY_STRING ("") |
47 | 46 | ||
48 | 47 | ||
48 | long long unsigned parse_arg_size(char *str) { | ||
49 | long long unsigned result = 0; | ||
50 | int len = strlen(str); | ||
51 | sscanf(str, "%llu", &result); | ||
52 | |||
53 | char suffix = *(str + len - 1); | ||
54 | if (!isdigit(suffix) && (suffix == 'k' || suffix == 'm' || suffix == 'g')) { | ||
55 | len -= 1; | ||
56 | } | ||
57 | |||
58 | /* checks for is value valid positive number */ | ||
59 | for (int i = 0; i < len; i++) { | ||
60 | if (!isdigit(*(str+i))) { | ||
61 | return 0; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | if (isdigit(suffix)) | ||
66 | return result; | ||
67 | |||
68 | switch (suffix) { | ||
69 | case 'k': | ||
70 | result *= 1024; | ||
71 | break; | ||
72 | case 'm': | ||
73 | result *= 1024 * 1024; | ||
74 | break; | ||
75 | case 'g': | ||
76 | result *= 1024 * 1024 * 1024; | ||
77 | break; | ||
78 | default: | ||
79 | result = 0; | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | return result; | ||
84 | } | ||
85 | |||
49 | // send the error to /var/log/auth.log and exit after a small delay | 86 | // send the error to /var/log/auth.log and exit after a small delay |
50 | void errLogExit(char* fmt, ...) { | 87 | void errLogExit(char* fmt, ...) { |
51 | va_list args; | 88 | va_list args; |
@@ -66,6 +103,72 @@ void errLogExit(char* fmt, ...) { | |||
66 | exit(1); | 103 | exit(1); |
67 | } | 104 | } |
68 | 105 | ||
106 | // Returns whether all supplementary groups can be safely dropped | ||
107 | int check_can_drop_all_groups() { | ||
108 | static int can_drop_all_groups = -1; | ||
109 | |||
110 | // Avoid needlessly checking (and printing) things twice | ||
111 | if (can_drop_all_groups != -1) | ||
112 | goto out; | ||
113 | |||
114 | // nvidia cards require video group; ignore nogroups | ||
115 | if (access("/dev/nvidiactl", R_OK) == 0 && arg_no3d == 0) { | ||
116 | fwarning("NVIDIA card detected, nogroups command ignored\n"); | ||
117 | can_drop_all_groups = 0; | ||
118 | goto out; | ||
119 | } | ||
120 | |||
121 | /* When we are not sure that the system has working seat-based ACLs | ||
122 | * (e.g.: probably yes on (e)udev + (e)logind, probably not on eudev + | ||
123 | * seatd), supplementary groups (e.g.: audio and input) might be needed | ||
124 | * to avoid breakage (e.g.: audio or gamepads not working). See #4600 | ||
125 | * and #4603. | ||
126 | */ | ||
127 | if (access("/run/systemd/seats/", F_OK) != 0) { | ||
128 | // TODO: wrc causes this to be printed even with (e)logind (see #4930) | ||
129 | //fwarning("logind not detected, nogroups command ignored\n"); | ||
130 | can_drop_all_groups = 0; | ||
131 | goto out; | ||
132 | } | ||
133 | |||
134 | if (arg_debug) | ||
135 | fprintf(stderr, "nogroups command not ignored\n"); | ||
136 | can_drop_all_groups = 1; | ||
137 | |||
138 | out: | ||
139 | return can_drop_all_groups; | ||
140 | } | ||
141 | |||
142 | static int find_group(gid_t group, const gid_t *groups, int ngroups) { | ||
143 | int i; | ||
144 | for (i = 0; i < ngroups; i++) { | ||
145 | if (group == groups[i]) | ||
146 | return i; | ||
147 | } | ||
148 | |||
149 | return -1; | ||
150 | } | ||
151 | |||
152 | // Gets group from "groupname" and adds it to "new_groups" if it exists on | ||
153 | // "groups". Always returns the current value of new_ngroups. | ||
154 | static int copy_group_ifcont(const char *groupname, | ||
155 | const gid_t *groups, int ngroups, | ||
156 | gid_t *new_groups, int *new_ngroups, int new_sz) { | ||
157 | if (*new_ngroups >= new_sz) { | ||
158 | errno = ERANGE; | ||
159 | goto out; | ||
160 | } | ||
161 | |||
162 | gid_t g = get_group_id(groupname); | ||
163 | if (g && find_group(g, groups, ngroups) >= 0) { | ||
164 | new_groups[*new_ngroups] = g; | ||
165 | (*new_ngroups)++; | ||
166 | } | ||
167 | |||
168 | out: | ||
169 | return *new_ngroups; | ||
170 | } | ||
171 | |||
69 | static void clean_supplementary_groups(gid_t gid) { | 172 | static void clean_supplementary_groups(gid_t gid) { |
70 | assert(cfg.username); | 173 | assert(cfg.username); |
71 | gid_t groups[MAX_GROUPS]; | 174 | gid_t groups[MAX_GROUPS]; |
@@ -74,35 +177,60 @@ static void clean_supplementary_groups(gid_t gid) { | |||
74 | if (rv == -1) | 177 | if (rv == -1) |
75 | goto clean_all; | 178 | goto clean_all; |
76 | 179 | ||
180 | if (arg_nogroups && check_can_drop_all_groups()) | ||
181 | goto clean_all; | ||
182 | |||
77 | // clean supplementary group list | 183 | // clean supplementary group list |
78 | // allow only firejail, tty, audio, video, games | ||
79 | gid_t new_groups[MAX_GROUPS]; | 184 | gid_t new_groups[MAX_GROUPS]; |
80 | int new_ngroups = 0; | 185 | int new_ngroups = 0; |
81 | char *allowed[] = { | 186 | char *allowed[] = { |
82 | "firejail", | 187 | "firejail", |
83 | "tty", | 188 | "tty", |
84 | "audio", | ||
85 | "video", | ||
86 | "games", | 189 | "games", |
87 | NULL | 190 | NULL |
88 | }; | 191 | }; |
89 | 192 | ||
90 | int i = 0; | 193 | int i = 0; |
91 | while (allowed[i]) { | 194 | while (allowed[i]) { |
92 | gid_t g = get_group_id(allowed[i]); | 195 | copy_group_ifcont(allowed[i], groups, ngroups, |
93 | if (g) { | 196 | new_groups, &new_ngroups, MAX_GROUPS); |
94 | int j; | ||
95 | for (j = 0; j < ngroups; j++) { | ||
96 | if (g == groups[j]) { | ||
97 | new_groups[new_ngroups] = g; | ||
98 | new_ngroups++; | ||
99 | break; | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | i++; | 197 | i++; |
104 | } | 198 | } |
105 | 199 | ||
200 | if (!arg_nosound) { | ||
201 | copy_group_ifcont("audio", groups, ngroups, | ||
202 | new_groups, &new_ngroups, MAX_GROUPS); | ||
203 | } | ||
204 | |||
205 | if (!arg_novideo) { | ||
206 | copy_group_ifcont("video", groups, ngroups, | ||
207 | new_groups, &new_ngroups, MAX_GROUPS); | ||
208 | } | ||
209 | |||
210 | if (!arg_no3d) { | ||
211 | copy_group_ifcont("render", groups, ngroups, | ||
212 | new_groups, &new_ngroups, MAX_GROUPS); | ||
213 | copy_group_ifcont("vglusers", groups, ngroups, | ||
214 | new_groups, &new_ngroups, MAX_GROUPS); | ||
215 | } | ||
216 | |||
217 | if (!arg_noprinters) { | ||
218 | copy_group_ifcont("lp", groups, ngroups, | ||
219 | new_groups, &new_ngroups, MAX_GROUPS); | ||
220 | } | ||
221 | |||
222 | if (!arg_nodvd) { | ||
223 | copy_group_ifcont("cdrom", groups, ngroups, | ||
224 | new_groups, &new_ngroups, MAX_GROUPS); | ||
225 | copy_group_ifcont("optical", groups, ngroups, | ||
226 | new_groups, &new_ngroups, MAX_GROUPS); | ||
227 | } | ||
228 | |||
229 | if (!arg_noinput) { | ||
230 | copy_group_ifcont("input", groups, ngroups, | ||
231 | new_groups, &new_ngroups, MAX_GROUPS); | ||
232 | } | ||
233 | |||
106 | if (new_ngroups) { | 234 | if (new_ngroups) { |
107 | rv = setgroups(new_ngroups, new_groups); | 235 | rv = setgroups(new_ngroups, new_groups); |
108 | if (rv) | 236 | if (rv) |
@@ -128,21 +256,22 @@ clean_all: | |||
128 | 256 | ||
129 | 257 | ||
130 | // drop privileges | 258 | // drop privileges |
131 | // - for root group or if nogroups is set, supplementary groups are not configured | 259 | // - for root group or if force_nogroups is set, supplementary groups are not configured |
132 | void drop_privs(int nogroups) { | 260 | void drop_privs(int force_nogroups) { |
133 | gid_t gid = getgid(); | 261 | gid_t gid = getgid(); |
134 | if (arg_debug) | 262 | if (arg_debug) |
135 | printf("Drop privileges: pid %d, uid %d, gid %d, nogroups %d\n", getpid(), getuid(), gid, nogroups); | 263 | printf("Drop privileges: pid %d, uid %d, gid %d, force_nogroups %d\n", |
264 | getpid(), getuid(), gid, force_nogroups); | ||
136 | 265 | ||
137 | // configure supplementary groups | 266 | // configure supplementary groups |
138 | EUID_ROOT(); | 267 | EUID_ROOT(); |
139 | if (gid == 0 || nogroups) { | 268 | if (gid == 0 || force_nogroups) { |
140 | if (setgroups(0, NULL) < 0) | 269 | if (setgroups(0, NULL) < 0) |
141 | errExit("setgroups"); | 270 | errExit("setgroups"); |
142 | if (arg_debug) | 271 | if (arg_debug) |
143 | printf("No supplementary groups\n"); | 272 | printf("No supplementary groups\n"); |
144 | } | 273 | } |
145 | else if (arg_noroot) | 274 | else if (arg_noroot || arg_nogroups) |
146 | clean_supplementary_groups(gid); | 275 | clean_supplementary_groups(gid); |
147 | 276 | ||
148 | // set uid/gid | 277 | // set uid/gid |
@@ -298,14 +427,14 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m | |||
298 | assert(destname); | 427 | assert(destname); |
299 | 428 | ||
300 | // open source | 429 | // open source |
301 | int src = open(srcname, O_RDONLY); | 430 | int src = open(srcname, O_RDONLY|O_CLOEXEC); |
302 | if (src < 0) { | 431 | if (src < 0) { |
303 | fwarning("cannot open source file %s, file not copied\n", srcname); | 432 | fwarning("cannot open source file %s, file not copied\n", srcname); |
304 | return -1; | 433 | return -1; |
305 | } | 434 | } |
306 | 435 | ||
307 | // open destination | 436 | // open destination |
308 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | 437 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
309 | if (dst < 0) { | 438 | if (dst < 0) { |
310 | fwarning("cannot open destination file %s, file not copied\n", destname); | 439 | fwarning("cannot open destination file %s, file not copied\n", destname); |
311 | close(src); | 440 | close(src); |
@@ -325,7 +454,7 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m | |||
325 | } | 454 | } |
326 | 455 | ||
327 | // return -1 if error, 0 if no error | 456 | // return -1 if error, 0 if no error |
328 | void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { | 457 | void copy_file_as_user(const char *srcname, const char *destname, mode_t mode) { |
329 | pid_t child = fork(); | 458 | pid_t child = fork(); |
330 | if (child < 0) | 459 | if (child < 0) |
331 | errExit("fork"); | 460 | errExit("fork"); |
@@ -333,13 +462,13 @@ void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid | |||
333 | // drop privileges | 462 | // drop privileges |
334 | drop_privs(0); | 463 | drop_privs(0); |
335 | 464 | ||
336 | // copy, set permissions and ownership | 465 | // copy, set permissions |
337 | int rv = copy_file(srcname, destname, uid, gid, mode); // already a regular user | 466 | int rv = copy_file(srcname, destname, -1, -1, mode); // already a regular user |
338 | if (rv) | 467 | if (rv) |
339 | fwarning("cannot copy %s\n", srcname); | 468 | fwarning("cannot copy %s\n", srcname); |
340 | #ifdef HAVE_GCOV | 469 | |
341 | __gcov_flush(); | 470 | __gcov_flush(); |
342 | #endif | 471 | |
343 | _exit(0); | 472 | _exit(0); |
344 | } | 473 | } |
345 | // wait for the child to finish | 474 | // wait for the child to finish |
@@ -348,7 +477,7 @@ void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid | |||
348 | 477 | ||
349 | void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { | 478 | void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { |
350 | // open destination | 479 | // open destination |
351 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | 480 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
352 | if (dst < 0) { | 481 | if (dst < 0) { |
353 | fwarning("cannot open destination file %s, file not copied\n", destname); | 482 | fwarning("cannot open destination file %s, file not copied\n", destname); |
354 | return; | 483 | return; |
@@ -361,7 +490,7 @@ void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_ | |||
361 | // drop privileges | 490 | // drop privileges |
362 | drop_privs(0); | 491 | drop_privs(0); |
363 | 492 | ||
364 | int src = open(srcname, O_RDONLY); | 493 | int src = open(srcname, O_RDONLY|O_CLOEXEC); |
365 | if (src < 0) { | 494 | if (src < 0) { |
366 | fwarning("cannot open source file %s, file not copied\n", srcname); | 495 | fwarning("cannot open source file %s, file not copied\n", srcname); |
367 | } else { | 496 | } else { |
@@ -371,9 +500,9 @@ void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_ | |||
371 | close(src); | 500 | close(src); |
372 | } | 501 | } |
373 | close(dst); | 502 | close(dst); |
374 | #ifdef HAVE_GCOV | 503 | |
375 | __gcov_flush(); | 504 | __gcov_flush(); |
376 | #endif | 505 | |
377 | _exit(0); | 506 | _exit(0); |
378 | } | 507 | } |
379 | // wait for the child to finish | 508 | // wait for the child to finish |
@@ -394,17 +523,17 @@ void touch_file_as_user(const char *fname, mode_t mode) { | |||
394 | // drop privileges | 523 | // drop privileges |
395 | drop_privs(0); | 524 | drop_privs(0); |
396 | 525 | ||
397 | FILE *fp = fopen(fname, "wx"); | 526 | int fd = open(fname, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR); |
398 | if (fp) { | 527 | if (fd > -1) { |
399 | fprintf(fp, "\n"); | 528 | int err = fchmod(fd, mode); |
400 | SET_PERMS_STREAM(fp, -1, -1, mode); | 529 | (void) err; |
401 | fclose(fp); | 530 | close(fd); |
402 | } | 531 | } |
403 | else | 532 | else |
404 | fwarning("cannot create %s\n", fname); | 533 | fwarning("cannot create %s\n", fname); |
405 | #ifdef HAVE_GCOV | 534 | |
406 | __gcov_flush(); | 535 | __gcov_flush(); |
407 | #endif | 536 | |
408 | _exit(0); | 537 | _exit(0); |
409 | } | 538 | } |
410 | // wait for the child to finish | 539 | // wait for the child to finish |
@@ -421,14 +550,14 @@ int is_dir(const char *fname) { | |||
421 | int rv; | 550 | int rv; |
422 | struct stat s; | 551 | struct stat s; |
423 | if (fname[strlen(fname) - 1] == '/') | 552 | if (fname[strlen(fname) - 1] == '/') |
424 | rv = stat(fname, &s); | 553 | rv = stat_as_user(fname, &s); |
425 | else { | 554 | else { |
426 | char *tmp; | 555 | char *tmp; |
427 | if (asprintf(&tmp, "%s/", fname) == -1) { | 556 | if (asprintf(&tmp, "%s/", fname) == -1) { |
428 | fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); | 557 | fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); |
429 | errExit("asprintf"); | 558 | errExit("asprintf"); |
430 | } | 559 | } |
431 | rv = stat(tmp, &s); | 560 | rv = stat_as_user(tmp, &s); |
432 | free(tmp); | 561 | free(tmp); |
433 | } | 562 | } |
434 | 563 | ||
@@ -447,18 +576,91 @@ int is_link(const char *fname) { | |||
447 | if (*fname == '\0') | 576 | if (*fname == '\0') |
448 | return 0; | 577 | return 0; |
449 | 578 | ||
450 | char *dup = strdup(fname); | 579 | // remove trailing '/' if any |
451 | if (!dup) | 580 | char *tmp = strdup(fname); |
581 | if (!tmp) | ||
452 | errExit("strdup"); | 582 | errExit("strdup"); |
453 | trim_trailing_slash_or_dot(dup); | 583 | trim_trailing_slash_or_dot(tmp); |
454 | 584 | ||
455 | char c; | 585 | char c; |
456 | ssize_t rv = readlink(dup, &c, 1); | 586 | ssize_t rv = readlink_as_user(tmp, &c, 1); |
587 | free(tmp); | ||
457 | 588 | ||
458 | free(dup); | ||
459 | return (rv != -1); | 589 | return (rv != -1); |
460 | } | 590 | } |
461 | 591 | ||
592 | char *realpath_as_user(const char *fname) { | ||
593 | assert(fname); | ||
594 | |||
595 | int called_as_root = 0; | ||
596 | if (geteuid() == 0) | ||
597 | called_as_root = 1; | ||
598 | |||
599 | if (called_as_root) | ||
600 | EUID_USER(); | ||
601 | |||
602 | char *rv = realpath(fname, NULL); | ||
603 | |||
604 | if (called_as_root) | ||
605 | EUID_ROOT(); | ||
606 | |||
607 | return rv; | ||
608 | } | ||
609 | |||
610 | ssize_t readlink_as_user(const char *fname, char *buf, size_t sz) { | ||
611 | assert(fname && buf && sz); | ||
612 | |||
613 | int called_as_root = 0; | ||
614 | if (geteuid() == 0) | ||
615 | called_as_root = 1; | ||
616 | |||
617 | if (called_as_root) | ||
618 | EUID_USER(); | ||
619 | |||
620 | ssize_t rv = readlink(fname, buf, sz); | ||
621 | |||
622 | if (called_as_root) | ||
623 | EUID_ROOT(); | ||
624 | |||
625 | return rv; | ||
626 | } | ||
627 | |||
628 | int stat_as_user(const char *fname, struct stat *s) { | ||
629 | assert(fname); | ||
630 | |||
631 | int called_as_root = 0; | ||
632 | if (geteuid() == 0) | ||
633 | called_as_root = 1; | ||
634 | |||
635 | if (called_as_root) | ||
636 | EUID_USER(); | ||
637 | |||
638 | int rv = stat(fname, s); | ||
639 | |||
640 | if (called_as_root) | ||
641 | EUID_ROOT(); | ||
642 | |||
643 | return rv; | ||
644 | } | ||
645 | |||
646 | int lstat_as_user(const char *fname, struct stat *s) { | ||
647 | assert(fname); | ||
648 | |||
649 | int called_as_root = 0; | ||
650 | if (geteuid() == 0) | ||
651 | called_as_root = 1; | ||
652 | |||
653 | if (called_as_root) | ||
654 | EUID_USER(); | ||
655 | |||
656 | int rv = lstat(fname, s); | ||
657 | |||
658 | if (called_as_root) | ||
659 | EUID_ROOT(); | ||
660 | |||
661 | return rv; | ||
662 | } | ||
663 | |||
462 | // remove all slashes and single dots from the end of a path | 664 | // remove all slashes and single dots from the end of a path |
463 | // for example /foo/bar///././. -> /foo/bar | 665 | // for example /foo/bar///././. -> /foo/bar |
464 | void trim_trailing_slash_or_dot(char *path) { | 666 | void trim_trailing_slash_or_dot(char *path) { |
@@ -544,11 +746,13 @@ char *split_comma(char *str) { | |||
544 | } | 746 | } |
545 | 747 | ||
546 | 748 | ||
547 | // remove consecutive and trailing slashes | 749 | // simplify absolute path by removing |
548 | // and return allocated memory | 750 | // 1) consecutive and trailing slashes, and |
549 | // e.g. /home//user/ -> /home/user | 751 | // 2) segments with a single dot |
752 | // for example /foo//./bar/ -> /foo/bar | ||
550 | char *clean_pathname(const char *path) { | 753 | char *clean_pathname(const char *path) { |
551 | assert(path); | 754 | assert(path && path[0] == '/'); |
755 | |||
552 | size_t len = strlen(path); | 756 | size_t len = strlen(path); |
553 | char *rv = malloc(len + 1); | 757 | char *rv = malloc(len + 1); |
554 | if (!rv) | 758 | if (!rv) |
@@ -557,15 +761,23 @@ char *clean_pathname(const char *path) { | |||
557 | size_t i = 0; | 761 | size_t i = 0; |
558 | size_t j = 0; | 762 | size_t j = 0; |
559 | while (path[i]) { | 763 | while (path[i]) { |
560 | while (path[i] == '/' && path[i+1] == '/') | 764 | if (path[i] == '/') { |
561 | i++; | 765 | while (path[i+1] == '/' || |
766 | (path[i+1] == '.' && path[i+2] == '/')) | ||
767 | i++; | ||
768 | } | ||
769 | |||
562 | rv[j++] = path[i++]; | 770 | rv[j++] = path[i++]; |
563 | } | 771 | } |
564 | rv[j] = '\0'; | 772 | rv[j] = '\0'; |
565 | 773 | ||
774 | // remove a trailing dot | ||
775 | if (j > 1 && rv[j - 1] == '.' && rv[j - 2] == '/') | ||
776 | rv[--j] = '\0'; | ||
777 | |||
566 | // remove a trailing slash | 778 | // remove a trailing slash |
567 | if (j > 1 && rv[j - 1] == '/') | 779 | if (j > 1 && rv[j - 1] == '/') |
568 | rv[j - 1] = '\0'; | 780 | rv[--j] = '\0'; |
569 | 781 | ||
570 | return rv; | 782 | return rv; |
571 | } | 783 | } |
@@ -616,7 +828,7 @@ int find_child(pid_t parent, pid_t *child) { | |||
616 | perror("asprintf"); | 828 | perror("asprintf"); |
617 | exit(1); | 829 | exit(1); |
618 | } | 830 | } |
619 | FILE *fp = fopen(file, "r"); | 831 | FILE *fp = fopen(file, "re"); |
620 | if (!fp) { | 832 | if (!fp) { |
621 | free(file); | 833 | free(file); |
622 | continue; | 834 | continue; |
@@ -637,9 +849,11 @@ int find_child(pid_t parent, pid_t *child) { | |||
637 | if (parent == atoi(ptr)) { | 849 | if (parent == atoi(ptr)) { |
638 | // we don't want /usr/bin/xdg-dbus-proxy! | 850 | // we don't want /usr/bin/xdg-dbus-proxy! |
639 | char *cmdline = pid_proc_cmdline(pid); | 851 | char *cmdline = pid_proc_cmdline(pid); |
640 | if (strncmp(cmdline, XDG_DBUS_PROXY_PATH, strlen(XDG_DBUS_PROXY_PATH)) != 0) | 852 | if (cmdline) { |
641 | *child = pid; | 853 | if (strncmp(cmdline, XDG_DBUS_PROXY_PATH, strlen(XDG_DBUS_PROXY_PATH)) != 0) |
642 | free(cmdline); | 854 | *child = pid; |
855 | free(cmdline); | ||
856 | } | ||
643 | } | 857 | } |
644 | break; // stop reading the file | 858 | break; // stop reading the file |
645 | } | 859 | } |
@@ -722,7 +936,7 @@ void update_map(char *mapping, char *map_file) { | |||
722 | if (mapping[j] == ',') | 936 | if (mapping[j] == ',') |
723 | mapping[j] = '\n'; | 937 | mapping[j] = '\n'; |
724 | 938 | ||
725 | fd = open(map_file, O_RDWR); | 939 | fd = open(map_file, O_RDWR|O_CLOEXEC); |
726 | if (fd == -1) { | 940 | if (fd == -1) { |
727 | fprintf(stderr, "Error: cannot open %s: %s\n", map_file, strerror(errno)); | 941 | fprintf(stderr, "Error: cannot open %s: %s\n", map_file, strerror(errno)); |
728 | exit(EXIT_FAILURE); | 942 | exit(EXIT_FAILURE); |
@@ -742,9 +956,9 @@ void wait_for_other(int fd) { | |||
742 | // wait for the parent to be initialized | 956 | // wait for the parent to be initialized |
743 | //**************************** | 957 | //**************************** |
744 | char childstr[BUFLEN + 1]; | 958 | char childstr[BUFLEN + 1]; |
745 | int newfd = dup(fd); | 959 | int newfd = fcntl(fd, F_DUPFD_CLOEXEC, 0); |
746 | if (newfd == -1) | 960 | if (newfd == -1) |
747 | errExit("dup"); | 961 | errExit("fcntl"); |
748 | FILE* stream; | 962 | FILE* stream; |
749 | stream = fdopen(newfd, "r"); | 963 | stream = fdopen(newfd, "r"); |
750 | *childstr = '\0'; | 964 | *childstr = '\0'; |
@@ -791,9 +1005,9 @@ void wait_for_other(int fd) { | |||
791 | 1005 | ||
792 | void notify_other(int fd) { | 1006 | void notify_other(int fd) { |
793 | FILE* stream; | 1007 | FILE* stream; |
794 | int newfd = dup(fd); | 1008 | int newfd = fcntl(fd, F_DUPFD_CLOEXEC, 0); |
795 | if (newfd == -1) | 1009 | if (newfd == -1) |
796 | errExit("dup"); | 1010 | errExit("fcntl"); |
797 | stream = fdopen(newfd, "w"); | 1011 | stream = fdopen(newfd, "w"); |
798 | fprintf(stream, "arg_noroot=%d\n", arg_noroot); | 1012 | fprintf(stream, "arg_noroot=%d\n", arg_noroot); |
799 | fflush(stream); | 1013 | fflush(stream); |
@@ -811,7 +1025,7 @@ uid_t pid_get_uid(pid_t pid) { | |||
811 | exit(1); | 1025 | exit(1); |
812 | } | 1026 | } |
813 | EUID_ROOT(); // grsecurity fix | 1027 | EUID_ROOT(); // grsecurity fix |
814 | FILE *fp = fopen(file, "r"); | 1028 | FILE *fp = fopen(file, "re"); |
815 | if (!fp) { | 1029 | if (!fp) { |
816 | free(file); | 1030 | free(file); |
817 | fprintf(stderr, "Error: cannot open /proc file\n"); | 1031 | fprintf(stderr, "Error: cannot open /proc file\n"); |
@@ -845,12 +1059,9 @@ uid_t pid_get_uid(pid_t pid) { | |||
845 | } | 1059 | } |
846 | 1060 | ||
847 | 1061 | ||
848 | 1062 | gid_t get_group_id(const char *groupname) { | |
849 | |||
850 | uid_t get_group_id(const char *group) { | ||
851 | // find tty group id | ||
852 | gid_t gid = 0; | 1063 | gid_t gid = 0; |
853 | struct group *g = getgrnam(group); | 1064 | struct group *g = getgrnam(groupname); |
854 | if (g) | 1065 | if (g) |
855 | gid = g->gr_gid; | 1066 | gid = g->gr_gid; |
856 | 1067 | ||
@@ -858,84 +1069,6 @@ uid_t get_group_id(const char *group) { | |||
858 | } | 1069 | } |
859 | 1070 | ||
860 | 1071 | ||
861 | static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { | ||
862 | (void) sb; | ||
863 | (void) typeflag; | ||
864 | (void) ftwbuf; | ||
865 | assert(fpath); | ||
866 | |||
867 | if (strcmp(fpath, ".") == 0) | ||
868 | return 0; | ||
869 | |||
870 | if (remove(fpath)) { // removes the link not the actual file | ||
871 | perror("remove"); | ||
872 | fprintf(stderr, "Error: cannot remove file from user .firejail directory: %s\n", fpath); | ||
873 | exit(1); | ||
874 | } | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | |||
880 | int remove_overlay_directory(void) { | ||
881 | EUID_ASSERT(); | ||
882 | struct stat s; | ||
883 | sleep(1); | ||
884 | |||
885 | char *path; | ||
886 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) | ||
887 | errExit("asprintf"); | ||
888 | |||
889 | if (lstat(path, &s) == 0) { | ||
890 | // deal with obvious problems such as symlinks and root ownership | ||
891 | if (!S_ISDIR(s.st_mode)) { | ||
892 | if (S_ISLNK(s.st_mode)) | ||
893 | fprintf(stderr, "Error: %s is a symbolic link\n", path); | ||
894 | else | ||
895 | fprintf(stderr, "Error: %s is not a directory\n", path); | ||
896 | exit(1); | ||
897 | } | ||
898 | if (s.st_uid != getuid()) { | ||
899 | fprintf(stderr, "Error: %s is not owned by the current user\n", path); | ||
900 | exit(1); | ||
901 | } | ||
902 | |||
903 | pid_t child = fork(); | ||
904 | if (child < 0) | ||
905 | errExit("fork"); | ||
906 | if (child == 0) { | ||
907 | // open ~/.firejail, fails if there is any symlink | ||
908 | int fd = safe_fd(path, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
909 | if (fd == -1) | ||
910 | errExit("safe_fd"); | ||
911 | // chdir to ~/.firejail | ||
912 | if (fchdir(fd) == -1) | ||
913 | errExit("fchdir"); | ||
914 | close(fd); | ||
915 | |||
916 | EUID_ROOT(); | ||
917 | // FTW_PHYS - do not follow symbolic links | ||
918 | if (nftw(".", remove_callback, 64, FTW_DEPTH | FTW_PHYS) == -1) | ||
919 | errExit("nftw"); | ||
920 | |||
921 | EUID_USER(); | ||
922 | // remove ~/.firejail | ||
923 | if (rmdir(path) == -1) | ||
924 | errExit("rmdir"); | ||
925 | #ifdef HAVE_GCOV | ||
926 | __gcov_flush(); | ||
927 | #endif | ||
928 | _exit(0); | ||
929 | } | ||
930 | // wait for the child to finish | ||
931 | waitpid(child, NULL, 0); | ||
932 | // check if ~/.firejail was deleted | ||
933 | if (stat(path, &s) == 0) | ||
934 | return 1; | ||
935 | } | ||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | // flush stdin if it is connected to a tty and has input | 1072 | // flush stdin if it is connected to a tty and has input |
940 | void flush_stdin(void) { | 1073 | void flush_stdin(void) { |
941 | if (!isatty(STDIN_FILENO)) | 1074 | if (!isatty(STDIN_FILENO)) |
@@ -963,33 +1096,34 @@ void flush_stdin(void) { | |||
963 | int create_empty_dir_as_user(const char *dir, mode_t mode) { | 1096 | int create_empty_dir_as_user(const char *dir, mode_t mode) { |
964 | assert(dir); | 1097 | assert(dir); |
965 | mode &= 07777; | 1098 | mode &= 07777; |
966 | struct stat s; | ||
967 | 1099 | ||
968 | if (stat(dir, &s)) { | 1100 | if (access(dir, F_OK) == 0) |
1101 | return 0; | ||
1102 | |||
1103 | pid_t child = fork(); | ||
1104 | if (child < 0) | ||
1105 | errExit("fork"); | ||
1106 | if (child == 0) { | ||
1107 | // drop privileges | ||
1108 | drop_privs(0); | ||
1109 | |||
969 | if (arg_debug) | 1110 | if (arg_debug) |
970 | printf("Creating empty %s directory\n", dir); | 1111 | printf("Creating empty %s directory\n", dir); |
971 | pid_t child = fork(); | 1112 | if (mkdir(dir, mode) == 0) { |
972 | if (child < 0) | 1113 | int err = chmod(dir, mode); |
973 | errExit("fork"); | 1114 | (void) err; |
974 | if (child == 0) { | ||
975 | // drop privileges | ||
976 | drop_privs(0); | ||
977 | |||
978 | if (mkdir(dir, mode) == 0) { | ||
979 | if (chmod(dir, mode) == -1) | ||
980 | {;} // do nothing | ||
981 | } | ||
982 | else if (arg_debug) | ||
983 | printf("Directory %s not created: %s\n", dir, strerror(errno)); | ||
984 | #ifdef HAVE_GCOV | ||
985 | __gcov_flush(); | ||
986 | #endif | ||
987 | _exit(0); | ||
988 | } | 1115 | } |
989 | waitpid(child, NULL, 0); | 1116 | else if (arg_debug) |
990 | if (stat(dir, &s) == 0) | 1117 | printf("Directory %s not created: %s\n", dir, strerror(errno)); |
991 | return 1; | 1118 | |
1119 | __gcov_flush(); | ||
1120 | |||
1121 | _exit(0); | ||
992 | } | 1122 | } |
1123 | waitpid(child, NULL, 0); | ||
1124 | |||
1125 | if (access(dir, F_OK) == 0) | ||
1126 | return 1; | ||
993 | return 0; | 1127 | return 0; |
994 | } | 1128 | } |
995 | 1129 | ||
@@ -1020,9 +1154,10 @@ void create_empty_file_as_root(const char *fname, mode_t mode) { | |||
1020 | if (stat(fname, &s)) { | 1154 | if (stat(fname, &s)) { |
1021 | if (arg_debug) | 1155 | if (arg_debug) |
1022 | printf("Creating empty %s file\n", fname); | 1156 | printf("Creating empty %s file\n", fname); |
1023 | |||
1024 | /* coverity[toctou] */ | 1157 | /* coverity[toctou] */ |
1025 | FILE *fp = fopen(fname, "w"); | 1158 | // don't fail if file already exists. This can be the case in a race |
1159 | // condition, when two jails launch at the same time. Compare to #1013 | ||
1160 | FILE *fp = fopen(fname, "we"); | ||
1026 | if (!fp) | 1161 | if (!fp) |
1027 | errExit("fopen"); | 1162 | errExit("fopen"); |
1028 | SET_PERMS_STREAM(fp, 0, 0, mode); | 1163 | SET_PERMS_STREAM(fp, 0, 0, mode); |
@@ -1097,20 +1232,35 @@ unsigned extract_timeout(const char *str) { | |||
1097 | } | 1232 | } |
1098 | 1233 | ||
1099 | void disable_file_or_dir(const char *fname) { | 1234 | void disable_file_or_dir(const char *fname) { |
1235 | assert(geteuid() == 0); | ||
1236 | assert(fname); | ||
1237 | |||
1238 | EUID_USER(); | ||
1239 | int fd = open(fname, O_PATH|O_CLOEXEC); | ||
1240 | EUID_ROOT(); | ||
1241 | if (fd < 0) | ||
1242 | return; | ||
1243 | |||
1100 | struct stat s; | 1244 | struct stat s; |
1101 | if (stat(fname, &s) != -1) { | 1245 | if (fstat(fd, &s) < 0) { // FUSE |
1102 | if (arg_debug) | 1246 | if (errno != EACCES) |
1103 | printf("blacklist %s\n", fname); | 1247 | errExit("fstat"); |
1104 | if (is_dir(fname)) { | 1248 | close(fd); |
1105 | if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | 1249 | return; |
1106 | errExit("disable directory"); | 1250 | } |
1107 | } | 1251 | |
1108 | else { | 1252 | if (arg_debug) |
1109 | if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | 1253 | printf("blacklist %s\n", fname); |
1110 | errExit("disable file"); | 1254 | if (S_ISDIR(s.st_mode)) { |
1111 | } | 1255 | if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0) |
1112 | fs_logger2("blacklist", fname); | 1256 | errExit("disable directory"); |
1113 | } | 1257 | } |
1258 | else { | ||
1259 | if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0) | ||
1260 | errExit("disable file"); | ||
1261 | } | ||
1262 | close(fd); | ||
1263 | fs_logger2("blacklist", fname); | ||
1114 | } | 1264 | } |
1115 | 1265 | ||
1116 | void disable_file_path(const char *path, const char *file) { | 1266 | void disable_file_path(const char *path, const char *file) { |
@@ -1126,13 +1276,13 @@ void disable_file_path(const char *path, const char *file) { | |||
1126 | } | 1276 | } |
1127 | 1277 | ||
1128 | // open an existing file without following any symbolic link | 1278 | // open an existing file without following any symbolic link |
1129 | int safe_fd(const char *path, int flags) { | 1279 | // relative paths are interpreted relative to dirfd |
1280 | // ignore dirfd if path is absolute | ||
1281 | // https://web.archive.org/web/20180419120236/https://blogs.gnome.org/jamesh/2018/04/19/secure-mounts | ||
1282 | int safer_openat(int dirfd, const char *path, int flags) { | ||
1283 | assert(path && path[0]); | ||
1130 | flags |= O_NOFOLLOW; | 1284 | flags |= O_NOFOLLOW; |
1131 | assert(path); | 1285 | |
1132 | if (*path != '/' || strstr(path, "..")) { | ||
1133 | fprintf(stderr, "Error: invalid path %s\n", path); | ||
1134 | exit(1); | ||
1135 | } | ||
1136 | int fd = -1; | 1286 | int fd = -1; |
1137 | 1287 | ||
1138 | #ifdef __NR_openat2 // kernel 5.6 or better | 1288 | #ifdef __NR_openat2 // kernel 5.6 or better |
@@ -1140,7 +1290,7 @@ int safe_fd(const char *path, int flags) { | |||
1140 | memset(&oh, 0, sizeof(oh)); | 1290 | memset(&oh, 0, sizeof(oh)); |
1141 | oh.flags = flags; | 1291 | oh.flags = flags; |
1142 | oh.resolve = RESOLVE_NO_SYMLINKS; | 1292 | oh.resolve = RESOLVE_NO_SYMLINKS; |
1143 | fd = syscall(__NR_openat2, -1, path, &oh, sizeof(struct open_how)); | 1293 | fd = syscall(__NR_openat2, dirfd, path, &oh, sizeof(struct open_how)); |
1144 | if (fd != -1 || errno != ENOSYS) | 1294 | if (fd != -1 || errno != ENOSYS) |
1145 | return fd; | 1295 | return fd; |
1146 | #endif | 1296 | #endif |
@@ -1151,18 +1301,23 @@ int safe_fd(const char *path, int flags) { | |||
1151 | if (!dup) | 1301 | if (!dup) |
1152 | errExit("strdup"); | 1302 | errExit("strdup"); |
1153 | char *tok = strtok(dup, "/"); | 1303 | char *tok = strtok(dup, "/"); |
1154 | if (!tok) { // root directory | 1304 | if (!tok) { // nothing to do, path is the root directory |
1155 | free(dup); | 1305 | free(dup); |
1156 | return open("/", flags); | 1306 | return openat(dirfd, path, flags); |
1157 | } | 1307 | } |
1158 | char *last_tok = EMPTY_STRING; | 1308 | char *last_tok = EMPTY_STRING; |
1159 | int parentfd = open("/", O_PATH|O_CLOEXEC); | 1309 | |
1310 | int parentfd; | ||
1311 | if (path[0] == '/') | ||
1312 | parentfd = open("/", O_PATH|O_CLOEXEC); | ||
1313 | else | ||
1314 | parentfd = fcntl(dirfd, F_DUPFD_CLOEXEC, 0); | ||
1160 | if (parentfd == -1) | 1315 | if (parentfd == -1) |
1161 | errExit("open"); | 1316 | errExit("open/fcntl"); |
1162 | 1317 | ||
1163 | while(1) { | 1318 | while (1) { |
1164 | // open path component, assuming it is a directory; this fails with ENOTDIR if it is a symbolic link | 1319 | // open path component, assuming it is a directory; this fails with ENOTDIR if it is a symbolic link |
1165 | // if token is a single dot, the previous directory is reopened | 1320 | // if token is a single dot, the directory referred to by parentfd is reopened |
1166 | fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 1321 | fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
1167 | if (fd == -1) { | 1322 | if (fd == -1) { |
1168 | // if the following token is NULL, the current token is the final path component | 1323 | // if the following token is NULL, the current token is the final path component |
@@ -1192,6 +1347,106 @@ int safe_fd(const char *path, int flags) { | |||
1192 | return fd; | 1347 | return fd; |
1193 | } | 1348 | } |
1194 | 1349 | ||
1350 | int remount_by_fd(int dst, unsigned long mountflags) { | ||
1351 | char *proc; | ||
1352 | if (asprintf(&proc, "/proc/self/fd/%d", dst) < 0) | ||
1353 | errExit("asprintf"); | ||
1354 | |||
1355 | int rv = mount(NULL, proc, NULL, mountflags|MS_BIND|MS_REMOUNT, NULL); | ||
1356 | if (rv < 0 && arg_debug) | ||
1357 | printf("Failed mount: %s\n", strerror(errno)); | ||
1358 | |||
1359 | free(proc); | ||
1360 | return rv; | ||
1361 | } | ||
1362 | |||
1363 | int bind_mount_by_fd(int src, int dst) { | ||
1364 | char *proc_src, *proc_dst; | ||
1365 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) < 0 || | ||
1366 | asprintf(&proc_dst, "/proc/self/fd/%d", dst) < 0) | ||
1367 | errExit("asprintf"); | ||
1368 | |||
1369 | int rv = mount(proc_src, proc_dst, NULL, MS_BIND|MS_REC, NULL); | ||
1370 | if (rv < 0 && arg_debug) | ||
1371 | printf("Failed mount: %s\n", strerror(errno)); | ||
1372 | |||
1373 | free(proc_src); | ||
1374 | free(proc_dst); | ||
1375 | return rv; | ||
1376 | } | ||
1377 | |||
1378 | int bind_mount_fd_to_path(int src, const char *destname) { | ||
1379 | char *proc; | ||
1380 | if (asprintf(&proc, "/proc/self/fd/%d", src) < 0) | ||
1381 | errExit("asprintf"); | ||
1382 | |||
1383 | int rv = mount(proc, destname, NULL, MS_BIND|MS_REC, NULL); | ||
1384 | if (rv < 0 && arg_debug) | ||
1385 | printf("Failed mount: %s\n", strerror(errno)); | ||
1386 | |||
1387 | free(proc); | ||
1388 | return rv; | ||
1389 | } | ||
1390 | |||
1391 | int bind_mount_path_to_fd(const char *srcname, int dst) { | ||
1392 | char *proc; | ||
1393 | if (asprintf(&proc, "/proc/self/fd/%d", dst) < 0) | ||
1394 | errExit("asprintf"); | ||
1395 | |||
1396 | int rv = mount(srcname, proc, NULL, MS_BIND|MS_REC, NULL); | ||
1397 | if (rv < 0 && arg_debug) | ||
1398 | printf("Failed mount: %s\n", strerror(errno)); | ||
1399 | |||
1400 | free(proc); | ||
1401 | return rv; | ||
1402 | } | ||
1403 | |||
1404 | void close_all(int *keep_list, size_t sz) { | ||
1405 | DIR *dir; | ||
1406 | if (!(dir = opendir("/proc/self/fd"))) { | ||
1407 | // sleep 2 seconds and try again | ||
1408 | sleep(2); | ||
1409 | if (!(dir = opendir("/proc/self/fd"))) { | ||
1410 | fprintf(stderr, "Error: cannot open /proc/self/fd directory\n"); | ||
1411 | exit(1); | ||
1412 | } | ||
1413 | } | ||
1414 | struct dirent *entry; | ||
1415 | while ((entry = readdir(dir)) != NULL) { | ||
1416 | if (strcmp(entry->d_name, ".") == 0 || | ||
1417 | strcmp(entry->d_name, "..") == 0) | ||
1418 | continue; | ||
1419 | |||
1420 | int fd = atoi(entry->d_name); | ||
1421 | |||
1422 | // don't close standard streams | ||
1423 | if (fd == STDIN_FILENO || | ||
1424 | fd == STDOUT_FILENO || | ||
1425 | fd == STDERR_FILENO) | ||
1426 | continue; | ||
1427 | |||
1428 | if (fd == dirfd(dir)) | ||
1429 | continue; // just postponed | ||
1430 | |||
1431 | // dont't close file descriptors in keep list | ||
1432 | int keep = 0; | ||
1433 | if (keep_list) { | ||
1434 | size_t i; | ||
1435 | for (i = 0; i < sz; i++) { | ||
1436 | if (keep_list[i] == fd) { | ||
1437 | keep = 1; | ||
1438 | break; | ||
1439 | } | ||
1440 | } | ||
1441 | } | ||
1442 | if (keep) | ||
1443 | continue; | ||
1444 | |||
1445 | close(fd); | ||
1446 | } | ||
1447 | closedir(dir); | ||
1448 | } | ||
1449 | |||
1195 | int has_handler(pid_t pid, int signal) { | 1450 | int has_handler(pid_t pid, int signal) { |
1196 | if (signal > 0 && signal <= SIGRTMAX) { | 1451 | if (signal > 0 && signal <= SIGRTMAX) { |
1197 | char *fname; | 1452 | char *fname; |
@@ -1293,25 +1548,22 @@ pid_t require_pid(const char *name) { | |||
1293 | // return 1 if there is a link somewhere in path of directory | 1548 | // return 1 if there is a link somewhere in path of directory |
1294 | static int has_link(const char *dir) { | 1549 | static int has_link(const char *dir) { |
1295 | assert(dir); | 1550 | assert(dir); |
1296 | int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 1551 | int fd = safer_openat(-1, dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
1297 | if (fd == -1) { | 1552 | if (fd != -1) |
1298 | if ((errno == ELOOP || errno == ENOTDIR) && is_dir(dir)) | ||
1299 | return 1; | ||
1300 | } | ||
1301 | else | ||
1302 | close(fd); | 1553 | close(fd); |
1554 | else if (errno == ELOOP || (errno == ENOTDIR && is_dir(dir))) | ||
1555 | return 1; | ||
1303 | return 0; | 1556 | return 0; |
1304 | } | 1557 | } |
1305 | 1558 | ||
1306 | void check_homedir(void) { | 1559 | void check_homedir(const char *dir) { |
1307 | assert(cfg.homedir); | 1560 | assert(dir); |
1308 | if (cfg.homedir[0] != '/') { | 1561 | if (dir[0] != '/') { |
1309 | fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir); | 1562 | fprintf(stderr, "Error: invalid user directory \"%s\"\n", dir); |
1310 | exit(1); | 1563 | exit(1); |
1311 | } | 1564 | } |
1312 | // symlinks are rejected in many places | 1565 | // symlinks are rejected in many places |
1313 | if (has_link(cfg.homedir)) { | 1566 | if (has_link(dir)) |
1314 | fprintf(stderr, "No full support for symbolic links in path of user directory.\n" | 1567 | fmessage("No full support for symbolic links in path of user directory.\n" |
1315 | "Please provide resolved path in password database (/etc/passwd).\n\n"); | 1568 | "Please provide resolved path in password database (/etc/passwd).\n\n"); |
1316 | } | ||
1317 | } | 1569 | } |
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index 1dabf272e..f173b6672 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -84,7 +84,7 @@ int x11_display(void) { | |||
84 | static int x11_abstract_sockets_present(void) { | 84 | static int x11_abstract_sockets_present(void) { |
85 | 85 | ||
86 | EUID_ROOT(); // grsecurity fix | 86 | EUID_ROOT(); // grsecurity fix |
87 | FILE *fp = fopen("/proc/net/unix", "r"); | 87 | FILE *fp = fopen("/proc/net/unix", "re"); |
88 | if (!fp) | 88 | if (!fp) |
89 | errExit("fopen"); | 89 | errExit("fopen"); |
90 | EUID_USER(); | 90 | EUID_USER(); |
@@ -204,7 +204,6 @@ static int random_display_number(void) { | |||
204 | void x11_start_xvfb(int argc, char **argv) { | 204 | void x11_start_xvfb(int argc, char **argv) { |
205 | EUID_ASSERT(); | 205 | EUID_ASSERT(); |
206 | int i; | 206 | int i; |
207 | struct stat s; | ||
208 | pid_t jail = 0; | 207 | pid_t jail = 0; |
209 | pid_t server = 0; | 208 | pid_t server = 0; |
210 | 209 | ||
@@ -348,7 +347,7 @@ void x11_start_xvfb(int argc, char **argv) { | |||
348 | // wait for x11 server to start | 347 | // wait for x11 server to start |
349 | while (++n < 10) { | 348 | while (++n < 10) { |
350 | sleep(1); | 349 | sleep(1); |
351 | if (stat(fname, &s) == 0) | 350 | if (access(fname, F_OK) == 0) |
352 | break; | 351 | break; |
353 | }; | 352 | }; |
354 | 353 | ||
@@ -427,7 +426,6 @@ static char *extract_setting(int argc, char **argv, const char *argument) { | |||
427 | void x11_start_xephyr(int argc, char **argv) { | 426 | void x11_start_xephyr(int argc, char **argv) { |
428 | EUID_ASSERT(); | 427 | EUID_ASSERT(); |
429 | int i; | 428 | int i; |
430 | struct stat s; | ||
431 | pid_t jail = 0; | 429 | pid_t jail = 0; |
432 | pid_t server = 0; | 430 | pid_t server = 0; |
433 | 431 | ||
@@ -586,7 +584,7 @@ void x11_start_xephyr(int argc, char **argv) { | |||
586 | // wait for x11 server to start | 584 | // wait for x11 server to start |
587 | while (++n < 10) { | 585 | while (++n < 10) { |
588 | sleep(1); | 586 | sleep(1); |
589 | if (stat(fname, &s) == 0) | 587 | if (access(fname, F_OK) == 0) |
590 | break; | 588 | break; |
591 | }; | 589 | }; |
592 | 590 | ||
@@ -701,7 +699,6 @@ static char * get_title_arg_str() { | |||
701 | static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, int display, char *display_str) { | 699 | static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, int display, char *display_str) { |
702 | EUID_ASSERT(); | 700 | EUID_ASSERT(); |
703 | int i; | 701 | int i; |
704 | struct stat s; | ||
705 | pid_t client = 0; | 702 | pid_t client = 0; |
706 | pid_t server = 0; | 703 | pid_t server = 0; |
707 | 704 | ||
@@ -818,7 +815,7 @@ static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, | |||
818 | // wait for x11 server to start | 815 | // wait for x11 server to start |
819 | while (++n < 10) { | 816 | while (++n < 10) { |
820 | sleep(1); | 817 | sleep(1); |
821 | if (stat(fname, &s) == 0) | 818 | if (access(fname, F_OK) == 0) |
822 | break; | 819 | break; |
823 | } | 820 | } |
824 | 821 | ||
@@ -1207,14 +1204,13 @@ void x11_xorg(void) { | |||
1207 | fmessage("Generating a new .Xauthority file\n"); | 1204 | fmessage("Generating a new .Xauthority file\n"); |
1208 | mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid()); | 1205 | mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid()); |
1209 | // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR | 1206 | // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR |
1207 | EUID_USER(); | ||
1210 | char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX"; | 1208 | char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX"; |
1211 | int fd = mkstemp(tmpfname); | 1209 | int fd = mkstemp(tmpfname); |
1212 | if (fd == -1) { | 1210 | if (fd == -1) { |
1213 | fprintf(stderr, "Error: cannot create .Xauthority file\n"); | 1211 | fprintf(stderr, "Error: cannot create .Xauthority file\n"); |
1214 | exit(1); | 1212 | exit(1); |
1215 | } | 1213 | } |
1216 | if (fchown(fd, getuid(), getgid()) == -1) | ||
1217 | errExit("chown"); | ||
1218 | close(fd); | 1214 | close(fd); |
1219 | 1215 | ||
1220 | // run xauth | 1216 | // run xauth |
@@ -1224,24 +1220,22 @@ void x11_xorg(void) { | |||
1224 | else | 1220 | else |
1225 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname, | 1221 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname, |
1226 | "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted"); | 1222 | "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted"); |
1227 | // remove xauth copy | ||
1228 | unlink(RUN_XAUTH_FILE); | ||
1229 | 1223 | ||
1230 | // ensure there is already a file ~/.Xauthority, so that bind-mount below will work. | 1224 | // ensure there is already a file ~/.Xauthority, so that bind-mount below will work. |
1231 | char *dest; | 1225 | char *dest; |
1232 | if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) | 1226 | if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) |
1233 | errExit("asprintf"); | 1227 | errExit("asprintf"); |
1234 | if (lstat(dest, &s) == -1) { | 1228 | if (access(dest, F_OK) == -1) { |
1235 | touch_file_as_user(dest, 0600); | 1229 | touch_file_as_user(dest, 0600); |
1236 | if (stat(dest, &s) == -1) { | 1230 | if (access(dest, F_OK) == -1) { |
1237 | fprintf(stderr, "Error: cannot create %s\n", dest); | 1231 | fprintf(stderr, "Error: cannot create %s\n", dest); |
1238 | exit(1); | 1232 | exit(1); |
1239 | } | 1233 | } |
1240 | } | 1234 | } |
1241 | // get a file descriptor for ~/.Xauthority | 1235 | // get a file descriptor for ~/.Xauthority |
1242 | int dst = safe_fd(dest, O_PATH|O_NOFOLLOW|O_CLOEXEC); | 1236 | int dst = safer_openat(-1, dest, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
1243 | if (dst == -1) | 1237 | if (dst == -1) |
1244 | errExit("safe_fd"); | 1238 | errExit("safer_openat"); |
1245 | // check if the actual mount destination is a user owned regular file | 1239 | // check if the actual mount destination is a user owned regular file |
1246 | if (fstat(dst, &s) == -1) | 1240 | if (fstat(dst, &s) == -1) |
1247 | errExit("fstat"); | 1241 | errExit("fstat"); |
@@ -1263,9 +1257,9 @@ void x11_xorg(void) { | |||
1263 | fs_remount(RUN_XAUTHORITY_SEC_DIR, MOUNT_NOEXEC, 0); | 1257 | fs_remount(RUN_XAUTHORITY_SEC_DIR, MOUNT_NOEXEC, 0); |
1264 | 1258 | ||
1265 | // get a file descriptor for the new Xauthority file | 1259 | // get a file descriptor for the new Xauthority file |
1266 | int src = safe_fd(tmpfname, O_PATH|O_NOFOLLOW|O_CLOEXEC); | 1260 | int src = safer_openat(-1, tmpfname, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
1267 | if (src == -1) | 1261 | if (src == -1) |
1268 | errExit("safe_fd"); | 1262 | errExit("safer_openat"); |
1269 | if (fstat(src, &s) == -1) | 1263 | if (fstat(src, &s) == -1) |
1270 | errExit("fstat"); | 1264 | errExit("fstat"); |
1271 | if (!S_ISREG(s.st_mode)) { | 1265 | if (!S_ISREG(s.st_mode)) { |
@@ -1276,21 +1270,16 @@ void x11_xorg(void) { | |||
1276 | // mount via the link in /proc/self/fd | 1270 | // mount via the link in /proc/self/fd |
1277 | if (arg_debug) | 1271 | if (arg_debug) |
1278 | printf("Mounting %s on %s\n", tmpfname, dest); | 1272 | printf("Mounting %s on %s\n", tmpfname, dest); |
1279 | char *proc_src, *proc_dst; | 1273 | EUID_ROOT(); |
1280 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) | 1274 | if (bind_mount_by_fd(src, dst)) { |
1281 | errExit("asprintf"); | ||
1282 | if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1) | ||
1283 | errExit("asprintf"); | ||
1284 | if (mount(proc_src, proc_dst, NULL, MS_BIND, NULL) == -1) { | ||
1285 | fprintf(stderr, "Error: cannot mount the new .Xauthority file\n"); | 1275 | fprintf(stderr, "Error: cannot mount the new .Xauthority file\n"); |
1286 | exit(1); | 1276 | exit(1); |
1287 | } | 1277 | } |
1278 | EUID_USER(); | ||
1288 | // check /proc/self/mountinfo to confirm the mount is ok | 1279 | // check /proc/self/mountinfo to confirm the mount is ok |
1289 | MountData *mptr = get_last_mount(); | 1280 | MountData *mptr = get_last_mount(); |
1290 | if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) | 1281 | if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) |
1291 | errLogExit("invalid .Xauthority mount"); | 1282 | errLogExit("invalid .Xauthority mount"); |
1292 | free(proc_src); | ||
1293 | free(proc_dst); | ||
1294 | close(src); | 1283 | close(src); |
1295 | close(dst); | 1284 | close(dst); |
1296 | 1285 | ||
@@ -1301,8 +1290,11 @@ void x11_xorg(void) { | |||
1301 | if (envar) { | 1290 | if (envar) { |
1302 | char *rp = realpath(envar, NULL); | 1291 | char *rp = realpath(envar, NULL); |
1303 | if (rp) { | 1292 | if (rp) { |
1304 | if (strcmp(rp, dest) != 0) | 1293 | if (strcmp(rp, dest) != 0) { |
1294 | EUID_ROOT(); | ||
1305 | disable_file_or_dir(rp); | 1295 | disable_file_or_dir(rp); |
1296 | EUID_USER(); | ||
1297 | } | ||
1306 | free(rp); | 1298 | free(rp); |
1307 | } | 1299 | } |
1308 | } | 1300 | } |
@@ -1311,9 +1303,13 @@ void x11_xorg(void) { | |||
1311 | free(dest); | 1303 | free(dest); |
1312 | 1304 | ||
1313 | // mask RUN_XAUTHORITY_SEC_DIR | 1305 | // mask RUN_XAUTHORITY_SEC_DIR |
1306 | EUID_ROOT(); | ||
1314 | if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) | 1307 | if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) |
1315 | errExit("mounting tmpfs"); | 1308 | errExit("mounting tmpfs"); |
1316 | fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR); | 1309 | fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR); |
1310 | |||
1311 | // cleanup | ||
1312 | unlink(RUN_XAUTH_FILE); | ||
1317 | #endif | 1313 | #endif |
1318 | } | 1314 | } |
1319 | 1315 | ||
@@ -1327,7 +1323,7 @@ void fs_x11(void) { | |||
1327 | struct stat s1, s2; | 1323 | struct stat s1, s2; |
1328 | if (stat("/tmp", &s1) != 0 || lstat("/tmp/.X11-unix", &s2) != 0) | 1324 | if (stat("/tmp", &s1) != 0 || lstat("/tmp/.X11-unix", &s2) != 0) |
1329 | return; | 1325 | return; |
1330 | if ((s1.st_mode & S_ISVTX) == 0) { | 1326 | if ((s1.st_mode & S_ISVTX) != S_ISVTX) { |
1331 | fwarning("cannot mask X11 sockets: sticky bit not set on /tmp directory\n"); | 1327 | fwarning("cannot mask X11 sockets: sticky bit not set on /tmp directory\n"); |
1332 | return; | 1328 | return; |
1333 | } | 1329 | } |
@@ -1335,68 +1331,46 @@ void fs_x11(void) { | |||
1335 | fwarning("cannot mask X11 sockets: /tmp/.X11-unix not owned by root user\n"); | 1331 | fwarning("cannot mask X11 sockets: /tmp/.X11-unix not owned by root user\n"); |
1336 | return; | 1332 | return; |
1337 | } | 1333 | } |
1334 | |||
1335 | // the mount source is under control of the user, so be careful and | ||
1336 | // mount without following symbolic links, using a file descriptor | ||
1338 | char *x11file; | 1337 | char *x11file; |
1339 | if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1) | 1338 | if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1) |
1340 | errExit("asprintf"); | 1339 | errExit("asprintf"); |
1341 | struct stat x11stat; | 1340 | int src = open(x11file, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
1342 | if (lstat(x11file, &x11stat) != 0 || !S_ISSOCK(x11stat.st_mode)) { | 1341 | if (src < 0) { |
1342 | free(x11file); | ||
1343 | return; | ||
1344 | } | ||
1345 | struct stat s3; | ||
1346 | if (fstat(src, &s3) < 0) | ||
1347 | errExit("fstat"); | ||
1348 | if (!S_ISSOCK(s3.st_mode)) { | ||
1349 | close(src); | ||
1343 | free(x11file); | 1350 | free(x11file); |
1344 | return; | 1351 | return; |
1345 | } | 1352 | } |
1346 | 1353 | ||
1347 | if (arg_debug || arg_debug_whitelists) | 1354 | if (arg_debug || arg_debug_whitelists) |
1348 | fprintf(stderr, "Masking all X11 sockets except %s\n", x11file); | 1355 | fprintf(stderr, "Masking all X11 sockets except %s\n", x11file); |
1349 | |||
1350 | // Move the real /tmp/.X11-unix to a scratch location | ||
1351 | // so we can still access x11file after we mount a | ||
1352 | // tmpfs over /tmp/.X11-unix. | ||
1353 | if (mkdir(RUN_WHITELIST_X11_DIR, 0700) == -1) | ||
1354 | errExit("mkdir"); | ||
1355 | if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0) | ||
1356 | errExit("mount bind"); | ||
1357 | |||
1358 | // This directory must be mode 1777 | 1356 | // This directory must be mode 1777 |
1359 | if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", | 1357 | if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", |
1360 | MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, | 1358 | MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, |
1361 | "mode=1777,uid=0,gid=0") < 0) | 1359 | "mode=1777,uid=0,gid=0") < 0) |
1362 | errExit("mounting tmpfs on /tmp/.X11-unix"); | 1360 | errExit("mounting tmpfs on /tmp/.X11-unix"); |
1361 | selinux_relabel_path("/tmp/.X11-unix", "/tmp/.X11-unix"); | ||
1363 | fs_logger("tmpfs /tmp/.X11-unix"); | 1362 | fs_logger("tmpfs /tmp/.X11-unix"); |
1364 | 1363 | ||
1365 | // create an empty root-owned file which will have the desired socket bind-mounted over it | 1364 | // create an empty root-owned file which will have the desired socket bind-mounted over it |
1366 | int fd = open(x11file, O_RDONLY|O_CREAT|O_EXCL, S_IRUSR | S_IWUSR); | 1365 | int dst = open(x11file, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR); |
1367 | if (fd < 0) | 1366 | if (dst < 0) |
1368 | errExit(x11file); | 1367 | errExit("open"); |
1369 | close(fd); | ||
1370 | 1368 | ||
1371 | // the mount source is under control of the user, so be careful and | 1369 | if (bind_mount_by_fd(src, dst)) |
1372 | // mount without following symbolic links, using a file descriptor | ||
1373 | char *wx11file; | ||
1374 | if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1) | ||
1375 | errExit("asprintf"); | ||
1376 | fd = safe_fd(wx11file, O_PATH|O_NOFOLLOW|O_CLOEXEC); | ||
1377 | if (fd == -1) | ||
1378 | errExit("opening X11 socket"); | ||
1379 | // confirm once more we are mounting a socket | ||
1380 | if (fstat(fd, &x11stat) == -1) | ||
1381 | errExit("fstat"); | ||
1382 | if (!S_ISSOCK(x11stat.st_mode)) { | ||
1383 | errno = ENOTSOCK; | ||
1384 | errExit("mounting X11 socket"); | ||
1385 | } | ||
1386 | char *proc; | ||
1387 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
1388 | errExit("asprintf"); | ||
1389 | if (mount(proc, x11file, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1390 | errExit("mount bind"); | 1370 | errExit("mount bind"); |
1371 | close(src); | ||
1372 | close(dst); | ||
1391 | fs_logger2("whitelist", x11file); | 1373 | fs_logger2("whitelist", x11file); |
1392 | close(fd); | ||
1393 | free(proc); | ||
1394 | |||
1395 | // block access to RUN_WHITELIST_X11_DIR | ||
1396 | if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, 0, MS_BIND, 0) < 0) | ||
1397 | errExit("mount"); | ||
1398 | fs_logger2("blacklist", RUN_WHITELIST_X11_DIR); | ||
1399 | free(wx11file); | ||
1400 | free(x11file); | 1374 | free(x11file); |
1401 | #endif | 1375 | #endif |
1402 | } | 1376 | } |
diff --git a/src/firemon/apparmor.c b/src/firemon/apparmor.c index eb810a9e7..7103ab7af 100644 --- a/src/firemon/apparmor.c +++ b/src/firemon/apparmor.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/arp.c b/src/firemon/arp.c index 1a69a67b1..1a01da016 100644 --- a/src/firemon/arp.c +++ b/src/firemon/arp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/caps.c b/src/firemon/caps.c index c0f305a5d..045cd1968 100644 --- a/src/firemon/caps.c +++ b/src/firemon/caps.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/cgroup.c b/src/firemon/cgroup.c index 97ba591a6..7ef76fa46 100644 --- a/src/firemon/cgroup.c +++ b/src/firemon/cgroup.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/cpu.c b/src/firemon/cpu.c index 91b455941..31e4eb7fd 100644 --- a/src/firemon/cpu.c +++ b/src/firemon/cpu.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/firemon.c b/src/firemon/firemon.c index 37870747d..91406d6a7 100644 --- a/src/firemon/firemon.c +++ b/src/firemon/firemon.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -52,7 +52,7 @@ static void my_handler(int s){ | |||
52 | 52 | ||
53 | if (terminal_set) | 53 | if (terminal_set) |
54 | tcsetattr(0, TCSANOW, &tlocal); | 54 | tcsetattr(0, TCSANOW, &tlocal); |
55 | exit(0); | 55 | _exit(0); |
56 | } | 56 | } |
57 | 57 | ||
58 | // find the second child process for the specified pid | 58 | // find the second child process for the specified pid |
diff --git a/src/firemon/firemon.h b/src/firemon/firemon.h index 5252ad34f..2fa294e8d 100644 --- a/src/firemon/firemon.h +++ b/src/firemon/firemon.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/interface.c b/src/firemon/interface.c index e04b6f431..f57616ed7 100644 --- a/src/firemon/interface.c +++ b/src/firemon/interface.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,6 +18,7 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firemon.h" | 20 | #include "firemon.h" |
21 | #include "../include/gcov_wrapper.h" | ||
21 | #include <sys/types.h> | 22 | #include <sys/types.h> |
22 | #include <sys/wait.h> | 23 | #include <sys/wait.h> |
23 | #include <netdb.h> | 24 | #include <netdb.h> |
@@ -145,9 +146,9 @@ static void print_sandbox(pid_t pid) { | |||
145 | if (rv) | 146 | if (rv) |
146 | return; | 147 | return; |
147 | net_ifprint(); | 148 | net_ifprint(); |
148 | #ifdef HAVE_GCOV | 149 | |
149 | __gcov_flush(); | 150 | __gcov_flush(); |
150 | #endif | 151 | |
151 | _exit(0); | 152 | _exit(0); |
152 | } | 153 | } |
153 | 154 | ||
diff --git a/src/firemon/list.c b/src/firemon/list.c index 51099a75c..d066c7a5f 100644 --- a/src/firemon/list.c +++ b/src/firemon/list.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/netstats.c b/src/firemon/netstats.c index 850959eb3..0a1b7e0c4 100644 --- a/src/firemon/netstats.c +++ b/src/firemon/netstats.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,6 +18,7 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firemon.h" | 20 | #include "firemon.h" |
21 | #include "../include/gcov_wrapper.h" | ||
21 | #include <termios.h> | 22 | #include <termios.h> |
22 | #include <sys/ioctl.h> | 23 | #include <sys/ioctl.h> |
23 | #include <sys/types.h> | 24 | #include <sys/types.h> |
@@ -242,8 +243,7 @@ void netstats(void) { | |||
242 | print_proc(i, itv, col); | 243 | print_proc(i, itv, col); |
243 | } | 244 | } |
244 | } | 245 | } |
245 | #ifdef HAVE_GCOV | 246 | |
246 | __gcov_flush(); | 247 | __gcov_flush(); |
247 | #endif | ||
248 | } | 248 | } |
249 | } | 249 | } |
diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c index 8085d2d29..ccc1ba1c6 100644 --- a/src/firemon/procevent.c +++ b/src/firemon/procevent.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,6 +18,7 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firemon.h" | 20 | #include "firemon.h" |
21 | #include "../include/gcov_wrapper.h" | ||
21 | #include <sys/socket.h> | 22 | #include <sys/socket.h> |
22 | #include <linux/connector.h> | 23 | #include <linux/connector.h> |
23 | #include <linux/netlink.h> | 24 | #include <linux/netlink.h> |
@@ -230,9 +231,7 @@ static void __attribute__((noreturn)) procevent_monitor(const int sock, pid_t my | |||
230 | tv.tv_usec = 0; | 231 | tv.tv_usec = 0; |
231 | 232 | ||
232 | while (1) { | 233 | while (1) { |
233 | #ifdef HAVE_GCOV | ||
234 | __gcov_flush(); | 234 | __gcov_flush(); |
235 | #endif | ||
236 | 235 | ||
237 | #define BUFFSIZE 4096 | 236 | #define BUFFSIZE 4096 |
238 | char __attribute__ ((aligned(NLMSG_ALIGNTO)))buf[BUFFSIZE]; | 237 | char __attribute__ ((aligned(NLMSG_ALIGNTO)))buf[BUFFSIZE]; |
diff --git a/src/firemon/route.c b/src/firemon/route.c index 9cf5054b2..86f4d85ae 100644 --- a/src/firemon/route.c +++ b/src/firemon/route.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/seccomp.c b/src/firemon/seccomp.c index 04111b6c0..ba0017eff 100644 --- a/src/firemon/seccomp.c +++ b/src/firemon/seccomp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/top.c b/src/firemon/top.c index a25e3c0d8..2bfa63380 100644 --- a/src/firemon/top.c +++ b/src/firemon/top.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,6 +18,7 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firemon.h" | 20 | #include "firemon.h" |
21 | #include "../include/gcov_wrapper.h" | ||
21 | #include <termios.h> | 22 | #include <termios.h> |
22 | #include <sys/ioctl.h> | 23 | #include <sys/ioctl.h> |
23 | #include <sys/types.h> | 24 | #include <sys/types.h> |
@@ -326,8 +327,7 @@ void top(void) { | |||
326 | } | 327 | } |
327 | } | 328 | } |
328 | head_print(col, row); | 329 | head_print(col, row); |
329 | #ifdef HAVE_GCOV | 330 | |
330 | __gcov_flush(); | 331 | __gcov_flush(); |
331 | #endif | ||
332 | } | 332 | } |
333 | } | 333 | } |
diff --git a/src/firemon/tree.c b/src/firemon/tree.c index 899214b9f..7ad413772 100644 --- a/src/firemon/tree.c +++ b/src/firemon/tree.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/firemon/usage.c b/src/firemon/usage.c index baaef3111..c6a664790 100644 --- a/src/firemon/usage.c +++ b/src/firemon/usage.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -38,12 +38,12 @@ static char *help_str = | |||
38 | "\t--name=name - print information only about named sandbox.\n\n" | 38 | "\t--name=name - print information only about named sandbox.\n\n" |
39 | "\t--netstats - monitor network statistics for sandboxes creating a new\n" | 39 | "\t--netstats - monitor network statistics for sandboxes creating a new\n" |
40 | "\t\tnetwork namespace.\n\n" | 40 | "\t\tnetwork namespace.\n\n" |
41 | "\t--nowrap - enable line wrapping in terminals.\n\n" | ||
42 | "\t--route - print route table for each sandbox.\n\n" | 41 | "\t--route - print route table for each sandbox.\n\n" |
43 | "\t--seccomp - print seccomp configuration for each sandbox.\n\n" | 42 | "\t--seccomp - print seccomp configuration for each sandbox.\n\n" |
44 | "\t--tree - print a tree of all sandboxed processes.\n\n" | 43 | "\t--tree - print a tree of all sandboxed processes.\n\n" |
45 | "\t--top - monitor the most CPU-intensive sandboxes.\n\n" | 44 | "\t--top - monitor the most CPU-intensive sandboxes.\n\n" |
46 | "\t--version - print program version and exit.\n\n" | 45 | "\t--version - print program version and exit.\n\n" |
46 | "\t--wrap - enable line wrapping in terminals.\n\n" | ||
47 | "\t--x11 - print X11 display number.\n\n" | 47 | "\t--x11 - print X11 display number.\n\n" |
48 | 48 | ||
49 | "Without any options, firemon monitors all fork, exec, id change, and exit\n" | 49 | "Without any options, firemon monitors all fork, exec, id change, and exit\n" |
diff --git a/src/firemon/x11.c b/src/firemon/x11.c index 97e24b2d2..16ee0a2d6 100644 --- a/src/firemon/x11.c +++ b/src/firemon/x11.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fldd/main.c b/src/fldd/main.c index 9d91557c1..898e0f36a 100644 --- a/src/fldd/main.c +++ b/src/fldd/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -261,12 +261,21 @@ static void walk_directory(const char *dirname) { | |||
261 | 261 | ||
262 | // check directory | 262 | // check directory |
263 | // entry->d_type field is supported in glibc since version 2.19 (Feb 2014) | 263 | // entry->d_type field is supported in glibc since version 2.19 (Feb 2014) |
264 | // we'll use stat to check for directories | 264 | // we'll use stat to check for directories using the real path |
265 | // (sometimes the path is a double symlink to a real file and stat would fail) | ||
266 | char *rpath = realpath(path, NULL); | ||
267 | if (!rpath) { | ||
268 | free(path); | ||
269 | continue; | ||
270 | } | ||
271 | free(path); | ||
272 | |||
265 | struct stat s; | 273 | struct stat s; |
266 | if (stat(path, &s) == -1) | 274 | if (stat(rpath, &s) == -1) |
267 | errExit("stat"); | 275 | errExit("stat"); |
268 | if (S_ISDIR(s.st_mode)) | 276 | if (S_ISDIR(s.st_mode)) |
269 | walk_directory(path); | 277 | walk_directory(rpath); |
278 | free(rpath); | ||
270 | } | 279 | } |
271 | closedir(dir); | 280 | closedir(dir); |
272 | } | 281 | } |
diff --git a/src/fnet/arp.c b/src/fnet/arp.c index 59798d32d..ed110c271 100644 --- a/src/fnet/arp.c +++ b/src/fnet/arp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fnet/fnet.h b/src/fnet/fnet.h index c0154b53e..41db5aa1b 100644 --- a/src/fnet/fnet.h +++ b/src/fnet/fnet.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fnet/interface.c b/src/fnet/interface.c index 91d91360d..072dbf381 100644 --- a/src/fnet/interface.c +++ b/src/fnet/interface.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fnet/main.c b/src/fnet/main.c index df8f7226c..d39fcfc84 100644 --- a/src/fnet/main.c +++ b/src/fnet/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fnet/veth.c b/src/fnet/veth.c index e09b1b1c5..bd6e33583 100644 --- a/src/fnet/veth.c +++ b/src/fnet/veth.c | |||
@@ -26,7 +26,7 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | /* | 28 | /* |
29 | * Copyright (C) 2014-2021 Firejail Authors | 29 | * Copyright (C) 2014-2022 Firejail Authors |
30 | * | 30 | * |
31 | * This file is part of firejail project | 31 | * This file is part of firejail project |
32 | * | 32 | * |
diff --git a/src/fnetfilter/main.c b/src/fnetfilter/main.c index 979f082d0..a89e12933 100644 --- a/src/fnetfilter/main.c +++ b/src/fnetfilter/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -187,10 +187,9 @@ printf("\n"); | |||
187 | char *command = (argc == 3)? argv[1]: NULL; | 187 | char *command = (argc == 3)? argv[1]: NULL; |
188 | //printf("command %s\n", command); | 188 | //printf("command %s\n", command); |
189 | //printf("destfile %s\n", destfile); | 189 | //printf("destfile %s\n", destfile); |
190 | |||
190 | // destfile is a real filename | 191 | // destfile is a real filename |
191 | int len = strlen(destfile); | 192 | reject_meta_chars(destfile, 0); |
192 | if (strcspn(destfile, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) | ||
193 | err_exit_cannot_open_file(destfile); | ||
194 | 193 | ||
195 | // handle default config (command = NULL, destfile) | 194 | // handle default config (command = NULL, destfile) |
196 | if (command == NULL) { | 195 | if (command == NULL) { |
diff --git a/src/fnettrace/Makefile.in b/src/fnettrace/Makefile.in new file mode 100644 index 000000000..755ddcc3a --- /dev/null +++ b/src/fnettrace/Makefile.in | |||
@@ -0,0 +1,17 @@ | |||
1 | .PHONY: all | ||
2 | all: fnettrace | ||
3 | |||
4 | include ../common.mk | ||
5 | |||
6 | %.o : %.c $(H_FILE_LIST) | ||
7 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | ||
8 | |||
9 | fnettrace: $(OBJS) | ||
10 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | ||
11 | |||
12 | .PHONY: clean | ||
13 | clean:; rm -fr *.o fnettrace *.gcov *.gcda *.gcno *.plist | ||
14 | |||
15 | .PHONY: distclean | ||
16 | distclean: clean | ||
17 | rm -fr Makefile | ||
diff --git a/src/fnettrace/fnettrace.h b/src/fnettrace/fnettrace.h new file mode 100644 index 000000000..b30a9f10d --- /dev/null +++ b/src/fnettrace/fnettrace.h | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #ifndef FNETTRACE_H | ||
21 | #define FNETTRACE_H | ||
22 | |||
23 | #include "../include/common.h" | ||
24 | #include <unistd.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <sys/types.h> | ||
27 | #include <sys/socket.h> | ||
28 | #include <netinet/in.h> | ||
29 | #include <time.h> | ||
30 | #include <stdarg.h> | ||
31 | #include <fcntl.h> | ||
32 | #include <sys/mman.h> | ||
33 | |||
34 | |||
35 | //#define DEBUG 1 | ||
36 | |||
37 | #define NETLOCK_INTERVAL 60 // seconds | ||
38 | #define DISPLAY_INTERVAL 2 // seconds | ||
39 | #define DISPLAY_TTL 4 // display intervals (4 * 2 seconds) | ||
40 | #define DISPLAY_BW_UNITS 20 // length of the bandwidth bar | ||
41 | |||
42 | |||
43 | static inline void ansi_topleft(void) { | ||
44 | char str[] = {0x1b, '[', '1', ';', '1', 'H', '\0'}; | ||
45 | printf("%s", str); | ||
46 | fflush(0); | ||
47 | } | ||
48 | |||
49 | static inline void ansi_clrscr(void) { | ||
50 | ansi_topleft(); | ||
51 | char str[] = {0x1b, '[', '0', 'J', '\0'}; | ||
52 | printf("%s", str); | ||
53 | fflush(0); | ||
54 | } | ||
55 | |||
56 | static inline uint8_t hash(uint32_t ip) { | ||
57 | uint8_t *ptr = (uint8_t *) &ip; | ||
58 | // simple byte xor | ||
59 | return *ptr ^ *(ptr + 1) ^ *(ptr + 2) ^ *(ptr + 3); | ||
60 | } | ||
61 | |||
62 | // main.c | ||
63 | void logprintf(char* fmt, ...); | ||
64 | |||
65 | // hostnames.c | ||
66 | extern int geoip_calls; | ||
67 | void load_hostnames(const char *fname); | ||
68 | char* retrieve_hostname(uint32_t ip); | ||
69 | |||
70 | // tail.c | ||
71 | void tail(const char *logfile); | ||
72 | |||
73 | #endif \ No newline at end of file | ||
diff --git a/src/fnettrace/hostnames.c b/src/fnettrace/hostnames.c new file mode 100644 index 000000000..dd92070bf --- /dev/null +++ b/src/fnettrace/hostnames.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include "fnettrace.h" | ||
21 | #include "radix.h" | ||
22 | #define MAXBUF 1024 | ||
23 | |||
24 | int geoip_calls = 0; | ||
25 | static int geoip_not_found = 0; | ||
26 | static char buf[MAXBUF]; | ||
27 | |||
28 | char *retrieve_hostname(uint32_t ip) { | ||
29 | if (geoip_not_found) | ||
30 | return NULL; | ||
31 | geoip_calls++; | ||
32 | |||
33 | char *rv = NULL; | ||
34 | char *cmd; | ||
35 | if (asprintf(&cmd, "/usr/bin/geoiplookup %d.%d.%d.%d", PRINT_IP(ip)) == -1) | ||
36 | errExit("asprintf"); | ||
37 | |||
38 | FILE *fp = popen(cmd, "r"); | ||
39 | if (fp) { | ||
40 | char *ptr; | ||
41 | if (fgets(buf, MAXBUF, fp)) { | ||
42 | ptr = strchr(buf, '\n'); | ||
43 | if (ptr) | ||
44 | *ptr = '\0'; | ||
45 | if (strncmp(buf, "GeoIP Country Edition:", 22) == 0) { | ||
46 | ptr = buf + 22; | ||
47 | if (*ptr == ' ' && *(ptr + 3) == ',' && *(ptr + 4) == ' ') { | ||
48 | rv = ptr + 5; | ||
49 | rv = radix_add(ip, 0xffffffff, rv); | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | fclose(fp); | ||
54 | return rv; | ||
55 | } | ||
56 | else | ||
57 | geoip_not_found = 1; | ||
58 | |||
59 | free(cmd); | ||
60 | |||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | void load_hostnames(const char *fname) { | ||
65 | assert(fname); | ||
66 | FILE *fp = fopen(fname, "r"); | ||
67 | if (!fp) { | ||
68 | fprintf(stderr, "Warning: cannot find %s file\n", fname); | ||
69 | return; | ||
70 | } | ||
71 | |||
72 | char buf[MAXBUF]; | ||
73 | int line = 0; | ||
74 | while (fgets(buf, MAXBUF, fp)) { | ||
75 | line++; | ||
76 | |||
77 | // skip empty spaces | ||
78 | char *start = buf; | ||
79 | while (*start == ' ' || *start == '\t') | ||
80 | start++; | ||
81 | // comments | ||
82 | if (*start == '#') | ||
83 | continue; | ||
84 | char *end = strchr(start, '#'); | ||
85 | if (end) | ||
86 | *end = '\0'; | ||
87 | |||
88 | // end | ||
89 | end = strchr(start, '\n'); | ||
90 | if (end) | ||
91 | *end = '\0'; | ||
92 | end = start + strlen(start); | ||
93 | if (end == start) // empty line | ||
94 | continue; | ||
95 | |||
96 | // line format: 1.2.3.4/32 name_without_empty_spaces | ||
97 | // a single empty space between address and name | ||
98 | end = strchr(start, ' '); | ||
99 | if (!end) | ||
100 | goto errexit; | ||
101 | *end = '\0'; | ||
102 | end++; | ||
103 | if (*end == '\0') | ||
104 | goto errexit; | ||
105 | |||
106 | uint32_t ip; | ||
107 | uint32_t mask; | ||
108 | if (atocidr(start, &ip, &mask)) { | ||
109 | fprintf(stderr, "Error: invalid CIDR address\n"); | ||
110 | goto errexit; | ||
111 | } | ||
112 | |||
113 | radix_add(ip, mask, end); | ||
114 | } | ||
115 | |||
116 | fclose(fp); | ||
117 | return; | ||
118 | |||
119 | |||
120 | errexit: | ||
121 | fprintf(stderr, "Error: invalid line %d in file %s\n", line, fname); | ||
122 | exit(1); | ||
123 | } | ||
124 | |||
diff --git a/src/fnettrace/main.c b/src/fnettrace/main.c new file mode 100644 index 000000000..31d49d839 --- /dev/null +++ b/src/fnettrace/main.c | |||
@@ -0,0 +1,665 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include "fnettrace.h" | ||
21 | #include "radix.h" | ||
22 | #include <sys/ioctl.h> | ||
23 | #define MAX_BUF_SIZE (64 * 1024) | ||
24 | |||
25 | static int arg_netfilter = 0; | ||
26 | static int arg_tail = 0; | ||
27 | static char *arg_log = NULL; | ||
28 | |||
29 | typedef struct hnode_t { | ||
30 | struct hnode_t *hnext; // used for hash table and unused linked list | ||
31 | struct hnode_t *dnext; // used to display stremas on the screen | ||
32 | uint32_t ip_src; | ||
33 | uint32_t bytes; // number of bytes received in the last display interval | ||
34 | uint16_t port_src; | ||
35 | uint8_t protocol; | ||
36 | // the firewall is build based on source address, and in the linked list | ||
37 | // we have elements with the same address but different ports | ||
38 | uint8_t ip_instance; | ||
39 | char *hostname; | ||
40 | int ttl; | ||
41 | } HNode; | ||
42 | |||
43 | // hash table | ||
44 | #define HMAX 256 | ||
45 | HNode *htable[HMAX] = {NULL}; | ||
46 | // display linked list | ||
47 | HNode *dlist = NULL; | ||
48 | |||
49 | |||
50 | // speed up malloc/free | ||
51 | #define HNODE_MAX_MALLOC 16 | ||
52 | static HNode *hnode_unused = NULL; | ||
53 | HNode *hmalloc(void) { | ||
54 | if (hnode_unused == NULL) { | ||
55 | hnode_unused = malloc(sizeof(HNode) * HNODE_MAX_MALLOC); | ||
56 | if (!hnode_unused) | ||
57 | errExit("malloc"); | ||
58 | memset(hnode_unused, 0, sizeof(HNode) * HNODE_MAX_MALLOC); | ||
59 | HNode *ptr = hnode_unused; | ||
60 | int i; | ||
61 | for ( i = 1; i < HNODE_MAX_MALLOC; i++, ptr++) | ||
62 | ptr->hnext = hnode_unused + i; | ||
63 | } | ||
64 | |||
65 | HNode *rv = hnode_unused; | ||
66 | hnode_unused = hnode_unused->hnext; | ||
67 | return rv; | ||
68 | } | ||
69 | |||
70 | void hfree(HNode *ptr) { | ||
71 | assert(ptr); | ||
72 | memset(ptr, 0, sizeof(HNode)); | ||
73 | ptr->hnext = hnode_unused; | ||
74 | hnode_unused = ptr; | ||
75 | } | ||
76 | |||
77 | |||
78 | static void hnode_add(uint32_t ip_src, uint8_t protocol, uint16_t port_src, uint32_t bytes) { | ||
79 | uint8_t h = hash(ip_src); | ||
80 | |||
81 | // find | ||
82 | int ip_instance = 0; | ||
83 | HNode *ptr = htable[h]; | ||
84 | while (ptr) { | ||
85 | if (ptr->ip_src == ip_src) { | ||
86 | ip_instance++; | ||
87 | if (ptr->port_src == port_src && ptr->protocol == protocol) { | ||
88 | ptr->bytes += bytes; | ||
89 | return; | ||
90 | } | ||
91 | } | ||
92 | ptr = ptr->hnext; | ||
93 | } | ||
94 | |||
95 | #ifdef DEBUG | ||
96 | printf("malloc %d.%d.%d.%d\n", PRINT_IP(ip_src)); | ||
97 | #endif | ||
98 | HNode *hnew = hmalloc(); | ||
99 | assert(hnew); | ||
100 | hnew->hostname = NULL; | ||
101 | hnew->ip_src = ip_src; | ||
102 | hnew->port_src = port_src; | ||
103 | hnew->protocol = protocol; | ||
104 | hnew->hnext = NULL; | ||
105 | hnew->bytes = bytes; | ||
106 | hnew->ip_instance = ip_instance + 1; | ||
107 | hnew->ttl = DISPLAY_TTL; | ||
108 | if (htable[h] == NULL) | ||
109 | htable[h] = hnew; | ||
110 | else { | ||
111 | hnew->hnext = htable[h]; | ||
112 | htable[h] = hnew; | ||
113 | } | ||
114 | |||
115 | // add to the end of list | ||
116 | hnew->dnext = NULL; | ||
117 | if (dlist == NULL) | ||
118 | dlist = hnew; | ||
119 | else { | ||
120 | ptr = dlist; | ||
121 | while (ptr->dnext != NULL) | ||
122 | ptr = ptr->dnext; | ||
123 | ptr->dnext = hnew; | ||
124 | } | ||
125 | |||
126 | if (arg_netfilter) | ||
127 | logprintf(" %d.%d.%d.%d ", PRINT_IP(hnew->ip_src)); | ||
128 | } | ||
129 | |||
130 | static void hnode_free(HNode *elem) { | ||
131 | assert(elem); | ||
132 | #ifdef DEBUG | ||
133 | printf("free %d.%d.%d.%d\n", PRINT_IP(elem->ip_src)); | ||
134 | #endif | ||
135 | |||
136 | uint8_t h = hash(elem->ip_src); | ||
137 | HNode *ptr = htable[h]; | ||
138 | assert(ptr); | ||
139 | |||
140 | HNode *prev = NULL; | ||
141 | while (ptr != elem) { | ||
142 | prev = ptr; | ||
143 | ptr = ptr->hnext; | ||
144 | } | ||
145 | if (prev == NULL) | ||
146 | htable[h] = elem->hnext; | ||
147 | else | ||
148 | prev->hnext = elem->hnext; | ||
149 | hfree(elem); | ||
150 | } | ||
151 | |||
152 | #ifdef DEBUG | ||
153 | static void debug_dlist(void) { | ||
154 | HNode *ptr = dlist; | ||
155 | while (ptr) { | ||
156 | printf("dlist %d.%d.%d.%d:%d\n", PRINT_IP(ptr->ip_src), ptr->port_src); | ||
157 | ptr = ptr->dnext; | ||
158 | } | ||
159 | } | ||
160 | static void debug_hnode(void) { | ||
161 | int i; | ||
162 | for (i = 0; i < HMAX; i++) { | ||
163 | HNode *ptr = htable[i]; | ||
164 | while (ptr) { | ||
165 | printf("hnode (%d) %d.%d.%d.%d:%d\n", i, PRINT_IP(ptr->ip_src), ptr->port_src); | ||
166 | ptr = ptr->hnext; | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | #endif | ||
171 | |||
172 | static char *bw_line[DISPLAY_BW_UNITS + 1] = { NULL }; | ||
173 | |||
174 | static char *print_bw(unsigned units) { | ||
175 | if (units > DISPLAY_BW_UNITS) | ||
176 | units = DISPLAY_BW_UNITS ; | ||
177 | |||
178 | if (bw_line[units] == NULL) { | ||
179 | char *ptr = malloc(DISPLAY_BW_UNITS + 2); | ||
180 | if (!ptr) | ||
181 | errExit("malloc"); | ||
182 | bw_line[units] = ptr; | ||
183 | |||
184 | unsigned i; | ||
185 | for (i = 0; i < DISPLAY_BW_UNITS; i++, ptr++) | ||
186 | sprintf(ptr, "%s", (i < units)? "*": " "); | ||
187 | sprintf(ptr, "%s", " "); | ||
188 | } | ||
189 | |||
190 | return bw_line[units]; | ||
191 | } | ||
192 | |||
193 | #define LINE_MAX 200 | ||
194 | static inline void adjust_line(char *str, int len, int cols) { | ||
195 | if (len > LINE_MAX) // functions such as snprintf truncate the string, and return the length of the untruncated string | ||
196 | len = LINE_MAX; | ||
197 | if (cols > 4 && len > cols) { | ||
198 | str[cols] = '\0'; | ||
199 | str[cols- 1] = '\n'; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | #define BWMAX_CNT 8 | ||
204 | static unsigned adjust_bandwidth(unsigned bw) { | ||
205 | static unsigned array[BWMAX_CNT] = {0}; | ||
206 | static int instance = 0; | ||
207 | |||
208 | array[instance] = bw; | ||
209 | int i; | ||
210 | unsigned sum = 0; | ||
211 | unsigned max = 0; | ||
212 | for ( i = 0; i < BWMAX_CNT; i++) { | ||
213 | sum += array[i]; | ||
214 | max = (max > array[i])? max: array[i]; | ||
215 | } | ||
216 | sum /= BWMAX_CNT; | ||
217 | |||
218 | if (++instance >= BWMAX_CNT) | ||
219 | instance = 0; | ||
220 | |||
221 | return (max < (sum / 2))? sum: max; | ||
222 | } | ||
223 | |||
224 | static void hnode_print(unsigned bw) { | ||
225 | assert(!arg_netfilter); | ||
226 | bw = (bw < 1024 * DISPLAY_INTERVAL)? 1024 * DISPLAY_INTERVAL: bw; | ||
227 | #ifdef DEBUG | ||
228 | printf("*********************\n"); | ||
229 | debug_dlist(); | ||
230 | printf("-----------------------------\n"); | ||
231 | debug_hnode(); | ||
232 | printf("*********************\n"); | ||
233 | #else | ||
234 | ansi_clrscr(); | ||
235 | #endif | ||
236 | |||
237 | // get terminal size | ||
238 | struct winsize sz; | ||
239 | int cols = 80; | ||
240 | if (isatty(STDIN_FILENO)) { | ||
241 | if (!ioctl(0, TIOCGWINSZ, &sz)) | ||
242 | cols = sz.ws_col; | ||
243 | } | ||
244 | if (cols > LINE_MAX) | ||
245 | cols = LINE_MAX; | ||
246 | char line[LINE_MAX + 1]; | ||
247 | |||
248 | // print stats line | ||
249 | bw = adjust_bandwidth(bw); | ||
250 | char stats[31]; | ||
251 | if (bw > (1024 * 1024 * DISPLAY_INTERVAL)) | ||
252 | sprintf(stats, "%u MB/s ", bw / (1024 * 1024 * DISPLAY_INTERVAL)); | ||
253 | else | ||
254 | sprintf(stats, "%u KB/s ", bw / (1024 * DISPLAY_INTERVAL)); | ||
255 | int len = snprintf(line, LINE_MAX, "%32s geoip %d, IP database %d\n", stats, geoip_calls, radix_nodes); | ||
256 | adjust_line(line, len, cols); | ||
257 | printf("%s", line); | ||
258 | |||
259 | HNode *ptr = dlist; | ||
260 | HNode *prev = NULL; | ||
261 | while (ptr) { | ||
262 | HNode *next = ptr->dnext; | ||
263 | if (--ptr->ttl > 0) { | ||
264 | char bytes[11]; | ||
265 | if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 1024 * 2)) // > 2 MB/second | ||
266 | snprintf(bytes, 11, "%u MB/s", | ||
267 | (unsigned) (ptr->bytes / (DISPLAY_INTERVAL * 1024* 1024))); | ||
268 | else if (ptr->bytes > (DISPLAY_INTERVAL * 1024 * 2)) // > 2 KB/second | ||
269 | snprintf(bytes, 11, "%u KB/s", | ||
270 | (unsigned) (ptr->bytes / (DISPLAY_INTERVAL * 1024))); | ||
271 | else | ||
272 | snprintf(bytes, 11, "%u B/s ", (unsigned) (ptr->bytes / DISPLAY_INTERVAL)); | ||
273 | |||
274 | if (!ptr->hostname) | ||
275 | ptr->hostname = radix_longest_prefix_match(ptr->ip_src); | ||
276 | if (!ptr->hostname) | ||
277 | ptr->hostname = retrieve_hostname(ptr->ip_src); | ||
278 | if (!ptr->hostname) | ||
279 | ptr->hostname = " "; | ||
280 | |||
281 | unsigned bwunit = bw / DISPLAY_BW_UNITS; | ||
282 | char *bwline; | ||
283 | if (bwunit == 0) | ||
284 | bwline = print_bw(0); | ||
285 | else | ||
286 | bwline = print_bw(ptr->bytes / bwunit); | ||
287 | |||
288 | char *protocol = ""; | ||
289 | if (ptr->port_src == 80) | ||
290 | protocol = "(HTTP)"; | ||
291 | else if (ptr->port_src == 853) | ||
292 | protocol = "(DoT)"; | ||
293 | else if (ptr->protocol == 0x11) | ||
294 | protocol = "(UDP)"; | ||
295 | /* | ||
296 | else (ptr->port_src == 443) | ||
297 | protocol = "TLS"; | ||
298 | else if (ptr->port_src == 53) | ||
299 | protocol = "DNS"; | ||
300 | */ | ||
301 | |||
302 | len = snprintf(line, LINE_MAX, "%10s %s %d.%d.%d.%d:%u%s %s\n", | ||
303 | bytes, bwline, PRINT_IP(ptr->ip_src), ptr->port_src, protocol, ptr->hostname); | ||
304 | adjust_line(line, len, cols); | ||
305 | printf("%s", line); | ||
306 | |||
307 | if (ptr->bytes) | ||
308 | ptr->ttl = DISPLAY_TTL; | ||
309 | ptr->bytes = 0; | ||
310 | prev = ptr; | ||
311 | } | ||
312 | else { | ||
313 | // free the element | ||
314 | if (prev == NULL) | ||
315 | dlist = next; | ||
316 | else | ||
317 | prev->dnext = next; | ||
318 | hnode_free(ptr); | ||
319 | } | ||
320 | |||
321 | ptr = next; | ||
322 | } | ||
323 | |||
324 | #ifdef DEBUG | ||
325 | { | ||
326 | int cnt = 0; | ||
327 | HNode *ptr = hnode_unused; | ||
328 | while (ptr) { | ||
329 | cnt++; | ||
330 | ptr = ptr->hnext; | ||
331 | } | ||
332 | printf("hnode unused %d\n", cnt); | ||
333 | } | ||
334 | #endif | ||
335 | } | ||
336 | |||
337 | static void run_trace(void) { | ||
338 | if (arg_netfilter) | ||
339 | logprintf("accumulating traffic for %d seconds\n", NETLOCK_INTERVAL); | ||
340 | |||
341 | // trace only rx ipv4 tcp and upd | ||
342 | int s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); | ||
343 | int s2 = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); | ||
344 | if (s1 < 0 || s2 < 0) | ||
345 | errExit("socket"); | ||
346 | |||
347 | unsigned start = time(NULL); | ||
348 | unsigned last_print_traces = 0; | ||
349 | unsigned last_print_remaining = 0; | ||
350 | unsigned char buf[MAX_BUF_SIZE]; | ||
351 | unsigned bw = 0; // bandwidth calculations | ||
352 | while (1) { | ||
353 | unsigned end = time(NULL); | ||
354 | if (arg_netfilter && end - start >= NETLOCK_INTERVAL) | ||
355 | break; | ||
356 | if (end % DISPLAY_INTERVAL == 1 && last_print_traces != end) { // first print after 1 second | ||
357 | if (!arg_netfilter) | ||
358 | hnode_print(bw); | ||
359 | last_print_traces = end; | ||
360 | bw = 0; | ||
361 | } | ||
362 | if (arg_netfilter && last_print_remaining != end) { | ||
363 | logprintf("."); | ||
364 | fflush(0); | ||
365 | last_print_remaining = end; | ||
366 | } | ||
367 | |||
368 | fd_set rfds; | ||
369 | FD_ZERO(&rfds); | ||
370 | FD_SET(s1, &rfds); | ||
371 | FD_SET(s2, &rfds); | ||
372 | int maxfd = (s1 > s2) ? s1 : s2; | ||
373 | maxfd++; | ||
374 | struct timeval tv; | ||
375 | tv.tv_sec = 1; | ||
376 | tv.tv_usec = 0; | ||
377 | int rv = select(maxfd, &rfds, NULL, NULL, &tv); | ||
378 | if (rv < 0) | ||
379 | errExit("select"); | ||
380 | else if (rv == 0) | ||
381 | continue; | ||
382 | |||
383 | int sock = (FD_ISSET(s1, &rfds)) ? s1 : s2; | ||
384 | |||
385 | unsigned bytes = recvfrom(sock, buf, MAX_BUF_SIZE, 0, NULL, NULL); | ||
386 | if (bytes >= 20) { // size of IP header | ||
387 | #ifdef DEBUG | ||
388 | { | ||
389 | uint32_t ip_src; | ||
390 | memcpy(&ip_src, buf + 12, 4); | ||
391 | ip_src = ntohl(ip_src); | ||
392 | |||
393 | uint32_t ip_dst; | ||
394 | memcpy(&ip_dst, buf + 16, 4); | ||
395 | ip_dst = ntohl(ip_dst); | ||
396 | printf("%d.%d.%d.%d -> %d.%d.%d.%d, %u bytes\n", PRINT_IP(ip_src), PRINT_IP(ip_dst), bytes); | ||
397 | } | ||
398 | #endif | ||
399 | // filter out loopback traffic | ||
400 | if (buf[12] != 127 && buf[16] != 127) { | ||
401 | bw += bytes + 14; // assume a 14 byte Ethernet layer | ||
402 | |||
403 | uint32_t ip_src; | ||
404 | memcpy(&ip_src, buf + 12, 4); | ||
405 | ip_src = ntohl(ip_src); | ||
406 | |||
407 | uint8_t hlen = (buf[0] & 0x0f) * 4; | ||
408 | uint16_t port_src; | ||
409 | memcpy(&port_src, buf + hlen, 2); | ||
410 | port_src = ntohs(port_src); | ||
411 | |||
412 | hnode_add(ip_src, buf[9], port_src, bytes + 14); | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | |||
417 | close(s1); | ||
418 | close(s2); | ||
419 | } | ||
420 | |||
421 | static char *filter_start = | ||
422 | "*filter\n" | ||
423 | ":INPUT DROP [0:0]\n" | ||
424 | ":FORWARD DROP [0:0]\n" | ||
425 | ":OUTPUT DROP [0:0]\n"; | ||
426 | |||
427 | // return 1 if error | ||
428 | static int print_filter(FILE *fp) { | ||
429 | if (dlist == NULL) | ||
430 | return 1; | ||
431 | fprintf(fp, "%s\n", filter_start); | ||
432 | fprintf(fp, "-A INPUT -s 127.0.0.0/8 -j ACCEPT\n"); | ||
433 | fprintf(fp, "-A OUTPUT -d 127.0.0.0/8 -j ACCEPT\n"); | ||
434 | fprintf(fp, "\n"); | ||
435 | |||
436 | int i; | ||
437 | for (i = 0; i < HMAX; i++) { | ||
438 | HNode *ptr = htable[i]; | ||
439 | while (ptr) { | ||
440 | // filter rules are targeting ip address, the port number is disregarded, | ||
441 | // so we look only at the first instance of an address | ||
442 | if (ptr->ip_instance == 1) { | ||
443 | char *protocol = (ptr->protocol == 6)? "tcp": "udp"; | ||
444 | fprintf(fp, "-A INPUT -s %d.%d.%d.%d -p %s -j ACCEPT\n", | ||
445 | PRINT_IP(ptr->ip_src), | ||
446 | protocol); | ||
447 | fprintf(fp, "-A OUTPUT -d %d.%d.%d.%d -p %s -j ACCEPT\n", | ||
448 | PRINT_IP(ptr->ip_src), | ||
449 | protocol); | ||
450 | fprintf(fp, "\n"); | ||
451 | } | ||
452 | ptr = ptr->hnext; | ||
453 | } | ||
454 | } | ||
455 | fprintf(fp, "COMMIT\n"); | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static char *flush_rules[] = { | ||
461 | "-P INPUT ACCEPT", | ||
462 | // "-P FORWARD DENY", | ||
463 | "-P OUTPUT ACCEPT", | ||
464 | "-F", | ||
465 | "-X", | ||
466 | // "-t nat -F", | ||
467 | // "-t nat -X", | ||
468 | // "-t mangle -F", | ||
469 | // "-t mangle -X", | ||
470 | // "iptables -t raw -F", | ||
471 | // "-t raw -X", | ||
472 | NULL | ||
473 | }; | ||
474 | |||
475 | static void deploy_netfilter(void) { | ||
476 | int rv; | ||
477 | char *cmd; | ||
478 | int i; | ||
479 | |||
480 | if (dlist == NULL) { | ||
481 | logprintf("Sorry, no network traffic was detected. The firewall was not configured.\n"); | ||
482 | return; | ||
483 | } | ||
484 | // find iptables command | ||
485 | char *iptables = NULL; | ||
486 | char *iptables_restore = NULL; | ||
487 | if (access("/sbin/iptables", X_OK) == 0) { | ||
488 | iptables = "/sbin/iptables"; | ||
489 | iptables_restore = "/sbin/iptables-restore"; | ||
490 | } | ||
491 | else if (access("/usr/sbin/iptables", X_OK) == 0) { | ||
492 | iptables = "/usr/sbin/iptables"; | ||
493 | iptables_restore = "/usr/sbin/iptables-restore"; | ||
494 | } | ||
495 | if (iptables == NULL || iptables_restore == NULL) { | ||
496 | fprintf(stderr, "Error: iptables command not found, netfilter not configured\n"); | ||
497 | exit(1); | ||
498 | } | ||
499 | |||
500 | // flush all netfilter rules | ||
501 | i = 0; | ||
502 | while (flush_rules[i]) { | ||
503 | char *cmd; | ||
504 | if (asprintf(&cmd, "%s %s", iptables, flush_rules[i]) == -1) | ||
505 | errExit("asprintf"); | ||
506 | int rv = system(cmd); | ||
507 | (void) rv; | ||
508 | free(cmd); | ||
509 | i++; | ||
510 | } | ||
511 | |||
512 | // create temporary file | ||
513 | char fname[] = "/tmp/firejail-XXXXXX"; | ||
514 | int fd = mkstemp(fname); | ||
515 | if (fd == -1) { | ||
516 | fprintf(stderr, "Error: cannot create temporary configuration file\n"); | ||
517 | exit(1); | ||
518 | } | ||
519 | |||
520 | FILE* fp = fdopen(fd, "w"); | ||
521 | if (!fp) { | ||
522 | rv = unlink(fname); | ||
523 | (void) rv; | ||
524 | fprintf(stderr, "Error: cannot create temporary configuration file\n"); | ||
525 | exit(1); | ||
526 | } | ||
527 | print_filter(fp); | ||
528 | fclose(fp); | ||
529 | |||
530 | logprintf("\n\n"); | ||
531 | logprintf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); | ||
532 | if (asprintf(&cmd, "cat %s >> %s", fname, arg_log) == -1) | ||
533 | errExit("asprintf"); | ||
534 | rv = system(cmd); | ||
535 | (void) rv; | ||
536 | free(cmd); | ||
537 | |||
538 | if (asprintf(&cmd, "cat %s", fname) == -1) | ||
539 | errExit("asprintf"); | ||
540 | rv = system(cmd); | ||
541 | (void) rv; | ||
542 | free(cmd); | ||
543 | logprintf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); | ||
544 | |||
545 | // configuring | ||
546 | if (asprintf(&cmd, "%s %s", iptables_restore, fname) == -1) | ||
547 | errExit("asprintf"); | ||
548 | rv = system(cmd); | ||
549 | if (rv) | ||
550 | fprintf(stdout, "Warning: possible netfilter problem!"); | ||
551 | free(cmd); | ||
552 | |||
553 | rv = unlink(fname); | ||
554 | (void) rv; | ||
555 | logprintf("\nfirewall deployed\n"); | ||
556 | } | ||
557 | |||
558 | void logprintf(char* fmt, ...) { | ||
559 | if (!arg_log) | ||
560 | return; | ||
561 | |||
562 | FILE *fp = fopen(arg_log, "a"); | ||
563 | if (fp) { // disregard if error | ||
564 | va_list args; | ||
565 | va_start(args,fmt); | ||
566 | vfprintf(fp, fmt, args); | ||
567 | va_end(args); | ||
568 | fclose(fp); | ||
569 | } | ||
570 | |||
571 | va_list args; | ||
572 | va_start(args,fmt); | ||
573 | vfprintf(stdout, fmt, args); | ||
574 | va_end(args); | ||
575 | } | ||
576 | |||
577 | static void usage(void) { | ||
578 | printf("Usage: fnettrace [OPTIONS]\n"); | ||
579 | printf("Options:\n"); | ||
580 | printf(" --help, -? - this help screen\n"); | ||
581 | printf(" --log=filename - netlocker logfile\n"); | ||
582 | printf(" --netfilter - build the firewall rules and commit them.\n"); | ||
583 | printf(" --tail - \"tail -f\" functionality\n"); | ||
584 | printf("Examples:\n"); | ||
585 | printf(" # fnettrace - traffic trace\n"); | ||
586 | printf(" # fnettrace --netfilter --log=logfile - netlocker, dump output in logfile\n"); | ||
587 | printf(" # fnettrace --tail --log=logifile - similar to \"tail -f logfile\"\n"); | ||
588 | printf("\n"); | ||
589 | } | ||
590 | |||
591 | int main(int argc, char **argv) { | ||
592 | int i; | ||
593 | |||
594 | #ifdef DEBUG | ||
595 | // radix test | ||
596 | radix_add(0x09000000, 0xff000000, "IBM"); | ||
597 | radix_add(0x09090909, 0xffffffff, "Quad9 DNS"); | ||
598 | radix_add(0x09000000, 0xff000000, "IBM"); | ||
599 | printf("This test should print \"IBM, Quad9 DNS, IBM\"\n"); | ||
600 | char *name = radix_longest_prefix_match(0x09040404); | ||
601 | printf("%s, ", name); | ||
602 | name = radix_longest_prefix_match(0x09090909); | ||
603 | printf("%s, ", name); | ||
604 | name = radix_longest_prefix_match(0x09322209); | ||
605 | printf("%s\n", name); | ||
606 | #endif | ||
607 | |||
608 | for (i = 1; i < argc; i++) { | ||
609 | if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-?") == 0) { | ||
610 | usage(); | ||
611 | return 0; | ||
612 | } | ||
613 | else if (strcmp(argv[i], "--netfilter") == 0) | ||
614 | arg_netfilter = 1; | ||
615 | else if (strcmp(argv[i], "--tail") == 0) | ||
616 | arg_tail = 1; | ||
617 | else if (strncmp(argv[i], "--log=", 6) == 0) | ||
618 | arg_log = argv[i] + 6; | ||
619 | else { | ||
620 | fprintf(stderr, "Error: invalid argument\n"); | ||
621 | return 1; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | // tail | ||
626 | if (arg_tail) { | ||
627 | if (!arg_log) { | ||
628 | fprintf(stderr, "Error: no log file\n"); | ||
629 | usage(); | ||
630 | exit(1); | ||
631 | } | ||
632 | |||
633 | tail(arg_log); | ||
634 | sleep(5); | ||
635 | exit(0); | ||
636 | } | ||
637 | |||
638 | if (getuid() != 0) { | ||
639 | fprintf(stderr, "Error: you need to be root to run this program\n"); | ||
640 | return 1; | ||
641 | } | ||
642 | |||
643 | ansi_clrscr(); | ||
644 | if (arg_netfilter) | ||
645 | logprintf("starting network lockdown\n"); | ||
646 | else { | ||
647 | char *fname = LIBDIR "/firejail/static-ip-map"; | ||
648 | load_hostnames(fname); | ||
649 | } | ||
650 | |||
651 | run_trace(); | ||
652 | if (arg_netfilter) { | ||
653 | // TCP path MTU discovery will not work properly since the firewall drops all ICMP packets | ||
654 | // Instead, we use iPacketization Layer PMTUD (RFC 4821) support in Linux kernel | ||
655 | int rv = system("echo 1 > /proc/sys/net/ipv4/tcp_mtu_probing"); | ||
656 | (void) rv; | ||
657 | |||
658 | deploy_netfilter(); | ||
659 | sleep(3); | ||
660 | if (arg_log) | ||
661 | unlink(arg_log); | ||
662 | } | ||
663 | |||
664 | return 0; | ||
665 | } | ||
diff --git a/src/fnettrace/radix.c b/src/fnettrace/radix.c new file mode 100644 index 000000000..c9493717d --- /dev/null +++ b/src/fnettrace/radix.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <stdint.h> | ||
24 | #include <assert.h> | ||
25 | #include "radix.h" | ||
26 | #include "fnettrace.h" | ||
27 | |||
28 | typedef struct rnode_t { | ||
29 | struct rnode_t *zero; | ||
30 | struct rnode_t *one; | ||
31 | char *name; | ||
32 | } RNode; | ||
33 | |||
34 | RNode *head = 0; | ||
35 | int radix_nodes = 0; | ||
36 | |||
37 | // get rid of the malloc overhead | ||
38 | #define RNODE_MAX_MALLOC 128 | ||
39 | static RNode *rnode_unused = NULL; | ||
40 | static int rnode_malloc_cnt = 0; | ||
41 | static RNode *rmalloc(void) { | ||
42 | if (rnode_unused == NULL || rnode_malloc_cnt >= RNODE_MAX_MALLOC) { | ||
43 | rnode_unused = malloc(sizeof(RNode) * RNODE_MAX_MALLOC); | ||
44 | if (!rnode_unused) | ||
45 | errExit("malloc"); | ||
46 | memset(rnode_unused, 0, sizeof(RNode) * RNODE_MAX_MALLOC); | ||
47 | rnode_malloc_cnt = 0; | ||
48 | } | ||
49 | |||
50 | rnode_malloc_cnt++; | ||
51 | return rnode_unused + rnode_malloc_cnt - 1; | ||
52 | } | ||
53 | |||
54 | |||
55 | static inline char *duplicate_name(const char *name) { | ||
56 | assert(name); | ||
57 | |||
58 | if (strcmp(name, "United States") == 0) | ||
59 | return "United States"; | ||
60 | else if (strcmp(name, "Amazon") == 0) | ||
61 | return "Amazon"; | ||
62 | return strdup(name); | ||
63 | } | ||
64 | |||
65 | static inline RNode *addOne(RNode *ptr, char *name) { | ||
66 | assert(ptr); | ||
67 | if (ptr->one) | ||
68 | return ptr->one; | ||
69 | RNode *node = rmalloc(); | ||
70 | assert(node); | ||
71 | if (name) { | ||
72 | node->name = duplicate_name(name); | ||
73 | if (!node->name) | ||
74 | errExit("duplicate name"); | ||
75 | } | ||
76 | |||
77 | ptr->one = node; | ||
78 | return node; | ||
79 | } | ||
80 | |||
81 | static inline RNode *addZero(RNode *ptr, char *name) { | ||
82 | assert(ptr); | ||
83 | if (ptr->zero) | ||
84 | return ptr->zero; | ||
85 | RNode *node = rmalloc(); | ||
86 | assert(node); | ||
87 | if (name) { | ||
88 | node->name = duplicate_name(name); | ||
89 | if (!node->name) | ||
90 | errExit("duplicate name"); | ||
91 | } | ||
92 | |||
93 | ptr->zero = node; | ||
94 | return node; | ||
95 | } | ||
96 | |||
97 | |||
98 | // add to radix tree | ||
99 | char *radix_add(uint32_t ip, uint32_t mask, char *name) { | ||
100 | assert(name); | ||
101 | uint32_t m = 0x80000000; | ||
102 | uint32_t lastm = 0; | ||
103 | if (head == 0) { | ||
104 | head = malloc(sizeof(RNode)); | ||
105 | memset(head, 0, sizeof(RNode)); | ||
106 | } | ||
107 | RNode *ptr = head; | ||
108 | radix_nodes++; | ||
109 | |||
110 | int i; | ||
111 | for (i = 0; i < 32; i++, m >>= 1) { | ||
112 | if (!(m & mask)) | ||
113 | break; | ||
114 | |||
115 | lastm |= m; | ||
116 | int valid = (lastm == mask)? 1: 0; | ||
117 | if (m & ip) | ||
118 | ptr = addOne(ptr, (valid)? name: NULL); | ||
119 | else | ||
120 | ptr = addZero(ptr, (valid)? name: NULL); | ||
121 | } | ||
122 | assert(ptr); | ||
123 | if (!ptr->name) { | ||
124 | ptr->name = duplicate_name(name); | ||
125 | if (!ptr->name) | ||
126 | errExit("duplicate_name"); | ||
127 | } | ||
128 | |||
129 | return ptr->name; | ||
130 | } | ||
131 | |||
132 | // find last match | ||
133 | char *radix_longest_prefix_match(uint32_t ip) { | ||
134 | if (!head) | ||
135 | return NULL; | ||
136 | |||
137 | uint32_t m = 0x80000000; | ||
138 | RNode *ptr = head; | ||
139 | RNode *rv = NULL; | ||
140 | |||
141 | int i; | ||
142 | for (i = 0; i < 32; i++, m >>= 1) { | ||
143 | if (m & ip) | ||
144 | ptr = ptr->one; | ||
145 | else | ||
146 | ptr = ptr->zero; | ||
147 | if (!ptr) | ||
148 | break; | ||
149 | if (ptr->name) | ||
150 | rv = ptr; | ||
151 | } | ||
152 | |||
153 | return (rv)? rv->name: NULL; | ||
154 | } | ||
155 | |||
diff --git a/src/fnettrace/radix.h b/src/fnettrace/radix.h new file mode 100644 index 000000000..c22c5c547 --- /dev/null +++ b/src/fnettrace/radix.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #ifndef RADIX_H | ||
21 | #define RADIX_H | ||
22 | |||
23 | extern int radix_nodes; | ||
24 | char *radix_longest_prefix_match(uint32_t ip); | ||
25 | char *radix_add(uint32_t ip, uint32_t mask, char *name); | ||
26 | |||
27 | #endif \ No newline at end of file | ||
diff --git a/src/fnettrace/static-ip-map b/src/fnettrace/static-ip-map new file mode 100644 index 000000000..e24ecf218 --- /dev/null +++ b/src/fnettrace/static-ip-map | |||
@@ -0,0 +1,4044 @@ | |||
1 | # | ||
2 | # Copyright (C) 2014-2022 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 | # Static Internet Map | ||
22 | # | ||
23 | # Unfortunately we cannot do a hostname lookup. This will leak a lot of | ||
24 | # information about what network resources we access. | ||
25 | # A static map, helped out by geoip package available on all Linux distros, | ||
26 | # will have to do it for now! | ||
27 | # | ||
28 | # Format: | ||
29 | # CIDR-IPv4-address-range hostname | ||
30 | # a single space between address and hostname | ||
31 | # use '#' for comments | ||
32 | # example: 9.9.9.0/24 Quad9 DNS | ||
33 | # | ||
34 | # | ||
35 | |||
36 | # local network addresses | ||
37 | 192.168.0.0/16 local network | ||
38 | 10.0.0.0/8 local network | ||
39 | 172.16.0.0/16 local network | ||
40 | |||
41 | # huge address ranges | ||
42 | 6.0.0.0/8 US Army | ||
43 | 7.0.0.0/8 US Army | ||
44 | 9.0.0.0/8 IBM | ||
45 | 11.0.0.0/8 US Army | ||
46 | 17.0.0.0/8 Apple | ||
47 | 19.0.0.0/8 Ford | ||
48 | 21.0.0.0/8 US Army | ||
49 | 22.0.0.0/8 US Army | ||
50 | 26.0.0.0/8 US Army | ||
51 | 28.0.0.0/8 US Army | ||
52 | 29.0.0.0/8 US Army | ||
53 | 30.0.0.0/8 US Army | ||
54 | 33.0.0.0/8 US Army | ||
55 | 48.0.0.0/8 Prudential US | ||
56 | 55.0.0.0/8 US Army | ||
57 | 56.0.0.0/8 US Postal Service | ||
58 | 214.0.0.0/8 US Army | ||
59 | 215.0.0.0/8 US Army | ||
60 | |||
61 | # whois/DNS | ||
62 | 1.1.1.0/24 Cloudflare DNS | ||
63 | 1.0.0.0/24 Cloudflare DNS | ||
64 | 8.8.4.0/24 Google DNS | ||
65 | 8.8.8.0/24 Google DNS | ||
66 | 9.9.9.0/24 Quad9 DNS | ||
67 | 45.90.28.0/22 NextDNS | ||
68 | 149.112.112.0/24 Quad9 DNS | ||
69 | 149.112.120.0/21 CIRA DNS Canada | ||
70 | 176.103.128.0/19 Adguard DNS | ||
71 | 185.228.168.0/24 Cleanbrowsing DNS | ||
72 | 193.0.0.0/21 whois.ripe.net Netherlands | ||
73 | 199.5.26.0/24 whois.arin.net US | ||
74 | 199.15.80.0/21 whois.publicinterestregistry.net Canada | ||
75 | 199.15.88.0/24 whois.publicinterestregistry.net Canada | ||
76 | 199.71.0.0/24 whois.arin.net US | ||
77 | 199.212.0.0/24 whois.arin.net US | ||
78 | 200.3.12.0/22 whois.lacnic.net Uruguay | ||
79 | 201.159.220.0/22 whois.lacnic.net Ecuador | ||
80 | |||
81 | # some popular websites | ||
82 | 31.13.24.0/21 Facebook | ||
83 | 31.13.64.0/18 Facebook | ||
84 | 64.63.0.0/18 Twitter | ||
85 | 69.171.224.0/19 Facebook | ||
86 | 104.244.40.0/21 Twitter | ||
87 | 129.134.0.0/16 Facebook | ||
88 | 140.82.112.0/20 GitHub | ||
89 | 157.240.0.0/16 Facebook | ||
90 | 185.199.108.0/22 GitHub | ||
91 | 188.64.224.0/21 Twitter | ||
92 | 192.0.64.0/18 Wordpress | ||
93 | 199.16.156.0/22 Twitter | ||
94 | 199.59.148.0/22 Twitter | ||
95 | 208.80.152.0/22 Wikipedia | ||
96 | |||
97 | # Akamai | ||
98 | 23.0.0.0/12 Akamai | ||
99 | 23.32.0.0/11 Akamai | ||
100 | 23.64.0.0/14 Akamai | ||
101 | 23.72.0.0/13 Akamai | ||
102 | 23.192.0.0/11 Akamai | ||
103 | 72.246.0.0/15 Akamai | ||
104 | 96.6.0.0/15 Akamai | ||
105 | 96.16.0.0/15 Akamai | ||
106 | 104.64.0.0/10 Akamai | ||
107 | 184.24.0.0/13 Akamai | ||
108 | 184.50.0.0/15 Akamai | ||
109 | 184.84.0.0/14 Akamai | ||
110 | |||
111 | # Fastly | ||
112 | 23.235.32.0/20 Fastly | ||
113 | 43.249.72.0/22 Fastly | ||
114 | 103.244.50.0/24 Fastly | ||
115 | 103.245.222.0/23 Fastly | ||
116 | 103.245.224.0/24 Fastly | ||
117 | 104.156.80.0/20 Fastly | ||
118 | 146.75.0.0/16 Fastly | ||
119 | 151.101.0.0/16 Fastly | ||
120 | 157.52.64.0/18 Fastly | ||
121 | 167.82.0.0/17 Fastly | ||
122 | 167.82.128.0/20 Fastly | ||
123 | 167.82.160.0/20 Fastly | ||
124 | 167.82.224.0/20 Fastly | ||
125 | 172.111.64.0/18 Fastly | ||
126 | 185.31.16.0/22 Fastly | ||
127 | 199.27.72.0/21 Fastly | ||
128 | 199.232.0.0/16 Fastly | ||
129 | |||
130 | # MCI/Verizon | ||
131 | 72.21.80.0/20 MCI | ||
132 | 108.29.0.0/16 MCI | ||
133 | 108.30.0.0/16 MCI | ||
134 | 108.31.0.0/16 MCI | ||
135 | 108.3.128.0/17 MCI | ||
136 | 108.32.0.0/17 MCI | ||
137 | 108.32.128.0/17 MCI | ||
138 | 108.33.254.0/24 MCI | ||
139 | 108.33.255.0/24 MCI | ||
140 | 108.34.128.0/17 MCI | ||
141 | 108.34.16.0/20 MCI | ||
142 | 108.34.32.0/19 MCI | ||
143 | 108.34.64.0/18 MCI | ||
144 | 108.35.0.0/16 MCI | ||
145 | 108.36.0.0/16 MCI | ||
146 | 108.3.64.0/18 MCI | ||
147 | 108.37.0.0/16 MCI | ||
148 | 108.39.0.0/17 MCI | ||
149 | 108.39.128.0/17 MCI | ||
150 | 108.40.0.0/17 MCI | ||
151 | 108.4.0.0/17 MCI | ||
152 | 108.41.0.0/16 MCI | ||
153 | 108.4.128.0/19 MCI | ||
154 | 108.4.160.0/19 MCI | ||
155 | 108.4.192.0/18 MCI | ||
156 | 108.44.0.0/18 MCI | ||
157 | 108.44.128.0/17 MCI | ||
158 | 108.44.64.0/18 MCI | ||
159 | 108.45.0.0/16 MCI | ||
160 | 108.46.0.0/16 MCI | ||
161 | 192.229.128.0/17 MCI | ||
162 | |||
163 | # Microsoft | ||
164 | 40.76.0.0/14 Microsoft | ||
165 | 40.96.0.0/12 Microsoft | ||
166 | 40.112.0.0/13 Microsoft | ||
167 | 40.124.0.0/16 Microsoft | ||
168 | 40.74.0.0/15 Microsoft | ||
169 | 40.80.0.0/12 Microsoft | ||
170 | 40.120.0.0/14 Microsoft | ||
171 | 40.125.0.0/17 Microsoft | ||
172 | 52.145.0.0/16 Microsoft | ||
173 | 52.148.0.0/14 Microsoft | ||
174 | 52.152.0.0/13 Microsoft | ||
175 | 52.146.0.0/15 Microsoft | ||
176 | 52.160.0.0/11 Microsoft | ||
177 | |||
178 | # Yahoo | ||
179 | 63.250.192.0/19 Yahoo | ||
180 | 66.196.64.0/18 Yahoo | ||
181 | 67.195.0.0/16 Yahoo | ||
182 | 69.147.64.0/18 Yahoo | ||
183 | 76.13.0.0/16 Yahoo | ||
184 | 98.136.0.0/14 Yahoo | ||
185 | 206.190.32.0/19 Yahoo | ||
186 | 209.73.160.0/19 Yahoo | ||
187 | 209.191.64.0/18 Yahoo | ||
188 | 216.115.96.0/20 Yahoo | ||
189 | |||
190 | |||
191 | # from https://support.google.com/a/answer/10026322?hl=en | ||
192 | # last update January 5, 2022 | ||
193 | 8.34.208.0/20 Google | ||
194 | 8.35.192.0/20 Google | ||
195 | 23.236.48.0/20 Google | ||
196 | 23.251.128.0/19 Google | ||
197 | 34.64.0.0/10 Google | ||
198 | 34.128.0.0/10 Google | ||
199 | 35.184.0.0/13 Google | ||
200 | 35.192.0.0/14 Google | ||
201 | 35.196.0.0/15 Google | ||
202 | 35.198.0.0/16 Google | ||
203 | 35.199.0.0/17 Google | ||
204 | 35.199.128.0/18 Google | ||
205 | 35.200.0.0/13 Google | ||
206 | 35.208.0.0/12 Google | ||
207 | 35.224.0.0/12 Google | ||
208 | 35.240.0.0/13 Google | ||
209 | 64.15.112.0/20 Google | ||
210 | 64.233.160.0/19 Google | ||
211 | 66.102.0.0/20 Google | ||
212 | 66.249.64.0/19 Google | ||
213 | 70.32.128.0/19 Google | ||
214 | 72.14.192.0/18 Google | ||
215 | 74.114.24.0/21 Google | ||
216 | 74.125.0.0/16 Google | ||
217 | 104.154.0.0/15 Google | ||
218 | 104.196.0.0/14 Google | ||
219 | 104.237.160.0/19 Google | ||
220 | 107.167.160.0/19 Google | ||
221 | 107.178.192.0/18 Google | ||
222 | 108.59.80.0/20 Google | ||
223 | 108.170.192.0/18 Google | ||
224 | 108.177.0.0/17 Google | ||
225 | 130.211.0.0/16 Google | ||
226 | 136.112.0.0/12 Google | ||
227 | 142.250.0.0/15 Google | ||
228 | 146.148.0.0/17 Google | ||
229 | 162.216.148.0/22 Google | ||
230 | 162.222.176.0/21 Google | ||
231 | 172.110.32.0/21 Google | ||
232 | 172.217.0.0/16 Google | ||
233 | 172.253.0.0/16 Google | ||
234 | 173.194.0.0/16 Google | ||
235 | 173.255.112.0/20 Google | ||
236 | 192.158.28.0/22 Google | ||
237 | 192.178.0.0/15 Google | ||
238 | 193.186.4.0/24 Google | ||
239 | 199.36.154.0/23 Google | ||
240 | 199.36.156.0/24 Google | ||
241 | 199.192.112.0/22 Google | ||
242 | 199.223.232.0/21 Google | ||
243 | 207.223.160.0/20 Google | ||
244 | 208.65.152.0/22 Google | ||
245 | 208.68.108.0/22 Google | ||
246 | 208.81.188.0/22 Google | ||
247 | 208.117.224.0/19 Google | ||
248 | 209.85.128.0/17 Google | ||
249 | 216.58.192.0/19 Google | ||
250 | 216.73.80.0/20 Google | ||
251 | 216.239.32.0/19 Google | ||
252 | |||
253 | |||
254 | #Cloudflare | ||
255 | # from https://www.cloudflare.com/ips/ | ||
256 | # update April 8, 2021 | ||
257 | 103.21.244.0/22 Cloudflare | ||
258 | 103.22.200.0/22 Cloudflare | ||
259 | 103.31.4.0/22 Cloudflare | ||
260 | 104.16.0.0/13 Cloudflare | ||
261 | 104.24.0.0/14 Cloudflare | ||
262 | 108.162.192.0/18 Cloudflare | ||
263 | 131.0.72.0/22 Cloudflare | ||
264 | 141.101.64.0/18 Cloudflare | ||
265 | 162.158.0.0/15 Cloudflare | ||
266 | 172.64.0.0/13 Cloudflare | ||
267 | 173.245.48.0/20 Cloudflare | ||
268 | 188.114.96.0/20 Cloudflare | ||
269 | 190.93.240.0/20 Cloudflare | ||
270 | 197.234.240.0/22 Cloudflare | ||
271 | 198.41.128.0/17 Cloudflare | ||
272 | |||
273 | # Amazon | ||
274 | # from https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html | ||
275 | # update January 6, 2022 | ||
276 | 3.0.0.0/15 Amazon | ||
277 | 3.2.0.0/24 Amazon | ||
278 | 3.2.2.0/24 Amazon | ||
279 | 3.2.3.0/24 Amazon | ||
280 | 3.2.8.0/21 Amazon | ||
281 | 3.3.0.0/23 Amazon | ||
282 | 3.3.5.0/24 Amazon | ||
283 | 3.3.6.0/23 Amazon | ||
284 | 3.3.8.0/21 Amazon | ||
285 | 3.3.16.0/21 Amazon | ||
286 | 3.3.24.0/22 Amazon | ||
287 | 3.3.28.0/22 Amazon | ||
288 | 3.4.0.0/24 Amazon | ||
289 | 3.4.1.0/24 Amazon | ||
290 | 3.4.2.0/24 Amazon | ||
291 | 3.4.3.0/24 Amazon | ||
292 | 3.4.4.0/24 Amazon | ||
293 | 3.4.6.0/24 Amazon | ||
294 | 3.4.7.0/24 Amazon | ||
295 | 3.4.16.0/21 Amazon | ||
296 | 3.4.24.0/21 Amazon | ||
297 | 3.5.0.0/19 Amazon | ||
298 | 3.5.32.0/22 Amazon | ||
299 | 3.5.36.0/22 Amazon | ||
300 | 3.5.40.0/22 Amazon | ||
301 | 3.5.44.0/22 Amazon | ||
302 | 3.5.48.0/22 Amazon | ||
303 | 3.5.52.0/22 Amazon | ||
304 | 3.5.64.0/21 Amazon | ||
305 | 3.5.72.0/23 Amazon | ||
306 | 3.5.76.0/22 Amazon | ||
307 | 3.5.80.0/21 Amazon | ||
308 | 3.5.128.0/22 Amazon | ||
309 | 3.5.132.0/23 Amazon | ||
310 | 3.5.134.0/23 Amazon | ||
311 | 3.5.136.0/22 Amazon | ||
312 | 3.5.140.0/22 Amazon | ||
313 | 3.5.144.0/23 Amazon | ||
314 | 3.5.146.0/23 Amazon | ||
315 | 3.5.148.0/22 Amazon | ||
316 | 3.5.152.0/21 Amazon | ||
317 | 3.5.160.0/22 Amazon | ||
318 | 3.5.164.0/22 Amazon | ||
319 | 3.5.168.0/23 Amazon | ||
320 | 3.5.208.0/22 Amazon | ||
321 | 3.5.212.0/23 Amazon | ||
322 | 3.5.216.0/22 Amazon | ||
323 | 3.5.220.0/22 Amazon | ||
324 | 3.5.224.0/22 Amazon | ||
325 | 3.5.228.0/22 Amazon | ||
326 | 3.5.232.0/22 Amazon | ||
327 | 3.5.236.0/22 Amazon | ||
328 | 3.5.240.0/22 Amazon | ||
329 | 3.5.244.0/22 Amazon | ||
330 | 3.5.248.0/22 Amazon | ||
331 | 3.5.252.0/22 Amazon | ||
332 | 3.6.0.0/15 Amazon | ||
333 | 3.8.0.0/14 Amazon | ||
334 | 3.12.0.0/16 Amazon | ||
335 | 3.13.0.0/16 Amazon | ||
336 | 3.14.0.0/15 Amazon | ||
337 | 3.16.0.0/14 Amazon | ||
338 | 3.20.0.0/14 Amazon | ||
339 | 3.24.0.0/14 Amazon | ||
340 | 3.28.0.0/15 Amazon | ||
341 | 3.30.0.0/15 Amazon | ||
342 | 3.32.0.0/16 Amazon | ||
343 | 3.33.34.0/24 Amazon | ||
344 | 3.33.35.0/24 Amazon | ||
345 | 3.33.128.0/17 Amazon | ||
346 | 3.34.0.0/15 Amazon | ||
347 | 3.36.0.0/14 Amazon | ||
348 | 3.48.0.0/12 Amazon | ||
349 | 3.64.0.0/12 Amazon | ||
350 | 3.80.0.0/12 Amazon | ||
351 | 3.96.0.0/15 Amazon | ||
352 | 3.98.0.0/15 Amazon | ||
353 | 3.100.0.0/16 Amazon | ||
354 | 3.101.0.0/16 Amazon | ||
355 | 3.104.0.0/14 Amazon | ||
356 | 3.108.0.0/14 Amazon | ||
357 | 3.112.0.0/14 Amazon | ||
358 | 3.116.0.0/14 Amazon | ||
359 | 3.120.0.0/14 Amazon | ||
360 | 3.124.0.0/14 Amazon | ||
361 | 3.128.0.0/15 Amazon | ||
362 | 3.130.0.0/16 Amazon | ||
363 | 3.131.0.0/16 Amazon | ||
364 | 3.132.0.0/14 Amazon | ||
365 | 3.136.0.0/13 Amazon | ||
366 | 3.144.0.0/13 Amazon | ||
367 | 3.152.0.0/13 Amazon | ||
368 | 3.208.0.0/12 Amazon | ||
369 | 3.224.0.0/12 Amazon | ||
370 | 3.240.0.0/13 Amazon | ||
371 | 3.248.0.0/13 Amazon | ||
372 | 13.32.0.0/15 Amazon | ||
373 | 13.34.0.128/27 Amazon | ||
374 | 13.34.0.160/27 Amazon | ||
375 | 13.34.1.0/27 Amazon | ||
376 | 13.34.1.32/27 Amazon | ||
377 | 13.34.3.128/27 Amazon | ||
378 | 13.34.3.160/27 Amazon | ||
379 | 13.34.3.192/27 Amazon | ||
380 | 13.34.3.224/27 Amazon | ||
381 | 13.34.4.64/27 Amazon | ||
382 | 13.34.4.96/27 Amazon | ||
383 | 13.34.5.12/32 Amazon | ||
384 | 13.34.5.13/32 Amazon | ||
385 | 13.34.5.14/32 Amazon | ||
386 | 13.34.5.15/32 Amazon | ||
387 | 13.34.5.16/32 Amazon | ||
388 | 13.34.5.17/32 Amazon | ||
389 | 13.34.5.44/32 Amazon | ||
390 | 13.34.5.45/32 Amazon | ||
391 | 13.34.5.46/32 Amazon | ||
392 | 13.34.5.47/32 Amazon | ||
393 | 13.34.5.48/32 Amazon | ||
394 | 13.34.5.49/32 Amazon | ||
395 | 13.34.5.78/32 Amazon | ||
396 | 13.34.5.79/32 Amazon | ||
397 | 13.34.5.80/32 Amazon | ||
398 | 13.34.5.81/32 Amazon | ||
399 | 13.34.5.110/32 Amazon | ||
400 | 13.34.5.111/32 Amazon | ||
401 | 13.34.5.112/32 Amazon | ||
402 | 13.34.5.113/32 Amazon | ||
403 | 13.34.5.128/27 Amazon | ||
404 | 13.34.5.160/27 Amazon | ||
405 | 13.34.5.192/27 Amazon | ||
406 | 13.34.5.224/27 Amazon | ||
407 | 13.34.6.192/27 Amazon | ||
408 | 13.34.6.224/27 Amazon | ||
409 | 13.34.7.64/27 Amazon | ||
410 | 13.34.7.96/27 Amazon | ||
411 | 13.34.8.64/27 Amazon | ||
412 | 13.34.8.96/27 Amazon | ||
413 | 13.34.9.0/27 Amazon | ||
414 | 13.34.9.32/27 Amazon | ||
415 | 13.34.10.128/27 Amazon | ||
416 | 13.34.10.160/27 Amazon | ||
417 | 13.34.11.0/27 Amazon | ||
418 | 13.34.11.32/27 Amazon | ||
419 | 13.34.11.128/27 Amazon | ||
420 | 13.34.11.160/27 Amazon | ||
421 | 13.34.12.64/27 Amazon | ||
422 | 13.34.12.96/27 Amazon | ||
423 | 13.34.12.192/27 Amazon | ||
424 | 13.34.12.242/32 Amazon | ||
425 | 13.34.12.243/32 Amazon | ||
426 | 13.34.12.244/32 Amazon | ||
427 | 13.34.12.245/32 Amazon | ||
428 | 13.34.13.18/32 Amazon | ||
429 | 13.34.13.19/32 Amazon | ||
430 | 13.34.13.20/32 Amazon | ||
431 | 13.34.13.21/32 Amazon | ||
432 | 13.34.13.50/32 Amazon | ||
433 | 13.34.13.51/32 Amazon | ||
434 | 13.34.13.52/32 Amazon | ||
435 | 13.34.13.53/32 Amazon | ||
436 | 13.34.14.128/27 Amazon | ||
437 | 13.34.14.160/27 Amazon | ||
438 | 13.34.14.192/27 Amazon | ||
439 | 13.34.14.224/27 Amazon | ||
440 | 13.34.15.0/27 Amazon | ||
441 | 13.34.15.32/27 Amazon | ||
442 | 13.34.16.64/27 Amazon | ||
443 | 13.34.16.96/27 Amazon | ||
444 | 13.34.16.192/27 Amazon | ||
445 | 13.34.17.24/29 Amazon | ||
446 | 13.34.17.64/27 Amazon | ||
447 | 13.34.17.96/27 Amazon | ||
448 | 13.34.18.192/27 Amazon | ||
449 | 13.34.18.224/27 Amazon | ||
450 | 13.34.19.192/27 Amazon | ||
451 | 13.34.19.224/27 Amazon | ||
452 | 13.34.20.0/27 Amazon | ||
453 | 13.34.20.32/27 Amazon | ||
454 | 13.34.20.64/27 Amazon | ||
455 | 13.34.20.96/27 Amazon | ||
456 | 13.34.21.64/27 Amazon | ||
457 | 13.34.21.96/27 Amazon | ||
458 | 13.34.22.88/29 Amazon | ||
459 | 13.34.22.160/27 Amazon | ||
460 | 13.34.22.192/27 Amazon | ||
461 | 13.34.22.224/27 Amazon | ||
462 | 13.34.23.0/27 Amazon | ||
463 | 13.34.23.32/27 Amazon | ||
464 | 13.34.23.64/27 Amazon | ||
465 | 13.34.23.96/27 Amazon | ||
466 | 13.34.23.128/27 Amazon | ||
467 | 13.34.23.160/27 Amazon | ||
468 | 13.34.23.192/27 Amazon | ||
469 | 13.34.23.224/27 Amazon | ||
470 | 13.34.24.64/27 Amazon | ||
471 | 13.34.24.96/27 Amazon | ||
472 | 13.34.24.128/27 Amazon | ||
473 | 13.34.24.160/27 Amazon | ||
474 | 13.34.24.192/27 Amazon | ||
475 | 13.34.25.64/27 Amazon | ||
476 | 13.34.25.96/27 Amazon | ||
477 | 13.34.25.128/27 Amazon | ||
478 | 13.34.25.160/27 Amazon | ||
479 | 13.34.25.192/27 Amazon | ||
480 | 13.34.25.248/29 Amazon | ||
481 | 13.34.26.0/27 Amazon | ||
482 | 13.34.26.32/27 Amazon | ||
483 | 13.34.26.64/27 Amazon | ||
484 | 13.34.26.96/27 Amazon | ||
485 | 13.34.26.128/27 Amazon | ||
486 | 13.34.26.160/27 Amazon | ||
487 | 13.34.26.192/27 Amazon | ||
488 | 13.34.26.224/27 Amazon | ||
489 | 13.34.27.16/32 Amazon | ||
490 | 13.34.27.17/32 Amazon | ||
491 | 13.34.27.32/27 Amazon | ||
492 | 13.34.27.64/27 Amazon | ||
493 | 13.34.27.96/27 Amazon | ||
494 | 13.34.27.128/27 Amazon | ||
495 | 13.34.28.0/27 Amazon | ||
496 | 13.34.28.32/27 Amazon | ||
497 | 13.34.28.64/27 Amazon | ||
498 | 13.34.28.96/27 Amazon | ||
499 | 13.34.28.128/27 Amazon | ||
500 | 13.34.28.160/27 Amazon | ||
501 | 13.34.28.192/27 Amazon | ||
502 | 13.34.28.224/27 Amazon | ||
503 | 13.34.29.0/27 Amazon | ||
504 | 13.34.29.32/27 Amazon | ||
505 | 13.34.29.64/27 Amazon | ||
506 | 13.34.29.96/27 Amazon | ||
507 | 13.34.29.128/27 Amazon | ||
508 | 13.34.29.160/27 Amazon | ||
509 | 13.34.29.192/27 Amazon | ||
510 | 13.34.29.224/27 Amazon | ||
511 | 13.34.30.0/27 Amazon | ||
512 | 13.34.30.32/27 Amazon | ||
513 | 13.34.30.64/27 Amazon | ||
514 | 13.34.30.96/27 Amazon | ||
515 | 13.34.30.128/27 Amazon | ||
516 | 13.34.30.160/27 Amazon | ||
517 | 13.34.30.192/27 Amazon | ||
518 | 13.34.30.224/27 Amazon | ||
519 | 13.34.31.0/27 Amazon | ||
520 | 13.34.31.32/27 Amazon | ||
521 | 13.34.31.64/27 Amazon | ||
522 | 13.34.31.96/27 Amazon | ||
523 | 13.34.31.128/27 Amazon | ||
524 | 13.34.31.160/27 Amazon | ||
525 | 13.34.31.192/27 Amazon | ||
526 | 13.34.31.224/27 Amazon | ||
527 | 13.34.32.0/27 Amazon | ||
528 | 13.34.32.32/27 Amazon | ||
529 | 13.34.32.64/27 Amazon | ||
530 | 13.34.32.96/27 Amazon | ||
531 | 13.34.32.128/27 Amazon | ||
532 | 13.34.32.160/27 Amazon | ||
533 | 13.34.33.0/27 Amazon | ||
534 | 13.34.33.32/27 Amazon | ||
535 | 13.34.33.64/27 Amazon | ||
536 | 13.34.33.96/27 Amazon | ||
537 | 13.34.33.128/27 Amazon | ||
538 | 13.34.33.160/27 Amazon | ||
539 | 13.34.33.192/27 Amazon | ||
540 | 13.34.33.224/27 Amazon | ||
541 | 13.34.34.0/27 Amazon | ||
542 | 13.34.34.32/27 Amazon | ||
543 | 13.34.34.64/27 Amazon | ||
544 | 13.34.34.96/27 Amazon | ||
545 | 13.34.34.128/27 Amazon | ||
546 | 13.34.34.160/27 Amazon | ||
547 | 13.34.34.192/27 Amazon | ||
548 | 13.34.34.224/27 Amazon | ||
549 | 13.34.35.0/27 Amazon | ||
550 | 13.34.35.32/27 Amazon | ||
551 | 13.34.35.64/27 Amazon | ||
552 | 13.34.35.96/27 Amazon | ||
553 | 13.34.35.128/27 Amazon | ||
554 | 13.34.35.160/27 Amazon | ||
555 | 13.34.35.192/27 Amazon | ||
556 | 13.34.35.224/27 Amazon | ||
557 | 13.34.36.0/27 Amazon | ||
558 | 13.34.36.32/27 Amazon | ||
559 | 13.34.36.64/27 Amazon | ||
560 | 13.34.36.96/27 Amazon | ||
561 | 13.34.36.128/27 Amazon | ||
562 | 13.34.36.160/27 Amazon | ||
563 | 13.34.36.192/27 Amazon | ||
564 | 13.34.36.224/27 Amazon | ||
565 | 13.34.37.0/27 Amazon | ||
566 | 13.34.37.32/27 Amazon | ||
567 | 13.34.37.64/27 Amazon | ||
568 | 13.34.37.96/27 Amazon | ||
569 | 13.34.37.128/27 Amazon | ||
570 | 13.34.37.160/27 Amazon | ||
571 | 13.34.37.192/27 Amazon | ||
572 | 13.34.37.224/27 Amazon | ||
573 | 13.34.38.0/27 Amazon | ||
574 | 13.34.38.32/27 Amazon | ||
575 | 13.34.38.64/27 Amazon | ||
576 | 13.34.38.96/27 Amazon | ||
577 | 13.34.38.128/27 Amazon | ||
578 | 13.34.38.160/27 Amazon | ||
579 | 13.34.39.0/27 Amazon | ||
580 | 13.34.39.32/27 Amazon | ||
581 | 13.34.39.64/27 Amazon | ||
582 | 13.34.39.96/27 Amazon | ||
583 | 13.34.39.128/27 Amazon | ||
584 | 13.34.39.160/27 Amazon | ||
585 | 13.34.39.192/27 Amazon | ||
586 | 13.34.39.224/27 Amazon | ||
587 | 13.34.40.0/27 Amazon | ||
588 | 13.34.40.32/27 Amazon | ||
589 | 13.34.40.64/27 Amazon | ||
590 | 13.34.40.96/27 Amazon | ||
591 | 13.34.40.128/27 Amazon | ||
592 | 13.34.40.160/27 Amazon | ||
593 | 13.34.40.192/27 Amazon | ||
594 | 13.34.40.224/27 Amazon | ||
595 | 13.34.41.0/27 Amazon | ||
596 | 13.34.41.32/27 Amazon | ||
597 | 13.34.41.64/27 Amazon | ||
598 | 13.34.41.96/27 Amazon | ||
599 | 13.34.41.128/27 Amazon | ||
600 | 13.34.41.160/27 Amazon | ||
601 | 13.34.41.192/27 Amazon | ||
602 | 13.34.41.224/27 Amazon | ||
603 | 13.34.42.0/27 Amazon | ||
604 | 13.34.42.32/27 Amazon | ||
605 | 13.34.42.64/27 Amazon | ||
606 | 13.34.42.96/27 Amazon | ||
607 | 13.34.42.128/27 Amazon | ||
608 | 13.34.42.160/27 Amazon | ||
609 | 13.34.42.192/27 Amazon | ||
610 | 13.34.42.224/27 Amazon | ||
611 | 13.34.43.0/27 Amazon | ||
612 | 13.34.43.32/27 Amazon | ||
613 | 13.34.43.64/27 Amazon | ||
614 | 13.34.43.96/27 Amazon | ||
615 | 13.34.43.128/27 Amazon | ||
616 | 13.34.43.160/27 Amazon | ||
617 | 13.34.43.192/27 Amazon | ||
618 | 13.34.43.224/27 Amazon | ||
619 | 13.34.44.0/27 Amazon | ||
620 | 13.34.44.32/27 Amazon | ||
621 | 13.34.44.64/27 Amazon | ||
622 | 13.34.44.96/27 Amazon | ||
623 | 13.34.44.128/27 Amazon | ||
624 | 13.34.44.160/27 Amazon | ||
625 | 13.34.44.192/27 Amazon | ||
626 | 13.34.44.224/27 Amazon | ||
627 | 13.34.45.0/27 Amazon | ||
628 | 13.34.45.32/27 Amazon | ||
629 | 13.34.45.64/27 Amazon | ||
630 | 13.34.45.96/27 Amazon | ||
631 | 13.34.45.128/27 Amazon | ||
632 | 13.34.45.160/27 Amazon | ||
633 | 13.34.45.192/27 Amazon | ||
634 | 13.34.45.224/27 Amazon | ||
635 | 13.34.46.0/27 Amazon | ||
636 | 13.34.46.32/27 Amazon | ||
637 | 13.34.46.64/27 Amazon | ||
638 | 13.34.46.96/27 Amazon | ||
639 | 13.34.46.128/27 Amazon | ||
640 | 13.34.46.160/27 Amazon | ||
641 | 13.34.46.192/27 Amazon | ||
642 | 13.34.46.224/27 Amazon | ||
643 | 13.34.47.0/27 Amazon | ||
644 | 13.34.47.32/27 Amazon | ||
645 | 13.34.47.64/27 Amazon | ||
646 | 13.34.47.96/27 Amazon | ||
647 | 13.34.47.128/27 Amazon | ||
648 | 13.34.47.160/27 Amazon | ||
649 | 13.34.47.192/27 Amazon | ||
650 | 13.34.47.224/27 Amazon | ||
651 | 13.34.48.0/27 Amazon | ||
652 | 13.34.48.32/27 Amazon | ||
653 | 13.34.48.64/27 Amazon | ||
654 | 13.34.48.96/27 Amazon | ||
655 | 13.34.48.128/27 Amazon | ||
656 | 13.34.48.160/27 Amazon | ||
657 | 13.34.48.192/27 Amazon | ||
658 | 13.34.48.224/27 Amazon | ||
659 | 13.34.49.0/27 Amazon | ||
660 | 13.34.49.32/27 Amazon | ||
661 | 13.34.49.64/27 Amazon | ||
662 | 13.34.49.96/27 Amazon | ||
663 | 13.34.49.128/27 Amazon | ||
664 | 13.34.49.160/27 Amazon | ||
665 | 13.34.49.192/27 Amazon | ||
666 | 13.34.49.224/27 Amazon | ||
667 | 13.34.50.0/27 Amazon | ||
668 | 13.34.50.32/27 Amazon | ||
669 | 13.34.50.64/27 Amazon | ||
670 | 13.34.50.96/27 Amazon | ||
671 | 13.34.50.128/27 Amazon | ||
672 | 13.34.50.160/27 Amazon | ||
673 | 13.34.50.192/27 Amazon | ||
674 | 13.34.50.224/27 Amazon | ||
675 | 13.34.51.0/27 Amazon | ||
676 | 13.34.51.32/27 Amazon | ||
677 | 13.34.51.64/27 Amazon | ||
678 | 13.34.51.96/27 Amazon | ||
679 | 13.34.51.128/27 Amazon | ||
680 | 13.34.51.160/27 Amazon | ||
681 | 13.34.51.192/27 Amazon | ||
682 | 13.34.51.224/27 Amazon | ||
683 | 13.34.52.0/27 Amazon | ||
684 | 13.34.52.32/27 Amazon | ||
685 | 13.34.52.64/27 Amazon | ||
686 | 13.34.52.96/27 Amazon | ||
687 | 13.34.52.128/27 Amazon | ||
688 | 13.34.52.160/27 Amazon | ||
689 | 13.34.52.192/27 Amazon | ||
690 | 13.34.52.224/27 Amazon | ||
691 | 13.34.53.0/27 Amazon | ||
692 | 13.34.53.32/27 Amazon | ||
693 | 13.34.53.64/27 Amazon | ||
694 | 13.34.53.96/27 Amazon | ||
695 | 13.34.53.128/27 Amazon | ||
696 | 13.34.53.160/27 Amazon | ||
697 | 13.34.53.192/27 Amazon | ||
698 | 13.34.53.224/27 Amazon | ||
699 | 13.34.54.0/27 Amazon | ||
700 | 13.34.54.32/27 Amazon | ||
701 | 13.34.54.64/27 Amazon | ||
702 | 13.34.54.96/27 Amazon | ||
703 | 13.34.54.128/27 Amazon | ||
704 | 13.34.54.160/27 Amazon | ||
705 | 13.34.54.192/27 Amazon | ||
706 | 13.34.54.224/27 Amazon | ||
707 | 13.34.55.0/27 Amazon | ||
708 | 13.34.55.32/27 Amazon | ||
709 | 13.34.55.64/27 Amazon | ||
710 | 13.34.55.96/27 Amazon | ||
711 | 13.34.55.128/27 Amazon | ||
712 | 13.34.55.160/27 Amazon | ||
713 | 13.34.55.192/27 Amazon | ||
714 | 13.34.55.224/27 Amazon | ||
715 | 13.34.56.0/27 Amazon | ||
716 | 13.34.56.32/27 Amazon | ||
717 | 13.34.56.64/27 Amazon | ||
718 | 13.34.56.96/27 Amazon | ||
719 | 13.34.56.128/27 Amazon | ||
720 | 13.34.56.160/27 Amazon | ||
721 | 13.34.56.192/27 Amazon | ||
722 | 13.34.56.224/27 Amazon | ||
723 | 13.34.57.0/27 Amazon | ||
724 | 13.34.57.32/27 Amazon | ||
725 | 13.34.57.64/27 Amazon | ||
726 | 13.34.57.96/27 Amazon | ||
727 | 13.34.57.128/27 Amazon | ||
728 | 13.34.57.160/27 Amazon | ||
729 | 13.34.57.192/27 Amazon | ||
730 | 13.34.57.224/27 Amazon | ||
731 | 13.34.58.0/27 Amazon | ||
732 | 13.34.58.32/27 Amazon | ||
733 | 13.34.58.64/27 Amazon | ||
734 | 13.34.58.96/27 Amazon | ||
735 | 13.34.58.128/27 Amazon | ||
736 | 13.34.58.160/27 Amazon | ||
737 | 13.34.58.192/27 Amazon | ||
738 | 13.34.58.224/27 Amazon | ||
739 | 13.34.59.0/27 Amazon | ||
740 | 13.34.59.32/27 Amazon | ||
741 | 13.34.59.64/27 Amazon | ||
742 | 13.34.59.96/27 Amazon | ||
743 | 13.34.59.128/27 Amazon | ||
744 | 13.34.59.160/27 Amazon | ||
745 | 13.34.59.192/27 Amazon | ||
746 | 13.34.59.224/27 Amazon | ||
747 | 13.34.60.0/27 Amazon | ||
748 | 13.34.60.32/27 Amazon | ||
749 | 13.34.60.64/27 Amazon | ||
750 | 13.34.60.96/27 Amazon | ||
751 | 13.34.60.128/27 Amazon | ||
752 | 13.34.60.160/27 Amazon | ||
753 | 13.34.60.192/27 Amazon | ||
754 | 13.34.60.224/27 Amazon | ||
755 | 13.34.61.0/27 Amazon | ||
756 | 13.34.61.32/27 Amazon | ||
757 | 13.34.61.64/27 Amazon | ||
758 | 13.34.61.96/27 Amazon | ||
759 | 13.34.61.128/27 Amazon | ||
760 | 13.34.61.160/27 Amazon | ||
761 | 13.34.61.192/27 Amazon | ||
762 | 13.34.61.224/27 Amazon | ||
763 | 13.34.62.0/27 Amazon | ||
764 | 13.34.62.32/27 Amazon | ||
765 | 13.34.62.128/27 Amazon | ||
766 | 13.34.62.160/27 Amazon | ||
767 | 13.34.62.192/27 Amazon | ||
768 | 13.34.62.224/27 Amazon | ||
769 | 13.34.63.0/27 Amazon | ||
770 | 13.34.63.32/27 Amazon | ||
771 | 13.34.63.64/27 Amazon | ||
772 | 13.34.63.96/27 Amazon | ||
773 | 13.34.63.128/27 Amazon | ||
774 | 13.34.63.160/27 Amazon | ||
775 | 13.35.0.0/16 Amazon | ||
776 | 13.36.0.0/14 Amazon | ||
777 | 13.40.0.0/14 Amazon | ||
778 | 13.44.0.0/14 Amazon | ||
779 | 13.48.0.0/15 Amazon | ||
780 | 13.50.0.0/16 Amazon | ||
781 | 13.51.0.0/16 Amazon | ||
782 | 13.52.0.0/16 Amazon | ||
783 | 13.53.0.0/16 Amazon | ||
784 | 13.54.0.0/15 Amazon | ||
785 | 13.56.0.0/16 Amazon | ||
786 | 13.57.0.0/16 Amazon | ||
787 | 13.58.0.0/15 Amazon | ||
788 | 13.112.0.0/14 Amazon | ||
789 | 13.124.0.0/16 Amazon | ||
790 | 13.125.0.0/16 Amazon | ||
791 | 13.126.0.0/15 Amazon | ||
792 | 13.200.0.0/13 Amazon | ||
793 | 13.208.0.0/16 Amazon | ||
794 | 13.209.0.0/16 Amazon | ||
795 | 13.210.0.0/15 Amazon | ||
796 | 13.212.0.0/15 Amazon | ||
797 | 13.214.0.0/15 Amazon | ||
798 | 13.224.0.0/14 Amazon | ||
799 | 13.228.0.0/15 Amazon | ||
800 | 13.230.0.0/15 Amazon | ||
801 | 13.232.0.0/14 Amazon | ||
802 | 13.236.0.0/14 Amazon | ||
803 | 13.244.0.0/15 Amazon | ||
804 | 13.246.0.0/16 Amazon | ||
805 | 13.247.0.0/16 Amazon | ||
806 | 13.248.0.0/20 Amazon | ||
807 | 13.248.16.0/21 Amazon | ||
808 | 13.248.24.0/22 Amazon | ||
809 | 13.248.28.0/22 Amazon | ||
810 | 13.248.32.0/20 Amazon | ||
811 | 13.248.48.0/21 Amazon | ||
812 | 13.248.56.0/22 Amazon | ||
813 | 13.248.60.0/22 Amazon | ||
814 | 13.248.64.0/24 Amazon | ||
815 | 13.248.65.0/24 Amazon | ||
816 | 13.248.66.0/24 Amazon | ||
817 | 13.248.67.0/24 Amazon | ||
818 | 13.248.68.0/24 Amazon | ||
819 | 13.248.69.0/24 Amazon | ||
820 | 13.248.70.0/24 Amazon | ||
821 | 13.248.71.0/24 Amazon | ||
822 | 13.248.96.0/24 Amazon | ||
823 | 13.248.97.0/24 Amazon | ||
824 | 13.248.98.0/24 Amazon | ||
825 | 13.248.99.0/24 Amazon | ||
826 | 13.248.100.0/24 Amazon | ||
827 | 13.248.101.0/24 Amazon | ||
828 | 13.248.102.0/24 Amazon | ||
829 | 13.248.103.0/24 Amazon | ||
830 | 13.248.104.0/24 Amazon | ||
831 | 13.248.105.0/24 Amazon | ||
832 | 13.248.106.0/24 Amazon | ||
833 | 13.248.107.0/24 Amazon | ||
834 | 13.248.108.0/24 Amazon | ||
835 | 13.248.109.0/24 Amazon | ||
836 | 13.248.111.0/24 Amazon | ||
837 | 13.248.112.0/24 Amazon | ||
838 | 13.248.113.0/24 Amazon | ||
839 | 13.248.114.0/24 Amazon | ||
840 | 13.248.115.0/24 Amazon | ||
841 | 13.248.116.0/24 Amazon | ||
842 | 13.248.117.0/24 Amazon | ||
843 | 13.248.118.0/24 Amazon | ||
844 | 13.248.119.0/24 Amazon | ||
845 | 13.248.120.0/24 Amazon | ||
846 | 13.248.121.0/24 Amazon | ||
847 | 13.248.122.0/24 Amazon | ||
848 | 13.248.123.0/24 Amazon | ||
849 | 13.248.124.0/24 Amazon | ||
850 | 13.248.125.0/24 Amazon | ||
851 | 13.248.126.0/24 Amazon | ||
852 | 13.248.127.0/24 Amazon | ||
853 | 13.248.128.0/17 Amazon | ||
854 | 13.249.0.0/16 Amazon | ||
855 | 13.250.0.0/15 Amazon | ||
856 | 15.152.0.0/16 Amazon | ||
857 | 15.156.0.0/15 Amazon | ||
858 | 15.158.0.0/16 Amazon | ||
859 | 15.160.0.0/16 Amazon | ||
860 | 15.161.0.0/16 Amazon | ||
861 | 15.164.0.0/15 Amazon | ||
862 | 15.168.0.0/16 Amazon | ||
863 | 15.177.0.0/18 Amazon | ||
864 | 15.177.64.0/23 Amazon | ||
865 | 15.177.66.0/23 Amazon | ||
866 | 15.177.68.0/23 Amazon | ||
867 | 15.177.70.0/23 Amazon | ||
868 | 15.177.72.0/24 Amazon | ||
869 | 15.177.73.0/24 Amazon | ||
870 | 15.177.74.0/24 Amazon | ||
871 | 15.177.75.0/24 Amazon | ||
872 | 15.177.76.0/24 Amazon | ||
873 | 15.177.77.0/24 Amazon | ||
874 | 15.177.78.0/24 Amazon | ||
875 | 15.177.79.0/24 Amazon | ||
876 | 15.177.80.0/24 Amazon | ||
877 | 15.177.81.0/24 Amazon | ||
878 | 15.177.82.0/24 Amazon | ||
879 | 15.177.83.0/24 Amazon | ||
880 | 15.177.84.0/24 Amazon | ||
881 | 15.177.85.0/24 Amazon | ||
882 | 15.177.86.0/24 Amazon | ||
883 | 15.177.87.0/24 Amazon | ||
884 | 15.177.88.0/24 Amazon | ||
885 | 15.177.89.0/24 Amazon | ||
886 | 15.177.90.0/24 Amazon | ||
887 | 15.177.91.0/24 Amazon | ||
888 | 15.177.92.0/24 Amazon | ||
889 | 15.181.0.0/20 Amazon | ||
890 | 15.181.16.0/20 Amazon | ||
891 | 15.181.32.0/21 Amazon | ||
892 | 15.181.40.0/21 Amazon | ||
893 | 15.181.48.0/20 Amazon | ||
894 | 15.181.64.0/20 Amazon | ||
895 | 15.181.80.0/20 Amazon | ||
896 | 15.181.96.0/20 Amazon | ||
897 | 15.181.112.0/22 Amazon | ||
898 | 15.181.116.0/22 Amazon | ||
899 | 15.181.120.0/21 Amazon | ||
900 | 15.181.128.0/20 Amazon | ||
901 | 15.181.144.0/20 Amazon | ||
902 | 15.181.160.0/20 Amazon | ||
903 | 15.181.176.0/20 Amazon | ||
904 | 15.181.192.0/19 Amazon | ||
905 | 15.181.224.0/21 Amazon | ||
906 | 15.181.232.0/21 Amazon | ||
907 | 15.181.240.0/24 Amazon | ||
908 | 15.181.241.0/24 Amazon | ||
909 | 15.181.242.0/24 Amazon | ||
910 | 15.181.243.0/24 Amazon | ||
911 | 15.181.244.0/24 Amazon | ||
912 | 15.181.245.0/24 Amazon | ||
913 | 15.181.246.0/24 Amazon | ||
914 | 15.181.247.0/24 Amazon | ||
915 | 15.181.248.0/24 Amazon | ||
916 | 15.181.249.0/24 Amazon | ||
917 | 15.181.250.0/24 Amazon | ||
918 | 15.181.251.0/24 Amazon | ||
919 | 15.181.252.0/24 Amazon | ||
920 | 15.181.253.0/24 Amazon | ||
921 | 15.181.254.0/24 Amazon | ||
922 | 15.184.0.0/16 Amazon | ||
923 | 15.185.0.0/16 Amazon | ||
924 | 15.188.0.0/16 Amazon | ||
925 | 15.191.0.0/16 Amazon | ||
926 | 15.193.0.0/19 Amazon | ||
927 | 15.197.0.0/23 Amazon | ||
928 | 15.197.2.0/24 Amazon | ||
929 | 15.197.3.0/24 Amazon | ||
930 | 15.197.4.0/22 Amazon | ||
931 | 15.197.8.0/22 Amazon | ||
932 | 15.197.12.0/22 Amazon | ||
933 | 15.197.16.0/23 Amazon | ||
934 | 15.197.18.0/23 Amazon | ||
935 | 15.197.20.0/22 Amazon | ||
936 | 15.197.24.0/22 Amazon | ||
937 | 15.197.28.0/23 Amazon | ||
938 | 15.197.30.0/23 Amazon | ||
939 | 15.197.32.0/23 Amazon | ||
940 | 15.197.128.0/17 Amazon | ||
941 | 15.200.0.0/16 Amazon | ||
942 | 15.205.0.0/16 Amazon | ||
943 | 15.206.0.0/15 Amazon | ||
944 | 15.220.0.0/20 Amazon | ||
945 | 15.220.16.0/20 Amazon | ||
946 | 15.220.220.0/23 Amazon | ||
947 | 15.220.222.0/23 Amazon | ||
948 | 15.220.224.0/23 Amazon | ||
949 | 15.220.226.0/24 Amazon | ||
950 | 15.220.250.0/23 Amazon | ||
951 | 15.220.252.0/22 Amazon | ||
952 | 15.221.0.0/24 Amazon | ||
953 | 15.221.1.0/24 Amazon | ||
954 | 15.221.2.0/24 Amazon | ||
955 | 15.221.3.0/24 Amazon | ||
956 | 15.221.4.0/23 Amazon | ||
957 | 15.221.6.0/24 Amazon | ||
958 | 15.221.7.0/24 Amazon | ||
959 | 15.221.8.0/21 Amazon | ||
960 | 15.221.16.0/22 Amazon | ||
961 | 15.221.20.0/22 Amazon | ||
962 | 15.221.24.0/21 Amazon | ||
963 | 15.221.33.0/24 Amazon | ||
964 | 15.221.34.0/24 Amazon | ||
965 | 15.221.35.0/24 Amazon | ||
966 | 15.221.36.0/22 Amazon | ||
967 | 15.221.40.0/21 Amazon | ||
968 | 15.221.48.0/24 Amazon | ||
969 | 15.221.49.0/24 Amazon | ||
970 | 15.221.50.0/24 Amazon | ||
971 | 15.221.51.0/24 Amazon | ||
972 | 15.221.52.0/24 Amazon | ||
973 | 15.221.53.0/24 Amazon | ||
974 | 15.222.0.0/15 Amazon | ||
975 | 15.228.0.0/15 Amazon | ||
976 | 15.230.0.4/32 Amazon | ||
977 | 15.230.0.5/32 Amazon | ||
978 | 15.230.0.6/31 Amazon | ||
979 | 15.230.0.12/31 Amazon | ||
980 | 15.230.0.14/32 Amazon | ||
981 | 15.230.4.19/32 Amazon | ||
982 | 15.230.4.152/31 Amazon | ||
983 | 15.230.4.154/31 Amazon | ||
984 | 15.230.4.156/31 Amazon | ||
985 | 15.230.4.158/31 Amazon | ||
986 | 15.230.4.160/31 Amazon | ||
987 | 15.230.4.162/31 Amazon | ||
988 | 15.230.4.176/28 Amazon | ||
989 | 15.230.5.0/24 Amazon | ||
990 | 15.230.6.0/24 Amazon | ||
991 | 15.230.14.12/32 Amazon | ||
992 | 15.230.14.18/31 Amazon | ||
993 | 15.230.14.20/31 Amazon | ||
994 | 15.230.14.252/31 Amazon | ||
995 | 15.230.16.0/32 Amazon | ||
996 | 15.230.16.12/32 Amazon | ||
997 | 15.230.16.17/32 Amazon | ||
998 | 15.230.16.18/31 Amazon | ||
999 | 15.230.16.20/31 Amazon | ||
1000 | 15.230.16.252/31 Amazon | ||
1001 | 15.230.18.0/24 Amazon | ||
1002 | 15.230.21.0/24 Amazon | ||
1003 | 15.230.22.0/24 Amazon | ||
1004 | 15.230.23.0/24 Amazon | ||
1005 | 15.230.24.0/22 Amazon | ||
1006 | 15.230.28.0/24 Amazon | ||
1007 | 15.230.29.0/24 Amazon | ||
1008 | 15.230.30.0/24 Amazon | ||
1009 | 15.230.31.0/24 Amazon | ||
1010 | 15.230.32.0/24 Amazon | ||
1011 | 15.230.35.0/24 Amazon | ||
1012 | 15.230.36.0/23 Amazon | ||
1013 | 15.230.38.0/24 Amazon | ||
1014 | 15.230.39.0/31 Amazon | ||
1015 | 15.230.39.2/31 Amazon | ||
1016 | 15.230.39.4/31 Amazon | ||
1017 | 15.230.39.6/31 Amazon | ||
1018 | 15.230.39.8/31 Amazon | ||
1019 | 15.230.39.10/31 Amazon | ||
1020 | 15.230.39.12/31 Amazon | ||
1021 | 15.230.39.14/31 Amazon | ||
1022 | 15.230.39.16/31 Amazon | ||
1023 | 15.230.39.18/31 Amazon | ||
1024 | 15.230.39.20/31 Amazon | ||
1025 | 15.230.39.22/31 Amazon | ||
1026 | 15.230.39.24/31 Amazon | ||
1027 | 15.230.39.26/31 Amazon | ||
1028 | 15.230.39.28/31 Amazon | ||
1029 | 15.230.39.30/31 Amazon | ||
1030 | 15.230.39.32/31 Amazon | ||
1031 | 15.230.39.34/31 Amazon | ||
1032 | 15.230.39.36/31 Amazon | ||
1033 | 15.230.39.38/31 Amazon | ||
1034 | 15.230.39.40/31 Amazon | ||
1035 | 15.230.39.42/31 Amazon | ||
1036 | 15.230.39.44/31 Amazon | ||
1037 | 15.230.39.46/31 Amazon | ||
1038 | 15.230.39.48/31 Amazon | ||
1039 | 15.230.39.50/31 Amazon | ||
1040 | 15.230.39.52/31 Amazon | ||
1041 | 15.230.39.54/31 Amazon | ||
1042 | 15.230.39.56/31 Amazon | ||
1043 | 15.230.39.58/31 Amazon | ||
1044 | 15.230.39.60/31 Amazon | ||
1045 | 15.230.39.62/31 Amazon | ||
1046 | 15.230.39.64/31 Amazon | ||
1047 | 15.230.39.66/31 Amazon | ||
1048 | 15.230.39.68/31 Amazon | ||
1049 | 15.230.39.70/31 Amazon | ||
1050 | 15.230.39.72/31 Amazon | ||
1051 | 15.230.39.74/31 Amazon | ||
1052 | 15.230.39.76/31 Amazon | ||
1053 | 15.230.39.78/31 Amazon | ||
1054 | 15.230.39.80/31 Amazon | ||
1055 | 15.230.39.82/31 Amazon | ||
1056 | 15.230.39.84/31 Amazon | ||
1057 | 15.230.39.86/31 Amazon | ||
1058 | 15.230.39.88/31 Amazon | ||
1059 | 15.230.39.90/31 Amazon | ||
1060 | 15.230.39.92/31 Amazon | ||
1061 | 15.230.39.94/31 Amazon | ||
1062 | 15.230.39.96/31 Amazon | ||
1063 | 15.230.39.98/31 Amazon | ||
1064 | 15.230.39.100/31 Amazon | ||
1065 | 15.230.39.102/31 Amazon | ||
1066 | 15.230.39.104/31 Amazon | ||
1067 | 15.230.39.106/31 Amazon | ||
1068 | 15.230.39.108/31 Amazon | ||
1069 | 15.230.39.110/31 Amazon | ||
1070 | 15.230.39.112/31 Amazon | ||
1071 | 15.230.39.114/31 Amazon | ||
1072 | 15.230.39.116/31 Amazon | ||
1073 | 15.230.39.118/31 Amazon | ||
1074 | 15.230.39.120/31 Amazon | ||
1075 | 15.230.39.122/31 Amazon | ||
1076 | 15.230.39.124/31 Amazon | ||
1077 | 15.230.39.126/31 Amazon | ||
1078 | 15.230.39.128/31 Amazon | ||
1079 | 15.230.39.130/31 Amazon | ||
1080 | 15.230.39.132/31 Amazon | ||
1081 | 15.230.39.134/31 Amazon | ||
1082 | 15.230.39.136/31 Amazon | ||
1083 | 15.230.39.138/31 Amazon | ||
1084 | 15.230.39.140/31 Amazon | ||
1085 | 15.230.39.142/31 Amazon | ||
1086 | 15.230.39.144/31 Amazon | ||
1087 | 15.230.39.146/31 Amazon | ||
1088 | 15.230.39.148/31 Amazon | ||
1089 | 15.230.39.150/31 Amazon | ||
1090 | 15.230.39.152/31 Amazon | ||
1091 | 15.230.39.154/31 Amazon | ||
1092 | 15.230.39.156/31 Amazon | ||
1093 | 15.230.39.158/31 Amazon | ||
1094 | 15.230.39.160/31 Amazon | ||
1095 | 15.230.39.162/31 Amazon | ||
1096 | 15.230.39.164/31 Amazon | ||
1097 | 15.230.39.166/31 Amazon | ||
1098 | 15.230.39.168/31 Amazon | ||
1099 | 15.230.39.170/31 Amazon | ||
1100 | 15.230.39.172/31 Amazon | ||
1101 | 15.230.39.174/31 Amazon | ||
1102 | 15.230.39.176/31 Amazon | ||
1103 | 15.230.39.178/31 Amazon | ||
1104 | 15.230.39.180/31 Amazon | ||
1105 | 15.230.39.182/31 Amazon | ||
1106 | 15.230.39.184/31 Amazon | ||
1107 | 15.230.39.186/31 Amazon | ||
1108 | 15.230.39.188/31 Amazon | ||
1109 | 15.230.39.190/31 Amazon | ||
1110 | 15.230.39.192/31 Amazon | ||
1111 | 15.230.39.194/31 Amazon | ||
1112 | 15.230.39.196/31 Amazon | ||
1113 | 15.230.39.198/31 Amazon | ||
1114 | 15.230.39.200/31 Amazon | ||
1115 | 15.230.39.202/31 Amazon | ||
1116 | 15.230.39.204/31 Amazon | ||
1117 | 15.230.39.206/31 Amazon | ||
1118 | 15.230.39.208/31 Amazon | ||
1119 | 15.230.39.210/31 Amazon | ||
1120 | 15.230.39.212/31 Amazon | ||
1121 | 15.230.39.214/31 Amazon | ||
1122 | 15.230.39.216/31 Amazon | ||
1123 | 15.230.39.218/31 Amazon | ||
1124 | 15.230.39.220/31 Amazon | ||
1125 | 15.230.39.222/31 Amazon | ||
1126 | 15.230.39.224/31 Amazon | ||
1127 | 15.230.39.226/31 Amazon | ||
1128 | 15.230.39.228/31 Amazon | ||
1129 | 15.230.39.230/31 Amazon | ||
1130 | 15.230.39.232/31 Amazon | ||
1131 | 15.230.39.234/31 Amazon | ||
1132 | 15.230.39.236/31 Amazon | ||
1133 | 15.230.39.238/31 Amazon | ||
1134 | 15.230.39.240/31 Amazon | ||
1135 | 15.230.39.242/31 Amazon | ||
1136 | 15.230.39.244/31 Amazon | ||
1137 | 15.230.39.246/31 Amazon | ||
1138 | 15.230.39.248/31 Amazon | ||
1139 | 15.230.39.250/31 Amazon | ||
1140 | 15.230.39.252/31 Amazon | ||
1141 | 15.230.39.254/31 Amazon | ||
1142 | 15.230.40.0/24 Amazon | ||
1143 | 15.230.41.0/24 Amazon | ||
1144 | 15.230.42.0/24 Amazon | ||
1145 | 15.230.43.0/24 Amazon | ||
1146 | 15.230.49.0/24 Amazon | ||
1147 | 15.230.50.0/24 Amazon | ||
1148 | 15.230.51.0/24 Amazon | ||
1149 | 15.230.52.0/24 Amazon | ||
1150 | 15.230.53.0/24 Amazon | ||
1151 | 15.230.54.0/24 Amazon | ||
1152 | 15.230.55.0/24 Amazon | ||
1153 | 15.230.56.0/24 Amazon | ||
1154 | 15.230.57.0/24 Amazon | ||
1155 | 15.230.58.0/24 Amazon | ||
1156 | 15.230.59.0/24 Amazon | ||
1157 | 15.230.60.0/24 Amazon | ||
1158 | 15.230.61.0/24 Amazon | ||
1159 | 15.230.64.192/26 Amazon | ||
1160 | 15.230.65.0/26 Amazon | ||
1161 | 15.230.65.64/26 Amazon | ||
1162 | 15.230.65.128/25 Amazon | ||
1163 | 15.230.66.0/25 Amazon | ||
1164 | 15.230.66.128/25 Amazon | ||
1165 | 15.230.67.0/26 Amazon | ||
1166 | 15.230.67.64/26 Amazon | ||
1167 | 15.230.67.128/26 Amazon | ||
1168 | 15.230.67.192/26 Amazon | ||
1169 | 15.230.68.0/26 Amazon | ||
1170 | 15.230.68.64/26 Amazon | ||
1171 | 15.230.68.128/26 Amazon | ||
1172 | 15.230.68.192/26 Amazon | ||
1173 | 15.230.69.0/26 Amazon | ||
1174 | 15.230.69.64/26 Amazon | ||
1175 | 15.230.69.128/26 Amazon | ||
1176 | 15.230.69.192/26 Amazon | ||
1177 | 15.230.70.0/26 Amazon | ||
1178 | 15.230.70.64/26 Amazon | ||
1179 | 15.230.70.128/26 Amazon | ||
1180 | 15.230.70.192/26 Amazon | ||
1181 | 15.230.71.0/26 Amazon | ||
1182 | 15.230.71.64/26 Amazon | ||
1183 | 15.230.71.128/26 Amazon | ||
1184 | 15.230.71.192/26 Amazon | ||
1185 | 15.230.72.0/26 Amazon | ||
1186 | 15.230.72.64/26 Amazon | ||
1187 | 15.230.72.128/26 Amazon | ||
1188 | 15.230.72.192/26 Amazon | ||
1189 | 15.230.73.0/26 Amazon | ||
1190 | 15.230.73.64/26 Amazon | ||
1191 | 15.230.73.128/26 Amazon | ||
1192 | 15.230.73.192/26 Amazon | ||
1193 | 15.230.74.0/26 Amazon | ||
1194 | 15.230.74.64/26 Amazon | ||
1195 | 15.230.74.128/26 Amazon | ||
1196 | 15.230.74.192/26 Amazon | ||
1197 | 15.230.75.0/26 Amazon | ||
1198 | 15.230.75.64/26 Amazon | ||
1199 | 15.230.75.128/26 Amazon | ||
1200 | 15.230.75.192/26 Amazon | ||
1201 | 15.230.76.0/26 Amazon | ||
1202 | 15.230.76.64/26 Amazon | ||
1203 | 15.230.76.128/26 Amazon | ||
1204 | 15.230.76.192/26 Amazon | ||
1205 | 15.230.77.0/26 Amazon | ||
1206 | 15.230.77.64/26 Amazon | ||
1207 | 15.230.77.128/26 Amazon | ||
1208 | 15.230.77.192/26 Amazon | ||
1209 | 15.230.78.0/26 Amazon | ||
1210 | 15.230.78.64/26 Amazon | ||
1211 | 15.230.78.128/26 Amazon | ||
1212 | 15.230.78.192/26 Amazon | ||
1213 | 15.230.79.0/26 Amazon | ||
1214 | 15.230.79.64/26 Amazon | ||
1215 | 15.230.79.128/26 Amazon | ||
1216 | 15.230.80.0/24 Amazon | ||
1217 | 15.230.81.0/24 Amazon | ||
1218 | 15.230.82.0/24 Amazon | ||
1219 | 15.230.83.0/24 Amazon | ||
1220 | 15.230.84.0/24 Amazon | ||
1221 | 15.230.85.0/24 Amazon | ||
1222 | 15.230.86.0/24 Amazon | ||
1223 | 15.230.87.0/24 Amazon | ||
1224 | 15.230.88.0/24 Amazon | ||
1225 | 15.230.89.0/24 Amazon | ||
1226 | 15.230.90.0/24 Amazon | ||
1227 | 15.230.91.0/24 Amazon | ||
1228 | 15.230.92.0/24 Amazon | ||
1229 | 15.230.93.0/24 Amazon | ||
1230 | 15.230.94.0/24 Amazon | ||
1231 | 15.230.129.0/24 Amazon | ||
1232 | 15.230.130.0/24 Amazon | ||
1233 | 15.230.131.0/32 Amazon | ||
1234 | 15.230.131.1/32 Amazon | ||
1235 | 15.230.131.2/32 Amazon | ||
1236 | 15.230.131.3/32 Amazon | ||
1237 | 15.230.131.4/32 Amazon | ||
1238 | 15.230.131.5/32 Amazon | ||
1239 | 15.230.131.6/32 Amazon | ||
1240 | 15.230.131.7/32 Amazon | ||
1241 | 15.230.131.8/32 Amazon | ||
1242 | 15.230.131.9/32 Amazon | ||
1243 | 15.230.131.10/31 Amazon | ||
1244 | 15.230.131.12/31 Amazon | ||
1245 | 15.230.131.14/32 Amazon | ||
1246 | 15.230.131.15/32 Amazon | ||
1247 | 15.230.131.16/28 Amazon | ||
1248 | 15.230.131.32/28 Amazon | ||
1249 | 15.230.131.48/28 Amazon | ||
1250 | 15.230.131.64/28 Amazon | ||
1251 | 15.230.131.80/28 Amazon | ||
1252 | 15.230.131.96/28 Amazon | ||
1253 | 15.230.131.112/28 Amazon | ||
1254 | 15.230.131.128/28 Amazon | ||
1255 | 15.230.131.144/28 Amazon | ||
1256 | 15.230.131.160/31 Amazon | ||
1257 | 15.230.131.162/31 Amazon | ||
1258 | 15.230.131.164/31 Amazon | ||
1259 | 15.230.131.166/31 Amazon | ||
1260 | 15.230.131.168/31 Amazon | ||
1261 | 15.230.131.170/31 Amazon | ||
1262 | 15.230.131.172/31 Amazon | ||
1263 | 15.230.131.174/31 Amazon | ||
1264 | 15.230.132.0/24 Amazon | ||
1265 | 15.230.133.0/28 Amazon | ||
1266 | 15.230.133.16/32 Amazon | ||
1267 | 15.230.133.17/32 Amazon | ||
1268 | 15.230.133.18/31 Amazon | ||
1269 | 15.230.133.20/31 Amazon | ||
1270 | 15.230.133.22/31 Amazon | ||
1271 | 15.230.133.24/32 Amazon | ||
1272 | 15.230.133.26/31 Amazon | ||
1273 | 15.230.133.28/31 Amazon | ||
1274 | 15.230.134.0/24 Amazon | ||
1275 | 15.230.135.0/24 Amazon | ||
1276 | 15.230.136.0/24 Amazon | ||
1277 | 15.230.137.0/24 Amazon | ||
1278 | 15.230.138.0/24 Amazon | ||
1279 | 15.230.140.0/24 Amazon | ||
1280 | 15.230.141.0/24 Amazon | ||
1281 | 15.230.142.0/24 Amazon | ||
1282 | 15.230.143.0/24 Amazon | ||
1283 | 15.230.144.0/24 Amazon | ||
1284 | 15.230.145.0/24 Amazon | ||
1285 | 15.230.148.0/24 Amazon | ||
1286 | 15.230.149.0/31 Amazon | ||
1287 | 15.230.149.2/31 Amazon | ||
1288 | 15.230.149.4/31 Amazon | ||
1289 | 15.230.149.8/31 Amazon | ||
1290 | 15.230.149.10/32 Amazon | ||
1291 | 15.230.149.11/32 Amazon | ||
1292 | 15.230.150.0/23 Amazon | ||
1293 | 15.230.152.0/24 Amazon | ||
1294 | 15.230.153.0/24 Amazon | ||
1295 | 15.230.154.0/23 Amazon | ||
1296 | 15.230.156.0/24 Amazon | ||
1297 | 15.230.157.0/24 Amazon | ||
1298 | 15.230.158.0/23 Amazon | ||
1299 | 15.230.160.0/24 Amazon | ||
1300 | 15.230.161.0/24 Amazon | ||
1301 | 15.230.162.0/24 Amazon | ||
1302 | 15.230.163.0/24 Amazon | ||
1303 | 15.230.164.0/24 Amazon | ||
1304 | 15.230.165.0/24 Amazon | ||
1305 | 15.230.166.0/24 Amazon | ||
1306 | 15.230.170.0/23 Amazon | ||
1307 | 15.230.173.0/24 Amazon | ||
1308 | 15.230.174.0/24 Amazon | ||
1309 | 15.230.176.0/24 Amazon | ||
1310 | 15.230.177.0/31 Amazon | ||
1311 | 15.230.177.2/31 Amazon | ||
1312 | 15.230.178.0/24 Amazon | ||
1313 | 15.230.179.0/29 Amazon | ||
1314 | 15.230.179.8/29 Amazon | ||
1315 | 15.230.179.16/29 Amazon | ||
1316 | 15.230.181.0/24 Amazon | ||
1317 | 15.230.182.0/24 Amazon | ||
1318 | 15.230.183.0/24 Amazon | ||
1319 | 15.230.184.0/24 Amazon | ||
1320 | 15.230.185.0/24 Amazon | ||
1321 | 15.230.186.0/24 Amazon | ||
1322 | 15.230.188.0/25 Amazon | ||
1323 | 15.230.188.128/25 Amazon | ||
1324 | 15.230.189.0/25 Amazon | ||
1325 | 15.230.189.128/25 Amazon | ||
1326 | 15.230.190.0/25 Amazon | ||
1327 | 15.230.190.128/25 Amazon | ||
1328 | 15.230.192.0/24 Amazon | ||
1329 | 15.230.193.0/24 Amazon | ||
1330 | 15.230.195.0/24 Amazon | ||
1331 | 15.230.196.0/24 Amazon | ||
1332 | 15.230.197.0/24 Amazon | ||
1333 | 15.230.198.0/24 Amazon | ||
1334 | 15.230.199.0/28 Amazon | ||
1335 | 15.230.200.0/24 Amazon | ||
1336 | 15.230.201.0/24 Amazon | ||
1337 | 15.230.202.0/30 Amazon | ||
1338 | 15.230.203.0/24 Amazon | ||
1339 | 15.230.204.0/32 Amazon | ||
1340 | 15.230.204.1/32 Amazon | ||
1341 | 15.230.204.2/32 Amazon | ||
1342 | 15.230.204.3/32 Amazon | ||
1343 | 15.230.205.0/24 Amazon | ||
1344 | 15.230.206.0/24 Amazon | ||
1345 | 15.230.207.0/24 Amazon | ||
1346 | 15.231.0.0/16 Amazon | ||
1347 | 15.236.0.0/15 Amazon | ||
1348 | 15.248.8.0/22 Amazon | ||
1349 | 15.248.16.0/22 Amazon | ||
1350 | 15.248.20.0/22 Amazon | ||
1351 | 15.248.24.0/22 Amazon | ||
1352 | 15.248.28.0/22 Amazon | ||
1353 | 15.248.32.0/22 Amazon | ||
1354 | 15.248.36.0/22 Amazon | ||
1355 | 15.248.40.0/22 Amazon | ||
1356 | 15.251.0.0/32 Amazon | ||
1357 | 15.251.0.1/32 Amazon | ||
1358 | 15.251.0.2/32 Amazon | ||
1359 | 15.251.0.3/32 Amazon | ||
1360 | 15.251.0.4/32 Amazon | ||
1361 | 15.251.0.5/32 Amazon | ||
1362 | 15.251.0.6/32 Amazon | ||
1363 | 15.251.0.7/32 Amazon | ||
1364 | 15.251.0.8/32 Amazon | ||
1365 | 15.251.0.9/32 Amazon | ||
1366 | 15.251.0.10/32 Amazon | ||
1367 | 15.251.0.11/32 Amazon | ||
1368 | 15.251.0.12/32 Amazon | ||
1369 | 15.251.0.13/32 Amazon | ||
1370 | 15.251.0.14/32 Amazon | ||
1371 | 15.251.0.15/32 Amazon | ||
1372 | 15.253.0.0/16 Amazon | ||
1373 | 15.254.0.0/16 Amazon | ||
1374 | 16.12.0.0/23 Amazon | ||
1375 | 16.12.2.0/24 Amazon | ||
1376 | 16.12.4.0/23 Amazon | ||
1377 | 16.12.6.0/23 Amazon | ||
1378 | 16.12.8.0/24 Amazon | ||
1379 | 16.16.0.0/16 Amazon | ||
1380 | 16.50.0.0/15 Amazon | ||
1381 | 16.62.0.0/15 Amazon | ||
1382 | 16.162.0.0/15 Amazon | ||
1383 | 16.168.0.0/15 Amazon | ||
1384 | 16.170.0.0/15 Amazon | ||
1385 | 18.60.0.0/15 Amazon | ||
1386 | 18.64.0.0/14 Amazon | ||
1387 | 18.100.0.0/15 Amazon | ||
1388 | 18.102.0.0/16 Amazon | ||
1389 | 18.116.0.0/14 Amazon | ||
1390 | 18.130.0.0/16 Amazon | ||
1391 | 18.132.0.0/14 Amazon | ||
1392 | 18.136.0.0/16 Amazon | ||
1393 | 18.138.0.0/15 Amazon | ||
1394 | 18.140.0.0/15 Amazon | ||
1395 | 18.142.0.0/15 Amazon | ||
1396 | 18.144.0.0/15 Amazon | ||
1397 | 18.148.0.0/14 Amazon | ||
1398 | 18.153.0.0/16 Amazon | ||
1399 | 18.156.0.0/14 Amazon | ||
1400 | 18.162.0.0/16 Amazon | ||
1401 | 18.163.0.0/16 Amazon | ||
1402 | 18.166.0.0/15 Amazon | ||
1403 | 18.168.0.0/14 Amazon | ||
1404 | 18.175.0.0/16 Amazon | ||
1405 | 18.176.0.0/15 Amazon | ||
1406 | 18.178.0.0/16 Amazon | ||
1407 | 18.179.0.0/16 Amazon | ||
1408 | 18.180.0.0/15 Amazon | ||
1409 | 18.182.0.0/16 Amazon | ||
1410 | 18.183.0.0/16 Amazon | ||
1411 | 18.184.0.0/15 Amazon | ||
1412 | 18.186.0.0/15 Amazon | ||
1413 | 18.188.0.0/16 Amazon | ||
1414 | 18.189.0.0/16 Amazon | ||
1415 | 18.190.0.0/16 Amazon | ||
1416 | 18.191.0.0/16 Amazon | ||
1417 | 18.192.0.0/15 Amazon | ||
1418 | 18.194.0.0/15 Amazon | ||
1419 | 18.196.0.0/15 Amazon | ||
1420 | 18.198.0.0/15 Amazon | ||
1421 | 18.200.0.0/16 Amazon | ||
1422 | 18.201.0.0/16 Amazon | ||
1423 | 18.202.0.0/15 Amazon | ||
1424 | 18.204.0.0/14 Amazon | ||
1425 | 18.208.0.0/13 Amazon | ||
1426 | 18.216.0.0/14 Amazon | ||
1427 | 18.220.0.0/14 Amazon | ||
1428 | 18.224.0.0/14 Amazon | ||
1429 | 18.228.0.0/16 Amazon | ||
1430 | 18.229.0.0/16 Amazon | ||
1431 | 18.230.0.0/16 Amazon | ||
1432 | 18.231.0.0/16 Amazon | ||
1433 | 18.232.0.0/14 Amazon | ||
1434 | 18.236.0.0/15 Amazon | ||
1435 | 18.246.0.0/16 Amazon | ||
1436 | 18.252.0.0/16 Amazon | ||
1437 | 18.253.0.0/16 Amazon | ||
1438 | 18.254.0.0/16 Amazon | ||
1439 | 23.20.0.0/14 Amazon | ||
1440 | 27.0.0.0/22 Amazon | ||
1441 | 34.192.0.0/12 Amazon | ||
1442 | 34.208.0.0/12 Amazon | ||
1443 | 34.224.0.0/12 Amazon | ||
1444 | 34.240.0.0/13 Amazon | ||
1445 | 34.248.0.0/13 Amazon | ||
1446 | 35.71.64.0/22 Amazon | ||
1447 | 35.71.96.0/24 Amazon | ||
1448 | 35.71.97.0/24 Amazon | ||
1449 | 35.71.128.0/17 Amazon | ||
1450 | 35.72.0.0/13 Amazon | ||
1451 | 35.80.0.0/12 Amazon | ||
1452 | 35.96.0.0/12 Amazon | ||
1453 | 35.152.0.0/16 Amazon | ||
1454 | 35.153.0.0/16 Amazon | ||
1455 | 35.154.0.0/16 Amazon | ||
1456 | 35.155.0.0/16 Amazon | ||
1457 | 35.156.0.0/14 Amazon | ||
1458 | 35.160.0.0/13 Amazon | ||
1459 | 35.168.0.0/13 Amazon | ||
1460 | 35.176.0.0/15 Amazon | ||
1461 | 35.178.0.0/15 Amazon | ||
1462 | 35.180.0.0/16 Amazon | ||
1463 | 35.181.0.0/16 Amazon | ||
1464 | 35.182.0.0/15 Amazon | ||
1465 | 36.103.232.0/25 Amazon | ||
1466 | 36.103.232.128/26 Amazon | ||
1467 | 43.192.0.0/15 Amazon | ||
1468 | 43.194.0.0/16 Amazon | ||
1469 | 43.195.0.0/16 Amazon | ||
1470 | 43.196.0.0/15 Amazon | ||
1471 | 43.198.0.0/15 Amazon | ||
1472 | 43.200.0.0/14 Amazon | ||
1473 | 43.204.0.0/15 Amazon | ||
1474 | 43.206.0.0/15 Amazon | ||
1475 | 43.224.76.0/30 Amazon | ||
1476 | 43.224.76.4/30 Amazon | ||
1477 | 43.224.76.8/30 Amazon | ||
1478 | 43.224.76.12/30 Amazon | ||
1479 | 43.224.76.16/30 Amazon | ||
1480 | 43.224.76.20/30 Amazon | ||
1481 | 43.224.76.24/30 Amazon | ||
1482 | 43.224.76.28/30 Amazon | ||
1483 | 43.224.76.32/30 Amazon | ||
1484 | 43.224.76.36/30 Amazon | ||
1485 | 43.224.76.40/30 Amazon | ||
1486 | 43.224.76.44/30 Amazon | ||
1487 | 43.224.76.48/30 Amazon | ||
1488 | 43.224.76.52/30 Amazon | ||
1489 | 43.224.76.56/30 Amazon | ||
1490 | 43.224.76.60/30 Amazon | ||
1491 | 43.224.76.64/30 Amazon | ||
1492 | 43.224.76.68/30 Amazon | ||
1493 | 43.224.76.72/30 Amazon | ||
1494 | 43.224.76.76/30 Amazon | ||
1495 | 43.224.76.80/30 Amazon | ||
1496 | 43.224.76.84/30 Amazon | ||
1497 | 43.224.76.88/30 Amazon | ||
1498 | 43.224.76.92/30 Amazon | ||
1499 | 43.224.76.96/30 Amazon | ||
1500 | 43.224.76.100/30 Amazon | ||
1501 | 43.224.76.104/30 Amazon | ||
1502 | 43.224.76.108/30 Amazon | ||
1503 | 43.224.76.112/30 Amazon | ||
1504 | 43.224.76.116/30 Amazon | ||
1505 | 43.224.76.120/30 Amazon | ||
1506 | 43.224.76.124/30 Amazon | ||
1507 | 43.224.76.128/30 Amazon | ||
1508 | 43.224.76.132/30 Amazon | ||
1509 | 43.224.76.136/30 Amazon | ||
1510 | 43.224.76.140/30 Amazon | ||
1511 | 43.224.76.144/30 Amazon | ||
1512 | 43.224.76.148/30 Amazon | ||
1513 | 43.224.76.152/30 Amazon | ||
1514 | 43.224.76.156/30 Amazon | ||
1515 | 43.224.76.160/30 Amazon | ||
1516 | 43.224.76.164/30 Amazon | ||
1517 | 43.224.76.168/30 Amazon | ||
1518 | 43.224.76.172/30 Amazon | ||
1519 | 43.224.76.176/30 Amazon | ||
1520 | 43.224.76.180/30 Amazon | ||
1521 | 43.224.76.184/30 Amazon | ||
1522 | 43.224.76.188/30 Amazon | ||
1523 | 43.224.76.192/30 Amazon | ||
1524 | 43.224.76.196/30 Amazon | ||
1525 | 43.224.76.200/30 Amazon | ||
1526 | 43.224.76.204/30 Amazon | ||
1527 | 43.224.76.208/30 Amazon | ||
1528 | 43.224.76.212/30 Amazon | ||
1529 | 43.224.76.216/30 Amazon | ||
1530 | 43.224.76.220/30 Amazon | ||
1531 | 43.224.76.224/30 Amazon | ||
1532 | 43.224.76.228/30 Amazon | ||
1533 | 43.224.76.232/30 Amazon | ||
1534 | 43.224.76.236/30 Amazon | ||
1535 | 43.224.76.240/30 Amazon | ||
1536 | 43.224.76.244/30 Amazon | ||
1537 | 43.224.76.248/30 Amazon | ||
1538 | 43.224.77.0/29 Amazon | ||
1539 | 43.224.77.8/29 Amazon | ||
1540 | 43.224.77.24/30 Amazon | ||
1541 | 43.224.77.28/30 Amazon | ||
1542 | 43.224.77.32/30 Amazon | ||
1543 | 43.224.77.36/30 Amazon | ||
1544 | 43.224.77.40/30 Amazon | ||
1545 | 43.224.77.44/30 Amazon | ||
1546 | 43.224.77.76/30 Amazon | ||
1547 | 43.224.77.80/30 Amazon | ||
1548 | 43.224.77.84/30 Amazon | ||
1549 | 43.224.77.88/30 Amazon | ||
1550 | 43.224.77.92/30 Amazon | ||
1551 | 43.224.77.96/30 Amazon | ||
1552 | 43.224.77.100/30 Amazon | ||
1553 | 43.224.77.104/30 Amazon | ||
1554 | 43.224.77.108/30 Amazon | ||
1555 | 43.224.77.112/30 Amazon | ||
1556 | 43.224.77.116/30 Amazon | ||
1557 | 43.224.77.120/30 Amazon | ||
1558 | 43.224.77.124/30 Amazon | ||
1559 | 43.224.77.128/30 Amazon | ||
1560 | 43.224.77.132/30 Amazon | ||
1561 | 43.224.77.136/30 Amazon | ||
1562 | 43.224.77.140/30 Amazon | ||
1563 | 43.224.77.144/30 Amazon | ||
1564 | 43.224.77.148/30 Amazon | ||
1565 | 43.224.77.152/30 Amazon | ||
1566 | 43.224.77.156/30 Amazon | ||
1567 | 43.224.77.168/30 Amazon | ||
1568 | 43.224.77.172/30 Amazon | ||
1569 | 43.224.77.176/30 Amazon | ||
1570 | 43.224.77.180/30 Amazon | ||
1571 | 43.224.77.184/30 Amazon | ||
1572 | 43.224.77.188/30 Amazon | ||
1573 | 43.224.77.192/30 Amazon | ||
1574 | 43.224.77.208/30 Amazon | ||
1575 | 43.224.77.212/30 Amazon | ||
1576 | 43.224.79.26/31 Amazon | ||
1577 | 43.224.79.28/31 Amazon | ||
1578 | 43.224.79.30/31 Amazon | ||
1579 | 43.224.79.32/31 Amazon | ||
1580 | 43.224.79.34/31 Amazon | ||
1581 | 43.224.79.36/31 Amazon | ||
1582 | 43.224.79.38/31 Amazon | ||
1583 | 43.224.79.40/31 Amazon | ||
1584 | 43.224.79.42/31 Amazon | ||
1585 | 43.224.79.44/31 Amazon | ||
1586 | 43.224.79.46/31 Amazon | ||
1587 | 43.224.79.48/31 Amazon | ||
1588 | 43.224.79.50/31 Amazon | ||
1589 | 43.224.79.52/31 Amazon | ||
1590 | 43.224.79.54/31 Amazon | ||
1591 | 43.224.79.56/31 Amazon | ||
1592 | 43.224.79.58/31 Amazon | ||
1593 | 43.224.79.60/31 Amazon | ||
1594 | 43.224.79.62/31 Amazon | ||
1595 | 43.224.79.64/31 Amazon | ||
1596 | 43.224.79.66/31 Amazon | ||
1597 | 43.224.79.68/31 Amazon | ||
1598 | 43.224.79.70/31 Amazon | ||
1599 | 43.224.79.72/31 Amazon | ||
1600 | 43.224.79.74/31 Amazon | ||
1601 | 43.224.79.76/31 Amazon | ||
1602 | 43.224.79.78/31 Amazon | ||
1603 | 43.224.79.80/31 Amazon | ||
1604 | 43.224.79.82/31 Amazon | ||
1605 | 43.224.79.84/31 Amazon | ||
1606 | 43.224.79.90/31 Amazon | ||
1607 | 43.224.79.92/31 Amazon | ||
1608 | 43.224.79.94/31 Amazon | ||
1609 | 43.224.79.96/31 Amazon | ||
1610 | 43.224.79.98/31 Amazon | ||
1611 | 43.224.79.100/31 Amazon | ||
1612 | 43.224.79.102/31 Amazon | ||
1613 | 43.224.79.104/31 Amazon | ||
1614 | 43.224.79.106/31 Amazon | ||
1615 | 43.224.79.108/31 Amazon | ||
1616 | 43.224.79.110/31 Amazon | ||
1617 | 43.224.79.112/31 Amazon | ||
1618 | 43.224.79.114/31 Amazon | ||
1619 | 43.224.79.116/31 Amazon | ||
1620 | 43.224.79.118/31 Amazon | ||
1621 | 43.224.79.120/31 Amazon | ||
1622 | 43.224.79.122/31 Amazon | ||
1623 | 43.224.79.124/31 Amazon | ||
1624 | 43.224.79.126/31 Amazon | ||
1625 | 43.224.79.128/31 Amazon | ||
1626 | 43.224.79.130/31 Amazon | ||
1627 | 43.224.79.136/31 Amazon | ||
1628 | 43.224.79.138/31 Amazon | ||
1629 | 43.224.79.140/31 Amazon | ||
1630 | 43.224.79.142/31 Amazon | ||
1631 | 43.224.79.144/31 Amazon | ||
1632 | 43.224.79.154/31 Amazon | ||
1633 | 43.224.79.156/31 Amazon | ||
1634 | 43.224.79.158/31 Amazon | ||
1635 | 43.224.79.160/31 Amazon | ||
1636 | 43.224.79.162/31 Amazon | ||
1637 | 43.224.79.164/31 Amazon | ||
1638 | 43.224.79.166/31 Amazon | ||
1639 | 43.224.79.168/31 Amazon | ||
1640 | 43.224.79.174/31 Amazon | ||
1641 | 43.224.79.176/31 Amazon | ||
1642 | 43.224.79.178/31 Amazon | ||
1643 | 43.224.79.180/31 Amazon | ||
1644 | 43.224.79.182/31 Amazon | ||
1645 | 43.224.79.184/31 Amazon | ||
1646 | 43.224.79.186/31 Amazon | ||
1647 | 43.224.79.188/31 Amazon | ||
1648 | 43.224.79.190/31 Amazon | ||
1649 | 43.224.79.192/31 Amazon | ||
1650 | 43.224.79.194/31 Amazon | ||
1651 | 43.224.79.196/31 Amazon | ||
1652 | 43.224.79.198/31 Amazon | ||
1653 | 43.224.79.200/31 Amazon | ||
1654 | 43.224.79.202/31 Amazon | ||
1655 | 43.224.79.204/31 Amazon | ||
1656 | 43.224.79.206/31 Amazon | ||
1657 | 43.224.79.208/31 Amazon | ||
1658 | 43.224.79.210/31 Amazon | ||
1659 | 43.224.79.212/31 Amazon | ||
1660 | 43.224.79.214/31 Amazon | ||
1661 | 43.224.79.216/31 Amazon | ||
1662 | 43.224.79.218/31 Amazon | ||
1663 | 43.224.79.220/31 Amazon | ||
1664 | 43.224.79.222/31 Amazon | ||
1665 | 43.224.79.224/31 Amazon | ||
1666 | 43.224.79.226/31 Amazon | ||
1667 | 43.224.79.228/31 Amazon | ||
1668 | 43.224.79.230/31 Amazon | ||
1669 | 43.224.79.232/31 Amazon | ||
1670 | 43.224.79.234/31 Amazon | ||
1671 | 43.224.79.236/31 Amazon | ||
1672 | 43.224.79.238/31 Amazon | ||
1673 | 43.224.79.240/31 Amazon | ||
1674 | 43.224.79.242/31 Amazon | ||
1675 | 43.224.79.244/31 Amazon | ||
1676 | 43.224.79.246/31 Amazon | ||
1677 | 43.224.79.248/31 Amazon | ||
1678 | 43.224.79.250/31 Amazon | ||
1679 | 43.224.79.252/31 Amazon | ||
1680 | 43.224.79.254/31 Amazon | ||
1681 | 43.249.45.0/24 Amazon | ||
1682 | 43.249.46.0/24 Amazon | ||
1683 | 43.249.47.0/24 Amazon | ||
1684 | 43.250.192.0/24 Amazon | ||
1685 | 43.250.193.0/24 Amazon | ||
1686 | 44.192.0.0/11 Amazon | ||
1687 | 44.224.0.0/11 Amazon | ||
1688 | 46.51.128.0/18 Amazon | ||
1689 | 46.51.192.0/20 Amazon | ||
1690 | 46.51.208.0/22 Amazon | ||
1691 | 46.51.216.0/21 Amazon | ||
1692 | 46.51.224.0/19 Amazon | ||
1693 | 46.137.0.0/17 Amazon | ||
1694 | 46.137.128.0/18 Amazon | ||
1695 | 46.137.192.0/19 Amazon | ||
1696 | 46.137.224.0/19 Amazon | ||
1697 | 50.16.0.0/15 Amazon | ||
1698 | 50.18.0.0/16 Amazon | ||
1699 | 50.19.0.0/16 Amazon | ||
1700 | 50.112.0.0/16 Amazon | ||
1701 | 51.20.0.0/14 Amazon | ||
1702 | 52.0.0.0/15 Amazon | ||
1703 | 52.2.0.0/15 Amazon | ||
1704 | 52.4.0.0/14 Amazon | ||
1705 | 52.8.0.0/16 Amazon | ||
1706 | 52.9.0.0/16 Amazon | ||
1707 | 52.10.0.0/15 Amazon | ||
1708 | 52.12.0.0/15 Amazon | ||
1709 | 52.14.0.0/16 Amazon | ||
1710 | 52.15.0.0/16 Amazon | ||
1711 | 52.16.0.0/15 Amazon | ||
1712 | 52.18.0.0/15 Amazon | ||
1713 | 52.20.0.0/14 Amazon | ||
1714 | 52.24.0.0/14 Amazon | ||
1715 | 52.28.0.0/16 Amazon | ||
1716 | 52.29.0.0/16 Amazon | ||
1717 | 52.30.0.0/15 Amazon | ||
1718 | 52.32.0.0/14 Amazon | ||
1719 | 52.36.0.0/14 Amazon | ||
1720 | 52.40.0.0/14 Amazon | ||
1721 | 52.44.0.0/15 Amazon | ||
1722 | 52.46.0.0/18 Amazon | ||
1723 | 52.46.64.0/20 Amazon | ||
1724 | 52.46.80.0/21 Amazon | ||
1725 | 52.46.88.0/22 Amazon | ||
1726 | 52.46.92.0/22 Amazon | ||
1727 | 52.46.96.0/19 Amazon | ||
1728 | 52.46.128.0/19 Amazon | ||
1729 | 52.46.164.0/23 Amazon | ||
1730 | 52.46.166.0/23 Amazon | ||
1731 | 52.46.168.0/23 Amazon | ||
1732 | 52.46.170.0/23 Amazon | ||
1733 | 52.46.172.0/22 Amazon | ||
1734 | 52.46.176.0/22 Amazon | ||
1735 | 52.46.180.0/22 Amazon | ||
1736 | 52.46.184.0/22 Amazon | ||
1737 | 52.46.188.24/30 Amazon | ||
1738 | 52.46.188.28/30 Amazon | ||
1739 | 52.46.188.36/30 Amazon | ||
1740 | 52.46.188.40/30 Amazon | ||
1741 | 52.46.188.44/30 Amazon | ||
1742 | 52.46.188.48/30 Amazon | ||
1743 | 52.46.188.52/30 Amazon | ||
1744 | 52.46.188.56/30 Amazon | ||
1745 | 52.46.188.60/30 Amazon | ||
1746 | 52.46.188.64/30 Amazon | ||
1747 | 52.46.188.68/30 Amazon | ||
1748 | 52.46.188.72/30 Amazon | ||
1749 | 52.46.188.76/30 Amazon | ||
1750 | 52.46.188.80/30 Amazon | ||
1751 | 52.46.188.84/30 Amazon | ||
1752 | 52.46.188.88/30 Amazon | ||
1753 | 52.46.188.92/30 Amazon | ||
1754 | 52.46.188.96/30 Amazon | ||
1755 | 52.46.188.108/30 Amazon | ||
1756 | 52.46.188.120/30 Amazon | ||
1757 | 52.46.188.132/30 Amazon | ||
1758 | 52.46.188.136/30 Amazon | ||
1759 | 52.46.188.140/30 Amazon | ||
1760 | 52.46.188.144/30 Amazon | ||
1761 | 52.46.188.148/30 Amazon | ||
1762 | 52.46.188.152/30 Amazon | ||
1763 | 52.46.188.156/30 Amazon | ||
1764 | 52.46.188.160/30 Amazon | ||
1765 | 52.46.188.164/30 Amazon | ||
1766 | 52.46.188.168/30 Amazon | ||
1767 | 52.46.188.172/30 Amazon | ||
1768 | 52.46.188.176/30 Amazon | ||
1769 | 52.46.188.180/30 Amazon | ||
1770 | 52.46.188.184/30 Amazon | ||
1771 | 52.46.188.188/30 Amazon | ||
1772 | 52.46.188.192/30 Amazon | ||
1773 | 52.46.188.204/30 Amazon | ||
1774 | 52.46.188.208/30 Amazon | ||
1775 | 52.46.188.216/30 Amazon | ||
1776 | 52.46.188.224/30 Amazon | ||
1777 | 52.46.188.228/30 Amazon | ||
1778 | 52.46.188.232/30 Amazon | ||
1779 | 52.46.188.236/30 Amazon | ||
1780 | 52.46.188.240/30 Amazon | ||
1781 | 52.46.188.244/30 Amazon | ||
1782 | 52.46.188.248/30 Amazon | ||
1783 | 52.46.188.252/30 Amazon | ||
1784 | 52.46.189.0/30 Amazon | ||
1785 | 52.46.189.4/30 Amazon | ||
1786 | 52.46.189.8/30 Amazon | ||
1787 | 52.46.189.12/30 Amazon | ||
1788 | 52.46.189.16/30 Amazon | ||
1789 | 52.46.189.32/30 Amazon | ||
1790 | 52.46.189.36/30 Amazon | ||
1791 | 52.46.189.40/30 Amazon | ||
1792 | 52.46.189.44/30 Amazon | ||
1793 | 52.46.189.48/30 Amazon | ||
1794 | 52.46.189.52/30 Amazon | ||
1795 | 52.46.189.56/30 Amazon | ||
1796 | 52.46.189.60/30 Amazon | ||
1797 | 52.46.189.64/30 Amazon | ||
1798 | 52.46.189.68/30 Amazon | ||
1799 | 52.46.189.72/30 Amazon | ||
1800 | 52.46.189.76/30 Amazon | ||
1801 | 52.46.189.80/30 Amazon | ||
1802 | 52.46.189.84/30 Amazon | ||
1803 | 52.46.189.88/30 Amazon | ||
1804 | 52.46.189.92/30 Amazon | ||
1805 | 52.46.189.96/30 Amazon | ||
1806 | 52.46.189.100/30 Amazon | ||
1807 | 52.46.189.104/30 Amazon | ||
1808 | 52.46.189.108/30 Amazon | ||
1809 | 52.46.189.112/30 Amazon | ||
1810 | 52.46.189.124/30 Amazon | ||
1811 | 52.46.189.128/30 Amazon | ||
1812 | 52.46.189.132/30 Amazon | ||
1813 | 52.46.189.136/30 Amazon | ||
1814 | 52.46.189.140/30 Amazon | ||
1815 | 52.46.189.156/30 Amazon | ||
1816 | 52.46.189.160/30 Amazon | ||
1817 | 52.46.189.168/30 Amazon | ||
1818 | 52.46.189.172/30 Amazon | ||
1819 | 52.46.189.176/30 Amazon | ||
1820 | 52.46.189.180/30 Amazon | ||
1821 | 52.46.189.192/30 Amazon | ||
1822 | 52.46.189.196/30 Amazon | ||
1823 | 52.46.189.200/30 Amazon | ||
1824 | 52.46.189.204/30 Amazon | ||
1825 | 52.46.189.216/30 Amazon | ||
1826 | 52.46.189.220/30 Amazon | ||
1827 | 52.46.189.224/30 Amazon | ||
1828 | 52.46.189.228/30 Amazon | ||
1829 | 52.46.189.240/30 Amazon | ||
1830 | 52.46.189.244/30 Amazon | ||
1831 | 52.46.189.248/30 Amazon | ||
1832 | 52.46.189.252/30 Amazon | ||
1833 | 52.46.190.0/30 Amazon | ||
1834 | 52.46.190.4/30 Amazon | ||
1835 | 52.46.190.8/30 Amazon | ||
1836 | 52.46.190.12/30 Amazon | ||
1837 | 52.46.190.32/30 Amazon | ||
1838 | 52.46.190.36/30 Amazon | ||
1839 | 52.46.190.40/30 Amazon | ||
1840 | 52.46.190.44/30 Amazon | ||
1841 | 52.46.190.52/30 Amazon | ||
1842 | 52.46.190.56/30 Amazon | ||
1843 | 52.46.190.60/30 Amazon | ||
1844 | 52.46.190.64/30 Amazon | ||
1845 | 52.46.190.68/30 Amazon | ||
1846 | 52.46.190.72/30 Amazon | ||
1847 | 52.46.190.76/30 Amazon | ||
1848 | 52.46.190.92/30 Amazon | ||
1849 | 52.46.190.96/30 Amazon | ||
1850 | 52.46.190.100/30 Amazon | ||
1851 | 52.46.190.104/30 Amazon | ||
1852 | 52.46.190.108/30 Amazon | ||
1853 | 52.46.190.120/30 Amazon | ||
1854 | 52.46.190.124/30 Amazon | ||
1855 | 52.46.190.144/30 Amazon | ||
1856 | 52.46.190.148/30 Amazon | ||
1857 | 52.46.190.152/30 Amazon | ||
1858 | 52.46.190.164/30 Amazon | ||
1859 | 52.46.190.168/30 Amazon | ||
1860 | 52.46.190.180/31 Amazon | ||
1861 | 52.46.190.182/31 Amazon | ||
1862 | 52.46.190.188/31 Amazon | ||
1863 | 52.46.190.190/31 Amazon | ||
1864 | 52.46.190.192/31 Amazon | ||
1865 | 52.46.190.202/31 Amazon | ||
1866 | 52.46.190.204/31 Amazon | ||
1867 | 52.46.190.206/31 Amazon | ||
1868 | 52.46.190.208/31 Amazon | ||
1869 | 52.46.190.210/31 Amazon | ||
1870 | 52.46.190.212/31 Amazon | ||
1871 | 52.46.190.214/31 Amazon | ||
1872 | 52.46.190.216/31 Amazon | ||
1873 | 52.46.190.222/31 Amazon | ||
1874 | 52.46.190.224/31 Amazon | ||
1875 | 52.46.190.226/31 Amazon | ||
1876 | 52.46.190.228/31 Amazon | ||
1877 | 52.46.190.230/31 Amazon | ||
1878 | 52.46.190.232/31 Amazon | ||
1879 | 52.46.190.234/31 Amazon | ||
1880 | 52.46.190.236/31 Amazon | ||
1881 | 52.46.190.238/31 Amazon | ||
1882 | 52.46.190.240/31 Amazon | ||
1883 | 52.46.190.242/31 Amazon | ||
1884 | 52.46.190.244/31 Amazon | ||
1885 | 52.46.190.254/31 Amazon | ||
1886 | 52.46.191.0/31 Amazon | ||
1887 | 52.46.191.2/31 Amazon | ||
1888 | 52.46.191.4/31 Amazon | ||
1889 | 52.46.191.6/31 Amazon | ||
1890 | 52.46.191.8/31 Amazon | ||
1891 | 52.46.191.10/31 Amazon | ||
1892 | 52.46.191.12/31 Amazon | ||
1893 | 52.46.191.18/31 Amazon | ||
1894 | 52.46.191.20/31 Amazon | ||
1895 | 52.46.191.22/31 Amazon | ||
1896 | 52.46.191.24/31 Amazon | ||
1897 | 52.46.191.26/31 Amazon | ||
1898 | 52.46.191.28/31 Amazon | ||
1899 | 52.46.191.34/31 Amazon | ||
1900 | 52.46.191.36/31 Amazon | ||
1901 | 52.46.191.42/31 Amazon | ||
1902 | 52.46.191.44/31 Amazon | ||
1903 | 52.46.191.46/31 Amazon | ||
1904 | 52.46.191.48/31 Amazon | ||
1905 | 52.46.191.52/31 Amazon | ||
1906 | 52.46.191.54/31 Amazon | ||
1907 | 52.46.191.60/31 Amazon | ||
1908 | 52.46.191.62/31 Amazon | ||
1909 | 52.46.191.64/31 Amazon | ||
1910 | 52.46.191.66/31 Amazon | ||
1911 | 52.46.191.68/31 Amazon | ||
1912 | 52.46.191.70/31 Amazon | ||
1913 | 52.46.191.72/31 Amazon | ||
1914 | 52.46.191.76/31 Amazon | ||
1915 | 52.46.191.78/31 Amazon | ||
1916 | 52.46.191.80/31 Amazon | ||
1917 | 52.46.191.82/31 Amazon | ||
1918 | 52.46.191.84/31 Amazon | ||
1919 | 52.46.191.86/31 Amazon | ||
1920 | 52.46.191.88/31 Amazon | ||
1921 | 52.46.191.90/31 Amazon | ||
1922 | 52.46.191.92/31 Amazon | ||
1923 | 52.46.191.94/31 Amazon | ||
1924 | 52.46.191.96/31 Amazon | ||
1925 | 52.46.191.98/31 Amazon | ||
1926 | 52.46.191.100/31 Amazon | ||
1927 | 52.46.191.102/31 Amazon | ||
1928 | 52.46.191.104/31 Amazon | ||
1929 | 52.46.191.106/31 Amazon | ||
1930 | 52.46.191.108/31 Amazon | ||
1931 | 52.46.191.110/31 Amazon | ||
1932 | 52.46.191.120/31 Amazon | ||
1933 | 52.46.191.122/31 Amazon | ||
1934 | 52.46.191.124/31 Amazon | ||
1935 | 52.46.191.126/31 Amazon | ||
1936 | 52.46.191.128/31 Amazon | ||
1937 | 52.46.191.130/31 Amazon | ||
1938 | 52.46.191.132/31 Amazon | ||
1939 | 52.46.191.134/31 Amazon | ||
1940 | 52.46.191.136/31 Amazon | ||
1941 | 52.46.191.140/31 Amazon | ||
1942 | 52.46.191.142/31 Amazon | ||
1943 | 52.46.191.144/31 Amazon | ||
1944 | 52.46.191.148/31 Amazon | ||
1945 | 52.46.191.150/31 Amazon | ||
1946 | 52.46.191.152/31 Amazon | ||
1947 | 52.46.191.156/31 Amazon | ||
1948 | 52.46.191.158/31 Amazon | ||
1949 | 52.46.191.164/31 Amazon | ||
1950 | 52.46.191.166/31 Amazon | ||
1951 | 52.46.191.168/31 Amazon | ||
1952 | 52.46.191.170/31 Amazon | ||
1953 | 52.46.191.172/31 Amazon | ||
1954 | 52.46.191.174/31 Amazon | ||
1955 | 52.46.191.176/31 Amazon | ||
1956 | 52.46.191.178/31 Amazon | ||
1957 | 52.46.191.180/31 Amazon | ||
1958 | 52.46.191.182/31 Amazon | ||
1959 | 52.46.191.184/31 Amazon | ||
1960 | 52.46.191.186/31 Amazon | ||
1961 | 52.46.191.188/31 Amazon | ||
1962 | 52.46.191.190/31 Amazon | ||
1963 | 52.46.191.192/31 Amazon | ||
1964 | 52.46.191.194/31 Amazon | ||
1965 | 52.46.191.200/31 Amazon | ||
1966 | 52.46.191.202/31 Amazon | ||
1967 | 52.46.191.210/31 Amazon | ||
1968 | 52.46.191.212/31 Amazon | ||
1969 | 52.46.191.214/31 Amazon | ||
1970 | 52.46.191.216/31 Amazon | ||
1971 | 52.46.191.218/31 Amazon | ||
1972 | 52.46.191.220/31 Amazon | ||
1973 | 52.46.191.222/31 Amazon | ||
1974 | 52.46.191.224/31 Amazon | ||
1975 | 52.46.191.226/31 Amazon | ||
1976 | 52.46.191.228/31 Amazon | ||
1977 | 52.46.191.230/31 Amazon | ||
1978 | 52.46.191.232/31 Amazon | ||
1979 | 52.46.191.234/31 Amazon | ||
1980 | 52.46.191.236/31 Amazon | ||
1981 | 52.46.191.238/31 Amazon | ||
1982 | 52.46.191.240/31 Amazon | ||
1983 | 52.46.192.0/20 Amazon | ||
1984 | 52.46.208.0/21 Amazon | ||
1985 | 52.46.216.0/22 Amazon | ||
1986 | 52.46.220.0/22 Amazon | ||
1987 | 52.46.224.0/20 Amazon | ||
1988 | 52.46.240.0/22 Amazon | ||
1989 | 52.46.249.0/24 Amazon | ||
1990 | 52.46.250.0/23 Amazon | ||
1991 | 52.46.252.0/22 Amazon | ||
1992 | 52.47.0.0/16 Amazon | ||
1993 | 52.48.0.0/14 Amazon | ||
1994 | 52.52.0.0/15 Amazon | ||
1995 | 52.54.0.0/15 Amazon | ||
1996 | 52.56.0.0/16 Amazon | ||
1997 | 52.57.0.0/16 Amazon | ||
1998 | 52.58.0.0/15 Amazon | ||
1999 | 52.60.0.0/16 Amazon | ||
2000 | 52.61.0.0/16 Amazon | ||
2001 | 52.62.0.0/15 Amazon | ||
2002 | 52.64.0.0/17 Amazon | ||
2003 | 52.64.128.0/17 Amazon | ||
2004 | 52.65.0.0/16 Amazon | ||
2005 | 52.66.0.0/16 Amazon | ||
2006 | 52.67.0.0/16 Amazon | ||
2007 | 52.68.0.0/15 Amazon | ||
2008 | 52.70.0.0/15 Amazon | ||
2009 | 52.72.0.0/15 Amazon | ||
2010 | 52.74.0.0/16 Amazon | ||
2011 | 52.75.0.0/16 Amazon | ||
2012 | 52.76.0.0/17 Amazon | ||
2013 | 52.76.128.0/17 Amazon | ||
2014 | 52.77.0.0/16 Amazon | ||
2015 | 52.78.0.0/16 Amazon | ||
2016 | 52.79.0.0/16 Amazon | ||
2017 | 52.80.0.0/16 Amazon | ||
2018 | 52.81.0.0/16 Amazon | ||
2019 | 52.82.0.0/17 Amazon | ||
2020 | 52.82.128.0/19 Amazon | ||
2021 | 52.82.160.0/22 Amazon | ||
2022 | 52.82.164.0/22 Amazon | ||
2023 | 52.82.168.0/24 Amazon | ||
2024 | 52.82.169.0/28 Amazon | ||
2025 | 52.82.169.16/28 Amazon | ||
2026 | 52.82.176.0/22 Amazon | ||
2027 | 52.82.180.0/22 Amazon | ||
2028 | 52.82.184.0/23 Amazon | ||
2029 | 52.82.187.0/24 Amazon | ||
2030 | 52.82.188.0/22 Amazon | ||
2031 | 52.82.192.0/18 Amazon | ||
2032 | 52.83.0.0/16 Amazon | ||
2033 | 52.84.0.0/15 Amazon | ||
2034 | 52.86.0.0/15 Amazon | ||
2035 | 52.88.0.0/15 Amazon | ||
2036 | 52.90.0.0/15 Amazon | ||
2037 | 52.92.0.0/17 Amazon | ||
2038 | 52.92.128.0/17 Amazon | ||
2039 | 52.93.0.0/24 Amazon | ||
2040 | 52.93.1.0/24 Amazon | ||
2041 | 52.93.2.0/24 Amazon | ||
2042 | 52.93.3.0/24 Amazon | ||
2043 | 52.93.4.0/24 Amazon | ||
2044 | 52.93.5.0/24 Amazon | ||
2045 | 52.93.8.0/22 Amazon | ||
2046 | 52.93.12.12/32 Amazon | ||
2047 | 52.93.12.13/32 Amazon | ||
2048 | 52.93.14.18/32 Amazon | ||
2049 | 52.93.14.19/32 Amazon | ||
2050 | 52.93.16.0/24 Amazon | ||
2051 | 52.93.17.0/24 Amazon | ||
2052 | 52.93.18.178/32 Amazon | ||
2053 | 52.93.18.179/32 Amazon | ||
2054 | 52.93.19.236/32 Amazon | ||
2055 | 52.93.19.237/32 Amazon | ||
2056 | 52.93.20.0/24 Amazon | ||
2057 | 52.93.21.14/32 Amazon | ||
2058 | 52.93.21.15/32 Amazon | ||
2059 | 52.93.32.176/32 Amazon | ||
2060 | 52.93.32.179/32 Amazon | ||
2061 | 52.93.32.180/32 Amazon | ||
2062 | 52.93.34.40/32 Amazon | ||
2063 | 52.93.34.42/32 Amazon | ||
2064 | 52.93.34.56/32 Amazon | ||
2065 | 52.93.34.57/32 Amazon | ||
2066 | 52.93.34.120/31 Amazon | ||
2067 | 52.93.34.122/31 Amazon | ||
2068 | 52.93.34.124/31 Amazon | ||
2069 | 52.93.34.126/31 Amazon | ||
2070 | 52.93.35.212/32 Amazon | ||
2071 | 52.93.35.213/32 Amazon | ||
2072 | 52.93.37.222/32 Amazon | ||
2073 | 52.93.37.223/32 Amazon | ||
2074 | 52.93.38.0/24 Amazon | ||
2075 | 52.93.43.0/24 Amazon | ||
2076 | 52.93.48.0/24 Amazon | ||
2077 | 52.93.50.128/32 Amazon | ||
2078 | 52.93.50.129/32 Amazon | ||
2079 | 52.93.50.130/32 Amazon | ||
2080 | 52.93.50.131/32 Amazon | ||
2081 | 52.93.50.132/31 Amazon | ||
2082 | 52.93.50.134/31 Amazon | ||
2083 | 52.93.50.136/31 Amazon | ||
2084 | 52.93.50.138/31 Amazon | ||
2085 | 52.93.50.140/31 Amazon | ||
2086 | 52.93.50.142/31 Amazon | ||
2087 | 52.93.50.144/31 Amazon | ||
2088 | 52.93.50.146/31 Amazon | ||
2089 | 52.93.50.148/31 Amazon | ||
2090 | 52.93.50.150/31 Amazon | ||
2091 | 52.93.50.152/31 Amazon | ||
2092 | 52.93.50.154/31 Amazon | ||
2093 | 52.93.50.156/31 Amazon | ||
2094 | 52.93.50.158/31 Amazon | ||
2095 | 52.93.50.160/31 Amazon | ||
2096 | 52.93.50.162/31 Amazon | ||
2097 | 52.93.50.164/31 Amazon | ||
2098 | 52.93.50.166/31 Amazon | ||
2099 | 52.93.50.168/31 Amazon | ||
2100 | 52.93.50.170/31 Amazon | ||
2101 | 52.93.50.172/31 Amazon | ||
2102 | 52.93.50.174/31 Amazon | ||
2103 | 52.93.50.176/31 Amazon | ||
2104 | 52.93.50.178/31 Amazon | ||
2105 | 52.93.50.180/31 Amazon | ||
2106 | 52.93.50.182/31 Amazon | ||
2107 | 52.93.50.184/31 Amazon | ||
2108 | 52.93.50.186/31 Amazon | ||
2109 | 52.93.50.188/31 Amazon | ||
2110 | 52.93.50.190/31 Amazon | ||
2111 | 52.93.50.192/31 Amazon | ||
2112 | 52.93.50.194/31 Amazon | ||
2113 | 52.93.51.28/32 Amazon | ||
2114 | 52.93.51.29/32 Amazon | ||
2115 | 52.93.55.144/31 Amazon | ||
2116 | 52.93.55.146/31 Amazon | ||
2117 | 52.93.55.148/31 Amazon | ||
2118 | 52.93.55.152/31 Amazon | ||
2119 | 52.93.55.154/31 Amazon | ||
2120 | 52.93.55.156/31 Amazon | ||
2121 | 52.93.55.158/31 Amazon | ||
2122 | 52.93.55.160/31 Amazon | ||
2123 | 52.93.55.162/31 Amazon | ||
2124 | 52.93.55.164/31 Amazon | ||
2125 | 52.93.55.166/31 Amazon | ||
2126 | 52.93.56.0/24 Amazon | ||
2127 | 52.93.57.0/24 Amazon | ||
2128 | 52.93.58.32/28 Amazon | ||
2129 | 52.93.59.0/24 Amazon | ||
2130 | 52.93.60.0/24 Amazon | ||
2131 | 52.93.62.0/24 Amazon | ||
2132 | 52.93.63.0/24 Amazon | ||
2133 | 52.93.64.0/24 Amazon | ||
2134 | 52.93.66.0/24 Amazon | ||
2135 | 52.93.67.0/24 Amazon | ||
2136 | 52.93.69.0/24 Amazon | ||
2137 | 52.93.71.37/32 Amazon | ||
2138 | 52.93.73.0/26 Amazon | ||
2139 | 52.93.75.0/24 Amazon | ||
2140 | 52.93.76.0/24 Amazon | ||
2141 | 52.93.78.0/24 Amazon | ||
2142 | 52.93.80.0/24 Amazon | ||
2143 | 52.93.81.0/24 Amazon | ||
2144 | 52.93.87.96/27 Amazon | ||
2145 | 52.93.91.96/32 Amazon | ||
2146 | 52.93.91.97/32 Amazon | ||
2147 | 52.93.91.98/32 Amazon | ||
2148 | 52.93.91.99/32 Amazon | ||
2149 | 52.93.91.100/32 Amazon | ||
2150 | 52.93.91.101/32 Amazon | ||
2151 | 52.93.91.102/32 Amazon | ||
2152 | 52.93.91.103/32 Amazon | ||
2153 | 52.93.91.104/32 Amazon | ||
2154 | 52.93.91.105/32 Amazon | ||
2155 | 52.93.91.106/32 Amazon | ||
2156 | 52.93.91.107/32 Amazon | ||
2157 | 52.93.91.108/32 Amazon | ||
2158 | 52.93.91.109/32 Amazon | ||
2159 | 52.93.91.110/32 Amazon | ||
2160 | 52.93.91.111/32 Amazon | ||
2161 | 52.93.91.112/32 Amazon | ||
2162 | 52.93.91.113/32 Amazon | ||
2163 | 52.93.91.114/32 Amazon | ||
2164 | 52.93.91.115/32 Amazon | ||
2165 | 52.93.92.64/31 Amazon | ||
2166 | 52.93.92.66/31 Amazon | ||
2167 | 52.93.92.68/31 Amazon | ||
2168 | 52.93.92.70/31 Amazon | ||
2169 | 52.93.92.72/31 Amazon | ||
2170 | 52.93.92.74/31 Amazon | ||
2171 | 52.93.96.0/24 Amazon | ||
2172 | 52.93.97.0/24 Amazon | ||
2173 | 52.93.98.0/24 Amazon | ||
2174 | 52.93.99.0/24 Amazon | ||
2175 | 52.93.112.0/24 Amazon | ||
2176 | 52.93.120.176/32 Amazon | ||
2177 | 52.93.120.177/32 Amazon | ||
2178 | 52.93.120.178/32 Amazon | ||
2179 | 52.93.120.179/32 Amazon | ||
2180 | 52.93.121.187/32 Amazon | ||
2181 | 52.93.121.188/32 Amazon | ||
2182 | 52.93.121.189/32 Amazon | ||
2183 | 52.93.121.190/32 Amazon | ||
2184 | 52.93.121.195/32 Amazon | ||
2185 | 52.93.121.196/32 Amazon | ||
2186 | 52.93.121.197/32 Amazon | ||
2187 | 52.93.121.198/32 Amazon | ||
2188 | 52.93.122.131/32 Amazon | ||
2189 | 52.93.122.202/32 Amazon | ||
2190 | 52.93.122.203/32 Amazon | ||
2191 | 52.93.122.218/32 Amazon | ||
2192 | 52.93.122.255/32 Amazon | ||
2193 | 52.93.123.6/32 Amazon | ||
2194 | 52.93.123.11/32 Amazon | ||
2195 | 52.93.123.98/32 Amazon | ||
2196 | 52.93.123.99/32 Amazon | ||
2197 | 52.93.123.136/32 Amazon | ||
2198 | 52.93.123.255/32 Amazon | ||
2199 | 52.93.124.14/32 Amazon | ||
2200 | 52.93.124.15/32 Amazon | ||
2201 | 52.93.124.96/32 Amazon | ||
2202 | 52.93.124.97/32 Amazon | ||
2203 | 52.93.124.210/32 Amazon | ||
2204 | 52.93.124.211/32 Amazon | ||
2205 | 52.93.124.212/32 Amazon | ||
2206 | 52.93.124.213/32 Amazon | ||
2207 | 52.93.125.42/32 Amazon | ||
2208 | 52.93.125.43/32 Amazon | ||
2209 | 52.93.126.76/32 Amazon | ||
2210 | 52.93.126.122/32 Amazon | ||
2211 | 52.93.126.123/32 Amazon | ||
2212 | 52.93.126.132/32 Amazon | ||
2213 | 52.93.126.133/32 Amazon | ||
2214 | 52.93.126.134/32 Amazon | ||
2215 | 52.93.126.135/32 Amazon | ||
2216 | 52.93.126.136/32 Amazon | ||
2217 | 52.93.126.137/32 Amazon | ||
2218 | 52.93.126.138/32 Amazon | ||
2219 | 52.93.126.139/32 Amazon | ||
2220 | 52.93.126.144/32 Amazon | ||
2221 | 52.93.126.145/32 Amazon | ||
2222 | 52.93.126.146/32 Amazon | ||
2223 | 52.93.126.147/32 Amazon | ||
2224 | 52.93.126.198/32 Amazon | ||
2225 | 52.93.126.199/32 Amazon | ||
2226 | 52.93.126.204/32 Amazon | ||
2227 | 52.93.126.205/32 Amazon | ||
2228 | 52.93.126.206/32 Amazon | ||
2229 | 52.93.126.207/32 Amazon | ||
2230 | 52.93.126.212/32 Amazon | ||
2231 | 52.93.126.213/32 Amazon | ||
2232 | 52.93.126.214/32 Amazon | ||
2233 | 52.93.126.215/32 Amazon | ||
2234 | 52.93.126.234/32 Amazon | ||
2235 | 52.93.126.235/32 Amazon | ||
2236 | 52.93.126.244/32 Amazon | ||
2237 | 52.93.126.245/32 Amazon | ||
2238 | 52.93.126.250/32 Amazon | ||
2239 | 52.93.126.251/32 Amazon | ||
2240 | 52.93.127.17/32 Amazon | ||
2241 | 52.93.127.18/32 Amazon | ||
2242 | 52.93.127.19/32 Amazon | ||
2243 | 52.93.127.24/32 Amazon | ||
2244 | 52.93.127.25/32 Amazon | ||
2245 | 52.93.127.26/32 Amazon | ||
2246 | 52.93.127.27/32 Amazon | ||
2247 | 52.93.127.68/32 Amazon | ||
2248 | 52.93.127.69/32 Amazon | ||
2249 | 52.93.127.70/32 Amazon | ||
2250 | 52.93.127.71/32 Amazon | ||
2251 | 52.93.127.92/32 Amazon | ||
2252 | 52.93.127.93/32 Amazon | ||
2253 | 52.93.127.94/32 Amazon | ||
2254 | 52.93.127.95/32 Amazon | ||
2255 | 52.93.127.96/32 Amazon | ||
2256 | 52.93.127.97/32 Amazon | ||
2257 | 52.93.127.98/32 Amazon | ||
2258 | 52.93.127.99/32 Amazon | ||
2259 | 52.93.127.100/32 Amazon | ||
2260 | 52.93.127.101/32 Amazon | ||
2261 | 52.93.127.102/32 Amazon | ||
2262 | 52.93.127.103/32 Amazon | ||
2263 | 52.93.127.104/32 Amazon | ||
2264 | 52.93.127.105/32 Amazon | ||
2265 | 52.93.127.106/32 Amazon | ||
2266 | 52.93.127.107/32 Amazon | ||
2267 | 52.93.127.108/32 Amazon | ||
2268 | 52.93.127.109/32 Amazon | ||
2269 | 52.93.127.110/32 Amazon | ||
2270 | 52.93.127.111/32 Amazon | ||
2271 | 52.93.127.112/32 Amazon | ||
2272 | 52.93.127.113/32 Amazon | ||
2273 | 52.93.127.114/32 Amazon | ||
2274 | 52.93.127.115/32 Amazon | ||
2275 | 52.93.127.116/32 Amazon | ||
2276 | 52.93.127.117/32 Amazon | ||
2277 | 52.93.127.118/32 Amazon | ||
2278 | 52.93.127.119/32 Amazon | ||
2279 | 52.93.127.120/32 Amazon | ||
2280 | 52.93.127.121/32 Amazon | ||
2281 | 52.93.127.122/32 Amazon | ||
2282 | 52.93.127.123/32 Amazon | ||
2283 | 52.93.127.124/32 Amazon | ||
2284 | 52.93.127.125/32 Amazon | ||
2285 | 52.93.127.126/32 Amazon | ||
2286 | 52.93.127.127/32 Amazon | ||
2287 | 52.93.127.128/32 Amazon | ||
2288 | 52.93.127.129/32 Amazon | ||
2289 | 52.93.127.130/32 Amazon | ||
2290 | 52.93.127.131/32 Amazon | ||
2291 | 52.93.127.132/32 Amazon | ||
2292 | 52.93.127.133/32 Amazon | ||
2293 | 52.93.127.138/32 Amazon | ||
2294 | 52.93.127.139/32 Amazon | ||
2295 | 52.93.127.146/32 Amazon | ||
2296 | 52.93.127.147/32 Amazon | ||
2297 | 52.93.127.148/32 Amazon | ||
2298 | 52.93.127.149/32 Amazon | ||
2299 | 52.93.127.152/32 Amazon | ||
2300 | 52.93.127.153/32 Amazon | ||
2301 | 52.93.127.154/32 Amazon | ||
2302 | 52.93.127.155/32 Amazon | ||
2303 | 52.93.127.156/32 Amazon | ||
2304 | 52.93.127.157/32 Amazon | ||
2305 | 52.93.127.158/32 Amazon | ||
2306 | 52.93.127.159/32 Amazon | ||
2307 | 52.93.127.160/32 Amazon | ||
2308 | 52.93.127.161/32 Amazon | ||
2309 | 52.93.127.162/32 Amazon | ||
2310 | 52.93.127.163/32 Amazon | ||
2311 | 52.93.127.164/32 Amazon | ||
2312 | 52.93.127.165/32 Amazon | ||
2313 | 52.93.127.166/32 Amazon | ||
2314 | 52.93.127.167/32 Amazon | ||
2315 | 52.93.127.168/32 Amazon | ||
2316 | 52.93.127.169/32 Amazon | ||
2317 | 52.93.127.172/32 Amazon | ||
2318 | 52.93.127.173/32 Amazon | ||
2319 | 52.93.127.174/32 Amazon | ||
2320 | 52.93.127.175/32 Amazon | ||
2321 | 52.93.127.176/32 Amazon | ||
2322 | 52.93.127.177/32 Amazon | ||
2323 | 52.93.127.178/32 Amazon | ||
2324 | 52.93.127.179/32 Amazon | ||
2325 | 52.93.127.180/32 Amazon | ||
2326 | 52.93.127.181/32 Amazon | ||
2327 | 52.93.127.182/32 Amazon | ||
2328 | 52.93.127.183/32 Amazon | ||
2329 | 52.93.127.184/32 Amazon | ||
2330 | 52.93.127.185/32 Amazon | ||
2331 | 52.93.127.194/32 Amazon | ||
2332 | 52.93.127.195/32 Amazon | ||
2333 | 52.93.127.196/32 Amazon | ||
2334 | 52.93.127.197/32 Amazon | ||
2335 | 52.93.127.198/32 Amazon | ||
2336 | 52.93.127.199/32 Amazon | ||
2337 | 52.93.127.200/32 Amazon | ||
2338 | 52.93.127.201/32 Amazon | ||
2339 | 52.93.127.202/32 Amazon | ||
2340 | 52.93.127.203/32 Amazon | ||
2341 | 52.93.127.204/32 Amazon | ||
2342 | 52.93.127.205/32 Amazon | ||
2343 | 52.93.127.206/32 Amazon | ||
2344 | 52.93.127.207/32 Amazon | ||
2345 | 52.93.127.216/32 Amazon | ||
2346 | 52.93.127.217/32 Amazon | ||
2347 | 52.93.127.218/32 Amazon | ||
2348 | 52.93.127.219/32 Amazon | ||
2349 | 52.93.127.220/32 Amazon | ||
2350 | 52.93.127.221/32 Amazon | ||
2351 | 52.93.127.232/32 Amazon | ||
2352 | 52.93.127.237/32 Amazon | ||
2353 | 52.93.127.238/32 Amazon | ||
2354 | 52.93.127.239/32 Amazon | ||
2355 | 52.93.127.244/32 Amazon | ||
2356 | 52.93.127.245/32 Amazon | ||
2357 | 52.93.127.246/32 Amazon | ||
2358 | 52.93.127.247/32 Amazon | ||
2359 | 52.93.127.248/32 Amazon | ||
2360 | 52.93.127.249/32 Amazon | ||
2361 | 52.93.127.250/32 Amazon | ||
2362 | 52.93.127.251/32 Amazon | ||
2363 | 52.93.127.252/32 Amazon | ||
2364 | 52.93.127.253/32 Amazon | ||
2365 | 52.93.127.254/32 Amazon | ||
2366 | 52.93.127.255/32 Amazon | ||
2367 | 52.93.129.95/32 Amazon | ||
2368 | 52.93.131.217/32 Amazon | ||
2369 | 52.93.133.127/32 Amazon | ||
2370 | 52.93.133.129/32 Amazon | ||
2371 | 52.93.133.131/32 Amazon | ||
2372 | 52.93.133.133/32 Amazon | ||
2373 | 52.93.133.153/32 Amazon | ||
2374 | 52.93.133.155/32 Amazon | ||
2375 | 52.93.133.175/32 Amazon | ||
2376 | 52.93.133.177/32 Amazon | ||
2377 | 52.93.133.179/32 Amazon | ||
2378 | 52.93.133.181/32 Amazon | ||
2379 | 52.93.134.181/32 Amazon | ||
2380 | 52.93.135.195/32 Amazon | ||
2381 | 52.93.137.0/24 Amazon | ||
2382 | 52.93.138.252/32 Amazon | ||
2383 | 52.93.138.253/32 Amazon | ||
2384 | 52.93.139.252/32 Amazon | ||
2385 | 52.93.139.253/32 Amazon | ||
2386 | 52.93.141.212/32 Amazon | ||
2387 | 52.93.141.213/32 Amazon | ||
2388 | 52.93.141.214/31 Amazon | ||
2389 | 52.93.141.216/31 Amazon | ||
2390 | 52.93.141.218/31 Amazon | ||
2391 | 52.93.141.220/31 Amazon | ||
2392 | 52.93.141.222/31 Amazon | ||
2393 | 52.93.141.224/31 Amazon | ||
2394 | 52.93.141.226/31 Amazon | ||
2395 | 52.93.141.228/31 Amazon | ||
2396 | 52.93.141.230/31 Amazon | ||
2397 | 52.93.141.232/31 Amazon | ||
2398 | 52.93.141.234/31 Amazon | ||
2399 | 52.93.141.236/31 Amazon | ||
2400 | 52.93.141.238/31 Amazon | ||
2401 | 52.93.141.240/31 Amazon | ||
2402 | 52.93.141.242/31 Amazon | ||
2403 | 52.93.141.244/31 Amazon | ||
2404 | 52.93.146.5/32 Amazon | ||
2405 | 52.93.149.0/24 Amazon | ||
2406 | 52.93.150.0/24 Amazon | ||
2407 | 52.93.151.0/24 Amazon | ||
2408 | 52.93.153.80/32 Amazon | ||
2409 | 52.93.153.148/32 Amazon | ||
2410 | 52.93.153.149/32 Amazon | ||
2411 | 52.93.153.168/32 Amazon | ||
2412 | 52.93.153.169/32 Amazon | ||
2413 | 52.93.153.170/32 Amazon | ||
2414 | 52.93.153.171/32 Amazon | ||
2415 | 52.93.153.172/32 Amazon | ||
2416 | 52.93.153.173/32 Amazon | ||
2417 | 52.93.153.174/32 Amazon | ||
2418 | 52.93.153.175/32 Amazon | ||
2419 | 52.93.153.176/32 Amazon | ||
2420 | 52.93.153.177/32 Amazon | ||
2421 | 52.93.153.178/32 Amazon | ||
2422 | 52.93.153.179/32 Amazon | ||
2423 | 52.93.156.0/22 Amazon | ||
2424 | 52.93.178.128/32 Amazon | ||
2425 | 52.93.178.129/32 Amazon | ||
2426 | 52.93.178.130/32 Amazon | ||
2427 | 52.93.178.131/32 Amazon | ||
2428 | 52.93.178.132/32 Amazon | ||
2429 | 52.93.178.133/32 Amazon | ||
2430 | 52.93.178.134/32 Amazon | ||
2431 | 52.93.178.135/32 Amazon | ||
2432 | 52.93.178.136/32 Amazon | ||
2433 | 52.93.178.137/32 Amazon | ||
2434 | 52.93.178.138/32 Amazon | ||
2435 | 52.93.178.139/32 Amazon | ||
2436 | 52.93.178.140/32 Amazon | ||
2437 | 52.93.178.141/32 Amazon | ||
2438 | 52.93.178.142/32 Amazon | ||
2439 | 52.93.178.143/32 Amazon | ||
2440 | 52.93.178.144/32 Amazon | ||
2441 | 52.93.178.145/32 Amazon | ||
2442 | 52.93.178.146/32 Amazon | ||
2443 | 52.93.178.147/32 Amazon | ||
2444 | 52.93.178.148/32 Amazon | ||
2445 | 52.93.178.149/32 Amazon | ||
2446 | 52.93.178.150/32 Amazon | ||
2447 | 52.93.178.151/32 Amazon | ||
2448 | 52.93.178.152/32 Amazon | ||
2449 | 52.93.178.153/32 Amazon | ||
2450 | 52.93.178.154/32 Amazon | ||
2451 | 52.93.178.155/32 Amazon | ||
2452 | 52.93.178.156/32 Amazon | ||
2453 | 52.93.178.157/32 Amazon | ||
2454 | 52.93.178.158/32 Amazon | ||
2455 | 52.93.178.159/32 Amazon | ||
2456 | 52.93.178.160/32 Amazon | ||
2457 | 52.93.178.161/32 Amazon | ||
2458 | 52.93.178.162/32 Amazon | ||
2459 | 52.93.178.163/32 Amazon | ||
2460 | 52.93.178.164/32 Amazon | ||
2461 | 52.93.178.165/32 Amazon | ||
2462 | 52.93.178.166/32 Amazon | ||
2463 | 52.93.178.167/32 Amazon | ||
2464 | 52.93.178.168/32 Amazon | ||
2465 | 52.93.178.169/32 Amazon | ||
2466 | 52.93.178.170/32 Amazon | ||
2467 | 52.93.178.171/32 Amazon | ||
2468 | 52.93.178.172/32 Amazon | ||
2469 | 52.93.178.173/32 Amazon | ||
2470 | 52.93.178.174/32 Amazon | ||
2471 | 52.93.178.175/32 Amazon | ||
2472 | 52.93.178.176/32 Amazon | ||
2473 | 52.93.178.177/32 Amazon | ||
2474 | 52.93.178.178/32 Amazon | ||
2475 | 52.93.178.179/32 Amazon | ||
2476 | 52.93.178.180/32 Amazon | ||
2477 | 52.93.178.181/32 Amazon | ||
2478 | 52.93.178.182/32 Amazon | ||
2479 | 52.93.178.183/32 Amazon | ||
2480 | 52.93.178.184/32 Amazon | ||
2481 | 52.93.178.185/32 Amazon | ||
2482 | 52.93.178.186/32 Amazon | ||
2483 | 52.93.178.187/32 Amazon | ||
2484 | 52.93.178.188/32 Amazon | ||
2485 | 52.93.178.189/32 Amazon | ||
2486 | 52.93.178.190/32 Amazon | ||
2487 | 52.93.178.191/32 Amazon | ||
2488 | 52.93.178.192/32 Amazon | ||
2489 | 52.93.178.193/32 Amazon | ||
2490 | 52.93.178.194/32 Amazon | ||
2491 | 52.93.178.195/32 Amazon | ||
2492 | 52.93.178.196/32 Amazon | ||
2493 | 52.93.178.197/32 Amazon | ||
2494 | 52.93.178.198/32 Amazon | ||
2495 | 52.93.178.199/32 Amazon | ||
2496 | 52.93.178.200/32 Amazon | ||
2497 | 52.93.178.201/32 Amazon | ||
2498 | 52.93.178.202/32 Amazon | ||
2499 | 52.93.178.203/32 Amazon | ||
2500 | 52.93.178.204/32 Amazon | ||
2501 | 52.93.178.205/32 Amazon | ||
2502 | 52.93.178.206/32 Amazon | ||
2503 | 52.93.178.207/32 Amazon | ||
2504 | 52.93.178.208/32 Amazon | ||
2505 | 52.93.178.209/32 Amazon | ||
2506 | 52.93.178.210/32 Amazon | ||
2507 | 52.93.178.211/32 Amazon | ||
2508 | 52.93.178.212/32 Amazon | ||
2509 | 52.93.178.213/32 Amazon | ||
2510 | 52.93.178.214/32 Amazon | ||
2511 | 52.93.178.215/32 Amazon | ||
2512 | 52.93.178.216/32 Amazon | ||
2513 | 52.93.178.217/32 Amazon | ||
2514 | 52.93.178.218/32 Amazon | ||
2515 | 52.93.178.219/32 Amazon | ||
2516 | 52.93.178.220/32 Amazon | ||
2517 | 52.93.178.221/32 Amazon | ||
2518 | 52.93.178.222/32 Amazon | ||
2519 | 52.93.178.223/32 Amazon | ||
2520 | 52.93.178.224/32 Amazon | ||
2521 | 52.93.178.225/32 Amazon | ||
2522 | 52.93.178.226/32 Amazon | ||
2523 | 52.93.178.227/32 Amazon | ||
2524 | 52.93.178.228/32 Amazon | ||
2525 | 52.93.178.229/32 Amazon | ||
2526 | 52.93.178.230/32 Amazon | ||
2527 | 52.93.178.231/32 Amazon | ||
2528 | 52.93.178.232/32 Amazon | ||
2529 | 52.93.178.233/32 Amazon | ||
2530 | 52.93.178.234/32 Amazon | ||
2531 | 52.93.178.235/32 Amazon | ||
2532 | 52.93.193.192/32 Amazon | ||
2533 | 52.93.193.193/32 Amazon | ||
2534 | 52.93.193.194/32 Amazon | ||
2535 | 52.93.193.195/32 Amazon | ||
2536 | 52.93.193.196/32 Amazon | ||
2537 | 52.93.193.197/32 Amazon | ||
2538 | 52.93.193.198/32 Amazon | ||
2539 | 52.93.193.199/32 Amazon | ||
2540 | 52.93.193.200/32 Amazon | ||
2541 | 52.93.193.201/32 Amazon | ||
2542 | 52.93.193.202/32 Amazon | ||
2543 | 52.93.193.203/32 Amazon | ||
2544 | 52.93.198.0/25 Amazon | ||
2545 | 52.93.229.148/32 Amazon | ||
2546 | 52.93.229.149/32 Amazon | ||
2547 | 52.93.236.0/24 Amazon | ||
2548 | 52.93.237.0/24 Amazon | ||
2549 | 52.93.240.146/31 Amazon | ||
2550 | 52.93.240.148/31 Amazon | ||
2551 | 52.93.240.150/31 Amazon | ||
2552 | 52.93.240.152/31 Amazon | ||
2553 | 52.93.240.154/31 Amazon | ||
2554 | 52.93.240.156/31 Amazon | ||
2555 | 52.93.240.158/31 Amazon | ||
2556 | 52.93.240.160/31 Amazon | ||
2557 | 52.93.240.162/31 Amazon | ||
2558 | 52.93.240.164/31 Amazon | ||
2559 | 52.93.240.166/31 Amazon | ||
2560 | 52.93.240.168/31 Amazon | ||
2561 | 52.93.240.170/31 Amazon | ||
2562 | 52.93.240.172/31 Amazon | ||
2563 | 52.93.240.174/31 Amazon | ||
2564 | 52.93.240.176/31 Amazon | ||
2565 | 52.93.240.178/31 Amazon | ||
2566 | 52.93.240.180/31 Amazon | ||
2567 | 52.93.240.182/31 Amazon | ||
2568 | 52.93.240.184/31 Amazon | ||
2569 | 52.93.240.186/31 Amazon | ||
2570 | 52.93.240.188/31 Amazon | ||
2571 | 52.93.240.190/31 Amazon | ||
2572 | 52.93.240.192/31 Amazon | ||
2573 | 52.93.240.194/31 Amazon | ||
2574 | 52.93.240.196/31 Amazon | ||
2575 | 52.93.240.198/31 Amazon | ||
2576 | 52.93.240.200/31 Amazon | ||
2577 | 52.93.240.202/31 Amazon | ||
2578 | 52.93.240.204/31 Amazon | ||
2579 | 52.93.245.0/24 Amazon | ||
2580 | 52.93.247.0/25 Amazon | ||
2581 | 52.93.248.0/24 Amazon | ||
2582 | 52.93.249.0/24 Amazon | ||
2583 | 52.93.250.0/23 Amazon | ||
2584 | 52.93.254.0/24 Amazon | ||
2585 | 52.94.0.0/22 Amazon | ||
2586 | 52.94.4.0/24 Amazon | ||
2587 | 52.94.5.0/24 Amazon | ||
2588 | 52.94.6.0/24 Amazon | ||
2589 | 52.94.7.0/24 Amazon | ||
2590 | 52.94.8.0/24 Amazon | ||
2591 | 52.94.9.0/24 Amazon | ||
2592 | 52.94.10.0/24 Amazon | ||
2593 | 52.94.11.0/24 Amazon | ||
2594 | 52.94.12.0/24 Amazon | ||
2595 | 52.94.13.0/24 Amazon | ||
2596 | 52.94.14.0/24 Amazon | ||
2597 | 52.94.15.0/24 Amazon | ||
2598 | 52.94.16.0/24 Amazon | ||
2599 | 52.94.17.0/24 Amazon | ||
2600 | 52.94.18.0/24 Amazon | ||
2601 | 52.94.19.0/24 Amazon | ||
2602 | 52.94.20.0/24 Amazon | ||
2603 | 52.94.22.0/24 Amazon | ||
2604 | 52.94.23.0/24 Amazon | ||
2605 | 52.94.24.0/23 Amazon | ||
2606 | 52.94.26.0/23 Amazon | ||
2607 | 52.94.28.0/23 Amazon | ||
2608 | 52.94.30.0/24 Amazon | ||
2609 | 52.94.32.0/20 Amazon | ||
2610 | 52.94.48.0/20 Amazon | ||
2611 | 52.94.64.0/22 Amazon | ||
2612 | 52.94.68.0/24 Amazon | ||
2613 | 52.94.69.0/24 Amazon | ||
2614 | 52.94.72.0/22 Amazon | ||
2615 | 52.94.76.0/22 Amazon | ||
2616 | 52.94.80.0/20 Amazon | ||
2617 | 52.94.96.0/20 Amazon | ||
2618 | 52.94.112.0/22 Amazon | ||
2619 | 52.94.116.0/22 Amazon | ||
2620 | 52.94.120.0/22 Amazon | ||
2621 | 52.94.124.0/22 Amazon | ||
2622 | 52.94.128.0/22 Amazon | ||
2623 | 52.94.132.0/22 Amazon | ||
2624 | 52.94.136.0/21 Amazon | ||
2625 | 52.94.148.0/22 Amazon | ||
2626 | 52.94.152.3/32 Amazon | ||
2627 | 52.94.152.9/32 Amazon | ||
2628 | 52.94.152.11/32 Amazon | ||
2629 | 52.94.152.12/32 Amazon | ||
2630 | 52.94.152.44/32 Amazon | ||
2631 | 52.94.152.60/32 Amazon | ||
2632 | 52.94.152.61/32 Amazon | ||
2633 | 52.94.152.62/32 Amazon | ||
2634 | 52.94.152.63/32 Amazon | ||
2635 | 52.94.152.64/32 Amazon | ||
2636 | 52.94.152.65/32 Amazon | ||
2637 | 52.94.152.66/32 Amazon | ||
2638 | 52.94.152.67/32 Amazon | ||
2639 | 52.94.152.68/32 Amazon | ||
2640 | 52.94.152.69/32 Amazon | ||
2641 | 52.94.160.0/20 Amazon | ||
2642 | 52.94.176.0/20 Amazon | ||
2643 | 52.94.192.0/22 Amazon | ||
2644 | 52.94.196.0/24 Amazon | ||
2645 | 52.94.197.0/24 Amazon | ||
2646 | 52.94.198.0/28 Amazon | ||
2647 | 52.94.198.16/28 Amazon | ||
2648 | 52.94.198.32/28 Amazon | ||
2649 | 52.94.198.48/28 Amazon | ||
2650 | 52.94.198.64/28 Amazon | ||
2651 | 52.94.198.80/28 Amazon | ||
2652 | 52.94.198.96/28 Amazon | ||
2653 | 52.94.198.112/28 Amazon | ||
2654 | 52.94.198.128/28 Amazon | ||
2655 | 52.94.198.144/28 Amazon | ||
2656 | 52.94.199.0/24 Amazon | ||
2657 | 52.94.200.0/24 Amazon | ||
2658 | 52.94.201.0/26 Amazon | ||
2659 | 52.94.204.0/23 Amazon | ||
2660 | 52.94.206.0/23 Amazon | ||
2661 | 52.94.208.0/21 Amazon | ||
2662 | 52.94.216.0/21 Amazon | ||
2663 | 52.94.224.0/20 Amazon | ||
2664 | 52.94.240.0/22 Amazon | ||
2665 | 52.94.244.0/22 Amazon | ||
2666 | 52.94.248.0/28 Amazon | ||
2667 | 52.94.248.16/28 Amazon | ||
2668 | 52.94.248.32/28 Amazon | ||
2669 | 52.94.248.48/28 Amazon | ||
2670 | 52.94.248.64/28 Amazon | ||
2671 | 52.94.248.80/28 Amazon | ||
2672 | 52.94.248.96/28 Amazon | ||
2673 | 52.94.248.112/28 Amazon | ||
2674 | 52.94.248.128/28 Amazon | ||
2675 | 52.94.248.144/28 Amazon | ||
2676 | 52.94.248.160/28 Amazon | ||
2677 | 52.94.248.176/28 Amazon | ||
2678 | 52.94.248.192/28 Amazon | ||
2679 | 52.94.248.208/28 Amazon | ||
2680 | 52.94.248.224/28 Amazon | ||
2681 | 52.94.249.32/28 Amazon | ||
2682 | 52.94.249.48/28 Amazon | ||
2683 | 52.94.249.64/28 Amazon | ||
2684 | 52.94.249.80/28 Amazon | ||
2685 | 52.94.249.96/28 Amazon | ||
2686 | 52.94.249.112/28 Amazon | ||
2687 | 52.94.249.128/28 Amazon | ||
2688 | 52.94.249.144/28 Amazon | ||
2689 | 52.94.249.160/28 Amazon | ||
2690 | 52.94.249.176/28 Amazon | ||
2691 | 52.94.249.192/28 Amazon | ||
2692 | 52.94.249.208/28 Amazon | ||
2693 | 52.94.249.224/28 Amazon | ||
2694 | 52.94.249.240/28 Amazon | ||
2695 | 52.94.250.0/28 Amazon | ||
2696 | 52.94.250.16/28 Amazon | ||
2697 | 52.94.252.0/23 Amazon | ||
2698 | 52.94.254.0/23 Amazon | ||
2699 | 52.95.0.0/20 Amazon | ||
2700 | 52.95.16.0/21 Amazon | ||
2701 | 52.95.24.0/22 Amazon | ||
2702 | 52.95.28.0/24 Amazon | ||
2703 | 52.95.29.0/26 Amazon | ||
2704 | 52.95.30.0/23 Amazon | ||
2705 | 52.95.34.0/24 Amazon | ||
2706 | 52.95.35.0/24 Amazon | ||
2707 | 52.95.36.0/22 Amazon | ||
2708 | 52.95.40.0/24 Amazon | ||
2709 | 52.95.41.0/24 Amazon | ||
2710 | 52.95.42.0/24 Amazon | ||
2711 | 52.95.48.0/22 Amazon | ||
2712 | 52.95.52.0/22 Amazon | ||
2713 | 52.95.56.0/22 Amazon | ||
2714 | 52.95.60.0/24 Amazon | ||
2715 | 52.95.61.0/24 Amazon | ||
2716 | 52.95.62.0/24 Amazon | ||
2717 | 52.95.63.0/24 Amazon | ||
2718 | 52.95.64.0/20 Amazon | ||
2719 | 52.95.80.0/20 Amazon | ||
2720 | 52.95.96.0/22 Amazon | ||
2721 | 52.95.100.0/22 Amazon | ||
2722 | 52.95.104.0/22 Amazon | ||
2723 | 52.95.108.0/23 Amazon | ||
2724 | 52.95.110.0/24 Amazon | ||
2725 | 52.95.111.0/24 Amazon | ||
2726 | 52.95.112.0/20 Amazon | ||
2727 | 52.95.128.0/21 Amazon | ||
2728 | 52.95.136.0/23 Amazon | ||
2729 | 52.95.138.0/24 Amazon | ||
2730 | 52.95.139.0/24 Amazon | ||
2731 | 52.95.140.0/23 Amazon | ||
2732 | 52.95.142.0/23 Amazon | ||
2733 | 52.95.144.0/24 Amazon | ||
2734 | 52.95.145.0/24 Amazon | ||
2735 | 52.95.146.0/23 Amazon | ||
2736 | 52.95.148.0/23 Amazon | ||
2737 | 52.95.150.0/24 Amazon | ||
2738 | 52.95.151.0/24 Amazon | ||
2739 | 52.95.152.0/23 Amazon | ||
2740 | 52.95.154.0/23 Amazon | ||
2741 | 52.95.156.0/24 Amazon | ||
2742 | 52.95.157.0/24 Amazon | ||
2743 | 52.95.158.0/23 Amazon | ||
2744 | 52.95.160.0/23 Amazon | ||
2745 | 52.95.162.0/24 Amazon | ||
2746 | 52.95.163.0/24 Amazon | ||
2747 | 52.95.164.0/23 Amazon | ||
2748 | 52.95.166.0/23 Amazon | ||
2749 | 52.95.168.0/24 Amazon | ||
2750 | 52.95.169.0/24 Amazon | ||
2751 | 52.95.170.0/23 Amazon | ||
2752 | 52.95.172.0/23 Amazon | ||
2753 | 52.95.174.0/24 Amazon | ||
2754 | 52.95.175.0/24 Amazon | ||
2755 | 52.95.176.0/24 Amazon | ||
2756 | 52.95.177.0/24 Amazon | ||
2757 | 52.95.178.0/23 Amazon | ||
2758 | 52.95.180.0/24 Amazon | ||
2759 | 52.95.181.0/24 Amazon | ||
2760 | 52.95.182.0/23 Amazon | ||
2761 | 52.95.184.0/23 Amazon | ||
2762 | 52.95.186.0/24 Amazon | ||
2763 | 52.95.187.0/24 Amazon | ||
2764 | 52.95.188.0/23 Amazon | ||
2765 | 52.95.190.0/24 Amazon | ||
2766 | 52.95.192.0/20 Amazon | ||
2767 | 52.95.208.0/22 Amazon | ||
2768 | 52.95.212.0/22 Amazon | ||
2769 | 52.95.216.0/22 Amazon | ||
2770 | 52.95.224.0/24 Amazon | ||
2771 | 52.95.225.0/24 Amazon | ||
2772 | 52.95.226.0/24 Amazon | ||
2773 | 52.95.227.0/24 Amazon | ||
2774 | 52.95.228.0/24 Amazon | ||
2775 | 52.95.229.0/24 Amazon | ||
2776 | 52.95.230.0/24 Amazon | ||
2777 | 52.95.235.0/24 Amazon | ||
2778 | 52.95.239.0/24 Amazon | ||
2779 | 52.95.240.0/24 Amazon | ||
2780 | 52.95.241.0/24 Amazon | ||
2781 | 52.95.242.0/24 Amazon | ||
2782 | 52.95.243.0/24 Amazon | ||
2783 | 52.95.244.0/24 Amazon | ||
2784 | 52.95.245.0/24 Amazon | ||
2785 | 52.95.246.0/24 Amazon | ||
2786 | 52.95.247.0/24 Amazon | ||
2787 | 52.95.248.0/24 Amazon | ||
2788 | 52.95.249.0/24 Amazon | ||
2789 | 52.95.250.0/24 Amazon | ||
2790 | 52.95.251.0/24 Amazon | ||
2791 | 52.95.252.0/24 Amazon | ||
2792 | 52.95.253.0/24 Amazon | ||
2793 | 52.95.254.0/24 Amazon | ||
2794 | 52.95.255.0/28 Amazon | ||
2795 | 52.95.255.16/28 Amazon | ||
2796 | 52.95.255.32/28 Amazon | ||
2797 | 52.95.255.48/28 Amazon | ||
2798 | 52.95.255.64/28 Amazon | ||
2799 | 52.95.255.80/28 Amazon | ||
2800 | 52.95.255.96/28 Amazon | ||
2801 | 52.95.255.112/28 Amazon | ||
2802 | 52.95.255.128/28 Amazon | ||
2803 | 52.95.255.144/28 Amazon | ||
2804 | 52.119.128.0/20 Amazon | ||
2805 | 52.119.144.0/21 Amazon | ||
2806 | 52.119.152.0/22 Amazon | ||
2807 | 52.119.156.0/22 Amazon | ||
2808 | 52.119.160.0/20 Amazon | ||
2809 | 52.119.176.0/21 Amazon | ||
2810 | 52.119.184.0/22 Amazon | ||
2811 | 52.119.188.0/22 Amazon | ||
2812 | 52.119.192.0/22 Amazon | ||
2813 | 52.119.196.0/22 Amazon | ||
2814 | 52.119.205.0/24 Amazon | ||
2815 | 52.119.206.0/23 Amazon | ||
2816 | 52.119.208.0/23 Amazon | ||
2817 | 52.119.210.0/23 Amazon | ||
2818 | 52.119.212.0/23 Amazon | ||
2819 | 52.119.214.0/23 Amazon | ||
2820 | 52.119.216.0/21 Amazon | ||
2821 | 52.119.224.0/21 Amazon | ||
2822 | 52.119.232.0/21 Amazon | ||
2823 | 52.119.240.0/21 Amazon | ||
2824 | 52.119.248.0/24 Amazon | ||
2825 | 52.119.249.0/24 Amazon | ||
2826 | 52.119.252.0/22 Amazon | ||
2827 | 52.124.128.0/17 Amazon | ||
2828 | 52.144.133.32/27 Amazon | ||
2829 | 52.144.192.0/26 Amazon | ||
2830 | 52.144.192.64/26 Amazon | ||
2831 | 52.144.192.128/26 Amazon | ||
2832 | 52.144.192.192/26 Amazon | ||
2833 | 52.144.193.0/26 Amazon | ||
2834 | 52.144.193.64/26 Amazon | ||
2835 | 52.144.193.128/26 Amazon | ||
2836 | 52.144.194.0/26 Amazon | ||
2837 | 52.144.194.64/26 Amazon | ||
2838 | 52.144.194.128/26 Amazon | ||
2839 | 52.144.194.192/26 Amazon | ||
2840 | 52.144.195.0/26 Amazon | ||
2841 | 52.144.196.192/26 Amazon | ||
2842 | 52.144.197.128/26 Amazon | ||
2843 | 52.144.197.192/26 Amazon | ||
2844 | 52.144.199.128/26 Amazon | ||
2845 | 52.144.200.64/26 Amazon | ||
2846 | 52.144.200.128/26 Amazon | ||
2847 | 52.144.201.64/26 Amazon | ||
2848 | 52.144.201.128/26 Amazon | ||
2849 | 52.144.205.0/26 Amazon | ||
2850 | 52.144.208.0/31 Amazon | ||
2851 | 52.144.208.2/31 Amazon | ||
2852 | 52.144.208.64/26 Amazon | ||
2853 | 52.144.208.128/26 Amazon | ||
2854 | 52.144.208.192/26 Amazon | ||
2855 | 52.144.209.0/26 Amazon | ||
2856 | 52.144.209.64/26 Amazon | ||
2857 | 52.144.209.128/26 Amazon | ||
2858 | 52.144.209.192/26 Amazon | ||
2859 | 52.144.210.0/26 Amazon | ||
2860 | 52.144.210.64/26 Amazon | ||
2861 | 52.144.210.128/26 Amazon | ||
2862 | 52.144.210.192/26 Amazon | ||
2863 | 52.144.211.0/26 Amazon | ||
2864 | 52.144.211.64/26 Amazon | ||
2865 | 52.144.211.128/26 Amazon | ||
2866 | 52.144.211.192/31 Amazon | ||
2867 | 52.144.211.194/31 Amazon | ||
2868 | 52.144.211.196/31 Amazon | ||
2869 | 52.144.211.198/31 Amazon | ||
2870 | 52.144.211.200/31 Amazon | ||
2871 | 52.144.211.202/31 Amazon | ||
2872 | 52.144.212.64/26 Amazon | ||
2873 | 52.144.212.192/26 Amazon | ||
2874 | 52.144.213.64/26 Amazon | ||
2875 | 52.144.214.128/26 Amazon | ||
2876 | 52.144.215.0/31 Amazon | ||
2877 | 52.144.215.2/31 Amazon | ||
2878 | 52.144.215.192/31 Amazon | ||
2879 | 52.144.215.194/31 Amazon | ||
2880 | 52.144.215.196/31 Amazon | ||
2881 | 52.144.215.198/31 Amazon | ||
2882 | 52.144.215.200/31 Amazon | ||
2883 | 52.144.215.202/31 Amazon | ||
2884 | 52.144.216.0/31 Amazon | ||
2885 | 52.144.216.2/31 Amazon | ||
2886 | 52.144.216.4/31 Amazon | ||
2887 | 52.144.216.6/31 Amazon | ||
2888 | 52.144.216.8/31 Amazon | ||
2889 | 52.144.216.10/31 Amazon | ||
2890 | 52.144.218.0/26 Amazon | ||
2891 | 52.144.218.64/26 Amazon | ||
2892 | 52.144.223.64/26 Amazon | ||
2893 | 52.144.223.128/26 Amazon | ||
2894 | 52.144.224.64/26 Amazon | ||
2895 | 52.144.224.128/26 Amazon | ||
2896 | 52.144.224.192/26 Amazon | ||
2897 | 52.144.225.0/26 Amazon | ||
2898 | 52.144.225.64/26 Amazon | ||
2899 | 52.144.225.128/26 Amazon | ||
2900 | 52.144.227.64/26 Amazon | ||
2901 | 52.144.227.192/26 Amazon | ||
2902 | 52.144.228.0/31 Amazon | ||
2903 | 52.144.228.2/31 Amazon | ||
2904 | 52.144.228.64/26 Amazon | ||
2905 | 52.144.228.128/26 Amazon | ||
2906 | 52.144.228.192/26 Amazon | ||
2907 | 52.144.229.0/26 Amazon | ||
2908 | 52.144.229.64/26 Amazon | ||
2909 | 52.144.230.0/26 Amazon | ||
2910 | 52.144.231.64/26 Amazon | ||
2911 | 52.144.233.64/31 Amazon | ||
2912 | 52.144.233.66/31 Amazon | ||
2913 | 52.144.233.68/31 Amazon | ||
2914 | 52.144.233.70/31 Amazon | ||
2915 | 52.144.233.128/31 Amazon | ||
2916 | 52.144.233.130/31 Amazon | ||
2917 | 52.144.233.132/31 Amazon | ||
2918 | 52.144.233.134/31 Amazon | ||
2919 | 52.144.233.192/26 Amazon | ||
2920 | 52.192.0.0/15 Amazon | ||
2921 | 52.194.0.0/15 Amazon | ||
2922 | 52.196.0.0/14 Amazon | ||
2923 | 52.200.0.0/13 Amazon | ||
2924 | 52.208.0.0/13 Amazon | ||
2925 | 52.216.0.0/15 Amazon | ||
2926 | 52.218.0.0/17 Amazon | ||
2927 | 52.218.128.0/17 Amazon | ||
2928 | 52.219.0.0/20 Amazon | ||
2929 | 52.219.16.0/22 Amazon | ||
2930 | 52.219.24.0/21 Amazon | ||
2931 | 52.219.32.0/21 Amazon | ||
2932 | 52.219.40.0/22 Amazon | ||
2933 | 52.219.44.0/22 Amazon | ||
2934 | 52.219.56.0/22 Amazon | ||
2935 | 52.219.60.0/23 Amazon | ||
2936 | 52.219.62.0/23 Amazon | ||
2937 | 52.219.64.0/22 Amazon | ||
2938 | 52.219.68.0/22 Amazon | ||
2939 | 52.219.72.0/22 Amazon | ||
2940 | 52.219.80.0/20 Amazon | ||
2941 | 52.219.96.0/20 Amazon | ||
2942 | 52.219.112.0/21 Amazon | ||
2943 | 52.219.120.0/22 Amazon | ||
2944 | 52.219.124.0/22 Amazon | ||
2945 | 52.219.128.0/22 Amazon | ||
2946 | 52.219.132.0/22 Amazon | ||
2947 | 52.219.136.0/22 Amazon | ||
2948 | 52.219.140.0/24 Amazon | ||
2949 | 52.219.141.0/24 Amazon | ||
2950 | 52.219.142.0/24 Amazon | ||
2951 | 52.219.143.0/24 Amazon | ||
2952 | 52.219.144.0/22 Amazon | ||
2953 | 52.219.148.0/23 Amazon | ||
2954 | 52.219.152.0/22 Amazon | ||
2955 | 52.219.156.0/22 Amazon | ||
2956 | 52.219.160.0/23 Amazon | ||
2957 | 52.219.164.0/22 Amazon | ||
2958 | 52.219.168.0/24 Amazon | ||
2959 | 52.219.169.0/24 Amazon | ||
2960 | 52.219.170.0/23 Amazon | ||
2961 | 52.219.172.0/22 Amazon | ||
2962 | 52.219.176.0/22 Amazon | ||
2963 | 52.219.180.0/22 Amazon | ||
2964 | 52.219.184.0/21 Amazon | ||
2965 | 52.219.192.0/23 Amazon | ||
2966 | 52.219.194.0/24 Amazon | ||
2967 | 52.219.195.0/24 Amazon | ||
2968 | 52.219.196.0/22 Amazon | ||
2969 | 52.219.200.0/24 Amazon | ||
2970 | 52.219.202.0/23 Amazon | ||
2971 | 52.219.204.0/22 Amazon | ||
2972 | 52.220.0.0/15 Amazon | ||
2973 | 52.222.0.0/17 Amazon | ||
2974 | 52.222.128.0/17 Amazon | ||
2975 | 52.223.0.0/17 Amazon | ||
2976 | 54.64.0.0/15 Amazon | ||
2977 | 54.66.0.0/16 Amazon | ||
2978 | 54.67.0.0/16 Amazon | ||
2979 | 54.68.0.0/14 Amazon | ||
2980 | 54.72.0.0/15 Amazon | ||
2981 | 54.74.0.0/15 Amazon | ||
2982 | 54.76.0.0/15 Amazon | ||
2983 | 54.78.0.0/16 Amazon | ||
2984 | 54.79.0.0/16 Amazon | ||
2985 | 54.80.0.0/13 Amazon | ||
2986 | 54.88.0.0/14 Amazon | ||
2987 | 54.92.0.0/17 Amazon | ||
2988 | 54.92.128.0/17 Amazon | ||
2989 | 54.93.0.0/16 Amazon | ||
2990 | 54.94.0.0/16 Amazon | ||
2991 | 54.95.0.0/16 Amazon | ||
2992 | 54.144.0.0/14 Amazon | ||
2993 | 54.148.0.0/15 Amazon | ||
2994 | 54.150.0.0/16 Amazon | ||
2995 | 54.151.0.0/17 Amazon | ||
2996 | 54.151.128.0/17 Amazon | ||
2997 | 54.152.0.0/16 Amazon | ||
2998 | 54.153.0.0/17 Amazon | ||
2999 | 54.153.128.0/17 Amazon | ||
3000 | 54.154.0.0/16 Amazon | ||
3001 | 54.155.0.0/16 Amazon | ||
3002 | 54.156.0.0/14 Amazon | ||
3003 | 54.160.0.0/13 Amazon | ||
3004 | 54.168.0.0/16 Amazon | ||
3005 | 54.169.0.0/16 Amazon | ||
3006 | 54.170.0.0/15 Amazon | ||
3007 | 54.172.0.0/15 Amazon | ||
3008 | 54.174.0.0/15 Amazon | ||
3009 | 54.176.0.0/15 Amazon | ||
3010 | 54.178.0.0/16 Amazon | ||
3011 | 54.179.0.0/16 Amazon | ||
3012 | 54.180.0.0/15 Amazon | ||
3013 | 54.182.0.0/16 Amazon | ||
3014 | 54.183.0.0/16 Amazon | ||
3015 | 54.184.0.0/13 Amazon | ||
3016 | 54.192.0.0/16 Amazon | ||
3017 | 54.193.0.0/16 Amazon | ||
3018 | 54.194.0.0/15 Amazon | ||
3019 | 54.196.0.0/15 Amazon | ||
3020 | 54.198.0.0/16 Amazon | ||
3021 | 54.199.0.0/16 Amazon | ||
3022 | 54.200.0.0/15 Amazon | ||
3023 | 54.202.0.0/15 Amazon | ||
3024 | 54.204.0.0/15 Amazon | ||
3025 | 54.206.0.0/16 Amazon | ||
3026 | 54.207.0.0/16 Amazon | ||
3027 | 54.208.0.0/15 Amazon | ||
3028 | 54.210.0.0/15 Amazon | ||
3029 | 54.212.0.0/15 Amazon | ||
3030 | 54.214.0.0/16 Amazon | ||
3031 | 54.215.0.0/16 Amazon | ||
3032 | 54.216.0.0/15 Amazon | ||
3033 | 54.218.0.0/16 Amazon | ||
3034 | 54.219.0.0/16 Amazon | ||
3035 | 54.220.0.0/16 Amazon | ||
3036 | 54.221.0.0/16 Amazon | ||
3037 | 54.222.0.0/19 Amazon | ||
3038 | 54.222.32.0/22 Amazon | ||
3039 | 54.222.36.0/22 Amazon | ||
3040 | 54.222.48.0/22 Amazon | ||
3041 | 54.222.52.0/22 Amazon | ||
3042 | 54.222.57.0/24 Amazon | ||
3043 | 54.222.58.0/28 Amazon | ||
3044 | 54.222.58.32/28 Amazon | ||
3045 | 54.222.58.48/28 Amazon | ||
3046 | 54.222.59.0/24 Amazon | ||
3047 | 54.222.64.0/23 Amazon | ||
3048 | 54.222.66.0/23 Amazon | ||
3049 | 54.222.68.0/23 Amazon | ||
3050 | 54.222.70.0/24 Amazon | ||
3051 | 54.222.71.0/24 Amazon | ||
3052 | 54.222.76.0/22 Amazon | ||
3053 | 54.222.80.0/21 Amazon | ||
3054 | 54.222.128.0/17 Amazon | ||
3055 | 54.223.0.0/16 Amazon | ||
3056 | 54.224.0.0/15 Amazon | ||
3057 | 54.226.0.0/15 Amazon | ||
3058 | 54.228.0.0/16 Amazon | ||
3059 | 54.229.0.0/16 Amazon | ||
3060 | 54.230.0.0/17 Amazon | ||
3061 | 54.230.128.0/18 Amazon | ||
3062 | 54.230.192.0/21 Amazon | ||
3063 | 54.230.200.0/21 Amazon | ||
3064 | 54.230.208.0/20 Amazon | ||
3065 | 54.230.224.0/19 Amazon | ||
3066 | 54.231.0.0/16 Amazon | ||
3067 | 54.232.0.0/16 Amazon | ||
3068 | 54.233.0.0/18 Amazon | ||
3069 | 54.233.64.0/18 Amazon | ||
3070 | 54.233.128.0/17 Amazon | ||
3071 | 54.234.0.0/15 Amazon | ||
3072 | 54.236.0.0/15 Amazon | ||
3073 | 54.238.0.0/16 Amazon | ||
3074 | 54.239.0.0/28 Amazon | ||
3075 | 54.239.0.16/28 Amazon | ||
3076 | 54.239.0.32/28 Amazon | ||
3077 | 54.239.0.48/28 Amazon | ||
3078 | 54.239.0.64/28 Amazon | ||
3079 | 54.239.0.80/28 Amazon | ||
3080 | 54.239.0.96/28 Amazon | ||
3081 | 54.239.0.112/28 Amazon | ||
3082 | 54.239.0.128/28 Amazon | ||
3083 | 54.239.0.144/28 Amazon | ||
3084 | 54.239.0.160/28 Amazon | ||
3085 | 54.239.0.176/28 Amazon | ||
3086 | 54.239.0.192/28 Amazon | ||
3087 | 54.239.0.208/28 Amazon | ||
3088 | 54.239.0.224/28 Amazon | ||
3089 | 54.239.0.240/28 Amazon | ||
3090 | 54.239.1.0/28 Amazon | ||
3091 | 54.239.1.16/28 Amazon | ||
3092 | 54.239.1.32/28 Amazon | ||
3093 | 54.239.1.48/28 Amazon | ||
3094 | 54.239.1.64/28 Amazon | ||
3095 | 54.239.1.80/28 Amazon | ||
3096 | 54.239.1.96/28 Amazon | ||
3097 | 54.239.1.112/28 Amazon | ||
3098 | 54.239.1.128/28 Amazon | ||
3099 | 54.239.1.144/28 Amazon | ||
3100 | 54.239.1.160/28 Amazon | ||
3101 | 54.239.1.176/28 Amazon | ||
3102 | 54.239.1.192/28 Amazon | ||
3103 | 54.239.1.208/28 Amazon | ||
3104 | 54.239.1.224/28 Amazon | ||
3105 | 54.239.2.0/23 Amazon | ||
3106 | 54.239.4.0/22 Amazon | ||
3107 | 54.239.8.0/21 Amazon | ||
3108 | 54.239.16.0/20 Amazon | ||
3109 | 54.239.32.0/21 Amazon | ||
3110 | 54.239.40.152/29 Amazon | ||
3111 | 54.239.48.0/22 Amazon | ||
3112 | 54.239.52.0/23 Amazon | ||
3113 | 54.239.54.0/23 Amazon | ||
3114 | 54.239.56.0/21 Amazon | ||
3115 | 54.239.64.0/21 Amazon | ||
3116 | 54.239.96.0/24 Amazon | ||
3117 | 54.239.98.0/24 Amazon | ||
3118 | 54.239.99.0/24 Amazon | ||
3119 | 54.239.100.0/23 Amazon | ||
3120 | 54.239.102.162/31 Amazon | ||
3121 | 54.239.102.232/31 Amazon | ||
3122 | 54.239.102.234/31 Amazon | ||
3123 | 54.239.102.236/31 Amazon | ||
3124 | 54.239.104.0/23 Amazon | ||
3125 | 54.239.106.0/23 Amazon | ||
3126 | 54.239.108.0/22 Amazon | ||
3127 | 54.239.112.0/24 Amazon | ||
3128 | 54.239.113.0/24 Amazon | ||
3129 | 54.239.115.0/25 Amazon | ||
3130 | 54.239.116.0/22 Amazon | ||
3131 | 54.239.120.0/21 Amazon | ||
3132 | 54.239.128.0/18 Amazon | ||
3133 | 54.239.192.0/19 Amazon | ||
3134 | 54.240.17.0/24 Amazon | ||
3135 | 54.240.128.0/18 Amazon | ||
3136 | 54.240.192.0/22 Amazon | ||
3137 | 54.240.196.0/24 Amazon | ||
3138 | 54.240.197.0/24 Amazon | ||
3139 | 54.240.198.0/24 Amazon | ||
3140 | 54.240.199.0/24 Amazon | ||
3141 | 54.240.200.0/24 Amazon | ||
3142 | 54.240.202.0/24 Amazon | ||
3143 | 54.240.203.0/24 Amazon | ||
3144 | 54.240.204.0/22 Amazon | ||
3145 | 54.240.208.0/22 Amazon | ||
3146 | 54.240.212.0/22 Amazon | ||
3147 | 54.240.216.0/22 Amazon | ||
3148 | 54.240.220.0/22 Amazon | ||
3149 | 54.240.225.0/24 Amazon | ||
3150 | 54.240.226.0/24 Amazon | ||
3151 | 54.240.227.0/24 Amazon | ||
3152 | 54.240.228.0/23 Amazon | ||
3153 | 54.240.230.0/23 Amazon | ||
3154 | 54.240.232.0/22 Amazon | ||
3155 | 54.240.236.1/32 Amazon | ||
3156 | 54.240.236.2/32 Amazon | ||
3157 | 54.240.236.5/32 Amazon | ||
3158 | 54.240.236.6/32 Amazon | ||
3159 | 54.240.236.9/32 Amazon | ||
3160 | 54.240.236.10/32 Amazon | ||
3161 | 54.240.236.13/32 Amazon | ||
3162 | 54.240.236.14/32 Amazon | ||
3163 | 54.240.236.17/32 Amazon | ||
3164 | 54.240.236.18/32 Amazon | ||
3165 | 54.240.236.21/32 Amazon | ||
3166 | 54.240.236.22/32 Amazon | ||
3167 | 54.240.236.25/32 Amazon | ||
3168 | 54.240.236.26/32 Amazon | ||
3169 | 54.240.236.29/32 Amazon | ||
3170 | 54.240.236.30/32 Amazon | ||
3171 | 54.240.236.33/32 Amazon | ||
3172 | 54.240.236.34/32 Amazon | ||
3173 | 54.240.236.37/32 Amazon | ||
3174 | 54.240.236.38/32 Amazon | ||
3175 | 54.240.236.41/32 Amazon | ||
3176 | 54.240.236.42/32 Amazon | ||
3177 | 54.240.236.45/32 Amazon | ||
3178 | 54.240.236.46/32 Amazon | ||
3179 | 54.240.236.49/32 Amazon | ||
3180 | 54.240.236.50/32 Amazon | ||
3181 | 54.240.236.53/32 Amazon | ||
3182 | 54.240.236.54/32 Amazon | ||
3183 | 54.240.236.57/32 Amazon | ||
3184 | 54.240.236.58/32 Amazon | ||
3185 | 54.240.236.61/32 Amazon | ||
3186 | 54.240.236.62/32 Amazon | ||
3187 | 54.240.236.65/32 Amazon | ||
3188 | 54.240.236.66/32 Amazon | ||
3189 | 54.240.236.69/32 Amazon | ||
3190 | 54.240.236.70/32 Amazon | ||
3191 | 54.240.236.73/32 Amazon | ||
3192 | 54.240.236.74/32 Amazon | ||
3193 | 54.240.236.77/32 Amazon | ||
3194 | 54.240.236.78/32 Amazon | ||
3195 | 54.240.236.81/32 Amazon | ||
3196 | 54.240.236.82/32 Amazon | ||
3197 | 54.240.236.85/32 Amazon | ||
3198 | 54.240.236.86/32 Amazon | ||
3199 | 54.240.236.89/32 Amazon | ||
3200 | 54.240.236.90/32 Amazon | ||
3201 | 54.240.236.93/32 Amazon | ||
3202 | 54.240.236.94/32 Amazon | ||
3203 | 54.240.241.0/24 Amazon | ||
3204 | 54.240.244.0/22 Amazon | ||
3205 | 54.240.248.0/21 Amazon | ||
3206 | 54.241.0.0/16 Amazon | ||
3207 | 54.242.0.0/15 Amazon | ||
3208 | 54.244.0.0/16 Amazon | ||
3209 | 54.245.0.0/16 Amazon | ||
3210 | 54.246.0.0/16 Amazon | ||
3211 | 54.247.0.0/16 Amazon | ||
3212 | 54.248.0.0/15 Amazon | ||
3213 | 54.250.0.0/16 Amazon | ||
3214 | 54.251.0.0/16 Amazon | ||
3215 | 54.252.0.0/16 Amazon | ||
3216 | 54.253.0.0/16 Amazon | ||
3217 | 54.254.0.0/16 Amazon | ||
3218 | 54.255.0.0/16 Amazon | ||
3219 | 58.254.138.0/25 Amazon | ||
3220 | 58.254.138.128/26 Amazon | ||
3221 | 63.32.0.0/14 Amazon | ||
3222 | 63.246.112.0/24 Amazon | ||
3223 | 63.246.113.0/24 Amazon | ||
3224 | 63.246.114.0/23 Amazon | ||
3225 | 63.246.119.0/24 Amazon | ||
3226 | 64.187.128.0/20 Amazon | ||
3227 | 64.252.64.0/18 Amazon | ||
3228 | 64.252.128.0/18 Amazon | ||
3229 | 65.0.0.0/14 Amazon | ||
3230 | 65.8.0.0/16 Amazon | ||
3231 | 65.9.0.0/17 Amazon | ||
3232 | 65.9.128.0/18 Amazon | ||
3233 | 67.202.0.0/18 Amazon | ||
3234 | 67.220.224.0/20 Amazon | ||
3235 | 67.220.240.0/20 Amazon | ||
3236 | 68.66.112.0/20 Amazon | ||
3237 | 68.79.0.0/18 Amazon | ||
3238 | 69.107.3.176/29 Amazon | ||
3239 | 69.107.3.184/29 Amazon | ||
3240 | 69.107.6.112/29 Amazon | ||
3241 | 69.107.6.120/29 Amazon | ||
3242 | 69.107.6.160/29 Amazon | ||
3243 | 69.107.6.168/29 Amazon | ||
3244 | 69.107.6.200/29 Amazon | ||
3245 | 69.107.6.208/29 Amazon | ||
3246 | 69.107.6.216/29 Amazon | ||
3247 | 69.107.6.224/29 Amazon | ||
3248 | 69.107.7.0/29 Amazon | ||
3249 | 69.107.7.8/29 Amazon | ||
3250 | 69.107.7.16/29 Amazon | ||
3251 | 69.107.7.32/29 Amazon | ||
3252 | 69.107.7.40/29 Amazon | ||
3253 | 69.107.7.48/29 Amazon | ||
3254 | 69.107.7.56/29 Amazon | ||
3255 | 69.107.7.64/29 Amazon | ||
3256 | 69.107.7.72/29 Amazon | ||
3257 | 69.107.7.80/29 Amazon | ||
3258 | 69.107.7.88/29 Amazon | ||
3259 | 69.107.7.96/29 Amazon | ||
3260 | 69.107.7.104/29 Amazon | ||
3261 | 69.107.7.112/29 Amazon | ||
3262 | 69.107.7.120/29 Amazon | ||
3263 | 69.107.7.128/29 Amazon | ||
3264 | 69.107.7.136/29 Amazon | ||
3265 | 69.230.192.0/18 Amazon | ||
3266 | 69.231.128.0/18 Amazon | ||
3267 | 69.234.192.0/18 Amazon | ||
3268 | 69.235.128.0/18 Amazon | ||
3269 | 70.132.0.0/18 Amazon | ||
3270 | 70.224.192.0/18 Amazon | ||
3271 | 70.232.64.0/20 Amazon | ||
3272 | 70.232.80.0/21 Amazon | ||
3273 | 70.232.88.0/22 Amazon | ||
3274 | 70.232.92.0/22 Amazon | ||
3275 | 70.232.96.0/20 Amazon | ||
3276 | 70.232.112.0/21 Amazon | ||
3277 | 70.232.120.0/22 Amazon | ||
3278 | 70.232.124.0/22 Amazon | ||
3279 | 71.131.192.0/18 Amazon | ||
3280 | 71.132.0.0/18 Amazon | ||
3281 | 71.137.0.0/22 Amazon | ||
3282 | 71.137.4.0/24 Amazon | ||
3283 | 71.137.8.0/22 Amazon | ||
3284 | 71.152.0.0/17 Amazon | ||
3285 | 72.21.192.0/19 Amazon | ||
3286 | 72.41.0.0/20 Amazon | ||
3287 | 72.44.32.0/19 Amazon | ||
3288 | 75.2.0.0/17 Amazon | ||
3289 | 75.101.128.0/17 Amazon | ||
3290 | 76.223.0.0/17 Amazon | ||
3291 | 79.125.0.0/17 Amazon | ||
3292 | 87.238.80.0/21 Amazon | ||
3293 | 96.127.0.0/17 Amazon | ||
3294 | 99.77.0.0/20 Amazon | ||
3295 | 99.77.16.0/21 Amazon | ||
3296 | 99.77.24.0/22 Amazon | ||
3297 | 99.77.28.0/22 Amazon | ||
3298 | 99.77.32.0/20 Amazon | ||
3299 | 99.77.48.0/21 Amazon | ||
3300 | 99.77.56.0/21 Amazon | ||
3301 | 99.77.128.0/18 Amazon | ||
3302 | 99.77.247.0/24 Amazon | ||
3303 | 99.77.250.0/24 Amazon | ||
3304 | 99.77.253.0/24 Amazon | ||
3305 | 99.77.254.0/24 Amazon | ||
3306 | 99.78.128.0/20 Amazon | ||
3307 | 99.78.144.0/21 Amazon | ||
3308 | 99.78.152.0/22 Amazon | ||
3309 | 99.78.156.0/22 Amazon | ||
3310 | 99.78.160.0/21 Amazon | ||
3311 | 99.78.168.0/23 Amazon | ||
3312 | 99.78.170.0/23 Amazon | ||
3313 | 99.78.172.0/24 Amazon | ||
3314 | 99.78.176.0/21 Amazon | ||
3315 | 99.78.184.0/22 Amazon | ||
3316 | 99.78.188.0/22 Amazon | ||
3317 | 99.78.192.0/22 Amazon | ||
3318 | 99.78.196.0/22 Amazon | ||
3319 | 99.78.208.0/22 Amazon | ||
3320 | 99.78.212.0/22 Amazon | ||
3321 | 99.78.216.0/22 Amazon | ||
3322 | 99.78.220.0/22 Amazon | ||
3323 | 99.78.228.0/22 Amazon | ||
3324 | 99.78.232.0/21 Amazon | ||
3325 | 99.78.240.0/20 Amazon | ||
3326 | 99.79.0.0/16 Amazon | ||
3327 | 99.80.0.0/15 Amazon | ||
3328 | 99.82.128.0/20 Amazon | ||
3329 | 99.82.144.0/21 Amazon | ||
3330 | 99.82.152.0/22 Amazon | ||
3331 | 99.82.156.0/22 Amazon | ||
3332 | 99.82.160.0/24 Amazon | ||
3333 | 99.82.161.0/24 Amazon | ||
3334 | 99.82.162.0/24 Amazon | ||
3335 | 99.82.163.0/24 Amazon | ||
3336 | 99.82.164.0/24 Amazon | ||
3337 | 99.82.165.0/24 Amazon | ||
3338 | 99.82.166.0/24 Amazon | ||
3339 | 99.82.167.0/24 Amazon | ||
3340 | 99.82.168.0/24 Amazon | ||
3341 | 99.82.169.0/24 Amazon | ||
3342 | 99.82.170.0/24 Amazon | ||
3343 | 99.82.171.0/24 Amazon | ||
3344 | 99.82.172.0/24 Amazon | ||
3345 | 99.82.173.0/24 Amazon | ||
3346 | 99.82.174.0/24 Amazon | ||
3347 | 99.82.175.0/24 Amazon | ||
3348 | 99.82.176.0/21 Amazon | ||
3349 | 99.82.184.0/22 Amazon | ||
3350 | 99.82.188.0/22 Amazon | ||
3351 | 99.83.64.0/21 Amazon | ||
3352 | 99.83.72.0/22 Amazon | ||
3353 | 99.83.76.0/22 Amazon | ||
3354 | 99.83.80.0/22 Amazon | ||
3355 | 99.83.84.0/22 Amazon | ||
3356 | 99.83.88.0/21 Amazon | ||
3357 | 99.83.96.0/24 Amazon | ||
3358 | 99.83.97.0/24 Amazon | ||
3359 | 99.83.98.0/24 Amazon | ||
3360 | 99.83.99.0/24 Amazon | ||
3361 | 99.83.100.0/24 Amazon | ||
3362 | 99.83.101.0/24 Amazon | ||
3363 | 99.83.112.0/21 Amazon | ||
3364 | 99.83.120.0/22 Amazon | ||
3365 | 99.83.128.0/17 Amazon | ||
3366 | 99.84.0.0/16 Amazon | ||
3367 | 99.86.0.0/16 Amazon | ||
3368 | 99.87.0.0/22 Amazon | ||
3369 | 99.87.4.0/22 Amazon | ||
3370 | 99.87.8.0/21 Amazon | ||
3371 | 99.87.16.0/20 Amazon | ||
3372 | 99.87.32.0/22 Amazon | ||
3373 | 99.150.0.0/21 Amazon | ||
3374 | 99.150.8.0/21 Amazon | ||
3375 | 99.150.16.0/21 Amazon | ||
3376 | 99.150.24.0/21 Amazon | ||
3377 | 99.150.32.0/21 Amazon | ||
3378 | 99.150.40.0/21 Amazon | ||
3379 | 99.150.48.0/21 Amazon | ||
3380 | 99.150.56.0/21 Amazon | ||
3381 | 99.150.64.0/21 Amazon | ||
3382 | 99.150.72.0/21 Amazon | ||
3383 | 99.150.80.0/21 Amazon | ||
3384 | 99.150.88.0/21 Amazon | ||
3385 | 99.150.96.0/21 Amazon | ||
3386 | 99.150.104.0/21 Amazon | ||
3387 | 99.150.112.0/21 Amazon | ||
3388 | 99.150.120.0/21 Amazon | ||
3389 | 99.151.64.0/21 Amazon | ||
3390 | 99.151.72.0/21 Amazon | ||
3391 | 99.151.80.0/21 Amazon | ||
3392 | 99.151.88.0/21 Amazon | ||
3393 | 99.151.96.0/21 Amazon | ||
3394 | 99.151.104.0/21 Amazon | ||
3395 | 99.151.112.0/21 Amazon | ||
3396 | 99.151.120.0/21 Amazon | ||
3397 | 99.151.128.0/21 Amazon | ||
3398 | 99.151.136.0/21 Amazon | ||
3399 | 99.151.144.0/21 Amazon | ||
3400 | 100.20.0.0/14 Amazon | ||
3401 | 100.24.0.0/13 Amazon | ||
3402 | 103.4.8.0/21 Amazon | ||
3403 | 103.8.172.0/22 Amazon | ||
3404 | 103.246.148.0/23 Amazon | ||
3405 | 103.246.150.0/23 Amazon | ||
3406 | 104.255.56.11/32 Amazon | ||
3407 | 104.255.56.12/32 Amazon | ||
3408 | 104.255.59.81/32 Amazon | ||
3409 | 104.255.59.82/32 Amazon | ||
3410 | 104.255.59.83/32 Amazon | ||
3411 | 104.255.59.85/32 Amazon | ||
3412 | 104.255.59.86/32 Amazon | ||
3413 | 104.255.59.87/32 Amazon | ||
3414 | 104.255.59.88/32 Amazon | ||
3415 | 104.255.59.91/32 Amazon | ||
3416 | 104.255.59.101/32 Amazon | ||
3417 | 104.255.59.102/32 Amazon | ||
3418 | 104.255.59.103/32 Amazon | ||
3419 | 104.255.59.104/32 Amazon | ||
3420 | 104.255.59.105/32 Amazon | ||
3421 | 104.255.59.106/32 Amazon | ||
3422 | 104.255.59.114/32 Amazon | ||
3423 | 104.255.59.115/32 Amazon | ||
3424 | 104.255.59.118/32 Amazon | ||
3425 | 104.255.59.119/32 Amazon | ||
3426 | 104.255.59.122/32 Amazon | ||
3427 | 104.255.59.130/32 Amazon | ||
3428 | 104.255.59.131/32 Amazon | ||
3429 | 104.255.59.132/32 Amazon | ||
3430 | 104.255.59.133/32 Amazon | ||
3431 | 104.255.59.134/32 Amazon | ||
3432 | 104.255.59.135/32 Amazon | ||
3433 | 104.255.59.136/32 Amazon | ||
3434 | 104.255.59.137/32 Amazon | ||
3435 | 104.255.59.138/32 Amazon | ||
3436 | 104.255.59.139/32 Amazon | ||
3437 | 107.20.0.0/14 Amazon | ||
3438 | 107.176.0.0/15 Amazon | ||
3439 | 108.128.0.0/13 Amazon | ||
3440 | 108.136.0.0/15 Amazon | ||
3441 | 108.138.0.0/15 Amazon | ||
3442 | 108.156.0.0/14 Amazon | ||
3443 | 108.166.224.0/21 Amazon | ||
3444 | 108.166.232.0/21 Amazon | ||
3445 | 108.166.240.0/21 Amazon | ||
3446 | 108.166.248.0/21 Amazon | ||
3447 | 108.175.48.0/22 Amazon | ||
3448 | 108.175.52.0/22 Amazon | ||
3449 | 108.175.56.0/22 Amazon | ||
3450 | 108.175.60.0/22 Amazon | ||
3451 | 116.129.226.0/25 Amazon | ||
3452 | 116.129.226.128/26 Amazon | ||
3453 | 118.193.97.64/26 Amazon | ||
3454 | 118.193.97.128/25 Amazon | ||
3455 | 119.147.182.0/25 Amazon | ||
3456 | 119.147.182.128/26 Amazon | ||
3457 | 120.52.12.64/26 Amazon | ||
3458 | 120.52.22.96/27 Amazon | ||
3459 | 120.52.39.128/27 Amazon | ||
3460 | 120.52.153.192/26 Amazon | ||
3461 | 120.232.236.0/25 Amazon | ||
3462 | 120.232.236.128/26 Amazon | ||
3463 | 120.253.240.192/26 Amazon | ||
3464 | 120.253.241.160/27 Amazon | ||
3465 | 120.253.245.128/26 Amazon | ||
3466 | 120.253.245.192/27 Amazon | ||
3467 | 122.248.192.0/18 Amazon | ||
3468 | 130.176.0.0/17 Amazon | ||
3469 | 130.176.128.0/18 Amazon | ||
3470 | 130.176.192.0/19 Amazon | ||
3471 | 130.176.224.0/20 Amazon | ||
3472 | 130.176.254.0/24 Amazon | ||
3473 | 130.176.255.0/24 Amazon | ||
3474 | 140.179.0.0/16 Amazon | ||
3475 | 142.4.160.0/29 Amazon | ||
3476 | 142.4.160.8/29 Amazon | ||
3477 | 142.4.160.16/29 Amazon | ||
3478 | 142.4.160.24/29 Amazon | ||
3479 | 142.4.160.32/29 Amazon | ||
3480 | 142.4.160.40/29 Amazon | ||
3481 | 142.4.160.48/29 Amazon | ||
3482 | 142.4.160.56/29 Amazon | ||
3483 | 142.4.160.64/29 Amazon | ||
3484 | 142.4.160.72/29 Amazon | ||
3485 | 142.4.160.80/29 Amazon | ||
3486 | 142.4.160.88/29 Amazon | ||
3487 | 142.4.160.96/29 Amazon | ||
3488 | 142.4.160.104/29 Amazon | ||
3489 | 142.4.160.112/29 Amazon | ||
3490 | 143.204.0.0/16 Amazon | ||
3491 | 144.220.0.0/16 Amazon | ||
3492 | 150.222.0.16/32 Amazon | ||
3493 | 150.222.0.17/32 Amazon | ||
3494 | 150.222.0.18/32 Amazon | ||
3495 | 150.222.0.19/32 Amazon | ||
3496 | 150.222.2.0/24 Amazon | ||
3497 | 150.222.3.176/32 Amazon | ||
3498 | 150.222.3.177/32 Amazon | ||
3499 | 150.222.3.178/32 Amazon | ||
3500 | 150.222.3.179/32 Amazon | ||
3501 | 150.222.3.180/32 Amazon | ||
3502 | 150.222.3.181/32 Amazon | ||
3503 | 150.222.3.182/32 Amazon | ||
3504 | 150.222.3.183/32 Amazon | ||
3505 | 150.222.3.184/32 Amazon | ||
3506 | 150.222.3.185/32 Amazon | ||
3507 | 150.222.3.186/32 Amazon | ||
3508 | 150.222.3.187/32 Amazon | ||
3509 | 150.222.3.188/32 Amazon | ||
3510 | 150.222.3.189/32 Amazon | ||
3511 | 150.222.3.190/32 Amazon | ||
3512 | 150.222.3.191/32 Amazon | ||
3513 | 150.222.3.192/31 Amazon | ||
3514 | 150.222.3.194/31 Amazon | ||
3515 | 150.222.3.196/31 Amazon | ||
3516 | 150.222.3.198/31 Amazon | ||
3517 | 150.222.3.200/31 Amazon | ||
3518 | 150.222.3.202/31 Amazon | ||
3519 | 150.222.3.204/31 Amazon | ||
3520 | 150.222.3.206/31 Amazon | ||
3521 | 150.222.3.208/31 Amazon | ||
3522 | 150.222.3.210/31 Amazon | ||
3523 | 150.222.3.212/31 Amazon | ||
3524 | 150.222.3.214/31 Amazon | ||
3525 | 150.222.3.216/31 Amazon | ||
3526 | 150.222.3.218/31 Amazon | ||
3527 | 150.222.3.220/31 Amazon | ||
3528 | 150.222.3.222/31 Amazon | ||
3529 | 150.222.3.224/31 Amazon | ||
3530 | 150.222.3.226/31 Amazon | ||
3531 | 150.222.3.228/31 Amazon | ||
3532 | 150.222.3.230/31 Amazon | ||
3533 | 150.222.3.232/31 Amazon | ||
3534 | 150.222.3.234/31 Amazon | ||
3535 | 150.222.3.236/31 Amazon | ||
3536 | 150.222.3.238/31 Amazon | ||
3537 | 150.222.3.240/31 Amazon | ||
3538 | 150.222.3.242/31 Amazon | ||
3539 | 150.222.3.244/31 Amazon | ||
3540 | 150.222.3.246/31 Amazon | ||
3541 | 150.222.3.248/31 Amazon | ||
3542 | 150.222.3.250/31 Amazon | ||
3543 | 150.222.3.252/31 Amazon | ||
3544 | 150.222.3.254/31 Amazon | ||
3545 | 150.222.5.0/24 Amazon | ||
3546 | 150.222.6.0/24 Amazon | ||
3547 | 150.222.7.0/24 Amazon | ||
3548 | 150.222.10.0/24 Amazon | ||
3549 | 150.222.11.0/31 Amazon | ||
3550 | 150.222.11.74/31 Amazon | ||
3551 | 150.222.11.76/31 Amazon | ||
3552 | 150.222.11.78/31 Amazon | ||
3553 | 150.222.11.80/31 Amazon | ||
3554 | 150.222.11.84/31 Amazon | ||
3555 | 150.222.11.86/31 Amazon | ||
3556 | 150.222.11.88/31 Amazon | ||
3557 | 150.222.11.90/31 Amazon | ||
3558 | 150.222.11.92/31 Amazon | ||
3559 | 150.222.11.94/31 Amazon | ||
3560 | 150.222.11.96/31 Amazon | ||
3561 | 150.222.12.0/24 Amazon | ||
3562 | 150.222.13.0/24 Amazon | ||
3563 | 150.222.14.72/31 Amazon | ||
3564 | 150.222.15.124/32 Amazon | ||
3565 | 150.222.15.125/32 Amazon | ||
3566 | 150.222.15.126/32 Amazon | ||
3567 | 150.222.15.127/32 Amazon | ||
3568 | 150.222.15.128/31 Amazon | ||
3569 | 150.222.15.130/31 Amazon | ||
3570 | 150.222.28.17/32 Amazon | ||
3571 | 150.222.28.18/31 Amazon | ||
3572 | 150.222.28.104/32 Amazon | ||
3573 | 150.222.28.105/32 Amazon | ||
3574 | 150.222.28.106/31 Amazon | ||
3575 | 150.222.28.108/31 Amazon | ||
3576 | 150.222.28.110/31 Amazon | ||
3577 | 150.222.28.112/31 Amazon | ||
3578 | 150.222.28.114/31 Amazon | ||
3579 | 150.222.28.116/31 Amazon | ||
3580 | 150.222.28.118/31 Amazon | ||
3581 | 150.222.28.120/31 Amazon | ||
3582 | 150.222.28.122/31 Amazon | ||
3583 | 150.222.28.124/31 Amazon | ||
3584 | 150.222.28.126/31 Amazon | ||
3585 | 150.222.28.128/31 Amazon | ||
3586 | 150.222.28.130/31 Amazon | ||
3587 | 150.222.28.132/31 Amazon | ||
3588 | 150.222.28.134/31 Amazon | ||
3589 | 150.222.28.136/31 Amazon | ||
3590 | 150.222.28.138/31 Amazon | ||
3591 | 150.222.28.140/31 Amazon | ||
3592 | 150.222.28.142/31 Amazon | ||
3593 | 150.222.66.0/24 Amazon | ||
3594 | 150.222.67.0/24 Amazon | ||
3595 | 150.222.69.0/24 Amazon | ||
3596 | 150.222.70.0/24 Amazon | ||
3597 | 150.222.71.0/24 Amazon | ||
3598 | 150.222.72.0/24 Amazon | ||
3599 | 150.222.73.0/24 Amazon | ||
3600 | 150.222.74.0/24 Amazon | ||
3601 | 150.222.75.0/24 Amazon | ||
3602 | 150.222.76.0/24 Amazon | ||
3603 | 150.222.77.0/24 Amazon | ||
3604 | 150.222.78.0/24 Amazon | ||
3605 | 150.222.79.0/24 Amazon | ||
3606 | 150.222.80.0/24 Amazon | ||
3607 | 150.222.81.0/24 Amazon | ||
3608 | 150.222.82.0/24 Amazon | ||
3609 | 150.222.83.0/24 Amazon | ||
3610 | 150.222.84.0/24 Amazon | ||
3611 | 150.222.85.0/24 Amazon | ||
3612 | 150.222.87.0/24 Amazon | ||
3613 | 150.222.88.0/24 Amazon | ||
3614 | 150.222.89.0/24 Amazon | ||
3615 | 150.222.90.0/24 Amazon | ||
3616 | 150.222.91.0/24 Amazon | ||
3617 | 150.222.92.0/22 Amazon | ||
3618 | 150.222.96.0/24 Amazon | ||
3619 | 150.222.97.0/24 Amazon | ||
3620 | 150.222.98.0/24 Amazon | ||
3621 | 150.222.99.0/24 Amazon | ||
3622 | 150.222.100.0/24 Amazon | ||
3623 | 150.222.101.0/24 Amazon | ||
3624 | 150.222.102.0/24 Amazon | ||
3625 | 150.222.104.0/24 Amazon | ||
3626 | 150.222.105.0/24 Amazon | ||
3627 | 150.222.106.0/24 Amazon | ||
3628 | 150.222.108.0/24 Amazon | ||
3629 | 150.222.109.0/24 Amazon | ||
3630 | 150.222.110.0/24 Amazon | ||
3631 | 150.222.112.0/24 Amazon | ||
3632 | 150.222.113.0/24 Amazon | ||
3633 | 150.222.114.0/24 Amazon | ||
3634 | 150.222.115.0/24 Amazon | ||
3635 | 150.222.116.0/24 Amazon | ||
3636 | 150.222.117.0/24 Amazon | ||
3637 | 150.222.118.0/24 Amazon | ||
3638 | 150.222.119.0/24 Amazon | ||
3639 | 150.222.120.20/31 Amazon | ||
3640 | 150.222.120.62/31 Amazon | ||
3641 | 150.222.120.224/31 Amazon | ||
3642 | 150.222.120.226/31 Amazon | ||
3643 | 150.222.120.228/31 Amazon | ||
3644 | 150.222.120.230/31 Amazon | ||
3645 | 150.222.120.232/31 Amazon | ||
3646 | 150.222.120.234/31 Amazon | ||
3647 | 150.222.120.240/31 Amazon | ||
3648 | 150.222.120.242/31 Amazon | ||
3649 | 150.222.120.244/31 Amazon | ||
3650 | 150.222.120.246/31 Amazon | ||
3651 | 150.222.120.248/31 Amazon | ||
3652 | 150.222.120.250/31 Amazon | ||
3653 | 150.222.120.252/32 Amazon | ||
3654 | 150.222.120.255/32 Amazon | ||
3655 | 150.222.121.0/24 Amazon | ||
3656 | 150.222.122.92/31 Amazon | ||
3657 | 150.222.122.94/31 Amazon | ||
3658 | 150.222.122.96/31 Amazon | ||
3659 | 150.222.122.98/31 Amazon | ||
3660 | 150.222.122.100/31 Amazon | ||
3661 | 150.222.122.102/31 Amazon | ||
3662 | 150.222.122.104/31 Amazon | ||
3663 | 150.222.122.106/31 Amazon | ||
3664 | 150.222.122.108/31 Amazon | ||
3665 | 150.222.122.110/31 Amazon | ||
3666 | 150.222.122.112/31 Amazon | ||
3667 | 150.222.122.114/31 Amazon | ||
3668 | 150.222.122.116/31 Amazon | ||
3669 | 150.222.129.19/32 Amazon | ||
3670 | 150.222.129.20/31 Amazon | ||
3671 | 150.222.129.62/31 Amazon | ||
3672 | 150.222.129.64/31 Amazon | ||
3673 | 150.222.129.66/31 Amazon | ||
3674 | 150.222.129.69/32 Amazon | ||
3675 | 150.222.129.110/31 Amazon | ||
3676 | 150.222.129.112/31 Amazon | ||
3677 | 150.222.129.114/31 Amazon | ||
3678 | 150.222.129.116/31 Amazon | ||
3679 | 150.222.129.118/31 Amazon | ||
3680 | 150.222.129.120/31 Amazon | ||
3681 | 150.222.129.122/31 Amazon | ||
3682 | 150.222.129.124/31 Amazon | ||
3683 | 150.222.129.126/31 Amazon | ||
3684 | 150.222.129.128/31 Amazon | ||
3685 | 150.222.129.130/31 Amazon | ||
3686 | 150.222.129.132/31 Amazon | ||
3687 | 150.222.129.134/31 Amazon | ||
3688 | 150.222.129.136/31 Amazon | ||
3689 | 150.222.129.138/31 Amazon | ||
3690 | 150.222.129.140/31 Amazon | ||
3691 | 150.222.129.142/31 Amazon | ||
3692 | 150.222.129.144/31 Amazon | ||
3693 | 150.222.129.146/31 Amazon | ||
3694 | 150.222.129.152/31 Amazon | ||
3695 | 150.222.129.154/31 Amazon | ||
3696 | 150.222.129.156/31 Amazon | ||
3697 | 150.222.129.158/31 Amazon | ||
3698 | 150.222.129.240/31 Amazon | ||
3699 | 150.222.129.242/31 Amazon | ||
3700 | 150.222.129.244/31 Amazon | ||
3701 | 150.222.129.246/31 Amazon | ||
3702 | 150.222.129.248/31 Amazon | ||
3703 | 150.222.129.250/31 Amazon | ||
3704 | 150.222.129.252/32 Amazon | ||
3705 | 150.222.129.255/32 Amazon | ||
3706 | 150.222.133.0/24 Amazon | ||
3707 | 150.222.134.0/24 Amazon | ||
3708 | 150.222.135.0/24 Amazon | ||
3709 | 150.222.136.0/24 Amazon | ||
3710 | 150.222.138.0/24 Amazon | ||
3711 | 150.222.139.116/30 Amazon | ||
3712 | 150.222.139.120/30 Amazon | ||
3713 | 150.222.139.124/30 Amazon | ||
3714 | 150.222.140.0/24 Amazon | ||
3715 | 150.222.141.0/24 Amazon | ||
3716 | 150.222.142.0/24 Amazon | ||
3717 | 150.222.143.0/24 Amazon | ||
3718 | 150.222.164.208/31 Amazon | ||
3719 | 150.222.164.210/32 Amazon | ||
3720 | 150.222.164.211/32 Amazon | ||
3721 | 150.222.164.220/31 Amazon | ||
3722 | 150.222.164.222/32 Amazon | ||
3723 | 150.222.176.0/22 Amazon | ||
3724 | 150.222.180.0/24 Amazon | ||
3725 | 150.222.196.0/24 Amazon | ||
3726 | 150.222.199.0/25 Amazon | ||
3727 | 150.222.202.0/24 Amazon | ||
3728 | 150.222.203.0/24 Amazon | ||
3729 | 150.222.204.0/24 Amazon | ||
3730 | 150.222.205.0/24 Amazon | ||
3731 | 150.222.206.0/24 Amazon | ||
3732 | 150.222.207.0/24 Amazon | ||
3733 | 150.222.208.64/32 Amazon | ||
3734 | 150.222.208.65/32 Amazon | ||
3735 | 150.222.208.66/31 Amazon | ||
3736 | 150.222.208.68/31 Amazon | ||
3737 | 150.222.208.70/31 Amazon | ||
3738 | 150.222.208.72/31 Amazon | ||
3739 | 150.222.208.74/31 Amazon | ||
3740 | 150.222.208.76/31 Amazon | ||
3741 | 150.222.208.78/31 Amazon | ||
3742 | 150.222.208.80/31 Amazon | ||
3743 | 150.222.208.82/31 Amazon | ||
3744 | 150.222.208.84/31 Amazon | ||
3745 | 150.222.208.86/31 Amazon | ||
3746 | 150.222.208.88/31 Amazon | ||
3747 | 150.222.208.90/31 Amazon | ||
3748 | 150.222.208.92/31 Amazon | ||
3749 | 150.222.208.94/31 Amazon | ||
3750 | 150.222.208.96/31 Amazon | ||
3751 | 150.222.210.0/24 Amazon | ||
3752 | 150.222.212.0/24 Amazon | ||
3753 | 150.222.213.40/32 Amazon | ||
3754 | 150.222.213.41/32 Amazon | ||
3755 | 150.222.214.0/24 Amazon | ||
3756 | 150.222.215.0/24 Amazon | ||
3757 | 150.222.217.17/32 Amazon | ||
3758 | 150.222.217.226/31 Amazon | ||
3759 | 150.222.217.228/30 Amazon | ||
3760 | 150.222.217.232/31 Amazon | ||
3761 | 150.222.217.234/31 Amazon | ||
3762 | 150.222.217.248/31 Amazon | ||
3763 | 150.222.217.250/31 Amazon | ||
3764 | 150.222.218.0/24 Amazon | ||
3765 | 150.222.219.0/24 Amazon | ||
3766 | 150.222.220.0/24 Amazon | ||
3767 | 150.222.221.0/24 Amazon | ||
3768 | 150.222.222.0/24 Amazon | ||
3769 | 150.222.223.0/24 Amazon | ||
3770 | 150.222.224.0/24 Amazon | ||
3771 | 150.222.226.0/24 Amazon | ||
3772 | 150.222.227.0/24 Amazon | ||
3773 | 150.222.228.0/24 Amazon | ||
3774 | 150.222.229.0/24 Amazon | ||
3775 | 150.222.230.92/32 Amazon | ||
3776 | 150.222.230.93/32 Amazon | ||
3777 | 150.222.230.94/31 Amazon | ||
3778 | 150.222.230.96/31 Amazon | ||
3779 | 150.222.230.98/31 Amazon | ||
3780 | 150.222.230.100/31 Amazon | ||
3781 | 150.222.230.102/31 Amazon | ||
3782 | 150.222.230.104/31 Amazon | ||
3783 | 150.222.230.106/31 Amazon | ||
3784 | 150.222.230.108/31 Amazon | ||
3785 | 150.222.230.110/31 Amazon | ||
3786 | 150.222.230.112/31 Amazon | ||
3787 | 150.222.230.114/31 Amazon | ||
3788 | 150.222.230.116/31 Amazon | ||
3789 | 150.222.230.118/31 Amazon | ||
3790 | 150.222.230.120/31 Amazon | ||
3791 | 150.222.230.122/31 Amazon | ||
3792 | 150.222.230.124/31 Amazon | ||
3793 | 150.222.231.0/24 Amazon | ||
3794 | 150.222.232.51/32 Amazon | ||
3795 | 150.222.232.88/32 Amazon | ||
3796 | 150.222.232.94/31 Amazon | ||
3797 | 150.222.232.96/28 Amazon | ||
3798 | 150.222.232.112/31 Amazon | ||
3799 | 150.222.232.114/31 Amazon | ||
3800 | 150.222.232.116/31 Amazon | ||
3801 | 150.222.232.118/31 Amazon | ||
3802 | 150.222.232.120/31 Amazon | ||
3803 | 150.222.233.0/24 Amazon | ||
3804 | 150.222.234.0/32 Amazon | ||
3805 | 150.222.234.1/32 Amazon | ||
3806 | 150.222.234.2/32 Amazon | ||
3807 | 150.222.234.3/32 Amazon | ||
3808 | 150.222.234.4/32 Amazon | ||
3809 | 150.222.234.5/32 Amazon | ||
3810 | 150.222.234.6/31 Amazon | ||
3811 | 150.222.234.8/31 Amazon | ||
3812 | 150.222.234.10/31 Amazon | ||
3813 | 150.222.234.12/31 Amazon | ||
3814 | 150.222.234.14/31 Amazon | ||
3815 | 150.222.234.16/31 Amazon | ||
3816 | 150.222.234.18/31 Amazon | ||
3817 | 150.222.234.20/31 Amazon | ||
3818 | 150.222.234.22/31 Amazon | ||
3819 | 150.222.234.24/31 Amazon | ||
3820 | 150.222.234.26/31 Amazon | ||
3821 | 150.222.234.28/31 Amazon | ||
3822 | 150.222.234.30/31 Amazon | ||
3823 | 150.222.234.32/31 Amazon | ||
3824 | 150.222.234.34/31 Amazon | ||
3825 | 150.222.234.36/31 Amazon | ||
3826 | 150.222.234.38/31 Amazon | ||
3827 | 150.222.234.40/31 Amazon | ||
3828 | 150.222.234.42/31 Amazon | ||
3829 | 150.222.234.44/31 Amazon | ||
3830 | 150.222.234.46/31 Amazon | ||
3831 | 150.222.234.48/31 Amazon | ||
3832 | 150.222.234.50/31 Amazon | ||
3833 | 150.222.234.52/31 Amazon | ||
3834 | 150.222.234.54/31 Amazon | ||
3835 | 150.222.234.56/31 Amazon | ||
3836 | 150.222.234.58/31 Amazon | ||
3837 | 150.222.234.60/31 Amazon | ||
3838 | 150.222.234.62/31 Amazon | ||
3839 | 150.222.234.64/31 Amazon | ||
3840 | 150.222.234.66/31 Amazon | ||
3841 | 150.222.234.68/31 Amazon | ||
3842 | 150.222.234.70/31 Amazon | ||
3843 | 150.222.234.72/31 Amazon | ||
3844 | 150.222.234.74/31 Amazon | ||
3845 | 150.222.234.76/31 Amazon | ||
3846 | 150.222.234.78/31 Amazon | ||
3847 | 150.222.234.80/31 Amazon | ||
3848 | 150.222.234.82/31 Amazon | ||
3849 | 150.222.234.84/31 Amazon | ||
3850 | 150.222.234.86/31 Amazon | ||
3851 | 150.222.234.96/31 Amazon | ||
3852 | 150.222.234.98/31 Amazon | ||
3853 | 150.222.234.100/31 Amazon | ||
3854 | 150.222.234.102/32 Amazon | ||
3855 | 150.222.234.103/32 Amazon | ||
3856 | 150.222.234.104/31 Amazon | ||
3857 | 150.222.234.106/31 Amazon | ||
3858 | 150.222.234.108/31 Amazon | ||
3859 | 150.222.234.110/31 Amazon | ||
3860 | 150.222.234.112/31 Amazon | ||
3861 | 150.222.234.114/31 Amazon | ||
3862 | 150.222.234.116/31 Amazon | ||
3863 | 150.222.234.118/31 Amazon | ||
3864 | 150.222.234.120/31 Amazon | ||
3865 | 150.222.234.122/31 Amazon | ||
3866 | 150.222.234.124/31 Amazon | ||
3867 | 150.222.234.126/31 Amazon | ||
3868 | 150.222.234.128/31 Amazon | ||
3869 | 150.222.234.130/31 Amazon | ||
3870 | 150.222.234.132/31 Amazon | ||
3871 | 150.222.234.134/31 Amazon | ||
3872 | 150.222.234.136/31 Amazon | ||
3873 | 150.222.234.138/31 Amazon | ||
3874 | 150.222.234.140/31 Amazon | ||
3875 | 150.222.234.142/31 Amazon | ||
3876 | 150.222.235.0/24 Amazon | ||
3877 | 150.222.236.0/24 Amazon | ||
3878 | 150.222.237.0/24 Amazon | ||
3879 | 150.222.239.0/24 Amazon | ||
3880 | 150.222.240.131/32 Amazon | ||
3881 | 150.222.240.135/32 Amazon | ||
3882 | 150.222.240.137/32 Amazon | ||
3883 | 150.222.240.161/32 Amazon | ||
3884 | 150.222.240.207/32 Amazon | ||
3885 | 150.222.240.237/32 Amazon | ||
3886 | 150.222.240.245/32 Amazon | ||
3887 | 150.222.240.247/32 Amazon | ||
3888 | 150.222.240.249/32 Amazon | ||
3889 | 150.222.240.251/32 Amazon | ||
3890 | 150.222.242.84/31 Amazon | ||
3891 | 150.222.242.97/32 Amazon | ||
3892 | 150.222.242.99/32 Amazon | ||
3893 | 150.222.242.214/31 Amazon | ||
3894 | 150.222.242.227/32 Amazon | ||
3895 | 150.222.242.229/32 Amazon | ||
3896 | 150.222.242.231/32 Amazon | ||
3897 | 150.222.242.233/32 Amazon | ||
3898 | 150.222.243.9/32 Amazon | ||
3899 | 150.222.243.11/32 Amazon | ||
3900 | 150.222.243.13/32 Amazon | ||
3901 | 150.222.243.15/32 Amazon | ||
3902 | 150.222.243.17/32 Amazon | ||
3903 | 150.222.243.19/32 Amazon | ||
3904 | 150.222.243.33/32 Amazon | ||
3905 | 150.222.243.35/32 Amazon | ||
3906 | 150.222.243.37/32 Amazon | ||
3907 | 150.222.243.39/32 Amazon | ||
3908 | 150.222.243.41/32 Amazon | ||
3909 | 150.222.243.43/32 Amazon | ||
3910 | 150.222.243.45/32 Amazon | ||
3911 | 150.222.243.47/32 Amazon | ||
3912 | 150.222.243.51/32 Amazon | ||
3913 | 150.222.243.53/32 Amazon | ||
3914 | 150.222.243.55/32 Amazon | ||
3915 | 150.222.243.57/32 Amazon | ||
3916 | 150.222.243.59/32 Amazon | ||
3917 | 150.222.243.177/32 Amazon | ||
3918 | 150.222.244.35/32 Amazon | ||
3919 | 150.222.244.37/32 Amazon | ||
3920 | 150.222.245.122/31 Amazon | ||
3921 | 150.222.252.244/31 Amazon | ||
3922 | 150.222.252.246/31 Amazon | ||
3923 | 150.222.252.248/31 Amazon | ||
3924 | 150.222.252.250/31 Amazon | ||
3925 | 157.175.0.0/16 Amazon | ||
3926 | 157.241.0.0/16 Amazon | ||
3927 | 160.1.0.0/16 Amazon | ||
3928 | 161.188.128.0/23 Amazon | ||
3929 | 161.188.130.0/23 Amazon | ||
3930 | 161.188.132.0/23 Amazon | ||
3931 | 161.188.134.0/23 Amazon | ||
3932 | 161.188.136.0/23 Amazon | ||
3933 | 161.188.138.0/23 Amazon | ||
3934 | 161.188.140.0/23 Amazon | ||
3935 | 161.188.142.0/23 Amazon | ||
3936 | 161.188.144.0/23 Amazon | ||
3937 | 161.188.146.0/23 Amazon | ||
3938 | 161.188.148.0/23 Amazon | ||
3939 | 161.188.150.0/23 Amazon | ||
3940 | 161.188.152.0/23 Amazon | ||
3941 | 161.188.154.0/23 Amazon | ||
3942 | 161.188.156.0/23 Amazon | ||
3943 | 161.188.158.0/23 Amazon | ||
3944 | 161.188.160.0/23 Amazon | ||
3945 | 161.189.0.0/16 Amazon | ||
3946 | 162.213.232.0/24 Amazon | ||
3947 | 162.213.233.0/24 Amazon | ||
3948 | 162.213.234.0/23 Amazon | ||
3949 | 162.222.148.0/22 Amazon | ||
3950 | 162.250.236.0/24 Amazon | ||
3951 | 162.250.237.0/24 Amazon | ||
3952 | 162.250.238.0/23 Amazon | ||
3953 | 172.96.97.0/24 Amazon | ||
3954 | 172.96.98.0/24 Amazon | ||
3955 | 172.96.110.0/24 Amazon | ||
3956 | 174.129.0.0/16 Amazon | ||
3957 | 175.41.128.0/18 Amazon | ||
3958 | 175.41.192.0/18 Amazon | ||
3959 | 176.32.64.0/19 Amazon | ||
3960 | 176.32.96.0/21 Amazon | ||
3961 | 176.32.104.0/21 Amazon | ||
3962 | 176.32.112.0/21 Amazon | ||
3963 | 176.32.120.0/22 Amazon | ||
3964 | 176.32.124.128/25 Amazon | ||
3965 | 176.32.125.0/25 Amazon | ||
3966 | 176.32.125.128/26 Amazon | ||
3967 | 176.32.125.192/27 Amazon | ||
3968 | 176.32.125.224/31 Amazon | ||
3969 | 176.32.125.226/31 Amazon | ||
3970 | 176.32.125.228/31 Amazon | ||
3971 | 176.32.125.230/31 Amazon | ||
3972 | 176.32.125.232/31 Amazon | ||
3973 | 176.32.125.234/31 Amazon | ||
3974 | 176.32.125.236/31 Amazon | ||
3975 | 176.32.125.238/31 Amazon | ||
3976 | 176.32.125.240/31 Amazon | ||
3977 | 176.32.125.242/31 Amazon | ||
3978 | 176.32.125.244/31 Amazon | ||
3979 | 176.32.125.246/31 Amazon | ||
3980 | 176.32.125.248/31 Amazon | ||
3981 | 176.32.125.250/31 Amazon | ||
3982 | 176.32.125.252/31 Amazon | ||
3983 | 176.32.125.254/31 Amazon | ||
3984 | 176.34.0.0/19 Amazon | ||
3985 | 176.34.32.0/19 Amazon | ||
3986 | 176.34.64.0/18 Amazon | ||
3987 | 176.34.128.0/17 Amazon | ||
3988 | 177.71.128.0/17 Amazon | ||
3989 | 177.72.240.0/21 Amazon | ||
3990 | 178.236.0.0/20 Amazon | ||
3991 | 180.163.57.0/25 Amazon | ||
3992 | 180.163.57.128/26 Amazon | ||
3993 | 184.72.0.0/18 Amazon | ||
3994 | 184.72.64.0/18 Amazon | ||
3995 | 184.72.128.0/17 Amazon | ||
3996 | 184.73.0.0/16 Amazon | ||
3997 | 184.169.128.0/17 Amazon | ||
3998 | 185.48.120.0/22 Amazon | ||
3999 | 185.143.16.0/24 Amazon | ||
4000 | 195.17.0.0/24 Amazon | ||
4001 | 198.99.2.0/24 Amazon | ||
4002 | 199.127.232.0/22 Amazon | ||
4003 | 203.83.220.0/22 Amazon | ||
4004 | 204.45.0.0/16 Amazon | ||
4005 | 204.236.128.0/18 Amazon | ||
4006 | 204.236.192.0/18 Amazon | ||
4007 | 204.246.160.0/22 Amazon | ||
4008 | 204.246.164.0/22 Amazon | ||
4009 | 204.246.168.0/22 Amazon | ||
4010 | 204.246.172.0/24 Amazon | ||
4011 | 204.246.173.0/24 Amazon | ||
4012 | 204.246.174.0/23 Amazon | ||
4013 | 204.246.176.0/20 Amazon | ||
4014 | 205.251.192.0/21 Amazon | ||
4015 | 205.251.200.0/21 Amazon | ||
4016 | 205.251.208.0/20 Amazon | ||
4017 | 205.251.224.0/22 Amazon | ||
4018 | 205.251.228.0/22 Amazon | ||
4019 | 205.251.232.0/22 Amazon | ||
4020 | 205.251.236.0/22 Amazon | ||
4021 | 205.251.240.0/22 Amazon | ||
4022 | 205.251.244.0/23 Amazon | ||
4023 | 205.251.246.0/24 Amazon | ||
4024 | 205.251.247.0/24 Amazon | ||
4025 | 205.251.248.0/24 Amazon | ||
4026 | 205.251.249.0/24 Amazon | ||
4027 | 205.251.250.0/23 Amazon | ||
4028 | 205.251.252.0/23 Amazon | ||
4029 | 205.251.254.0/24 Amazon | ||
4030 | 207.171.160.0/20 Amazon | ||
4031 | 207.171.176.0/20 Amazon | ||
4032 | 208.86.88.0/23 Amazon | ||
4033 | 208.86.90.0/23 Amazon | ||
4034 | 208.110.48.0/20 Amazon | ||
4035 | 209.54.176.0/21 Amazon | ||
4036 | 209.54.184.0/21 Amazon | ||
4037 | 216.137.32.0/19 Amazon | ||
4038 | 216.182.224.0/21 Amazon | ||
4039 | 216.182.232.0/22 Amazon | ||
4040 | 216.182.236.0/23 Amazon | ||
4041 | 216.182.238.0/23 Amazon | ||
4042 | 223.71.11.0/27 Amazon | ||
4043 | 223.71.71.96/27 Amazon | ||
4044 | 223.71.71.128/25 Amazon | ||
diff --git a/src/fnettrace/tail.c b/src/fnettrace/tail.c new file mode 100644 index 000000000..a910788d6 --- /dev/null +++ b/src/fnettrace/tail.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include "fnettrace.h" | ||
21 | |||
22 | void tail(const char *logfile) { | ||
23 | assert(logfile); | ||
24 | |||
25 | // wait for no more than 5 seconds for the logfile to appear in the filesystem | ||
26 | int cnt = 5; | ||
27 | while (access(logfile, R_OK) && cnt > 0) | ||
28 | cnt--; | ||
29 | if (cnt == 0) | ||
30 | exit(1); | ||
31 | |||
32 | off_t last_size = 0; | ||
33 | |||
34 | while (1) { | ||
35 | int fd = open(logfile, O_RDONLY); | ||
36 | if (fd == -1) | ||
37 | return; | ||
38 | |||
39 | off_t size = lseek(fd, 0, SEEK_END); | ||
40 | if (size < 0) { | ||
41 | close(fd); | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | char *content = NULL; | ||
46 | int mmapped = 0; | ||
47 | if (size && size != last_size) { | ||
48 | content = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); | ||
49 | close(fd); | ||
50 | if (content != MAP_FAILED) | ||
51 | mmapped = 1; | ||
52 | } | ||
53 | |||
54 | if (mmapped) { | ||
55 | printf("%.*s", (int) (size - last_size), content + last_size); | ||
56 | fflush(0); | ||
57 | munmap(content, size); | ||
58 | last_size = size; | ||
59 | } | ||
60 | |||
61 | sleep(1); | ||
62 | } | ||
63 | } | ||
diff --git a/src/fsec-optimize/fsec_optimize.h b/src/fsec-optimize/fsec_optimize.h index fc9dd7db8..2a77f69aa 100644 --- a/src/fsec-optimize/fsec_optimize.h +++ b/src/fsec-optimize/fsec_optimize.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fsec-optimize/main.c b/src/fsec-optimize/main.c index 84bf2d4f9..ec3420e16 100644 --- a/src/fsec-optimize/main.c +++ b/src/fsec-optimize/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fsec-optimize/optimizer.c b/src/fsec-optimize/optimizer.c index 4c02de59d..20333a8a8 100644 --- a/src/fsec-optimize/optimizer.c +++ b/src/fsec-optimize/optimizer.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fsec-print/fsec_print.h b/src/fsec-print/fsec_print.h index 75a82c11a..a754e2295 100644 --- a/src/fsec-print/fsec_print.h +++ b/src/fsec-print/fsec_print.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fsec-print/main.c b/src/fsec-print/main.c index 5bca93d50..039377999 100644 --- a/src/fsec-print/main.c +++ b/src/fsec-print/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fsec-print/print.c b/src/fsec-print/print.c index 143a7a53e..f6af20f04 100644 --- a/src/fsec-print/print.c +++ b/src/fsec-print/print.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index 97eac9ed8..65337da2a 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 326c29a44..48665ab71 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fseccomp/protocol.c b/src/fseccomp/protocol.c index 48dda61dd..25742c173 100644 --- a/src/fseccomp/protocol.c +++ b/src/fseccomp/protocol.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c index 99e671799..49b789755 100644 --- a/src/fseccomp/seccomp.c +++ b/src/fseccomp/seccomp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c index 846c7f335..ee18ca74f 100644 --- a/src/fseccomp/seccomp_file.c +++ b/src/fseccomp/seccomp_file.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fseccomp/seccomp_secondary.c b/src/fseccomp/seccomp_secondary.c index 540892026..d4ccd96b2 100644 --- a/src/fseccomp/seccomp_secondary.c +++ b/src/fseccomp/seccomp_secondary.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/fshaper/fshaper.sh b/src/fshaper/fshaper.sh index f9a6c4f06..a8379612d 100755 --- a/src/fshaper/fshaper.sh +++ b/src/fshaper/fshaper.sh | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # This file is part of Firejail project | 2 | # This file is part of Firejail project |
3 | # Copyright (C) 2014-2021 Firejail Authors | 3 | # Copyright (C) 2014-2022 Firejail Authors |
4 | # License GPL v2 | 4 | # License GPL v2 |
5 | 5 | ||
6 | TCFILE="" | 6 | TCFILE="" |
diff --git a/src/ftee/ftee.h b/src/ftee/ftee.h index a556efb75..458308a4c 100644 --- a/src/ftee/ftee.h +++ b/src/ftee/ftee.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/ftee/main.c b/src/ftee/main.c index 4d447f2c4..d408566fa 100644 --- a/src/ftee/main.c +++ b/src/ftee/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/include/common.h b/src/include/common.h index 5bcbaad88..c9640435a 100644 --- a/src/include/common.h +++ b/src/include/common.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -73,6 +73,25 @@ static inline int atoip(const char *str, uint32_t *ip) { | |||
73 | return 0; | 73 | return 0; |
74 | } | 74 | } |
75 | 75 | ||
76 | // read an IPv4 address in CIDR format, for example 192.168.1.0/24 | ||
77 | static inline int atocidr(const char *str, uint32_t *ip, uint32_t *mask) { | ||
78 | unsigned a, b, c, d, e; | ||
79 | |||
80 | // extract ip | ||
81 | int rv = sscanf(str, "%u.%u.%u.%u/%u", &a, &b, &c, &d, &e); | ||
82 | if (rv != 5 || a > 255 || b > 255 || c > 255 || d > 255 || e > 32) | ||
83 | return 1; | ||
84 | *ip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d; | ||
85 | |||
86 | // extract mask | ||
87 | uint32_t tmp; | ||
88 | unsigned i; | ||
89 | for (i = 0, *mask = 0, tmp = 0x80000000; i < e; i++, tmp >>= 1) { | ||
90 | *mask |= tmp; | ||
91 | } | ||
92 | return 0; | ||
93 | } | ||
94 | |||
76 | // verify an ip address is in the network range given by ifip and mask | 95 | // verify an ip address is in the network range given by ifip and mask |
77 | static inline char *in_netrange(uint32_t ip, uint32_t ifip, uint32_t ifmask) { | 96 | static inline char *in_netrange(uint32_t ip, uint32_t ifip, uint32_t ifmask) { |
78 | if ((ip & ifmask) != (ifip & ifmask)) | 97 | if ((ip & ifmask) != (ifip & ifmask)) |
@@ -121,6 +140,12 @@ char *pid_proc_comm(const pid_t pid); | |||
121 | char *pid_proc_cmdline(const pid_t pid); | 140 | char *pid_proc_cmdline(const pid_t pid); |
122 | int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid); | 141 | int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid); |
123 | int pid_hidepid(void); | 142 | int pid_hidepid(void); |
143 | char *do_replace_cntrl_chars(char *str, char c); | ||
144 | char *replace_cntrl_chars(const char *str, char c); | ||
145 | int has_cntrl_chars(const char *str); | ||
146 | void reject_cntrl_chars(const char *fname); | ||
147 | void reject_meta_chars(const char *fname, int globbing); | ||
124 | void warn_dumpable(void); | 148 | void warn_dumpable(void); |
125 | const char *gnu_basename(const char *path); | 149 | const char *gnu_basename(const char *path); |
150 | int *str_to_int_array(const char *str, size_t *sz); | ||
126 | #endif | 151 | #endif |
diff --git a/src/include/euid_common.h b/src/include/euid_common.h index 8d8dd95f6..f40cbb9de 100644 --- a/src/include/euid_common.h +++ b/src/include/euid_common.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/include/firejail_user.h b/src/include/firejail_user.h index cf17fa0cf..6cf895db8 100644 --- a/src/include/firejail_user.h +++ b/src/include/firejail_user.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/include/gcov_wrapper.h b/src/include/gcov_wrapper.h new file mode 100644 index 000000000..144181ca0 --- /dev/null +++ b/src/include/gcov_wrapper.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2022 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 | #ifndef GCOV_WRAPPER_H | ||
22 | #define GCOV_WRAPPER_H | ||
23 | |||
24 | #ifdef HAS_GCOV | ||
25 | #include <gcov.h> | ||
26 | |||
27 | /* | ||
28 | * __gcov_flush was removed on gcc 11.1.0 (as it's no longer needed), but it | ||
29 | * appears to be the safe/"correct" way to do things on previous versions (as | ||
30 | * it ensured proper locking, which is now done elsewhere). Thus, keep using | ||
31 | * it in the code and ensure that it exists, in order to support gcc <11.1.0 | ||
32 | * and gcc >=11.1.0, respectively. | ||
33 | */ | ||
34 | #if __GNUC__ > 11 || (__GNUC__ == 11 && __GNUC_MINOR__ >= 1) | ||
35 | static void __gcov_flush(void) { | ||
36 | __gcov_dump(); | ||
37 | __gcov_reset(); | ||
38 | } | ||
39 | #endif | ||
40 | #else | ||
41 | #define __gcov_dump() ((void)0) | ||
42 | #define __gcov_reset() ((void)0) | ||
43 | #define __gcov_flush() ((void)0) | ||
44 | #endif /* HAS_GCOV */ | ||
45 | |||
46 | #endif /* GCOV_WRAPPER_H */ | ||
diff --git a/src/include/ldd_utils.h b/src/include/ldd_utils.h index ffd6e189f..e9dac1171 100644 --- a/src/include/ldd_utils.h +++ b/src/include/ldd_utils.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/include/pid.h b/src/include/pid.h index 17e51f660..7e235b713 100644 --- a/src/include/pid.h +++ b/src/include/pid.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/include/rundefs.h b/src/include/rundefs.h index d14f6782f..4ba3e27f4 100644 --- a/src/include/rundefs.h +++ b/src/include/rundefs.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -79,24 +79,8 @@ | |||
79 | #define PATH_SECCOMP_MDWX_32 LIBDIR "/firejail/seccomp.mdwx.32" | 79 | #define PATH_SECCOMP_MDWX_32 LIBDIR "/firejail/seccomp.mdwx.32" |
80 | #define PATH_SECCOMP_BLOCK_SECONDARY LIBDIR "/firejail/seccomp.block_secondary" // secondary arch blocking filter built during make | 80 | #define PATH_SECCOMP_BLOCK_SECONDARY LIBDIR "/firejail/seccomp.block_secondary" // secondary arch blocking filter built during make |
81 | 81 | ||
82 | |||
83 | #define RUN_DEV_DIR RUN_MNT_DIR "/dev" | 82 | #define RUN_DEV_DIR RUN_MNT_DIR "/dev" |
84 | #define RUN_DEVLOG_FILE RUN_MNT_DIR "/devlog" | 83 | #define RUN_DEVLOG_FILE RUN_MNT_DIR "/devlog" |
85 | |||
86 | #define RUN_WHITELIST_X11_DIR RUN_MNT_DIR "/orig-x11" | ||
87 | #define RUN_WHITELIST_HOME_USER_DIR RUN_MNT_DIR "/orig-home-user" // home directory whitelisting | ||
88 | #define RUN_WHITELIST_RUN_USER_DIR RUN_MNT_DIR "/orig-run-user" // run directory whitelisting | ||
89 | #define RUN_WHITELIST_TMP_DIR RUN_MNT_DIR "/orig-tmp" | ||
90 | #define RUN_WHITELIST_MEDIA_DIR RUN_MNT_DIR "/orig-media" | ||
91 | #define RUN_WHITELIST_MNT_DIR RUN_MNT_DIR "/orig-mnt" | ||
92 | #define RUN_WHITELIST_VAR_DIR RUN_MNT_DIR "/orig-var" | ||
93 | #define RUN_WHITELIST_DEV_DIR RUN_MNT_DIR "/orig-dev" | ||
94 | #define RUN_WHITELIST_OPT_DIR RUN_MNT_DIR "/orig-opt" | ||
95 | #define RUN_WHITELIST_SRV_DIR RUN_MNT_DIR "/orig-srv" | ||
96 | #define RUN_WHITELIST_ETC_DIR RUN_MNT_DIR "/orig-etc" | ||
97 | #define RUN_WHITELIST_SHARE_DIR RUN_MNT_DIR "/orig-share" | ||
98 | #define RUN_WHITELIST_MODULE_DIR RUN_MNT_DIR "/orig-module" | ||
99 | |||
100 | #define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" // private options | 84 | #define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" // private options |
101 | #define RUN_XAUTH_FILE RUN_MNT_DIR "/xauth" // x11=xorg | 85 | #define RUN_XAUTH_FILE RUN_MNT_DIR "/xauth" // x11=xorg |
102 | #define RUN_XAUTHORITY_SEC_DIR RUN_MNT_DIR "/.sec.Xauthority" // x11=xorg | 86 | #define RUN_XAUTHORITY_SEC_DIR RUN_MNT_DIR "/.sec.Xauthority" // x11=xorg |
diff --git a/src/include/seccomp.h b/src/include/seccomp.h index 43bb73a04..9dbe25bfa 100644 --- a/src/include/seccomp.h +++ b/src/include/seccomp.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/include/syscall.h b/src/include/syscall.h index 015dd01b9..68be16a04 100644 --- a/src/include/syscall.h +++ b/src/include/syscall.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/jailtest/Makefile.in b/src/jailcheck/Makefile.in index 6306d24ec..d218c1f90 100644 --- a/src/jailtest/Makefile.in +++ b/src/jailcheck/Makefile.in | |||
@@ -1,16 +1,16 @@ | |||
1 | .PHONY: all | 1 | .PHONY: all |
2 | all: jailtest | 2 | all: jailcheck |
3 | 3 | ||
4 | include ../common.mk | 4 | include ../common.mk |
5 | 5 | ||
6 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/pid.h | 6 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/pid.h |
7 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 7 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
8 | 8 | ||
9 | jailtest: $(OBJS) | 9 | jailcheck: $(OBJS) |
10 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/pid.o $(LIBS) $(EXTRA_LDFLAGS) | 10 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/pid.o $(LIBS) $(EXTRA_LDFLAGS) |
11 | 11 | ||
12 | .PHONY: clean | 12 | .PHONY: clean |
13 | clean:; rm -fr *.o jailtest *.gcov *.gcda *.gcno *.plist | 13 | clean:; rm -fr *.o jailcheck *.gcov *.gcda *.gcno *.plist |
14 | 14 | ||
15 | .PHONY: distclean | 15 | .PHONY: distclean |
16 | distclean: clean | 16 | distclean: clean |
diff --git a/src/jailtest/access.c b/src/jailcheck/access.c index 4e737dc7a..3e99b0b52 100644 --- a/src/jailtest/access.c +++ b/src/jailcheck/access.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "jailtest.h" | 20 | #include "jailcheck.h" |
21 | #include <dirent.h> | 21 | #include <dirent.h> |
22 | #include <sys/wait.h> | 22 | #include <sys/wait.h> |
23 | 23 | ||
@@ -36,7 +36,7 @@ void access_setup(const char *directory) { | |||
36 | assert(user_home_dir); | 36 | assert(user_home_dir); |
37 | 37 | ||
38 | if (files_cnt >= MAX_TEST_FILES) { | 38 | if (files_cnt >= MAX_TEST_FILES) { |
39 | fprintf(stderr, "Error: maximum number of test directories exceded\n"); | 39 | fprintf(stderr, "Error: maximum number of test directories exceeded\n"); |
40 | exit(1); | 40 | exit(1); |
41 | } | 41 | } |
42 | 42 | ||
@@ -74,7 +74,7 @@ void access_setup(const char *directory) { | |||
74 | 74 | ||
75 | // create a test file | 75 | // create a test file |
76 | char *test_file; | 76 | char *test_file; |
77 | if (asprintf(&test_file, "%s/jailtest-access-%d", path, getpid()) == -1) | 77 | if (asprintf(&test_file, "%s/jailcheck-access-%d", path, getpid()) == -1) |
78 | errExit("asprintf"); | 78 | errExit("asprintf"); |
79 | 79 | ||
80 | FILE *fp = fopen(test_file, "w"); | 80 | FILE *fp = fopen(test_file, "w"); |
diff --git a/src/jailtest/apparmor.c b/src/jailcheck/apparmor.c index 9ddfea3de..521ce047e 100644 --- a/src/jailtest/apparmor.c +++ b/src/jailcheck/apparmor.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "jailtest.h" | 20 | #include "jailcheck.h" |
21 | 21 | ||
22 | #ifdef HAVE_APPARMOR | 22 | #ifdef HAVE_APPARMOR |
23 | #include <sys/apparmor.h> | 23 | #include <sys/apparmor.h> |
diff --git a/src/jailtest/jailtest.h b/src/jailcheck/jailcheck.h index 0c4883061..2d25ee8ce 100644 --- a/src/jailtest/jailtest.h +++ b/src/jailcheck/jailcheck.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,8 +17,8 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #ifndef JAILTEST_H | 20 | #ifndef JAILCHECK_H |
21 | #define JAILTEST_H | 21 | #define JAILCHECK_H |
22 | 22 | ||
23 | #include "../include/common.h" | 23 | #include "../include/common.h" |
24 | 24 | ||
@@ -53,10 +53,12 @@ void apparmor_test(pid_t pid); | |||
53 | // seccomp.c | 53 | // seccomp.c |
54 | void seccomp_test(pid_t pid); | 54 | void seccomp_test(pid_t pid); |
55 | 55 | ||
56 | // network.c | ||
57 | void network_test(void); | ||
56 | // utils.c | 58 | // utils.c |
57 | char *get_sudo_user(void); | 59 | char *get_sudo_user(void); |
58 | char *get_homedir(const char *user, uid_t *uid, gid_t *gid); | 60 | char *get_homedir(const char *user, uid_t *uid, gid_t *gid); |
59 | int find_child(pid_t pid); | 61 | int find_child(pid_t pid); |
60 | pid_t switch_to_child(pid_t pid); | 62 | pid_t switch_to_child(pid_t pid); |
61 | 63 | ||
62 | #endif \ No newline at end of file | 64 | #endif |
diff --git a/src/jailtest/main.c b/src/jailcheck/main.c index 3369dca39..04fc3a6af 100644 --- a/src/jailtest/main.c +++ b/src/jailcheck/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "jailtest.h" | 20 | #include "jailcheck.h" |
21 | #include "../include/firejail_user.h" | 21 | #include "../include/firejail_user.h" |
22 | #include "../include/pid.h" | 22 | #include "../include/pid.h" |
23 | #include <sys/wait.h> | 23 | #include <sys/wait.h> |
@@ -30,7 +30,7 @@ char *user_run_dir = NULL; | |||
30 | int arg_debug = 0; | 30 | int arg_debug = 0; |
31 | 31 | ||
32 | static char *usage_str = | 32 | static char *usage_str = |
33 | "Usage: jailtest [options] directory [directory]\n\n" | 33 | "Usage: jailcheck [options] directory [directory]\n\n" |
34 | "Options:\n" | 34 | "Options:\n" |
35 | " --debug - print debug messages.\n" | 35 | " --debug - print debug messages.\n" |
36 | " --help, -? - this help screen.\n" | 36 | " --help, -? - this help screen.\n" |
@@ -157,6 +157,7 @@ int main(int argc, char **argv) { | |||
157 | seccomp_test(pid); | 157 | seccomp_test(pid); |
158 | fflush(0); | 158 | fflush(0); |
159 | 159 | ||
160 | // filesystem tests | ||
160 | pid_t child = fork(); | 161 | pid_t child = fork(); |
161 | if (child == -1) | 162 | if (child == -1) |
162 | errExit("fork"); | 163 | errExit("fork"); |
@@ -185,6 +186,28 @@ int main(int argc, char **argv) { | |||
185 | } | 186 | } |
186 | int status; | 187 | int status; |
187 | wait(&status); | 188 | wait(&status); |
189 | |||
190 | // network test | ||
191 | child = fork(); | ||
192 | if (child == -1) | ||
193 | errExit("fork"); | ||
194 | if (child == 0) { | ||
195 | int rv = join_namespace(pid, "net"); | ||
196 | if (rv == 0) | ||
197 | network_test(); | ||
198 | else { | ||
199 | printf(" Error: I cannot join the process network stack\n"); | ||
200 | exit(1); | ||
201 | } | ||
202 | |||
203 | // drop privileges in order not to trigger cleanup() | ||
204 | if (setgid(user_gid) != 0) | ||
205 | errExit("setgid"); | ||
206 | if (setuid(user_uid) != 0) | ||
207 | errExit("setuid"); | ||
208 | return 0; | ||
209 | } | ||
210 | wait(&status); | ||
188 | } | 211 | } |
189 | } | 212 | } |
190 | 213 | ||
diff --git a/src/jailcheck/network.c b/src/jailcheck/network.c new file mode 100644 index 000000000..8f70c6ff0 --- /dev/null +++ b/src/jailcheck/network.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2022 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 | #include "jailcheck.h" | ||
21 | #include <netdb.h> | ||
22 | #include <arpa/inet.h> | ||
23 | #include <ifaddrs.h> | ||
24 | #include <net/if.h> | ||
25 | #include <linux/connector.h> | ||
26 | #include <linux/netlink.h> | ||
27 | #include <linux/if_link.h> | ||
28 | #include <linux/sockios.h> | ||
29 | #include <sys/ioctl.h> | ||
30 | |||
31 | |||
32 | void network_test(void) { | ||
33 | // I am root running in a network namespace | ||
34 | struct ifaddrs *ifaddr, *ifa; | ||
35 | int found = 0; | ||
36 | |||
37 | // walk through the linked list | ||
38 | if (getifaddrs(&ifaddr) == -1) | ||
39 | errExit("getifaddrs"); | ||
40 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | ||
41 | if (strcmp(ifa->ifa_name, "lo") == 0) | ||
42 | continue; | ||
43 | |||
44 | found = 1; | ||
45 | break; | ||
46 | } | ||
47 | |||
48 | freeifaddrs(ifaddr); | ||
49 | |||
50 | if (found) | ||
51 | printf(" Networking: enabled\n"); | ||
52 | else | ||
53 | printf(" Networking: disabled\n"); | ||
54 | } | ||
55 | |||
56 | |||
57 | |||
diff --git a/src/jailtest/noexec.c b/src/jailcheck/noexec.c index 4347b7eef..4cf5dabde 100644 --- a/src/jailtest/noexec.c +++ b/src/jailcheck/noexec.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "jailtest.h" | 20 | #include "jailcheck.h" |
21 | #include <sys/wait.h> | 21 | #include <sys/wait.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <fcntl.h> | 23 | #include <fcntl.h> |
@@ -67,7 +67,7 @@ void noexec_test(const char *path) { | |||
67 | return; | 67 | return; |
68 | 68 | ||
69 | char *fname; | 69 | char *fname; |
70 | if (asprintf(&fname, "%s/jailtest-noexec-%d", path, getpid()) == -1) | 70 | if (asprintf(&fname, "%s/jailcheck-noexec-%d", path, getpid()) == -1) |
71 | errExit("asprintf"); | 71 | errExit("asprintf"); |
72 | 72 | ||
73 | pid_t child = fork(); | 73 | pid_t child = fork(); |
@@ -110,4 +110,4 @@ void noexec_test(const char *path) { | |||
110 | wait(&status); | 110 | wait(&status); |
111 | int rv = unlink(fname); | 111 | int rv = unlink(fname); |
112 | (void) rv; | 112 | (void) rv; |
113 | } \ No newline at end of file | 113 | } |
diff --git a/src/jailtest/seccomp.c b/src/jailcheck/seccomp.c index 2cecb4b4d..ac8064f0b 100644 --- a/src/jailtest/seccomp.c +++ b/src/jailcheck/seccomp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "jailtest.h" | 20 | #include "jailcheck.h" |
21 | #define MAXBUF 4096 | 21 | #define MAXBUF 4096 |
22 | 22 | ||
23 | void seccomp_test(pid_t pid) { | 23 | void seccomp_test(pid_t pid) { |
diff --git a/src/jailtest/sysfiles.c b/src/jailcheck/sysfiles.c index 7e4709453..0df95d496 100644 --- a/src/jailtest/sysfiles.c +++ b/src/jailcheck/sysfiles.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "jailtest.h" | 20 | #include "jailcheck.h" |
21 | #include <dirent.h> | 21 | #include <dirent.h> |
22 | #include <sys/wait.h> | 22 | #include <sys/wait.h> |
23 | 23 | ||
@@ -34,7 +34,7 @@ void sysfiles_setup(const char *file) { | |||
34 | assert(file); | 34 | assert(file); |
35 | 35 | ||
36 | if (files_cnt >= MAX_TEST_FILES) { | 36 | if (files_cnt >= MAX_TEST_FILES) { |
37 | fprintf(stderr, "Error: maximum number of system test files exceded\n"); | 37 | fprintf(stderr, "Error: maximum number of system test files exceeded\n"); |
38 | exit(1); | 38 | exit(1); |
39 | } | 39 | } |
40 | 40 | ||
diff --git a/src/jailtest/utils.c b/src/jailcheck/utils.c index 41c21b753..65431e2e1 100644 --- a/src/jailtest/utils.c +++ b/src/jailcheck/utils.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "jailtest.h" | 20 | #include "jailcheck.h" |
21 | #include "../include/pid.h" | 21 | #include "../include/pid.h" |
22 | #include <errno.h> | 22 | #include <errno.h> |
23 | #include <pwd.h> | 23 | #include <pwd.h> |
diff --git a/src/jailtest/virtual.c b/src/jailcheck/virtual.c index fcdcf9720..93172d65c 100644 --- a/src/jailtest/virtual.c +++ b/src/jailcheck/virtual.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "jailtest.h" | 20 | #include "jailcheck.h" |
21 | #include <dirent.h> | 21 | #include <dirent.h> |
22 | #include <sys/wait.h> | 22 | #include <sys/wait.h> |
23 | 23 | ||
@@ -43,7 +43,7 @@ void virtual_setup(const char *directory) { | |||
43 | 43 | ||
44 | // create a test file | 44 | // create a test file |
45 | char *test_file; | 45 | char *test_file; |
46 | if (asprintf(&test_file, "%s/jailtest-private-%d", directory, getpid()) == -1) | 46 | if (asprintf(&test_file, "%s/jailcheck-private-%d", directory, getpid()) == -1) |
47 | errExit("asprintf"); | 47 | errExit("asprintf"); |
48 | 48 | ||
49 | FILE *fp = fopen(test_file, "w"); | 49 | FILE *fp = fopen(test_file, "w"); |
diff --git a/src/lib/common.c b/src/lib/common.c index f1bd7a6fe..8e84fab26 100644 --- a/src/lib/common.c +++ b/src/lib/common.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -31,6 +31,7 @@ | |||
31 | #include <dirent.h> | 31 | #include <dirent.h> |
32 | #include <string.h> | 32 | #include <string.h> |
33 | #include <time.h> | 33 | #include <time.h> |
34 | #include <limits.h> | ||
34 | #include "../include/common.h" | 35 | #include "../include/common.h" |
35 | #define BUFLEN 4096 | 36 | #define BUFLEN 4096 |
36 | 37 | ||
@@ -320,6 +321,115 @@ const char *gnu_basename(const char *path) { | |||
320 | return last_slash+1; | 321 | return last_slash+1; |
321 | } | 322 | } |
322 | 323 | ||
324 | char *do_replace_cntrl_chars(char *str, char c) { | ||
325 | if (str) { | ||
326 | size_t i; | ||
327 | for (i = 0; str[i]; i++) { | ||
328 | if (iscntrl((unsigned char) str[i])) | ||
329 | str[i] = c; | ||
330 | } | ||
331 | } | ||
332 | return str; | ||
333 | } | ||
334 | |||
335 | char *replace_cntrl_chars(const char *str, char c) { | ||
336 | assert(str); | ||
337 | |||
338 | char *rv = strdup(str); | ||
339 | if (!rv) | ||
340 | errExit("strdup"); | ||
341 | |||
342 | do_replace_cntrl_chars(rv, c); | ||
343 | return rv; | ||
344 | } | ||
345 | |||
346 | int has_cntrl_chars(const char *str) { | ||
347 | assert(str); | ||
348 | |||
349 | size_t i; | ||
350 | for (i = 0; str[i]; i++) { | ||
351 | if (iscntrl((unsigned char) str[i])) | ||
352 | return 1; | ||
353 | } | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | void reject_cntrl_chars(const char *fname) { | ||
358 | assert(fname); | ||
359 | |||
360 | if (has_cntrl_chars(fname)) { | ||
361 | char *fname_print = replace_cntrl_chars(fname, '?'); | ||
362 | |||
363 | fprintf(stderr, "Error: \"%s\" is an invalid filename: no control characters are allowed\n", fname_print); | ||
364 | exit(1); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | void reject_meta_chars(const char *fname, int globbing) { | ||
369 | assert(fname); | ||
370 | |||
371 | reject_cntrl_chars(fname); | ||
372 | |||
373 | const char *reject = "\\&!?\"<>%^{};,*[]"; | ||
374 | if (globbing) | ||
375 | reject = "\\&!\"<>%^{};,"; // file globbing ('*?[]') is allowed | ||
376 | |||
377 | const char *c = strpbrk(fname, reject); | ||
378 | if (c) { | ||
379 | fprintf(stderr, "Error: \"%s\" is an invalid filename: rejected character: \"%c\"\n", fname, *c); | ||
380 | exit(1); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | // takes string with comma separated int values, returns int array | ||
385 | int *str_to_int_array(const char *str, size_t *sz) { | ||
386 | assert(str && sz); | ||
387 | |||
388 | size_t curr_sz = 0; | ||
389 | size_t arr_sz = 16; | ||
390 | int *rv = malloc(arr_sz * sizeof(int)); | ||
391 | if (!rv) | ||
392 | errExit("malloc"); | ||
393 | |||
394 | char *dup = strdup(str); | ||
395 | if (!dup) | ||
396 | errExit("strdup"); | ||
397 | char *tok = strtok(dup, ","); | ||
398 | if (!tok) { | ||
399 | free(dup); | ||
400 | free(rv); | ||
401 | goto errout; | ||
402 | } | ||
403 | |||
404 | while (tok) { | ||
405 | char *end; | ||
406 | long val = strtol(tok, &end, 10); | ||
407 | if (end == tok || *end != '\0' || val < INT_MIN || val > INT_MAX) { | ||
408 | free(dup); | ||
409 | free(rv); | ||
410 | goto errout; | ||
411 | } | ||
412 | |||
413 | if (curr_sz == arr_sz) { | ||
414 | arr_sz *= 2; | ||
415 | rv = realloc(rv, arr_sz * sizeof(int)); | ||
416 | if (!rv) | ||
417 | errExit("realloc"); | ||
418 | } | ||
419 | rv[curr_sz++] = val; | ||
420 | |||
421 | tok = strtok(NULL, ","); | ||
422 | } | ||
423 | free(dup); | ||
424 | |||
425 | *sz = curr_sz; | ||
426 | return rv; | ||
427 | |||
428 | errout: | ||
429 | *sz = 0; | ||
430 | return NULL; | ||
431 | } | ||
432 | |||
323 | //************************** | 433 | //************************** |
324 | // time trace based on getticks function | 434 | // time trace based on getticks function |
325 | //************************** | 435 | //************************** |
diff --git a/src/lib/errno.c b/src/lib/errno.c index 9edb44c22..b666c5646 100644 --- a/src/lib/errno.c +++ b/src/lib/errno.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/lib/firejail_user.c b/src/lib/firejail_user.c index d6a3c71ab..bf338ee43 100644 --- a/src/lib/firejail_user.c +++ b/src/lib/firejail_user.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/lib/ldd_utils.c b/src/lib/ldd_utils.c index cd60d74e4..bc4f7cf9c 100644 --- a/src/lib/ldd_utils.c +++ b/src/lib/ldd_utils.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -50,7 +50,7 @@ int is_lib_64(const char *exe) { | |||
50 | unsigned char buf[EI_NIDENT]; | 50 | unsigned char buf[EI_NIDENT]; |
51 | ssize_t len = 0; | 51 | ssize_t len = 0; |
52 | while (len < EI_NIDENT) { | 52 | while (len < EI_NIDENT) { |
53 | ssize_t sz = read(fd, buf, EI_NIDENT); | 53 | ssize_t sz = read(fd, buf + len, EI_NIDENT - len); |
54 | if (sz <= 0) | 54 | if (sz <= 0) |
55 | goto doexit; | 55 | goto doexit; |
56 | len += sz; | 56 | len += sz; |
diff --git a/src/lib/pid.c b/src/lib/pid.c index ca62aaa42..ad6403f65 100644 --- a/src/lib/pid.c +++ b/src/lib/pid.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/lib/syscall.c b/src/lib/syscall.c index b3131ac17..a17f6423a 100644 --- a/src/lib/syscall.c +++ b/src/lib/syscall.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -253,9 +253,6 @@ static const SyscallGroupList sysgroups[] = { | |||
253 | #ifdef SYS_fanotify_init | 253 | #ifdef SYS_fanotify_init |
254 | "fanotify_init," | 254 | "fanotify_init," |
255 | #endif | 255 | #endif |
256 | #ifdef SYS_kcmp | ||
257 | "kcmp," | ||
258 | #endif | ||
259 | #ifdef SYS_add_key | 256 | #ifdef SYS_add_key |
260 | "add_key," | 257 | "add_key," |
261 | #endif | 258 | #endif |
@@ -1681,14 +1678,14 @@ void syscalls_in_list(const char *list, const char *slist, int fd, char **prelis | |||
1681 | sl.postlist = NULL; | 1678 | sl.postlist = NULL; |
1682 | syscall_check_list(list, syscall_in_list, 0, 0, &sl, native); | 1679 | syscall_check_list(list, syscall_in_list, 0, 0, &sl, native); |
1683 | if (!arg_quiet) { | 1680 | if (!arg_quiet) { |
1684 | printf("Seccomp list in: %s,", list); | 1681 | fprintf(stderr, "Seccomp list in: %s,", list); |
1685 | if (sl.slist) | 1682 | if (sl.slist) |
1686 | printf(" check list: %s,", sl.slist); | 1683 | fprintf(stderr, " check list: %s,", sl.slist); |
1687 | if (sl.prelist) | 1684 | if (sl.prelist) |
1688 | printf(" prelist: %s,", sl.prelist); | 1685 | fprintf(stderr, " prelist: %s,", sl.prelist); |
1689 | if (sl.postlist) | 1686 | if (sl.postlist) |
1690 | printf(" postlist: %s", sl.postlist); | 1687 | fprintf(stderr, " postlist: %s", sl.postlist); |
1691 | printf("\n"); | 1688 | fprintf(stderr, "\n"); |
1692 | } | 1689 | } |
1693 | *prelist = sl.prelist; | 1690 | *prelist = sl.prelist; |
1694 | *postlist = sl.postlist; | 1691 | *postlist = sl.postlist; |
diff --git a/src/libpostexecseccomp/libpostexecseccomp.c b/src/libpostexecseccomp/libpostexecseccomp.c index 1d1eb283b..e2339547e 100644 --- a/src/libpostexecseccomp/libpostexecseccomp.c +++ b/src/libpostexecseccomp/libpostexecseccomp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/libtrace/libtrace.c b/src/libtrace/libtrace.c index d88512b0a..c0832cbde 100644 --- a/src/libtrace/libtrace.c +++ b/src/libtrace/libtrace.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -18,12 +18,12 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #define _GNU_SOURCE | 20 | #define _GNU_SOURCE |
21 | #include <errno.h> | ||
21 | #include <stdio.h> | 22 | #include <stdio.h> |
22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
23 | #include <string.h> | 24 | #include <string.h> |
24 | #include <dlfcn.h> | 25 | #include <dlfcn.h> |
25 | #include <sys/types.h> | 26 | #include <sys/types.h> |
26 | #include <limits.h> | ||
27 | #include <unistd.h> | 27 | #include <unistd.h> |
28 | #include <sys/socket.h> | 28 | #include <sys/socket.h> |
29 | #include <netinet/in.h> | 29 | #include <netinet/in.h> |
@@ -706,10 +706,14 @@ __attribute__((constructor)) | |||
706 | static void log_exec(int argc, char** argv) { | 706 | static void log_exec(int argc, char** argv) { |
707 | (void) argc; | 707 | (void) argc; |
708 | (void) argv; | 708 | (void) argv; |
709 | static char buf[PATH_MAX + 1]; | 709 | char *buf = realpath("/proc/self/exe", NULL); |
710 | int rv = readlink("/proc/self/exe", buf, PATH_MAX); | 710 | if (buf == NULL) { |
711 | if (rv != -1) { | 711 | if (errno == ENOMEM) { |
712 | buf[rv] = '\0'; // readlink does not add a '\0' at the end | 712 | tprintf(ftty, "realpath: %s\n", strerror(errno)); |
713 | exit(1); | ||
714 | } | ||
715 | } else { | ||
713 | tprintf(ftty, "%u:%s:exec %s:0\n", mypid, myname, buf); | 716 | tprintf(ftty, "%u:%s:exec %s:0\n", mypid, myname, buf); |
717 | free(buf); | ||
714 | } | 718 | } |
715 | } | 719 | } |
diff --git a/src/libtracelog/libtracelog.c b/src/libtracelog/libtracelog.c index b946cc889..760ac7612 100644 --- a/src/libtracelog/libtracelog.c +++ b/src/libtracelog/libtracelog.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/man/Makefile.in b/src/man/Makefile.in index 3711d5cec..fbd2d795e 100644 --- a/src/man/Makefile.in +++ b/src/man/Makefile.in | |||
@@ -1,5 +1,5 @@ | |||
1 | .PHONY: all | 1 | .PHONY: all |
2 | all: firecfg.man firejail.man firejail-login.man firejail-users.man firejail-profile.man firemon.man jailtest.man | 2 | all: firecfg.man firejail.man firejail-login.man firejail-users.man firejail-profile.man firemon.man jailcheck.man |
3 | 3 | ||
4 | include ../common.mk | 4 | include ../common.mk |
5 | 5 | ||
diff --git a/src/man/firecfg.txt b/src/man/firecfg.txt index dbb9397c6..189e9cc8d 100644 --- a/src/man/firecfg.txt +++ b/src/man/firecfg.txt | |||
@@ -27,7 +27,7 @@ desktop managers are supported in this moment | |||
27 | To set it up, run "sudo firecfg" after installing Firejail software. | 27 | To set it up, run "sudo firecfg" after installing Firejail software. |
28 | The same command should also be run after | 28 | The same command should also be run after |
29 | installing new programs. If the program is supported by Firejail, the symbolic link in /usr/local/bin | 29 | installing new programs. If the program is supported by Firejail, the symbolic link in /usr/local/bin |
30 | will be created. For a full list of programs supported by default run "cat /usr/lib/firejail/firecfg.config". | 30 | will be created. For a full list of programs supported by default run "cat /etc/firejail/firecfg.config". |
31 | 31 | ||
32 | For user-driven manual integration, see \fBDESKTOP INTEGRATION\fR section in \fBman 1 firejail\fR. | 32 | For user-driven manual integration, see \fBDESKTOP INTEGRATION\fR section in \fBman 1 firejail\fR. |
33 | .SH DEFAULT ACTIONS | 33 | .SH DEFAULT ACTIONS |
@@ -135,4 +135,4 @@ Homepage: https://firejail.wordpress.com | |||
135 | .BR firejail-profile (5), | 135 | .BR firejail-profile (5), |
136 | .BR firejail-login (5), | 136 | .BR firejail-login (5), |
137 | .BR firejail-users (5), | 137 | .BR firejail-users (5), |
138 | .BR jailtest (1) | 138 | .BR jailcheck (1) |
diff --git a/src/man/firejail-login.txt b/src/man/firejail-login.txt index 1b8a4931c..05afd55b5 100644 --- a/src/man/firejail-login.txt +++ b/src/man/firejail-login.txt | |||
@@ -39,4 +39,4 @@ Homepage: https://firejail.wordpress.com | |||
39 | .BR firecfg (1), | 39 | .BR firecfg (1), |
40 | .BR firejail-profile (5), | 40 | .BR firejail-profile (5), |
41 | .BR firejail-users (5), | 41 | .BR firejail-users (5), |
42 | .BR jailtest (1) | 42 | .BR jailcheck (1) |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 9d11add06..e962e18da 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -1,18 +1,84 @@ | |||
1 | .TH FIREJAIL-PROFILE 5 "MONTH YEAR" "VERSION" "firejail profiles man page" | 1 | .TH FIREJAIL-PROFILE 5 "MONTH YEAR" "VERSION" "firejail profiles man page" |
2 | .SH NAME | 2 | .SH NAME |
3 | profile \- Security profile file syntax for Firejail | 3 | profile \- Security profile file syntax, and information about building new application profiles. |
4 | 4 | ||
5 | .SH USAGE | 5 | .SH SYNOPSIS |
6 | |||
7 | Using a specific profile: | ||
8 | .PP | ||
9 | .RS | ||
6 | .TP | 10 | .TP |
7 | firejail \-\-profile=filename.profile | 11 | \fBfirejail \-\-profile=filename.profile |
12 | .br | ||
13 | |||
14 | .br | ||
15 | Example: | ||
16 | .br | ||
17 | $ firejail --profile=/etc/firejail/kdenlive.profile --appimage kdenlive.appimage | ||
18 | .br | ||
19 | |||
20 | .br | ||
21 | .TP | ||
22 | \fBfirejail \-\-profile=profile_name | ||
23 | .br | ||
24 | |||
25 | .br | ||
26 | Example: | ||
27 | .br | ||
28 | $ firejail --profile=kdenlive --appimage kdenlive.appimage | ||
29 | .br | ||
30 | |||
31 | .br | ||
32 | .RE | ||
33 | .PP | ||
34 | |||
35 | |||
36 | |||
37 | Building a profile manually: | ||
38 | .PP | ||
39 | .RS | ||
40 | Start with the template in /usr/share/doc/firejail/profile.template and modify it in a text editor. | ||
41 | To integrate the program in your desktop environment copy the profile file in ~/.config/firejail | ||
42 | directory and run "sudo firecfg". | ||
8 | .RE | 43 | .RE |
9 | firejail \-\-profile=profile_name | 44 | .PP |
45 | |||
46 | Aliases and redirections: | ||
47 | .PP | ||
48 | .RS | ||
49 | In some cases the same profile can be used for several applications. | ||
50 | One such example is LibreOffice. | ||
51 | Build a regular profile for the main application, and for the rest use | ||
52 | /usr/share/doc/firejail/redirect_alias-profile.template. | ||
53 | .RE | ||
54 | .PP | ||
55 | |||
56 | Running the profile builder: | ||
57 | .PP | ||
58 | .RS | ||
59 | .TP | ||
60 | \fBfirejail \-\-build=appname.profile appname | ||
61 | .br | ||
62 | |||
63 | .br | ||
64 | Example: | ||
65 | .br | ||
66 | $ firejail --build=blobby.profile blobby | ||
67 | .br | ||
68 | |||
69 | .br | ||
70 | Run the program in "firejail \-\-build" and try to exercise as many program features as possible. | ||
71 | The profile is extracted and saved in the current directory. Open it in a text editor and add or remove | ||
72 | sandboxing options as necessary. Test again after modifying the profile. To integrate the program | ||
73 | in your desktop environment copy the profile file in ~/.config/firejail directory and run "sudo firecfg". | ||
74 | .RE | ||
75 | .PP | ||
10 | 76 | ||
11 | .SH DESCRIPTION | 77 | .SH DESCRIPTION |
12 | Several command line options can be passed to the program using | 78 | Several command line options can be passed to the program using |
13 | profile files. Firejail chooses the profile file as follows: | 79 | profile files. Firejail chooses the profile file as follows: |
14 | 80 | ||
15 | \fB1.\fR If a profile file is provided by the user with \-\-profile option, the profile file is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. | 81 | \fB1.\fR If a profile file is provided by the user with \-\-profile option, the profile file is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. |
16 | Example: | 82 | Example: |
17 | .PP | 83 | .PP |
18 | .RS | 84 | .RS |
@@ -94,6 +160,11 @@ Example: "blacklist ~/My Virtual Machines" | |||
94 | 160 | ||
95 | .TP | 161 | .TP |
96 | \fB# this is a comment | 162 | \fB# this is a comment |
163 | Example: | ||
164 | |||
165 | # disable networking | ||
166 | .br | ||
167 | net none # this command creates an empty network namespace | ||
97 | 168 | ||
98 | .TP | 169 | .TP |
99 | \fB?CONDITIONAL: profile line | 170 | \fB?CONDITIONAL: profile line |
@@ -103,7 +174,7 @@ Example: "?HAS_APPIMAGE: whitelist ${HOME}/special/appimage/dir" | |||
103 | 174 | ||
104 | This example will load the whitelist profile line only if the \-\-appimage option has been specified on the command line. | 175 | This example will load the whitelist profile line only if the \-\-appimage option has been specified on the command line. |
105 | 176 | ||
106 | Currently the only conditionals supported this way are HAS_APPIMAGE, HAS_NET, HAS_NODBUS, HAS_NOSOUND, HAS_PRIVATE and HAS_X11. The conditionals BROWSER_DISABLE_U2F and BROWSER_ALLOW_DRM | 177 | Currently the only conditionals supported this way are HAS_APPIMAGE, HAS_NET, HAS_NODBUS, HAS_NOSOUND, HAS_PRIVATE and HAS_X11. The conditionals ALLOW_TRAY, BROWSER_DISABLE_U2F and BROWSER_ALLOW_DRM |
107 | can be enabled or disabled globally in Firejail's configuration file. | 178 | can be enabled or disabled globally in Firejail's configuration file. |
108 | 179 | ||
109 | The profile line may be any profile line that you would normally use in a profile \fBexcept\fR for "quiet" and "include" lines. | 180 | The profile line may be any profile line that you would normally use in a profile \fBexcept\fR for "quiet" and "include" lines. |
@@ -205,6 +276,10 @@ Mount-bind file1 on top of file2. This option is only available when running as | |||
205 | \fBdisable-mnt | 276 | \fBdisable-mnt |
206 | Disable /mnt, /media, /run/mount and /run/media access. | 277 | Disable /mnt, /media, /run/mount and /run/media access. |
207 | .TP | 278 | .TP |
279 | \fBkeep-config-pulse | ||
280 | Disable automatic ~/.config/pulse init, for complex setups such as remote | ||
281 | pulse servers or non-standard socket paths. | ||
282 | .TP | ||
208 | \fBkeep-dev-shm | 283 | \fBkeep-dev-shm |
209 | /dev/shm directory is untouched (even with private-dev). | 284 | /dev/shm directory is untouched (even with private-dev). |
210 | .TP | 285 | .TP |
@@ -249,16 +324,16 @@ Remount the file or the directory noexec, nodev and nosuid. | |||
249 | #ifdef HAVE_OVERLAYFS | 324 | #ifdef HAVE_OVERLAYFS |
250 | .TP | 325 | .TP |
251 | \fBoverlay | 326 | \fBoverlay |
252 | Mount a filesystem overlay on top of the current filesystem. | 327 | Mount a filesystem overlay on top of the current filesystem. |
253 | The overlay is stored in $HOME/.firejail/<PID> directory. | 328 | The overlay is stored in $HOME/.firejail/<PID> directory. |
254 | .TP | 329 | .TP |
255 | \fBoverlay-named name | 330 | \fBoverlay-named name |
256 | Mount a filesystem overlay on top of the current filesystem. | 331 | Mount a filesystem overlay on top of the current filesystem. |
257 | The overlay is stored in $HOME/.firejail/name directory. | 332 | The overlay is stored in $HOME/.firejail/name directory. |
258 | .TP | 333 | .TP |
259 | \fBoverlay-tmpfs | 334 | \fBoverlay-tmpfs |
260 | Mount a filesystem overlay on top of the current filesystem. | 335 | Mount a filesystem overlay on top of the current filesystem. |
261 | All filesystem modifications are discarded when the sandbox is closed. | 336 | All filesystem modifications are discarded when the sandbox is closed. |
262 | #endif | 337 | #endif |
263 | .TP | 338 | .TP |
264 | \fBprivate | 339 | \fBprivate |
@@ -274,6 +349,7 @@ Build a new /bin in a temporary filesystem, and copy the programs in the list. | |||
274 | The files in the list must be expressed as relative to the /bin, | 349 | The files in the list must be expressed as relative to the /bin, |
275 | /sbin, /usr/bin, /usr/sbin, or /usr/local/bin directories. | 350 | /sbin, /usr/bin, /usr/sbin, or /usr/local/bin directories. |
276 | The same directory is also bind-mounted over /sbin, /usr/bin and /usr/sbin. | 351 | The same directory is also bind-mounted over /sbin, /usr/bin and /usr/sbin. |
352 | Multiple private-bin commands are allowed and they accumulate. | ||
277 | .TP | 353 | .TP |
278 | \fBprivate-cache | 354 | \fBprivate-cache |
279 | Mount an empty temporary filesystem on top of the .cache directory in user home. All | 355 | Mount an empty temporary filesystem on top of the .cache directory in user home. All |
@@ -283,7 +359,7 @@ modifications are discarded when the sandbox is closed. | |||
283 | Set working directory inside jail to the home directory, and failing that, the root directory. | 359 | Set working directory inside jail to the home directory, and failing that, the root directory. |
284 | .TP | 360 | .TP |
285 | \fBprivate-cwd directory | 361 | \fBprivate-cwd directory |
286 | Set working directory inside the jail. | 362 | Set working directory inside the jail. Full directory path is required. Symbolic links are not allowed. |
287 | .TP | 363 | .TP |
288 | \fBprivate-dev | 364 | \fBprivate-dev |
289 | Create a new /dev directory. Only disc, dri, dvb, hidraw, null, full, zero, tty, pts, ptmx, | 365 | Create a new /dev directory. Only disc, dri, dvb, hidraw, null, full, zero, tty, pts, ptmx, |
@@ -299,6 +375,7 @@ the /etc directory, and must not contain the / character | |||
299 | (e.g., /etc/foo must be expressed as foo, but /etc/foo/bar -- | 375 | (e.g., /etc/foo must be expressed as foo, but /etc/foo/bar -- |
300 | expressed as foo/bar -- is disallowed). | 376 | expressed as foo/bar -- is disallowed). |
301 | All modifications are discarded when the sandbox is closed. | 377 | All modifications are discarded when the sandbox is closed. |
378 | Multiple private-etc commands are allowed and they accumulate. | ||
302 | #ifdef HAVE_PRIVATE_HOME | 379 | #ifdef HAVE_PRIVATE_HOME |
303 | .TP | 380 | .TP |
304 | \fBprivate-home file,directory | 381 | \fBprivate-home file,directory |
@@ -345,7 +422,7 @@ Make directory or file read-only. | |||
345 | Make directory or file read-write. | 422 | Make directory or file read-write. |
346 | .TP | 423 | .TP |
347 | \fBtmpfs directory | 424 | \fBtmpfs directory |
348 | Mount an empty tmpfs filesystem on top of directory. This option is available only when running the sandbox as root. | 425 | Mount an empty tmpfs filesystem on top of directory. Directories outside user home or not owned by the user are not allowed. Sandboxes running as root are exempt from these restrictions. |
349 | .TP | 426 | .TP |
350 | \fBtracelog | 427 | \fBtracelog |
351 | Blacklist violations logged to syslog. | 428 | Blacklist violations logged to syslog. |
@@ -353,13 +430,19 @@ Blacklist violations logged to syslog. | |||
353 | \fBwhitelist file_or_directory | 430 | \fBwhitelist file_or_directory |
354 | Whitelist directory or file. A temporary file system is mounted on the top directory, and the | 431 | Whitelist directory or file. A temporary file system is mounted on the top directory, and the |
355 | whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, | 432 | whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, |
356 | everything else is discarded when the sandbox is closed. The top directory could be | 433 | everything else is discarded when the sandbox is closed. The top directory can be |
357 | user home, /dev, /etc, /media, /mnt, /opt, /srv, /sys/module, /usr/share, /var, and /tmp. | 434 | all directories in / (except /proc and /sys), /sys/module, /run/user/$UID, $HOME and |
435 | all directories in /usr. | ||
358 | .br | 436 | .br |
359 | 437 | ||
360 | .br | 438 | .br |
361 | Symbolic link handling: with the exception of user home, both the link and the real file should be in | 439 | Symbolic link handling: with the exception of user home, both the link and the real file should be in |
362 | the same top directory. For user home, both the link and the real file should be owned by the user. | 440 | the same top directory. For user home, both the link and the real file should be owned by the user. |
441 | |||
442 | .TP | ||
443 | \fBwhitelist-ro file_or_directory | ||
444 | Equivalent to "whitelist file_or_directory" followed by "read-only file_or_directory" | ||
445 | |||
363 | .TP | 446 | .TP |
364 | \fBwritable-etc | 447 | \fBwritable-etc |
365 | Mount /etc directory read-write. | 448 | Mount /etc directory read-write. |
@@ -408,17 +491,21 @@ Sets the NO_NEW_PRIVS prctl. This ensures that child processes | |||
408 | cannot acquire new privileges using execve(2); in particular, | 491 | cannot acquire new privileges using execve(2); in particular, |
409 | this means that calling a suid binary (or one with file capabilities) | 492 | this means that calling a suid binary (or one with file capabilities) |
410 | does not result in an increase of privilege. | 493 | does not result in an increase of privilege. |
494 | .TP | ||
495 | \fBnoprinters | ||
496 | Disable printers. | ||
411 | #ifdef HAVE_USERNS | 497 | #ifdef HAVE_USERNS |
412 | .TP | 498 | .TP |
413 | \fBnoroot | 499 | \fBnoroot |
414 | Use this command to enable an user namespace. The namespace has only one user, the current user. | 500 | Use this command to enable an user namespace. The namespace has only one user, the current user. |
415 | There is no root account (uid 0) defined in the namespace. | 501 | There is no root account (uid 0) defined in the namespace. |
416 | #endif | 502 | #endif |
417 | .TP | 503 | .TP |
418 | \fBprotocol protocol1,protocol2,protocol3 | 504 | \fBprotocol protocol1,protocol2,protocol3 |
419 | Enable protocol filter. The filter is based on seccomp and checks the | 505 | Enable protocol filter. The filter is based on seccomp and checks the |
420 | first argument to socket system call. Recognized values: \fBunix\fR, | 506 | first argument to socket system call. Recognized values: \fBunix\fR, |
421 | \fBinet\fR, \fBinet6\fR, \fBnetlink\fR, \fBpacket\fR and \fBbluetooth\fR. | 507 | \fBinet\fR, \fBinet6\fR, \fBnetlink\fR, \fBpacket\fR, and \fBbluetooth\fR. |
508 | Multiple protocol commands are allowed. | ||
422 | .TP | 509 | .TP |
423 | \fBseccomp | 510 | \fBseccomp |
424 | Enable seccomp filter and blacklist the syscalls in the default list. See man 1 firejail for more details. | 511 | Enable seccomp filter and blacklist the syscalls in the default list. See man 1 firejail for more details. |
@@ -530,7 +617,7 @@ Allow the application to see but not talk to the name org.freedesktop.Notificati | |||
530 | Allow the application to call methods of the interface org.freedesktop.Notifications of the object exposed at the path /org/freedesktop/Notifications by the client owning the bus name org.freedesktop.Notifications on the system DBus. | 617 | Allow the application to call methods of the interface org.freedesktop.Notifications of the object exposed at the path /org/freedesktop/Notifications by the client owning the bus name org.freedesktop.Notifications on the system DBus. |
531 | .TP | 618 | .TP |
532 | \fBdbus-system.broadcast org.freedesktop.Notifications=org.freedesktop.Notifications.*@/org/freedesktop/Notifications | 619 | \fBdbus-system.broadcast org.freedesktop.Notifications=org.freedesktop.Notifications.*@/org/freedesktop/Notifications |
533 | Allow the application to receive broadcast signals from the the interface org.freedesktop.Notifications of the object exposed at the path /org/freedesktop/Notifications by the client owning the bus name org.freedesktop.Notifications on the system DBus. | 620 | Allow the application to receive broadcast signals from the interface org.freedesktop.Notifications of the object exposed at the path /org/freedesktop/Notifications by the client owning the bus name org.freedesktop.Notifications on the system DBus. |
534 | .TP | 621 | .TP |
535 | \fBdbus-user filter | 622 | \fBdbus-user filter |
536 | Enable filtered access to the session DBus. Filters can be specified with the dbus-user.talk and dbus-user.own commands. | 623 | Enable filtered access to the session DBus. Filters can be specified with the dbus-user.talk and dbus-user.own commands. |
@@ -640,6 +727,11 @@ env CFLAGS="-W -Wall -Werror" | |||
640 | .TP | 727 | .TP |
641 | \fBipc-namespace | 728 | \fBipc-namespace |
642 | Enable IPC namespace. | 729 | Enable IPC namespace. |
730 | |||
731 | .TP | ||
732 | \fBkeep-fd | ||
733 | Inherit open file descriptors to sandbox. | ||
734 | |||
643 | .TP | 735 | .TP |
644 | \fBname sandboxname | 736 | \fBname sandboxname |
645 | Set sandbox name. Example: | 737 | Set sandbox name. Example: |
@@ -652,9 +744,8 @@ name browser | |||
652 | \fBno3d | 744 | \fBno3d |
653 | Disable 3D hardware acceleration. | 745 | Disable 3D hardware acceleration. |
654 | .TP | 746 | .TP |
655 | \fBnoautopulse | 747 | \fBnoautopulse \fR(deprecated) |
656 | Disable automatic ~/.config/pulse init, for complex setups such as remote | 748 | See keep-config-pulse. |
657 | pulse servers or non-standard socket paths. | ||
658 | .TP | 749 | .TP |
659 | \fBnodvd | 750 | \fBnodvd |
660 | Disable DVD and audio CD devices. | 751 | Disable DVD and audio CD devices. |
@@ -662,6 +753,9 @@ Disable DVD and audio CD devices. | |||
662 | \fBnogroups | 753 | \fBnogroups |
663 | Disable supplementary user groups | 754 | Disable supplementary user groups |
664 | .TP | 755 | .TP |
756 | \fBnoinput | ||
757 | Disable input devices. | ||
758 | .TP | ||
665 | \fBnosound | 759 | \fBnosound |
666 | Disable sound system. | 760 | Disable sound system. |
667 | .TP | 761 | .TP |
@@ -674,8 +768,8 @@ Disable U2F devices. | |||
674 | \fBnovideo | 768 | \fBnovideo |
675 | Disable video capture devices. | 769 | Disable video capture devices. |
676 | .TP | 770 | .TP |
677 | \fBnoinput | 771 | \fBmachine-id |
678 | Disable input devices. | 772 | Spoof id number in /etc/machine-id file - a new random id is generated inside the sandbox. |
679 | .TP | 773 | .TP |
680 | \fBshell none | 774 | \fBshell none |
681 | Run the program directly, without a shell. | 775 | Run the program directly, without a shell. |
@@ -795,8 +889,8 @@ a DHCP client and releasing the lease manually. | |||
795 | 889 | ||
796 | .TP | 890 | .TP |
797 | \fBiprange address,address | 891 | \fBiprange address,address |
798 | Assign an IP address in the provided range to the last network | 892 | Assign an IP address in the provided range to the last network |
799 | interface defined by a net command. A default gateway is assigned by default. | 893 | interface defined by a net command. A default gateway is assigned by default. |
800 | .br | 894 | .br |
801 | 895 | ||
802 | .br | 896 | .br |
@@ -814,10 +908,6 @@ iprange 192.168.1.150,192.168.1.160 | |||
814 | Assign MAC addresses to the last network interface defined by a net command. | 908 | Assign MAC addresses to the last network interface defined by a net command. |
815 | 909 | ||
816 | .TP | 910 | .TP |
817 | \fBmachine-id | ||
818 | Spoof id number in /etc/machine-id file - a new random id is generated inside the sandbox. | ||
819 | |||
820 | .TP | ||
821 | \fBmtu number | 911 | \fBmtu number |
822 | Assign a MTU value to the last network interface defined by a net command. | 912 | Assign a MTU value to the last network interface defined by a net command. |
823 | 913 | ||
@@ -880,18 +970,37 @@ be created and configured using "ip netns". | |||
880 | Use this name for the interface connected to the bridge for --net=bridge_interface commands, | 970 | Use this name for the interface connected to the bridge for --net=bridge_interface commands, |
881 | instead of the default one. | 971 | instead of the default one. |
882 | #endif | 972 | #endif |
973 | |||
883 | .SH Other | 974 | .SH Other |
884 | .TP | 975 | .TP |
885 | \fBdeterministic-exit-code | 976 | \fBdeterministic-exit-code |
886 | Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. | 977 | Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. |
887 | 978 | ||
888 | .TP | 979 | .TP |
980 | \fBdeterministic-shutdown | ||
981 | Always shut down the sandbox after the first child has terminated. The default behavior is to keep the sandbox alive as long as it contains running processes. | ||
982 | |||
983 | .TP | ||
889 | \fBjoin-or-start sandboxname | 984 | \fBjoin-or-start sandboxname |
890 | Join the sandbox identified by name or start a new one. | 985 | Join the sandbox identified by name or start a new one. |
891 | Same as "firejail --join=sandboxname" command if sandbox with specified name exists, otherwise same as "name sandboxname". | 986 | Same as "firejail --join=sandboxname" command if sandbox with specified name exists, otherwise same as "name sandboxname". |
892 | 987 | ||
893 | .SH FILES | 988 | .SH FILES |
894 | /etc/firejail/filename.profile, $HOME/.config/firejail/filename.profile | 989 | .TP |
990 | \fB/etc/firejail/appname.profile | ||
991 | Global Firejail configuration consisting mainly of profiles for each application supported by default. | ||
992 | |||
993 | .TP | ||
994 | \fB$HOME/.config/firejail/appname.profile | ||
995 | User application profiles, will take precedence over the global profiles. | ||
996 | |||
997 | .TP | ||
998 | \fB/usr/share/doc/firejail/profile.template | ||
999 | Template for building new profiles. | ||
1000 | |||
1001 | .TP | ||
1002 | \fB/usr/share/doc/firejail/redirect_alias-profile.template | ||
1003 | Template for aliasing/redirecting profiles. | ||
895 | 1004 | ||
896 | .SH LICENSE | 1005 | .SH LICENSE |
897 | Firejail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. | 1006 | Firejail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |
@@ -903,7 +1012,7 @@ Homepage: https://firejail.wordpress.com | |||
903 | .BR firecfg (1), | 1012 | .BR firecfg (1), |
904 | .BR firejail-login (5), | 1013 | .BR firejail-login (5), |
905 | .BR firejail-users (5), | 1014 | .BR firejail-users (5), |
906 | .BR jailtest (1) | 1015 | .BR jailcheck (1) |
907 | 1016 | ||
908 | .UR https://github.com/netblue30/firejail/wiki/Creating-Profiles | 1017 | .UR https://github.com/netblue30/firejail/wiki/Creating-Profiles |
909 | .UE | 1018 | .UE |
diff --git a/src/man/firejail-users.txt b/src/man/firejail-users.txt index c5a9c1848..e3cce7ed5 100644 --- a/src/man/firejail-users.txt +++ b/src/man/firejail-users.txt | |||
@@ -59,4 +59,4 @@ Homepage: https://firejail.wordpress.com | |||
59 | .BR firecfg (1), | 59 | .BR firecfg (1), |
60 | .BR firejail-profile (5), | 60 | .BR firejail-profile (5), |
61 | .BR firejail-login (5), | 61 | .BR firejail-login (5), |
62 | .BR jailtest (1) | 62 | .BR jailcheck (1) |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 23ec23fb1..f9deaeaa4 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -45,7 +45,7 @@ firejail {\-? | \-\-debug-caps | \-\-debug-errnos | \-\-debug-syscalls | \-\-deb | |||
45 | #ifdef HAVE_LTS | 45 | #ifdef HAVE_LTS |
46 | This is Firejail long-term support (LTS), an enterprise focused version of the software, | 46 | This is Firejail long-term support (LTS), an enterprise focused version of the software, |
47 | LTS is usually supported for two or three years. | 47 | LTS is usually supported for two or three years. |
48 | During this time only bugs and the occasional documentation problems are fixed. | 48 | During this time only bugs and the occasional documentation problems are fixed. |
49 | The attack surface of the SUID executable was greatly reduced by removing some of the features. | 49 | The attack surface of the SUID executable was greatly reduced by removing some of the features. |
50 | .br | 50 | .br |
51 | 51 | ||
@@ -109,7 +109,7 @@ ptrace system call allows a full bypass of the seccomp filter. | |||
109 | .br | 109 | .br |
110 | Example: | 110 | Example: |
111 | .br | 111 | .br |
112 | $ firejail --allow-debuggers --profile=/etc/firejail/firefox.profile strace -f firefox | 112 | $ firejail --allow-debuggers --profile=/etc/firejail/firefox.profile strace -f firefox |
113 | .TP | 113 | .TP |
114 | \fB\-\-allusers | 114 | \fB\-\-allusers |
115 | All directories under /home are visible inside the sandbox. By default, only current user home directory is visible. | 115 | All directories under /home are visible inside the sandbox. By default, only current user home directory is visible. |
@@ -147,12 +147,12 @@ private-bin and private-lib are disabled by default when running appimages. | |||
147 | .br | 147 | .br |
148 | Example: | 148 | Example: |
149 | .br | 149 | .br |
150 | $ firejail --appimage krita-3.0-x86_64.appimage | 150 | $ firejail --appimage --profile=krita krita-3.0-x86_64.appimage |
151 | .br | 151 | .br |
152 | $ firejail --appimage --private krita-3.0-x86_64.appimage | 152 | $ firejail --appimage --private --profile=krita krita-3.0-x86_64.appimage |
153 | .br | 153 | .br |
154 | #ifdef HAVE_X11 | 154 | #ifdef HAVE_X11 |
155 | $ firejail --appimage --net=none --x11 krita-3.0-x86_64.appimage | 155 | $ firejail --appimage --net=none --x11 --profile=krita krita-3.0-x86_64.appimage |
156 | #endif | 156 | #endif |
157 | .TP | 157 | .TP |
158 | #ifdef HAVE_NETWORK | 158 | #ifdef HAVE_NETWORK |
@@ -185,10 +185,7 @@ $ firejail "\-\-blacklist=/home/username/My Virtual Machines" | |||
185 | $ firejail \-\-blacklist=/home/username/My\\ Virtual\\ Machines | 185 | $ firejail \-\-blacklist=/home/username/My\\ Virtual\\ Machines |
186 | .TP | 186 | .TP |
187 | \fB\-\-build | 187 | \fB\-\-build |
188 | The command builds a whitelisted profile. The profile is printed on the screen. If /usr/bin/strace is installed on the system, it also | 188 | The command builds a whitelisted profile. The profile is printed on the screen. The program is run in a very relaxed sandbox, with only --caps.drop=all and --nonewprivs. Programs that raise user privileges are not supported. |
189 | builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox, | ||
190 | with only --caps.drop=all and --nonewprivs. Programs that raise user privileges are not supported | ||
191 | in order to allow strace to run. Chromium and Chromium-based browsers will not work. | ||
192 | .br | 189 | .br |
193 | 190 | ||
194 | .br | 191 | .br |
@@ -197,10 +194,8 @@ Example: | |||
197 | $ firejail --build vlc ~/Videos/test.mp4 | 194 | $ firejail --build vlc ~/Videos/test.mp4 |
198 | .TP | 195 | .TP |
199 | \fB\-\-build=profile-file | 196 | \fB\-\-build=profile-file |
200 | The command builds a whitelisted profile, and saves it in profile-file. If /usr/bin/strace is installed on the system, it also | 197 | The command builds a whitelisted profile, and saves it in profile-file. The program is run in a very relaxed sandbox, |
201 | builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox, | 198 | with only --caps.drop=all and --nonewprivs. Programs that raise user privileges are not supported. |
202 | with only --caps.drop=all and --nonewprivs. Programs that raise user privileges are not supported | ||
203 | in order to allow strace to run. Chromium and Chromium-based browsers will not work. | ||
204 | .br | 199 | .br |
205 | 200 | ||
206 | .br | 201 | .br |
@@ -290,8 +285,8 @@ $ firejail \-\-caps.print=3272 | |||
290 | Print content of file from sandbox container, see FILE TRANSFER section for more details. | 285 | Print content of file from sandbox container, see FILE TRANSFER section for more details. |
291 | #endif | 286 | #endif |
292 | .TP | 287 | .TP |
293 | \fB\-\-cgroup=tasks-file | 288 | \fB\-\-cgroup=file |
294 | Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. | 289 | Place the sandbox in the specified control group. file is the full path of a tasks or cgroup.procs file. |
295 | .br | 290 | .br |
296 | 291 | ||
297 | .br | 292 | .br |
@@ -310,6 +305,11 @@ regular user, nonewprivs and a default capabilities filter are enabled. | |||
310 | Example: | 305 | Example: |
311 | .br | 306 | .br |
312 | $ firejail \-\-chroot=/media/ubuntu warzone2100 | 307 | $ firejail \-\-chroot=/media/ubuntu warzone2100 |
308 | .br | ||
309 | |||
310 | .br | ||
311 | For automatic mounting of X11 and PulseAudio sockets set environment variables | ||
312 | FIREJAIL_CHROOT_X11 and FIREJAIL_CHROOT_PULSE. | ||
313 | #endif | 313 | #endif |
314 | .TP | 314 | .TP |
315 | \fB\-\-cpu=cpu-number,cpu-number,cpu-number | 315 | \fB\-\-cpu=cpu-number,cpu-number,cpu-number |
@@ -701,6 +701,12 @@ $ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox | |||
701 | \fB\-\-deterministic-exit-code | 701 | \fB\-\-deterministic-exit-code |
702 | Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. | 702 | Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. |
703 | .br | 703 | .br |
704 | |||
705 | .TP | ||
706 | \fB\-\-deterministic-shutdown | ||
707 | Always shut down the sandbox after the first child has terminated. The default behavior is to keep the sandbox alive as long as it contains running processes. | ||
708 | .br | ||
709 | |||
704 | .TP | 710 | .TP |
705 | \fB\-\-disable-mnt | 711 | \fB\-\-disable-mnt |
706 | Blacklist /mnt, /media, /run/mount and /run/media access. | 712 | Blacklist /mnt, /media, /run/mount and /run/media access. |
@@ -810,6 +816,26 @@ Example: | |||
810 | $ firejail \-\-hosts-file=~/myhosts firefox | 816 | $ firejail \-\-hosts-file=~/myhosts firefox |
811 | 817 | ||
812 | .TP | 818 | .TP |
819 | \fB\-\-ids-check | ||
820 | Check file hashes previously generated by \-\-ids-check. See INTRUSION DETECTION SYSTEM section for more details. | ||
821 | .br | ||
822 | |||
823 | .br | ||
824 | Example: | ||
825 | .br | ||
826 | $ firejail \-\-ids-check | ||
827 | |||
828 | .TP | ||
829 | \fB\-\-ids-init | ||
830 | Initialize file hashes. See INTRUSION DETECTION SYSTEM section for more details. | ||
831 | .br | ||
832 | |||
833 | .br | ||
834 | Example: | ||
835 | .br | ||
836 | $ firejail \-\-ids-init | ||
837 | |||
838 | .TP | ||
813 | \fB\-\-ignore=command | 839 | \fB\-\-ignore=command |
814 | Ignore command in profile file. | 840 | Ignore command in profile file. |
815 | .br | 841 | .br |
@@ -947,7 +973,7 @@ $ firejail \-\-net=eth0 \-\-\iprange=192.168.1.100,192.168.1.150 | |||
947 | 973 | ||
948 | .TP | 974 | .TP |
949 | \fB\-\-ipc-namespace | 975 | \fB\-\-ipc-namespace |
950 | Enable a new IPC namespace if the sandbox was started as a regular user. IPC namespace is enabled by default | 976 | Enable a new IPC namespace if the sandbox was started as a regular user. IPC namespace is enabled by default |
951 | for sandboxes started as root. | 977 | for sandboxes started as root. |
952 | .br | 978 | .br |
953 | 979 | ||
@@ -1014,7 +1040,7 @@ $ sudo firejail --join-network=browser /sbin/iptables -vL | |||
1014 | .br | 1040 | .br |
1015 | 1041 | ||
1016 | .br | 1042 | .br |
1017 | # verify IP addresses | 1043 | # verify IP addresses |
1018 | .br | 1044 | .br |
1019 | $ sudo firejail --join-network=browser ip addr | 1045 | $ sudo firejail --join-network=browser ip addr |
1020 | .br | 1046 | .br |
@@ -1052,6 +1078,17 @@ Same as "firejail --join=name" if sandbox with specified name exists, otherwise | |||
1052 | Note that in contrary to other join options there is respective profile option. | 1078 | Note that in contrary to other join options there is respective profile option. |
1053 | 1079 | ||
1054 | .TP | 1080 | .TP |
1081 | \fB\-\-keep-config-pulse | ||
1082 | Disable automatic ~/.config/pulse init, for complex setups such as remote | ||
1083 | pulse servers or non-standard socket paths. | ||
1084 | .br | ||
1085 | |||
1086 | .br | ||
1087 | Example: | ||
1088 | .br | ||
1089 | $ firejail \-\-keep-config-pulse firefox | ||
1090 | |||
1091 | .TP | ||
1055 | \fB\-\-keep-dev-shm | 1092 | \fB\-\-keep-dev-shm |
1056 | /dev/shm directory is untouched (even with --private-dev) | 1093 | /dev/shm directory is untouched (even with --private-dev) |
1057 | .br | 1094 | .br |
@@ -1062,6 +1099,26 @@ Example: | |||
1062 | $ firejail --keep-dev-shm --private-dev | 1099 | $ firejail --keep-dev-shm --private-dev |
1063 | 1100 | ||
1064 | .TP | 1101 | .TP |
1102 | \fB\-\-keep-fd=all | ||
1103 | Inherit all open file descriptors to the sandbox. By default only file descriptors 0, 1 and 2 are inherited to the sandbox, and all other file descriptors are closed. | ||
1104 | .br | ||
1105 | |||
1106 | .br | ||
1107 | Example: | ||
1108 | .br | ||
1109 | $ firejail --keep-fd=all | ||
1110 | |||
1111 | .TP | ||
1112 | \fB\-\-keep-fd=file_descriptor | ||
1113 | Don't close specified open file descriptors. By default only file descriptors 0, 1 and 2 are inherited to the sandbox, and all other file descriptors are closed. | ||
1114 | .br | ||
1115 | |||
1116 | .br | ||
1117 | Example: | ||
1118 | .br | ||
1119 | $ firejail --keep-fd=3,4,5 | ||
1120 | |||
1121 | .TP | ||
1065 | \fB\-\-keep-var-tmp | 1122 | \fB\-\-keep-var-tmp |
1066 | /var/tmp directory is untouched. | 1123 | /var/tmp directory is untouched. |
1067 | .br | 1124 | .br |
@@ -1214,7 +1271,7 @@ $ firejail \-\-net=br0 \-\-net=br1 | |||
1214 | .TP | 1271 | .TP |
1215 | \fB\-\-net=ethernet_interface|wireless_interface | 1272 | \fB\-\-net=ethernet_interface|wireless_interface |
1216 | Enable a new network namespace and connect it | 1273 | Enable a new network namespace and connect it |
1217 | to this ethernet interface using the standard Linux macvlan|ipvaln | 1274 | to this ethernet interface using the standard Linux macvlan|ipvlan |
1218 | driver. Unless specified with option \-\-ip and \-\-defaultgw, an | 1275 | driver. Unless specified with option \-\-ip and \-\-defaultgw, an |
1219 | IP address and a default gateway will be assigned automatically | 1276 | IP address and a default gateway will be assigned automatically |
1220 | to the sandbox. The IP address is verified using ARP before | 1277 | to the sandbox. The IP address is verified using ARP before |
@@ -1401,6 +1458,30 @@ $ firejail --name=browser --net=eth0 --netfilter firefox & | |||
1401 | $ firejail --netfilter6.print=browser | 1458 | $ firejail --netfilter6.print=browser |
1402 | 1459 | ||
1403 | .TP | 1460 | .TP |
1461 | \fB\-\-netlock | ||
1462 | Several type of programs (email clients, multiplayer games etc.) talk to a very small | ||
1463 | number of IP addresses. But the best example is tor browser. It only talks to a guard node, | ||
1464 | and there are two or three more on standby in case the main one fails. | ||
1465 | During startup, the browser contacts all of them, after that it keeps talking to the main | ||
1466 | one... for weeks! | ||
1467 | |||
1468 | Use the network locking feature to build and deploy a custom network firewall in your sandbox. | ||
1469 | The firewall allows only the traffic to the IP addresses detected during the program | ||
1470 | startup. Traffic to any other address is quietly dropped. By default the network monitoring | ||
1471 | time is one minute. | ||
1472 | |||
1473 | A network namespace (\-\-net=eth0) is required for this feature to work. Example: | ||
1474 | .br | ||
1475 | |||
1476 | .br | ||
1477 | $ firejail --net=eth0 --netlock \\ | ||
1478 | .br | ||
1479 | --private=~/tor-browser_en-US ./start-tor-browser.desktop | ||
1480 | .br | ||
1481 | |||
1482 | .br | ||
1483 | |||
1484 | .TP | ||
1404 | \fB\-\-netmask=address | 1485 | \fB\-\-netmask=address |
1405 | Use this option when you want to assign an IP address in a new namespace and | 1486 | Use this option when you want to assign an IP address in a new namespace and |
1406 | the parent interface specified by --net is not configured. An IP address and | 1487 | the parent interface specified by --net is not configured. An IP address and |
@@ -1437,6 +1518,40 @@ PID User RX(KB/s) TX(KB/s) Command | |||
1437 | 1294 netblue 53.355 1.473 firejail \-\-net=eth0 firefox | 1518 | 1294 netblue 53.355 1.473 firejail \-\-net=eth0 firefox |
1438 | .br | 1519 | .br |
1439 | 7383 netblue 9.045 0.112 firejail \-\-net=eth0 transmission | 1520 | 7383 netblue 9.045 0.112 firejail \-\-net=eth0 transmission |
1521 | .TP | ||
1522 | \fB\-\-nettrace[=name|pid] | ||
1523 | Monitor TCP and UDP traffic coming into the sandbox specified by name or pid. Only networked sandboxes | ||
1524 | created with \-\-net are supported. | ||
1525 | .br | ||
1526 | |||
1527 | .br | ||
1528 | Without a name/pid, Firejail will monitor the main system network namespace. | ||
1529 | .br | ||
1530 | |||
1531 | .br | ||
1532 | $ firejail --nettrace=browser | ||
1533 | .br | ||
1534 | |||
1535 | .br | ||
1536 | 95 KB/s geoip 457, IP database 4436 | ||
1537 | .br | ||
1538 | 52 KB/s *********** 64.222.84.207:443 United States | ||
1539 | .br | ||
1540 | 33 KB/s ******* 89.147.74.105:63930 Hungary | ||
1541 | .br | ||
1542 | 0 B/s 45.90.28.0:443 NextDNS | ||
1543 | .br | ||
1544 | 0 B/s 94.70.122.176:52309(UDP) Greece | ||
1545 | .br | ||
1546 | 339 B/s 104.26.7.35:443 Cloudflare | ||
1547 | .br | ||
1548 | |||
1549 | .br | ||
1550 | If /usr/bin/geoiplookup is installed (geoip-bin package in Debian), | ||
1551 | the country the IP address originates from is added to the trace. | ||
1552 | We also use the static IP map in /etc/firejail/hostnames | ||
1553 | to print the domain names for some of the more common websites and cloud platforms. | ||
1554 | No external services are contacted for reverse IP lookup. | ||
1440 | #endif | 1555 | #endif |
1441 | .TP | 1556 | .TP |
1442 | \fB\-\-nice=value | 1557 | \fB\-\-nice=value |
@@ -1460,15 +1575,8 @@ Example: | |||
1460 | $ firejail --no3d firefox | 1575 | $ firejail --no3d firefox |
1461 | 1576 | ||
1462 | .TP | 1577 | .TP |
1463 | \fB\-\-noautopulse | 1578 | \fB\-\-noautopulse \fR(deprecated) |
1464 | Disable automatic ~/.config/pulse init, for complex setups such as remote | 1579 | See --keep-config-pulse. |
1465 | pulse servers or non-standard socket paths. | ||
1466 | .br | ||
1467 | |||
1468 | .br | ||
1469 | Example: | ||
1470 | .br | ||
1471 | $ firejail \-\-noautopulse firefox | ||
1472 | 1580 | ||
1473 | .TP | 1581 | .TP |
1474 | \fB\-\-noblacklist=dirname_or_filename | 1582 | \fB\-\-noblacklist=dirname_or_filename |
@@ -1576,6 +1684,10 @@ does not result in an increase of privilege. This option | |||
1576 | is enabled by default if seccomp filter is activated. | 1684 | is enabled by default if seccomp filter is activated. |
1577 | 1685 | ||
1578 | .TP | 1686 | .TP |
1687 | \fB\-\-noprinters | ||
1688 | Disable printers. | ||
1689 | |||
1690 | .TP | ||
1579 | \fB\-\-noprofile | 1691 | \fB\-\-noprofile |
1580 | Do not use a security profile. | 1692 | Do not use a security profile. |
1581 | .br | 1693 | .br |
@@ -1797,8 +1909,9 @@ The files in the list must be expressed as relative to the /bin, | |||
1797 | /sbin, /usr/bin, /usr/sbin, or /usr/local/bin directories. | 1909 | /sbin, /usr/bin, /usr/sbin, or /usr/local/bin directories. |
1798 | If no listed files are found, /bin directory will be empty. | 1910 | If no listed files are found, /bin directory will be empty. |
1799 | The same directory is also bind-mounted over /sbin, /usr/bin, /usr/sbin and /usr/local/bin. | 1911 | The same directory is also bind-mounted over /sbin, /usr/bin, /usr/sbin and /usr/local/bin. |
1800 | All modifications are discarded when the sandbox is closed. File globbing is supported, | 1912 | All modifications are discarded when the sandbox is closed. |
1801 | see \fBFILE GLOBBING\fR section for more details. | 1913 | Multiple private-bin commands are allowed and they accumulate. |
1914 | File globbing is supported, see \fBFILE GLOBBING\fR section for more details. | ||
1802 | .br | 1915 | .br |
1803 | 1916 | ||
1804 | .br | 1917 | .br |
@@ -1828,7 +1941,6 @@ $ firejail \-\-private-cache openbox | |||
1828 | .TP | 1941 | .TP |
1829 | \fB\-\-private-cwd | 1942 | \fB\-\-private-cwd |
1830 | Set working directory inside jail to the home directory, and failing that, the root directory. | 1943 | Set working directory inside jail to the home directory, and failing that, the root directory. |
1831 | .br | ||
1832 | Does not impact working directory of profile include paths. | 1944 | Does not impact working directory of profile include paths. |
1833 | .br | 1945 | .br |
1834 | 1946 | ||
@@ -1849,7 +1961,7 @@ $ pwd | |||
1849 | .TP | 1961 | .TP |
1850 | \fB\-\-private-cwd=directory | 1962 | \fB\-\-private-cwd=directory |
1851 | Set working directory inside the jail. | 1963 | Set working directory inside the jail. |
1852 | .br | 1964 | Full directory path is required. Symbolic links are not allowed. |
1853 | Does not impact working directory of profile include paths. | 1965 | Does not impact working directory of profile include paths. |
1854 | .br | 1966 | .br |
1855 | 1967 | ||
@@ -1892,11 +2004,10 @@ $ | |||
1892 | Build a new /etc in a temporary | 2004 | Build a new /etc in a temporary |
1893 | filesystem, and copy the files and directories in the list. | 2005 | filesystem, and copy the files and directories in the list. |
1894 | The files and directories in the list must be expressed as relative to | 2006 | The files and directories in the list must be expressed as relative to |
1895 | the /etc directory, and must not contain the / character | 2007 | the /etc directory (e.g., /etc/foo must be expressed as foo). |
1896 | (e.g., /etc/foo must be expressed as foo, but /etc/foo/bar -- | ||
1897 | expressed as foo/bar -- is disallowed). | ||
1898 | If no listed file is found, /etc directory will be empty. | 2008 | If no listed file is found, /etc directory will be empty. |
1899 | All modifications are discarded when the sandbox is closed. | 2009 | All modifications are discarded when the sandbox is closed. |
2010 | Multiple private-etc commands are allowed and they accumulate. | ||
1900 | .br | 2011 | .br |
1901 | 2012 | ||
1902 | .br | 2013 | .br |
@@ -1997,7 +2108,7 @@ Build a new /srv in a temporary | |||
1997 | filesystem, and copy the files and directories in the list. | 2108 | filesystem, and copy the files and directories in the list. |
1998 | The files and directories in the list must be expressed as relative to | 2109 | The files and directories in the list must be expressed as relative to |
1999 | the /srv directory, and must not contain the / character | 2110 | the /srv directory, and must not contain the / character |
2000 | (e.g., /opt/srv must be expressed as foo, but /srv/foo/bar -- | 2111 | (e.g., /srv/foo must be expressed as foo, but /srv/foo/bar -- |
2001 | expressed as srv/bar -- is disallowed). | 2112 | expressed as srv/bar -- is disallowed). |
2002 | If no listed file is found, /srv directory will be empty. | 2113 | If no listed file is found, /srv directory will be empty. |
2003 | All modifications are discarded when the sandbox is closed. | 2114 | All modifications are discarded when the sandbox is closed. |
@@ -2055,7 +2166,7 @@ $ firejail \-\-profile.print=browser | |||
2055 | .TP | 2166 | .TP |
2056 | \fB\-\-protocol=protocol,protocol,protocol | 2167 | \fB\-\-protocol=protocol,protocol,protocol |
2057 | Enable protocol filter. The filter is based on seccomp and checks the first argument to socket system call. | 2168 | Enable protocol filter. The filter is based on seccomp and checks the first argument to socket system call. |
2058 | Recognized values: unix, inet, inet6, netlink, packet and bluetooth. This option is not supported for i386 architecture. | 2169 | Recognized values: unix, inet, inet6, netlink, packet, and bluetooth. This option is not supported for i386 architecture. |
2059 | .br | 2170 | .br |
2060 | 2171 | ||
2061 | .br | 2172 | .br |
@@ -2127,11 +2238,12 @@ $ firejail --read-only=~/test --read-write=~/test/a | |||
2127 | .TP | 2238 | .TP |
2128 | \fB\-\-rlimit-as=number | 2239 | \fB\-\-rlimit-as=number |
2129 | Set the maximum size of the process's virtual memory (address space) in bytes. | 2240 | Set the maximum size of the process's virtual memory (address space) in bytes. |
2241 | Use k(ilobyte), m(egabyte) or g(igabyte) for size suffix (base 1024). | ||
2130 | 2242 | ||
2131 | .TP | 2243 | .TP |
2132 | \fB\-\-rlimit-cpu=number | 2244 | \fB\-\-rlimit-cpu=number |
2133 | Set the maximum limit, in seconds, for the amount of CPU time each | 2245 | Set the maximum limit, in seconds, for the amount of CPU time each |
2134 | sandboxed process can consume. When the limit is reached, the processes are killed. | 2246 | sandboxed process can consume. When the limit is reached, the processes are killed. |
2135 | 2247 | ||
2136 | The CPU limit is a limit on CPU seconds rather than elapsed time. CPU seconds is basically how many seconds | 2248 | The CPU limit is a limit on CPU seconds rather than elapsed time. CPU seconds is basically how many seconds |
2137 | the CPU has been in use and does not necessarily directly relate to the elapsed time. Linux kernel keeps | 2249 | the CPU has been in use and does not necessarily directly relate to the elapsed time. Linux kernel keeps |
@@ -2140,6 +2252,7 @@ track of CPU seconds for each process independently. | |||
2140 | .TP | 2252 | .TP |
2141 | \fB\-\-rlimit-fsize=number | 2253 | \fB\-\-rlimit-fsize=number |
2142 | Set the maximum file size that can be created by a process. | 2254 | Set the maximum file size that can be created by a process. |
2255 | Use k(ilobyte), m(egabyte) or g(igabyte) for size suffix (base 1024). | ||
2143 | .TP | 2256 | .TP |
2144 | \fB\-\-rlimit-nofile=number | 2257 | \fB\-\-rlimit-nofile=number |
2145 | Set the maximum number of files that can be opened by a process. | 2258 | Set the maximum number of files that can be opened by a process. |
@@ -2174,7 +2287,7 @@ $ firejail \-\-net=eth0 \-\-scan | |||
2174 | .TP | 2287 | .TP |
2175 | \fB\-\-seccomp | 2288 | \fB\-\-seccomp |
2176 | Enable seccomp filter and blacklist the syscalls in the default list, | 2289 | Enable seccomp filter and blacklist the syscalls in the default list, |
2177 | which is @default-nodebuggers unless allow-debuggers is specified, | 2290 | which is @default-nodebuggers unless \-\-allow-debuggers is specified, |
2178 | then it is @default. | 2291 | then it is @default. |
2179 | 2292 | ||
2180 | .br | 2293 | .br |
@@ -2185,18 +2298,18 @@ system call groups are defined: @aio, @basic-io, @chown, @clock, | |||
2185 | @network-io, @obsolete, @privileged, @process, @raw-io, @reboot, | 2298 | @network-io, @obsolete, @privileged, @process, @raw-io, @reboot, |
2186 | @resources, @setuid, @swap, @sync, @system-service and @timer. | 2299 | @resources, @setuid, @swap, @sync, @system-service and @timer. |
2187 | More information about groups can be found in /usr/share/doc/firejail/syscalls.txt | 2300 | More information about groups can be found in /usr/share/doc/firejail/syscalls.txt |
2301 | .br | ||
2188 | 2302 | ||
2189 | In addition, a system call can be specified by its number instead of | 2303 | .br |
2190 | name with prefix $, so for example $165 would be equal to mount on i386. | 2304 | The default list can be customized, see \-\-seccomp= for a description. |
2191 | Exceptions can be allowed with prefix !. | 2305 | It can be customized also globally in /etc/firejail/firejail.config file. |
2306 | .br | ||
2192 | 2307 | ||
2193 | .br | 2308 | .br |
2194 | System architecture is strictly imposed only if flag | 2309 | System architecture is strictly imposed only if flag |
2195 | \-\-seccomp.block-secondary is used. The filter is applied at run time | 2310 | \-\-seccomp.block-secondary is used. The filter is applied at run time |
2196 | only if the correct architecture was detected. For the case of I386 | 2311 | only if the correct architecture was detected. For the case of I386 |
2197 | and AMD64 both 32-bit and 64-bit filters are installed. On a 64 bit | 2312 | and AMD64 both 32-bit and 64-bit filters are installed. |
2198 | architecture, an additional filter for 32 bit system calls can be | ||
2199 | installed with \-\-seccomp.32. | ||
2200 | .br | 2313 | .br |
2201 | 2314 | ||
2202 | .br | 2315 | .br |
@@ -2207,11 +2320,14 @@ Firejail will print seccomp violations to the audit log if the kernel was compil | |||
2207 | Example: | 2320 | Example: |
2208 | .br | 2321 | .br |
2209 | $ firejail \-\-seccomp | 2322 | $ firejail \-\-seccomp |
2323 | |||
2324 | |||
2210 | .TP | 2325 | .TP |
2211 | \fB\-\-seccomp=syscall,@group,!syscall2 | 2326 | \fB\-\-seccomp=syscall,@group,!syscall2 |
2212 | Enable seccomp filter, whitelist "syscall2", but blacklist the default | 2327 | Enable seccomp filter, blacklist the default list and the syscalls or syscall groups |
2213 | list and the syscalls or syscall groups specified by the | 2328 | specified by the command, but don't blacklist "syscall2". On a 64 bit |
2214 | command. | 2329 | architecture, an additional filter for 32 bit system calls can be |
2330 | installed with \-\-seccomp.32. | ||
2215 | .br | 2331 | .br |
2216 | 2332 | ||
2217 | .br | 2333 | .br |
@@ -2221,6 +2337,13 @@ $ firejail \-\-seccomp=utime,utimensat,utimes firefox | |||
2221 | .br | 2337 | .br |
2222 | $ firejail \-\-seccomp=@clock,mkdir,unlinkat transmission-gtk | 2338 | $ firejail \-\-seccomp=@clock,mkdir,unlinkat transmission-gtk |
2223 | .br | 2339 | .br |
2340 | $ firejail '\-\-seccomp=@ipc,!pipe,!pipe2' audacious | ||
2341 | .br | ||
2342 | |||
2343 | .br | ||
2344 | Syscalls can be specified by their number if prefix $ is added, | ||
2345 | so for example $165 would be equal to mount on i386. | ||
2346 | .br | ||
2224 | 2347 | ||
2225 | .br | 2348 | .br |
2226 | Instead of dropping the syscall by returning EPERM, another error | 2349 | Instead of dropping the syscall by returning EPERM, another error |
@@ -2233,6 +2356,7 @@ by using \fBsyscall:kill\fR syntax, or the attempt may be logged with | |||
2233 | 2356 | ||
2234 | .br | 2357 | .br |
2235 | Example: | 2358 | Example: |
2359 | .br | ||
2236 | $ firejail \-\-seccomp=unlinkat:ENOENT,utimensat,utimes | 2360 | $ firejail \-\-seccomp=unlinkat:ENOENT,utimensat,utimes |
2237 | .br | 2361 | .br |
2238 | Parent pid 10662, child pid 10663 | 2362 | Parent pid 10662, child pid 10663 |
@@ -2241,9 +2365,13 @@ Child process initialized | |||
2241 | .br | 2365 | .br |
2242 | $ touch testfile | 2366 | $ touch testfile |
2243 | .br | 2367 | .br |
2368 | $ ls testfile | ||
2369 | .br | ||
2370 | testfile | ||
2371 | .br | ||
2244 | $ rm testfile | 2372 | $ rm testfile |
2245 | .br | 2373 | .br |
2246 | rm: cannot remove `testfile': Operation not permitted | 2374 | rm: cannot remove `testfile': No such file or directory |
2247 | .br | 2375 | .br |
2248 | 2376 | ||
2249 | .br | 2377 | .br |
@@ -2256,7 +2384,7 @@ filters. | |||
2256 | .br | 2384 | .br |
2257 | Example: | 2385 | Example: |
2258 | .br | 2386 | .br |
2259 | $ firejail \-\-noprofile \-\-shell=none \-\-seccomp=execve bash | 2387 | $ firejail \-\-noprofile \-\-shell=none \-\-seccomp=execve sh |
2260 | .br | 2388 | .br |
2261 | Parent pid 32751, child pid 32752 | 2389 | Parent pid 32751, child pid 32752 |
2262 | .br | 2390 | .br |
@@ -2268,8 +2396,7 @@ Child process initialized in 46.44 ms | |||
2268 | .br | 2396 | .br |
2269 | $ ls | 2397 | $ ls |
2270 | .br | 2398 | .br |
2271 | Bad system call | 2399 | Operation not permitted |
2272 | .br | ||
2273 | 2400 | ||
2274 | .TP | 2401 | .TP |
2275 | \fB\-\-seccomp.block-secondary | 2402 | \fB\-\-seccomp.block-secondary |
@@ -2313,15 +2440,15 @@ Child process initialized | |||
2313 | .br | 2440 | .br |
2314 | $ touch testfile | 2441 | $ touch testfile |
2315 | .br | 2442 | .br |
2443 | $ ls testfile | ||
2444 | .br | ||
2445 | testfile | ||
2446 | .br | ||
2316 | $ rm testfile | 2447 | $ rm testfile |
2317 | .br | 2448 | .br |
2318 | rm: cannot remove `testfile': Operation not permitted | 2449 | rm: cannot remove `testfile': No such file or directory |
2319 | .br | 2450 | .br |
2320 | 2451 | ||
2321 | |||
2322 | |||
2323 | |||
2324 | |||
2325 | .TP | 2452 | .TP |
2326 | \fB\-\-seccomp.keep=syscall,@group,!syscall2 | 2453 | \fB\-\-seccomp.keep=syscall,@group,!syscall2 |
2327 | Enable seccomp filter, blacklist all syscall not listed and "syscall2". | 2454 | Enable seccomp filter, blacklist all syscall not listed and "syscall2". |
@@ -2556,6 +2683,13 @@ $ firejail \-\-list | |||
2556 | .br | 2683 | .br |
2557 | $ firejail \-\-shutdown=3272 | 2684 | $ firejail \-\-shutdown=3272 |
2558 | .TP | 2685 | .TP |
2686 | \fB\-\-tab | ||
2687 | Enable shell tab completion in sandboxes using private or whitelisted home directories. | ||
2688 | .br | ||
2689 | |||
2690 | .br | ||
2691 | $ firejail \-\-private --tab | ||
2692 | .TP | ||
2559 | \fB\-\-timeout=hh:mm:ss | 2693 | \fB\-\-timeout=hh:mm:ss |
2560 | Kill the sandbox automatically after the time has elapsed. The time is specified in hours/minutes/seconds format. | 2694 | Kill the sandbox automatically after the time has elapsed. The time is specified in hours/minutes/seconds format. |
2561 | .br | 2695 | .br |
@@ -2564,14 +2698,13 @@ Kill the sandbox automatically after the time has elapsed. The time is specified | |||
2564 | $ firejail \-\-timeout=01:30:00 firefox | 2698 | $ firejail \-\-timeout=01:30:00 firefox |
2565 | .TP | 2699 | .TP |
2566 | \fB\-\-tmpfs=dirname | 2700 | \fB\-\-tmpfs=dirname |
2567 | Mount a writable tmpfs filesystem on directory dirname. This option is available only when running the sandbox as root. | 2701 | Mount a writable tmpfs filesystem on directory dirname. Directories outside user home or not owned by the user are not allowed. Sandboxes running as root are exempt from these restrictions. File globbing is supported, see \fBFILE GLOBBING\fR section for more details. |
2568 | File globbing is supported, see \fBFILE GLOBBING\fR section for more details. | ||
2569 | .br | 2702 | .br |
2570 | 2703 | ||
2571 | .br | 2704 | .br |
2572 | Example: | 2705 | Example: |
2573 | .br | 2706 | .br |
2574 | # firejail \-\-tmpfs=/var | 2707 | $ firejail \-\-tmpfs=~/.local/share |
2575 | .TP | 2708 | .TP |
2576 | \fB\-\-top | 2709 | \fB\-\-top |
2577 | Monitor the most CPU-intensive sandboxes, see \fBMONITORING\fR section for more details. | 2710 | Monitor the most CPU-intensive sandboxes, see \fBMONITORING\fR section for more details. |
@@ -2721,8 +2854,9 @@ $ firejail \-\-net=br0 --veth-name=if0 | |||
2721 | \fB\-\-whitelist=dirname_or_filename | 2854 | \fB\-\-whitelist=dirname_or_filename |
2722 | Whitelist directory or file. A temporary file system is mounted on the top directory, and the | 2855 | Whitelist directory or file. A temporary file system is mounted on the top directory, and the |
2723 | whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, | 2856 | whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, |
2724 | everything else is discarded when the sandbox is closed. The top directory could be | 2857 | everything else is discarded when the sandbox is closed. The top directory can be |
2725 | user home, /dev, /etc, /media, /mnt, /opt, /run/user/$UID, /srv, /sys/module, /tmp, /usr/share and /var. | 2858 | all directories in / (except /proc and /sys), /sys/module, /run/user/$UID, $HOME and |
2859 | all directories in /usr. | ||
2726 | .br | 2860 | .br |
2727 | 2861 | ||
2728 | .br | 2862 | .br |
@@ -2848,7 +2982,7 @@ and it is installed by default on most Linux distributions. It provides support | |||
2848 | connection model. Untrusted clients are restricted in certain ways to prevent them from reading window | 2982 | connection model. Untrusted clients are restricted in certain ways to prevent them from reading window |
2849 | contents of other clients, stealing input events, etc. | 2983 | contents of other clients, stealing input events, etc. |
2850 | 2984 | ||
2851 | The untrusted mode has several limitations. A lot of regular programs assume they are a trusted X11 clients | 2985 | The untrusted mode has several limitations. A lot of regular programs assume they are a trusted X11 clients |
2852 | and will crash or lock up when run in untrusted mode. Chromium browser and xterm are two examples. | 2986 | and will crash or lock up when run in untrusted mode. Chromium browser and xterm are two examples. |
2853 | Firefox and transmission-gtk seem to be working fine. | 2987 | Firefox and transmission-gtk seem to be working fine. |
2854 | A network namespace is not required for this option. | 2988 | A network namespace is not required for this option. |
@@ -3179,6 +3313,65 @@ $ firejail \-\-put=mybrowser xpra-clipboard.png ~/Downloads/xpra-clipboard.png | |||
3179 | $ firejail \-\-cat=mybrowser ~/.bashrc | 3313 | $ firejail \-\-cat=mybrowser ~/.bashrc |
3180 | .br | 3314 | .br |
3181 | #endif | 3315 | #endif |
3316 | |||
3317 | .SH INTRUSION DETECTION SYSTEM (IDS) | ||
3318 | The host-based intrusion detection system tracks down and audits user and system file modifications. | ||
3319 | The feature is configured using /etc/firejail/ids.config file, the checksums are stored in /var/lib/firejail/USERNAME.ids, | ||
3320 | where USERNAME is the name of the current user. We use BLAKE2 cryptographic function for hashing. | ||
3321 | |||
3322 | As a regular user, initialize the database: | ||
3323 | .br | ||
3324 | |||
3325 | .br | ||
3326 | $ firejail --ids-init | ||
3327 | .br | ||
3328 | Opening config file /etc/firejail/ids.config | ||
3329 | .br | ||
3330 | Loading config file /etc/firejail/ids.config | ||
3331 | .br | ||
3332 | Opening config file /etc/firejail/ids.config.local | ||
3333 | .br | ||
3334 | 500 1000 1500 2000 | ||
3335 | .br | ||
3336 | 2466 files scanned | ||
3337 | .br | ||
3338 | IDS database initialized | ||
3339 | .br | ||
3340 | |||
3341 | .br | ||
3342 | The default configuration targets several system executables in directories such as /bin, /sbin, /usr/bin, /usr/sbin, and several critical config files in user home directory | ||
3343 | such as ~/.bashrc, ~/.xinitrc, and ~/.config/autostart. Several system config files in /etc directory are also hashed. | ||
3344 | .br | ||
3345 | |||
3346 | .br | ||
3347 | Run --ids-check to audit the system: | ||
3348 | .br | ||
3349 | |||
3350 | .br | ||
3351 | $ firejail --ids-check | ||
3352 | .br | ||
3353 | Opening config file /etc/firejail/ids.config | ||
3354 | .br | ||
3355 | Loading config file /etc/firejail/ids.config | ||
3356 | .br | ||
3357 | Opening config file /etc/firejail/ids.config.local | ||
3358 | .br | ||
3359 | 500 1000 1500 | ||
3360 | .br | ||
3361 | Warning: modified /home/netblue/.bashrc | ||
3362 | .br | ||
3363 | 2000 | ||
3364 | .br | ||
3365 | 2466 files scanned: modified 1, permissions 0, new 0, removed 0 | ||
3366 | .br | ||
3367 | |||
3368 | .br | ||
3369 | The program will print the files that have been modified since the database was created, or the files with different access permissions. | ||
3370 | New files and deleted files are also flagged. | ||
3371 | |||
3372 | Currently while scanning the file system, symbolic links are not followed, and files the user doesn't have read access to are silently dropped. | ||
3373 | The program can also be run as root (sudo firejail --ids-init/--ids-check). | ||
3374 | |||
3182 | .SH MONITORING | 3375 | .SH MONITORING |
3183 | Option \-\-list prints a list of all sandboxes. The format | 3376 | Option \-\-list prints a list of all sandboxes. The format |
3184 | for each process entry is as follows: | 3377 | for each process entry is as follows: |
@@ -3239,7 +3432,7 @@ The owner of the sandbox. | |||
3239 | .SH RESTRICTED SHELL | 3432 | .SH RESTRICTED SHELL |
3240 | To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in | 3433 | To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in |
3241 | /etc/passwd file for each user that needs to be restricted. Alternatively, | 3434 | /etc/passwd file for each user that needs to be restricted. Alternatively, |
3242 | you can specify /usr/bin/firejail in adduser command: | 3435 | you can specify /usr/bin/firejail in adduser command: |
3243 | 3436 | ||
3244 | adduser \-\-shell /usr/bin/firejail username | 3437 | adduser \-\-shell /usr/bin/firejail username |
3245 | 3438 | ||
@@ -3249,7 +3442,7 @@ Additional arguments passed to firejail executable upon login are declared in /e | |||
3249 | Several command line options can be passed to the program using | 3442 | Several command line options can be passed to the program using |
3250 | profile files. Firejail chooses the profile file as follows: | 3443 | profile files. Firejail chooses the profile file as follows: |
3251 | 3444 | ||
3252 | 1. If a profile file is provided by the user with --profile=FILE option, the profile FILE is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. If there is a file with the same name as the given profile name, it will be used instead of doing the profile search. To force a profile search, prefix the profile name with a colon (:), eg. --profile=:PROFILE_NAME. | 3445 | 1. If a profile file is provided by the user with --profile=FILE option, the profile FILE is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. If there is a file with the same name as the given profile name, it will be used instead of doing the profile search. To force a profile search, prefix the profile name with a colon (:), eg. --profile=:PROFILE_NAME. |
3253 | Example: | 3446 | Example: |
3254 | .PP | 3447 | .PP |
3255 | .RS | 3448 | .RS |
@@ -3365,7 +3558,7 @@ Homepage: https://firejail.wordpress.com | |||
3365 | .BR firejail-profile (5), | 3558 | .BR firejail-profile (5), |
3366 | .BR firejail-login (5), | 3559 | .BR firejail-login (5), |
3367 | .BR firejail-users (5), | 3560 | .BR firejail-users (5), |
3368 | .BR jailtest (1) | 3561 | .BR jailcheck (1) |
3369 | 3562 | ||
3370 | .UR https://github.com/netblue30/firejail/wiki | 3563 | .UR https://github.com/netblue30/firejail/wiki |
3371 | .UE , | 3564 | .UE , |
diff --git a/src/man/firemon.txt b/src/man/firemon.txt index 64f15a1f0..c4e6e15b3 100644 --- a/src/man/firemon.txt +++ b/src/man/firemon.txt | |||
@@ -56,7 +56,7 @@ Print route table for each sandbox. | |||
56 | Print seccomp configuration for each sandbox. | 56 | Print seccomp configuration for each sandbox. |
57 | .TP | 57 | .TP |
58 | \fB\-\-top | 58 | \fB\-\-top |
59 | Monitor the most CPU-intensive sandboxes. This command is similar to | 59 | Monitor the most CPU-intensive sandboxes. This command is similar to |
60 | the regular UNIX top command, however it applies only to sandboxes. | 60 | the regular UNIX top command, however it applies only to sandboxes. |
61 | .TP | 61 | .TP |
62 | \fB\-\-tree | 62 | \fB\-\-tree |
@@ -120,4 +120,4 @@ Homepage: https://firejail.wordpress.com | |||
120 | .BR firejail-profile (5), | 120 | .BR firejail-profile (5), |
121 | .BR firejail-login (5), | 121 | .BR firejail-login (5), |
122 | .BR firejail-users (5), | 122 | .BR firejail-users (5), |
123 | .BR jailtest (1) | 123 | .BR jailcheck (1) |
diff --git a/src/man/jailtest.txt b/src/man/jailcheck.txt index b52fc5eed..483f47fb9 100644 --- a/src/man/jailtest.txt +++ b/src/man/jailcheck.txt | |||
@@ -1,29 +1,30 @@ | |||
1 | .TH JAILTEST 1 "MONTH YEAR" "VERSION" "JAILTEST man page" | 1 | .TH JAILCHECK 1 "MONTH YEAR" "VERSION" "JAILCHECK man page" |
2 | .SH NAME | 2 | .SH NAME |
3 | jailtest \- Simple utility program to test running sandboxes | 3 | jailcheck \- Simple utility program to test running sandboxes |
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | sudo jailtest [OPTIONS] [directory] | 5 | sudo jailcheck [OPTIONS] [directory] |
6 | .SH DESCRIPTION | 6 | .SH DESCRIPTION |
7 | WORK IN PROGRESS! | 7 | jailcheck attaches itself to all sandboxes started by the user and performs some basic tests |
8 | jailtest attaches itself to all sandboxes started by the user and performs some basic tests | ||
9 | on the sandbox filesystem: | 8 | on the sandbox filesystem: |
10 | .TP | 9 | .TP |
11 | \fB1. Virtual directories | 10 | \fB1. Virtual directories |
12 | jailtest extracts a list with the main virtual directories installed by the sandbox. | 11 | jailcheck extracts a list with the main virtual directories installed by the sandbox. |
13 | These directories are build by firejail at startup using --private* and --whitelist commands. | 12 | These directories are build by firejail at startup using --private* and --whitelist commands. |
14 | .TP | 13 | .TP |
15 | \fB2. Noexec test | 14 | \fB2. Noexec test |
16 | jailtest inserts executable programs in /home/username, /tmp, and /var/tmp directories | 15 | jailcheck inserts executable programs in /home/username, /tmp, and /var/tmp directories |
17 | and tries to run them from inside the sandbox, thus testing if the directory is executable or not. | 16 | and tries to run them from inside the sandbox, thus testing if the directory is executable or not. |
18 | .TP | 17 | .TP |
19 | \fB3. Read access test | 18 | \fB3. Read access test |
20 | jailtest creates test files in the directories specified by the user and tries to read | 19 | jailcheck creates test files in the directories specified by the user and tries to read |
21 | them from inside the sandbox. | 20 | them from inside the sandbox. |
22 | .TP | 21 | .TP |
23 | \fB4. AppArmor test | 22 | \fB4. AppArmor test |
24 | .TP | 23 | .TP |
25 | \fB5. Seccomp test | 24 | \fB5. Seccomp test |
26 | .TP | 25 | .TP |
26 | \fB6. Networking test | ||
27 | .TP | ||
27 | The program is started as root using sudo. | 28 | The program is started as root using sudo. |
28 | 29 | ||
29 | .SH OPTIONS | 30 | .SH OPTIONS |
@@ -49,7 +50,7 @@ It is followed by relevant sandbox information, such as the virtual directories | |||
49 | 50 | ||
50 | .SH EXAMPLE | 51 | .SH EXAMPLE |
51 | 52 | ||
52 | $ sudo jailtest | 53 | $ sudo jailcheck |
53 | .br | 54 | .br |
54 | 2014:netblue::firejail /usr/bin/gimp | 55 | 2014:netblue::firejail /usr/bin/gimp |
55 | .br | 56 | .br |
@@ -57,6 +58,8 @@ $ sudo jailtest | |||
57 | .br | 58 | .br |
58 | Warning: I can run programs in /home/netblue | 59 | Warning: I can run programs in /home/netblue |
59 | .br | 60 | .br |
61 | Networking: disabled | ||
62 | .br | ||
60 | 63 | ||
61 | .br | 64 | .br |
62 | 2055:netblue::firejail /usr/bin/ssh -X netblue@x.y.z.net | 65 | 2055:netblue::firejail /usr/bin/ssh -X netblue@x.y.z.net |
@@ -65,12 +68,16 @@ $ sudo jailtest | |||
65 | .br | 68 | .br |
66 | Warning: I can read ~/.ssh | 69 | Warning: I can read ~/.ssh |
67 | .br | 70 | .br |
71 | Networking: enabled | ||
72 | .br | ||
68 | 73 | ||
69 | .br | 74 | .br |
70 | 2186:netblue:libreoffice:firejail --appimage /opt/LibreOffice-fresh.appimage | 75 | 2186:netblue:libreoffice:firejail --appimage /opt/LibreOffice-fresh.appimage |
71 | .br | 76 | .br |
72 | Virtual dirs: /tmp, /var/tmp, /dev, | 77 | Virtual dirs: /tmp, /var/tmp, /dev, |
73 | .br | 78 | .br |
79 | Networking: enabled | ||
80 | .br | ||
74 | 81 | ||
75 | .br | 82 | .br |
76 | 26090:netblue::/usr/bin/firejail /opt/firefox/firefox | 83 | 26090:netblue::/usr/bin/firejail /opt/firefox/firefox |
@@ -79,6 +86,8 @@ $ sudo jailtest | |||
79 | .br | 86 | .br |
80 | /run/user/1000, | 87 | /run/user/1000, |
81 | .br | 88 | .br |
89 | Networking: enabled | ||
90 | .br | ||
82 | 91 | ||
83 | .br | 92 | .br |
84 | 26160:netblue:tor:firejail --private=~/tor-browser_en-US ./start-tor | 93 | 26160:netblue:tor:firejail --private=~/tor-browser_en-US ./start-tor |
@@ -91,6 +100,8 @@ $ sudo jailtest | |||
91 | .br | 100 | .br |
92 | Warning: I can run programs in /home/netblue | 101 | Warning: I can run programs in /home/netblue |
93 | .br | 102 | .br |
103 | Networking: enabled | ||
104 | .br | ||
94 | 105 | ||
95 | 106 | ||
96 | .SH LICENSE | 107 | .SH LICENSE |
diff --git a/src/man/preproc.awk b/src/man/preproc.awk index 1ce5c82de..d3a2b71c9 100755 --- a/src/man/preproc.awk +++ b/src/man/preproc.awk | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/usr/bin/gawk -E | 1 | #!/usr/bin/gawk -E |
2 | 2 | ||
3 | # Copyright (c) 2019-2021 rusty-snake | 3 | # Copyright (c) 2019-2022 rusty-snake |
4 | # | 4 | # |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy |
6 | # of this software and associated documentation files (the "Software"), to deal | 6 | # of this software and associated documentation files (the "Software"), to deal |
diff --git a/src/profstats/Makefile.in b/src/profstats/Makefile.in index e025f5939..fa1b4f200 100644 --- a/src/profstats/Makefile.in +++ b/src/profstats/Makefile.in | |||
@@ -3,7 +3,7 @@ all: profstats | |||
3 | 3 | ||
4 | include ../common.mk | 4 | include ../common.mk |
5 | 5 | ||
6 | %.o : %.c $(H_FILE_LIST) | 6 | %.o : %.c $(H_FILE_LIST) ../include/common.h |
7 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ | 7 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ |
8 | 8 | ||
9 | profstats: $(OBJS) | 9 | profstats: $(OBJS) |
diff --git a/src/profstats/main.c b/src/profstats/main.c index 5035280b1..595a94c11 100644 --- a/src/profstats/main.c +++ b/src/profstats/main.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
@@ -17,10 +17,8 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include <stdio.h> | 20 | |
21 | #include <stdlib.h> | 21 | #include "../include/common.h" |
22 | #include <string.h> | ||
23 | #include <assert.h> | ||
24 | 22 | ||
25 | #define MAXBUF 2048 | 23 | #define MAXBUF 2048 |
26 | // stats | 24 | // stats |
@@ -46,6 +44,7 @@ static int cnt_whitelistusrshare = 0; // include whitelist-usr-share-common.inc | |||
46 | static int cnt_ssh = 0; | 44 | static int cnt_ssh = 0; |
47 | static int cnt_mdwx = 0; | 45 | static int cnt_mdwx = 0; |
48 | static int cnt_whitelisthome = 0; | 46 | static int cnt_whitelisthome = 0; |
47 | static int cnt_noroot = 0; | ||
49 | 48 | ||
50 | static int level = 0; | 49 | static int level = 0; |
51 | static int arg_debug = 0; | 50 | static int arg_debug = 0; |
@@ -65,27 +64,31 @@ static int arg_mdwx = 0; | |||
65 | static int arg_dbus_system_none = 0; | 64 | static int arg_dbus_system_none = 0; |
66 | static int arg_dbus_user_none = 0; | 65 | static int arg_dbus_user_none = 0; |
67 | static int arg_whitelisthome = 0; | 66 | static int arg_whitelisthome = 0; |
68 | 67 | static int arg_noroot = 0; | |
68 | static int arg_print_blacklist = 0; | ||
69 | static int arg_print_whitelist = 0; | ||
69 | 70 | ||
70 | static char *profile = NULL; | 71 | static char *profile = NULL; |
71 | 72 | ||
72 | |||
73 | static void usage(void) { | 73 | static void usage(void) { |
74 | printf("proftool - print profile statistics\n"); | 74 | printf("profstats - print profile statistics\n"); |
75 | printf("Usage: proftool [options] file[s]\n"); | 75 | printf("Usage: profstats [options] file[s]\n"); |
76 | printf("Options:\n"); | 76 | printf("Options:\n"); |
77 | printf(" --apparmor - print profiles without apparmor\n"); | 77 | printf(" --apparmor - print profiles without apparmor\n"); |
78 | printf(" --caps - print profiles without caps\n"); | 78 | printf(" --caps - print profiles without caps\n"); |
79 | printf(" --dbus-system-none - profiles without \"dbus-system none\"\n"); | 79 | printf(" --dbus-system-none - print profiles without \"dbus-system none\"\n"); |
80 | printf(" --dbus-user-none - profiles without \"dbus-user none\"\n"); | 80 | printf(" --dbus-user-none - print profiles without \"dbus-user none\"\n"); |
81 | printf(" --ssh - print profiles without \"include disable-common.inc\"\n"); | 81 | printf(" --ssh - print profiles without \"include disable-common.inc\"\n"); |
82 | printf(" --noexec - print profiles without \"include disable-exec.inc\"\n"); | 82 | printf(" --noexec - print profiles without \"include disable-exec.inc\"\n"); |
83 | printf(" --noroot - print profiles without \"noroot\"\n"); | ||
83 | printf(" --private-bin - print profiles without private-bin\n"); | 84 | printf(" --private-bin - print profiles without private-bin\n"); |
84 | printf(" --private-dev - print profiles without private-dev\n"); | 85 | printf(" --private-dev - print profiles without private-dev\n"); |
85 | printf(" --private-etc - print profiles without private-etc\n"); | 86 | printf(" --private-etc - print profiles without private-etc\n"); |
86 | printf(" --private-tmp - print profiles without private-tmp\n"); | 87 | printf(" --private-tmp - print profiles without private-tmp\n"); |
88 | printf(" --print-blacklist - print all --blacklist for a profile\n"); | ||
89 | printf(" --print-whitelist - print all --private and --whitelist for a profile\n"); | ||
87 | printf(" --seccomp - print profiles without seccomp\n"); | 90 | printf(" --seccomp - print profiles without seccomp\n"); |
88 | printf(" --memory-deny-write-execute - profile without \"memory-deny-write-execute\"\n"); | 91 | printf(" --memory-deny-write-execute - print profiles without \"memory-deny-write-execute\"\n"); |
89 | printf(" --whitelist-home - print profiles whitelisting home directory\n"); | 92 | printf(" --whitelist-home - print profiles whitelisting home directory\n"); |
90 | printf(" --whitelist-var - print profiles without \"include whitelist-var-common.inc\"\n"); | 93 | printf(" --whitelist-var - print profiles without \"include whitelist-var-common.inc\"\n"); |
91 | printf(" --whitelist-runuser - print profiles without \"include whitelist-runuser-common.inc\" or \"blacklist ${RUNUSER}\"\n"); | 94 | printf(" --whitelist-runuser - print profiles without \"include whitelist-runuser-common.inc\" or \"blacklist ${RUNUSER}\"\n"); |
@@ -94,8 +97,9 @@ static void usage(void) { | |||
94 | printf("\n"); | 97 | printf("\n"); |
95 | } | 98 | } |
96 | 99 | ||
97 | void process_file(const char *fname) { | 100 | static void process_file(char *fname) { |
98 | assert(fname); | 101 | assert(fname); |
102 | char *tmpfname = NULL; | ||
99 | 103 | ||
100 | if (arg_debug) | 104 | if (arg_debug) |
101 | printf("processing #%s#\n", fname); | 105 | printf("processing #%s#\n", fname); |
@@ -104,9 +108,19 @@ void process_file(const char *fname) { | |||
104 | 108 | ||
105 | FILE *fp = fopen(fname, "r"); | 109 | FILE *fp = fopen(fname, "r"); |
106 | if (!fp) { | 110 | if (!fp) { |
107 | fprintf(stderr, "Warning: cannot open %s, while processing %s\n", fname, profile); | 111 | // the file was not found in the current directory |
108 | level--; | 112 | // look for it in /etc/firejail directory |
109 | return; | 113 | if (asprintf(&tmpfname, "%s/%s", SYSCONFDIR, fname) == -1) |
114 | errExit("asprintf"); | ||
115 | |||
116 | fp = fopen(tmpfname, "r"); | ||
117 | if (!fp) { | ||
118 | fprintf(stderr, "Warning: cannot open %s or %s, while processing %s\n", fname, tmpfname, profile); | ||
119 | free(tmpfname); | ||
120 | level--; | ||
121 | return; | ||
122 | } | ||
123 | fname = tmpfname; | ||
110 | } | 124 | } |
111 | 125 | ||
112 | int have_include_local = 0; | 126 | int have_include_local = 0; |
@@ -122,12 +136,26 @@ void process_file(const char *fname) { | |||
122 | if (*ptr == '\n' || *ptr == '#') | 136 | if (*ptr == '\n' || *ptr == '#') |
123 | continue; | 137 | continue; |
124 | 138 | ||
139 | if (arg_print_blacklist) { | ||
140 | if (strncmp(ptr, "blacklist", 9) == 0 || | ||
141 | strncmp(ptr, "noblacklist", 11) == 0) | ||
142 | printf("%s: %s\n", fname, ptr); | ||
143 | } | ||
144 | else if (arg_print_whitelist) { | ||
145 | if (strncmp(ptr, "whitelist", 9) == 0 || | ||
146 | strncmp(ptr, "nowhitelist", 11) == 0 || | ||
147 | strncmp(ptr, "private", 7) == 0) | ||
148 | printf("%s: %s\n", fname, ptr); | ||
149 | } | ||
150 | |||
125 | if (strncmp(ptr, "seccomp", 7) == 0) | 151 | if (strncmp(ptr, "seccomp", 7) == 0) |
126 | cnt_seccomp++; | 152 | cnt_seccomp++; |
127 | else if (strncmp(ptr, "caps", 4) == 0) | 153 | else if (strncmp(ptr, "caps", 4) == 0) |
128 | cnt_caps++; | 154 | cnt_caps++; |
129 | else if (strncmp(ptr, "include disable-exec.inc", 24) == 0) | 155 | else if (strncmp(ptr, "include disable-exec.inc", 24) == 0) |
130 | cnt_noexec++; | 156 | cnt_noexec++; |
157 | else if (strncmp(ptr, "noroot", 6) == 0) | ||
158 | cnt_noroot++; | ||
131 | else if (strncmp(ptr, "include whitelist-var-common.inc", 32) == 0) | 159 | else if (strncmp(ptr, "include whitelist-var-common.inc", 32) == 0) |
132 | cnt_whitelistvar++; | 160 | cnt_whitelistvar++; |
133 | else if (strncmp(ptr, "include whitelist-runuser-common.inc", 36) == 0 || | 161 | else if (strncmp(ptr, "include whitelist-runuser-common.inc", 36) == 0 || |
@@ -185,6 +213,8 @@ void process_file(const char *fname) { | |||
185 | if (!have_include_local) | 213 | if (!have_include_local) |
186 | printf("No include .local found in %s\n", fname); | 214 | printf("No include .local found in %s\n", fname); |
187 | level--; | 215 | level--; |
216 | if (tmpfname) | ||
217 | free(tmpfname); | ||
188 | } | 218 | } |
189 | 219 | ||
190 | int main(int argc, char **argv) { | 220 | int main(int argc, char **argv) { |
@@ -212,6 +242,8 @@ int main(int argc, char **argv) { | |||
212 | arg_mdwx = 1; | 242 | arg_mdwx = 1; |
213 | else if (strcmp(argv[i], "--noexec") == 0) | 243 | else if (strcmp(argv[i], "--noexec") == 0) |
214 | arg_noexec = 1; | 244 | arg_noexec = 1; |
245 | else if (strcmp(argv[i], "--noroot") == 0) | ||
246 | arg_noroot = 1; | ||
215 | else if (strcmp(argv[i], "--private-bin") == 0) | 247 | else if (strcmp(argv[i], "--private-bin") == 0) |
216 | arg_privatebin = 1; | 248 | arg_privatebin = 1; |
217 | else if (strcmp(argv[i], "--private-dev") == 0) | 249 | else if (strcmp(argv[i], "--private-dev") == 0) |
@@ -220,6 +252,10 @@ int main(int argc, char **argv) { | |||
220 | arg_privatetmp = 1; | 252 | arg_privatetmp = 1; |
221 | else if (strcmp(argv[i], "--private-etc") == 0) | 253 | else if (strcmp(argv[i], "--private-etc") == 0) |
222 | arg_privateetc = 1; | 254 | arg_privateetc = 1; |
255 | else if (strcmp(argv[i], "--print-blacklist") == 0) | ||
256 | arg_print_blacklist = 1; | ||
257 | else if (strcmp(argv[i], "--print-whitelist") == 0) | ||
258 | arg_print_whitelist = 1; | ||
223 | else if (strcmp(argv[i], "--whitelist-home") == 0) | 259 | else if (strcmp(argv[i], "--whitelist-home") == 0) |
224 | arg_whitelisthome = 1; | 260 | arg_whitelisthome = 1; |
225 | else if (strcmp(argv[i], "--whitelist-var") == 0) | 261 | else if (strcmp(argv[i], "--whitelist-var") == 0) |
@@ -256,6 +292,7 @@ int main(int argc, char **argv) { | |||
256 | int caps = cnt_caps; | 292 | int caps = cnt_caps; |
257 | int apparmor = cnt_apparmor; | 293 | int apparmor = cnt_apparmor; |
258 | int noexec = cnt_noexec; | 294 | int noexec = cnt_noexec; |
295 | int noroot = cnt_noroot; | ||
259 | int privatebin = cnt_privatebin; | 296 | int privatebin = cnt_privatebin; |
260 | int privatetmp = cnt_privatetmp; | 297 | int privatetmp = cnt_privatetmp; |
261 | int privatedev = cnt_privatedev; | 298 | int privatedev = cnt_privatedev; |
@@ -313,6 +350,8 @@ int main(int argc, char **argv) { | |||
313 | printf("No seccomp found in %s\n", argv[i]); | 350 | printf("No seccomp found in %s\n", argv[i]); |
314 | if (arg_noexec && noexec == cnt_noexec) | 351 | if (arg_noexec && noexec == cnt_noexec) |
315 | printf("No include disable-exec.inc found in %s\n", argv[i]); | 352 | printf("No include disable-exec.inc found in %s\n", argv[i]); |
353 | if (arg_noroot && noroot == cnt_noroot) | ||
354 | printf("No noroot found in %s\n", argv[i]); | ||
316 | if (arg_privatedev && privatedev == cnt_privatedev) | 355 | if (arg_privatedev && privatedev == cnt_privatedev) |
317 | printf("No private-dev found in %s\n", argv[i]); | 356 | printf("No private-dev found in %s\n", argv[i]); |
318 | if (arg_privatebin && privatebin == cnt_privatebin) | 357 | if (arg_privatebin && privatebin == cnt_privatebin) |
@@ -337,6 +376,9 @@ int main(int argc, char **argv) { | |||
337 | assert(level == 0); | 376 | assert(level == 0); |
338 | } | 377 | } |
339 | 378 | ||
379 | if (arg_print_blacklist || arg_print_whitelist) | ||
380 | return 0; | ||
381 | |||
340 | printf("\n"); | 382 | printf("\n"); |
341 | printf("Stats:\n"); | 383 | printf("Stats:\n"); |
342 | printf(" profiles\t\t\t%d\n", cnt_profiles); | 384 | printf(" profiles\t\t\t%d\n", cnt_profiles); |
@@ -346,6 +388,7 @@ int main(int argc, char **argv) { | |||
346 | printf(" seccomp\t\t\t%d\n", cnt_seccomp); | 388 | printf(" seccomp\t\t\t%d\n", cnt_seccomp); |
347 | printf(" capabilities\t\t%d\n", cnt_caps); | 389 | printf(" capabilities\t\t%d\n", cnt_caps); |
348 | printf(" noexec\t\t\t%d (include disable-exec.inc)\n", cnt_noexec); | 390 | printf(" noexec\t\t\t%d (include disable-exec.inc)\n", cnt_noexec); |
391 | printf(" noroot\t\t\t%d\n", cnt_noroot); | ||
349 | printf(" memory-deny-write-execute\t%d\n", cnt_mdwx); | 392 | printf(" memory-deny-write-execute\t%d\n", cnt_mdwx); |
350 | printf(" apparmor\t\t\t%d\n", cnt_apparmor); | 393 | printf(" apparmor\t\t\t%d\n", cnt_apparmor); |
351 | printf(" private-bin\t\t\t%d\n", cnt_privatebin); | 394 | printf(" private-bin\t\t\t%d\n", cnt_privatebin); |
diff --git a/src/tools/check-caps.sh b/src/tools/check-caps.sh index b7026b1cd..62c3b9066 100755 --- a/src/tools/check-caps.sh +++ b/src/tools/check-caps.sh | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # This file is part of Firejail project | 2 | # This file is part of Firejail project |
3 | # Copyright (C) 2014-2021 Firejail Authors | 3 | # Copyright (C) 2014-2022 Firejail Authors |
4 | # License GPL v2 | 4 | # License GPL v2 |
5 | 5 | ||
6 | if [ $# -eq 0 ] | 6 | if [ $# -eq 0 ] |
diff --git a/src/tools/extract_caps.c b/src/tools/extract_caps.c index 8da9c452b..5e5b3cdc6 100644 --- a/src/tools/extract_caps.c +++ b/src/tools/extract_caps.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/tools/extract_errnos.sh b/src/tools/extract_errnos.sh index 34c416b04..bb430b3e1 100644 --- a/src/tools/extract_errnos.sh +++ b/src/tools/extract_errnos.sh | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # This file is part of Firejail project | 2 | # This file is part of Firejail project |
3 | # Copyright (C) 2014-2021 Firejail Authors | 3 | # Copyright (C) 2014-2022 Firejail Authors |
4 | # License GPL v2 | 4 | # License GPL v2 |
5 | 5 | ||
6 | echo -e "#include <errno.h>\n#include <attr/xattr.h>" | \ | 6 | echo -e "#include <errno.h>\n#include <attr/xattr.h>" | \ |
diff --git a/src/tools/extract_seccomp.c b/src/tools/extract_seccomp.c index b5f92d2df..6b644796b 100644 --- a/src/tools/extract_seccomp.c +++ b/src/tools/extract_seccomp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/tools/extract_syscalls.c b/src/tools/extract_syscalls.c index 9159b6576..f77a84123 100644 --- a/src/tools/extract_syscalls.c +++ b/src/tools/extract_syscalls.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/tools/mkcoverit.sh b/src/tools/mkcoverit.sh index 86d798a11..c7a57cd21 100755 --- a/src/tools/mkcoverit.sh +++ b/src/tools/mkcoverit.sh | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # This file is part of Firejail project | 2 | # This file is part of Firejail project |
3 | # Copyright (C) 2014-2021 Firejail Authors | 3 | # Copyright (C) 2014-2022 Firejail Authors |
4 | # License GPL v2 | 4 | # License GPL v2 |
5 | 5 | ||
6 | # unpack firejail archive | 6 | # unpack firejail archive |
diff --git a/src/tools/testuid.c b/src/tools/testuid.c index a18d57d5e..1bc617522 100644 --- a/src/tools/testuid.c +++ b/src/tools/testuid.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/tools/ttytest.c b/src/tools/ttytest.c index 0f72753bc..9e40d289a 100644 --- a/src/tools/ttytest.c +++ b/src/tools/ttytest.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/tools/unixsocket.c b/src/tools/unixsocket.c index c4ecabca7..bd638269d 100644 --- a/src/tools/unixsocket.c +++ b/src/tools/unixsocket.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2014-2021 Firejail Authors | 2 | * Copyright (C) 2014-2022 Firejail Authors |
3 | * | 3 | * |
4 | * This file is part of firejail project | 4 | * This file is part of firejail project |
5 | * | 5 | * |
diff --git a/src/zsh_completion/_firejail.in b/src/zsh_completion/_firejail.in index fd27bb35f..f7cd3cdff 100644 --- a/src/zsh_completion/_firejail.in +++ b/src/zsh_completion/_firejail.in | |||
@@ -62,6 +62,9 @@ _firejail_args=( | |||
62 | '--tree[print a tree of all sandboxed processes]' | 62 | '--tree[print a tree of all sandboxed processes]' |
63 | '--version[print program version and exit]' | 63 | '--version[print program version and exit]' |
64 | 64 | ||
65 | '--ids-check[verify file system]' | ||
66 | '--ids-init[initialize IDS database]' | ||
67 | |||
65 | '--debug[print sandbox debug messages]' | 68 | '--debug[print sandbox debug messages]' |
66 | '--debug-blacklists[debug blacklisting]' | 69 | '--debug-blacklists[debug blacklisting]' |
67 | '--debug-caps[print all recognized capabilities]' | 70 | '--debug-caps[print all recognized capabilities]' |
@@ -91,6 +94,7 @@ _firejail_args=( | |||
91 | '--cgroup=-[place the sandbox in the specified control group]: :' | 94 | '--cgroup=-[place the sandbox in the specified control group]: :' |
92 | '--cpu=-[set cpu affinity]: :->cpus' | 95 | '--cpu=-[set cpu affinity]: :->cpus' |
93 | "--deterministic-exit-code[always exit with first child's status code]" | 96 | "--deterministic-exit-code[always exit with first child's status code]" |
97 | '--deterministic-shutdown[terminate orphan processes]' | ||
94 | '*--dns=-[set DNS server]: :' | 98 | '*--dns=-[set DNS server]: :' |
95 | '*--env=-[set environment variable]: :' | 99 | '*--env=-[set environment variable]: :' |
96 | '--hostname=-[set sandbox hostname]: :' | 100 | '--hostname=-[set sandbox hostname]: :' |
@@ -98,9 +102,11 @@ _firejail_args=( | |||
98 | '*--ignore=-[ignore command in profile files]: :' | 102 | '*--ignore=-[ignore command in profile files]: :' |
99 | '--ipc-namespace[enable a new IPC namespace]' | 103 | '--ipc-namespace[enable a new IPC namespace]' |
100 | '--join-or-start=-[join the sandbox or start a new one name|pid]: :_all_firejails' | 104 | '--join-or-start=-[join the sandbox or start a new one name|pid]: :_all_firejails' |
105 | '--keep-config-pulse[disable automatic ~/.config/pulse init]' | ||
101 | '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]' | 106 | '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]' |
107 | '--keep-fd[inherit open file descriptors to sandbox]' | ||
102 | '--keep-var-tmp[/var/tmp directory is untouched]' | 108 | '--keep-var-tmp[/var/tmp directory is untouched]' |
103 | '--machine-id[preserve /etc/machine-id]' | 109 | '--machine-id[spoof /etc/machine-id with a random id]' |
104 | '--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]' | 110 | '--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]' |
105 | '*--mkdir=-[create a directory]:' | 111 | '*--mkdir=-[create a directory]:' |
106 | '*--mkfile=-[create a file]:' | 112 | '*--mkfile=-[create a file]:' |
@@ -116,7 +122,9 @@ _firejail_args=( | |||
116 | '--nodvd[disable DVD and audio CD devices]' | 122 | '--nodvd[disable DVD and audio CD devices]' |
117 | '*--noexec=-[remount the file or directory noexec nosuid and nodev]: :_files' | 123 | '*--noexec=-[remount the file or directory noexec nosuid and nodev]: :_files' |
118 | '--nogroups[disable supplementary groups]' | 124 | '--nogroups[disable supplementary groups]' |
125 | '--noinput[disable input devices]' | ||
119 | '--nonewprivs[sets the NO_NEW_PRIVS prctl]' | 126 | '--nonewprivs[sets the NO_NEW_PRIVS prctl]' |
127 | '--noprinters[disable printers]' | ||
120 | '--nosound[disable sound system]' | 128 | '--nosound[disable sound system]' |
121 | '--nou2f[disable U2F devices]' | 129 | '--nou2f[disable U2F devices]' |
122 | '--novideo[disable video devices]' | 130 | '--novideo[disable video devices]' |
@@ -213,7 +221,7 @@ _firejail_args=( | |||
213 | '--netfilter.print=-[print the firewall name|pid]: :_all_firejails' | 221 | '--netfilter.print=-[print the firewall name|pid]: :_all_firejails' |
214 | '--netfilter6=-[enable IPv6 firewall]: :' | 222 | '--netfilter6=-[enable IPv6 firewall]: :' |
215 | '--netfilter6.print=-[print the IPv6 firewall name|pid]: :_all_firejails' | 223 | '--netfilter6.print=-[print the IPv6 firewall name|pid]: :_all_firejails' |
216 | '--netmask=-[define a network mask when dealing with unconfigured parrent interfaces]: :' | 224 | '--netmask=-[define a network mask when dealing with unconfigured parent interfaces]: :' |
217 | '--netns=-[Run the program in a named, persistent network namespace]: :' | 225 | '--netns=-[Run the program in a named, persistent network namespace]: :' |
218 | '--netstats[monitor network statistics]' | 226 | '--netstats[monitor network statistics]' |
219 | '--interface=-[move interface in sandbox]: :' | 227 | '--interface=-[move interface in sandbox]: :' |
@@ -249,10 +257,8 @@ _firejail_args=( | |||
249 | '*--tmpfs=-[mount a tmpfs filesystem on directory dirname]: :_files -/' | 257 | '*--tmpfs=-[mount a tmpfs filesystem on directory dirname]: :_files -/' |
250 | #endif | 258 | #endif |
251 | 259 | ||
252 | #ifdef HAVE_WHITELIST | ||
253 | '*--nowhitelist=-[disable whitelist for file or directory]: :_files' | 260 | '*--nowhitelist=-[disable whitelist for file or directory]: :_files' |
254 | '*--whitelist=-[whitelist directory or file]: :_files' | 261 | '*--whitelist=-[whitelist directory or file]: :_files' |
255 | #endif | ||
256 | 262 | ||
257 | #ifdef HAVE_X11 | 263 | #ifdef HAVE_X11 |
258 | '--x11[enable X11 sandboxing. The software checks first if Xpra is installed, then it checks if Xephyr is installed. If all fails, it will attempt to use X11 security extension]' | 264 | '--x11[enable X11 sandboxing. The software checks first if Xpra is installed, then it checks if Xephyr is installed. If all fails, it will attempt to use X11 security extension]' |