diff options
author | smitsohu <smitsohu@gmail.com> | 2018-12-14 03:04:07 +0100 |
---|---|---|
committer | smitsohu <smitsohu@gmail.com> | 2018-12-14 03:04:07 +0100 |
commit | e56c09e19f34a0dd6d6d442cc0d2782409a0b53e (patch) | |
tree | 36d286616a0b9efe3beaec1d3ea3a10e70efa863 | |
parent | firecfg: improve error string (diff) | |
download | firejail-e56c09e19f34a0dd6d6d442cc0d2782409a0b53e.tar.gz firejail-e56c09e19f34a0dd6d6d442cc0d2782409a0b53e.tar.zst firejail-e56c09e19f34a0dd6d6d442cc0d2782409a0b53e.zip |
add explicit nonewprivs support to join option; accompanying small improvements
-rw-r--r-- | src/firejail/firejail.h | 1 | ||||
-rw-r--r-- | src/firejail/join.c | 49 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 32 |
3 files changed, 68 insertions, 14 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index bd392846a..245ea5bde 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -46,6 +46,7 @@ | |||
46 | #define RUN_CPU_CFG "/run/firejail/mnt/cpu" | 46 | #define RUN_CPU_CFG "/run/firejail/mnt/cpu" |
47 | #define RUN_GROUPS_CFG "/run/firejail/mnt/groups" | 47 | #define RUN_GROUPS_CFG "/run/firejail/mnt/groups" |
48 | #define RUN_PROTOCOL_CFG "/run/firejail/mnt/protocol" | 48 | #define RUN_PROTOCOL_CFG "/run/firejail/mnt/protocol" |
49 | #define RUN_NONEWPRIVS_CFG "/run/firejail/mnt/nonewprivs" | ||
49 | #define RUN_HOME_DIR "/run/firejail/mnt/home" | 50 | #define RUN_HOME_DIR "/run/firejail/mnt/home" |
50 | #define RUN_ETC_DIR "/run/firejail/mnt/etc" | 51 | #define RUN_ETC_DIR "/run/firejail/mnt/etc" |
51 | #define RUN_OPT_DIR "/run/firejail/mnt/opt" | 52 | #define RUN_OPT_DIR "/run/firejail/mnt/opt" |
diff --git a/src/firejail/join.c b/src/firejail/join.c index c849b200c..50ef58f4b 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -100,21 +100,40 @@ static void extract_nogroups(pid_t pid) { | |||
100 | errExit("asprintf"); | 100 | errExit("asprintf"); |
101 | 101 | ||
102 | struct stat s; | 102 | struct stat s; |
103 | if (stat(fname, &s) == -1) | 103 | if (stat(fname, &s) == -1) { |
104 | free(fname); | ||
104 | return; | 105 | return; |
106 | } | ||
105 | 107 | ||
106 | arg_nogroups = 1; | 108 | arg_nogroups = 1; |
107 | free(fname); | 109 | free(fname); |
108 | } | 110 | } |
109 | 111 | ||
112 | static void extract_nonewprivs(pid_t pid) { | ||
113 | char *fname; | ||
114 | if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_NONEWPRIVS_CFG) == -1) | ||
115 | errExit("asprintf"); | ||
116 | |||
117 | struct stat s; | ||
118 | if (stat(fname, &s) == -1) { | ||
119 | free(fname); | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | arg_nonewprivs = 1; | ||
124 | free(fname); | ||
125 | } | ||
126 | |||
110 | static void extract_cpu(pid_t pid) { | 127 | static void extract_cpu(pid_t pid) { |
111 | char *fname; | 128 | char *fname; |
112 | if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_CPU_CFG) == -1) | 129 | if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_CPU_CFG) == -1) |
113 | errExit("asprintf"); | 130 | errExit("asprintf"); |
114 | 131 | ||
115 | struct stat s; | 132 | struct stat s; |
116 | if (stat(fname, &s) == -1) | 133 | if (stat(fname, &s) == -1) { |
134 | free(fname); | ||
117 | return; | 135 | return; |
136 | } | ||
118 | 137 | ||
119 | // there is a CPU_CFG file, load it! | 138 | // there is a CPU_CFG file, load it! |
120 | load_cpu(fname); | 139 | load_cpu(fname); |
@@ -127,8 +146,10 @@ static void extract_cgroup(pid_t pid) { | |||
127 | errExit("asprintf"); | 146 | errExit("asprintf"); |
128 | 147 | ||
129 | struct stat s; | 148 | struct stat s; |
130 | if (stat(fname, &s) == -1) | 149 | if (stat(fname, &s) == -1) { |
150 | free(fname); | ||
131 | return; | 151 | return; |
152 | } | ||
132 | 153 | ||
133 | // there is a cgroup file CGROUP_CFG, load it! | 154 | // there is a cgroup file CGROUP_CFG, load it! |
134 | load_cgroup(fname); | 155 | load_cgroup(fname); |
@@ -154,7 +175,10 @@ static void extract_caps_seccomp(pid_t pid) { | |||
154 | if (strncmp(buf, "Seccomp:", 8) == 0) { | 175 | if (strncmp(buf, "Seccomp:", 8) == 0) { |
155 | char *ptr = buf + 8; | 176 | char *ptr = buf + 8; |
156 | int val; | 177 | int val; |
157 | sscanf(ptr, "%d", &val); | 178 | if (sscanf(ptr, "%d", &val) != 1) { |
179 | fprintf(stderr, "Error: cannot read stat file for process %u\n", pid); | ||
180 | exit(1); | ||
181 | } | ||
158 | if (val == 2) | 182 | if (val == 2) |
159 | apply_seccomp = 1; | 183 | apply_seccomp = 1; |
160 | break; | 184 | break; |
@@ -162,7 +186,10 @@ static void extract_caps_seccomp(pid_t pid) { | |||
162 | else if (strncmp(buf, "CapBnd:", 7) == 0) { | 186 | else if (strncmp(buf, "CapBnd:", 7) == 0) { |
163 | char *ptr = buf + 7; | 187 | char *ptr = buf + 7; |
164 | unsigned long long val; | 188 | unsigned long long val; |
165 | sscanf(ptr, "%llx", &val); | 189 | if (sscanf(ptr, "%llx", &val) != 1) { |
190 | fprintf(stderr, "Error: cannot read stat file for process %u\n", pid); | ||
191 | exit(1); | ||
192 | } | ||
166 | apply_caps = 1; | 193 | apply_caps = 1; |
167 | caps = val; | 194 | caps = val; |
168 | } | 195 | } |
@@ -229,7 +256,7 @@ pid_t switch_to_child(pid_t pid) { | |||
229 | char *comm = pid_proc_comm(pid); | 256 | char *comm = pid_proc_comm(pid); |
230 | if (!comm) { | 257 | if (!comm) { |
231 | if (errno == ENOENT) { | 258 | if (errno == ENOENT) { |
232 | fprintf(stderr, "Error: cannot find process with id %d\n", pid); | 259 | fprintf(stderr, "Error: cannot find process with pid %d\n", pid); |
233 | exit(1); | 260 | exit(1); |
234 | } | 261 | } |
235 | else { | 262 | else { |
@@ -285,6 +312,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
285 | EUID_ROOT(); | 312 | EUID_ROOT(); |
286 | // in user mode set caps seccomp, cpu, cgroup, etc | 313 | // in user mode set caps seccomp, cpu, cgroup, etc |
287 | if (getuid() != 0) { | 314 | if (getuid() != 0) { |
315 | extract_nonewprivs(pid); | ||
288 | extract_caps_seccomp(pid); | 316 | extract_caps_seccomp(pid); |
289 | extract_cpu(pid); | 317 | extract_cpu(pid); |
290 | extract_cgroup(pid); | 318 | extract_cgroup(pid); |
@@ -296,7 +324,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
296 | if (cfg.cgroup) // not available for uid 0 | 324 | if (cfg.cgroup) // not available for uid 0 |
297 | set_cgroup(cfg.cgroup); | 325 | set_cgroup(cfg.cgroup); |
298 | 326 | ||
299 | // get umask, it will be set by start_application() | 327 | // set umask, also uid 0 |
300 | extract_umask(pid); | 328 | extract_umask(pid); |
301 | 329 | ||
302 | // join namespaces | 330 | // join namespaces |
@@ -383,6 +411,13 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
383 | caps_set(caps); | 411 | caps_set(caps); |
384 | } | 412 | } |
385 | 413 | ||
414 | // set nonewprivs | ||
415 | if (arg_nonewprivs == 1) { // not available for uid 0 | ||
416 | prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
417 | if (arg_debug) | ||
418 | printf("NO_NEW_PRIVS set\n"); | ||
419 | } | ||
420 | |||
386 | EUID_USER(); | 421 | EUID_USER(); |
387 | // set nice | 422 | // set nice |
388 | if (arg_nice) { | 423 | if (arg_nice) { |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 95732b95e..2113ef70f 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -109,7 +109,7 @@ static void set_caps(void) { | |||
109 | caps_drop_dac_override(); | 109 | caps_drop_dac_override(); |
110 | } | 110 | } |
111 | 111 | ||
112 | void save_nogroups(void) { | 112 | static void save_nogroups(void) { |
113 | if (arg_nogroups == 0) | 113 | if (arg_nogroups == 0) |
114 | return; | 114 | return; |
115 | 115 | ||
@@ -126,7 +126,23 @@ void save_nogroups(void) { | |||
126 | 126 | ||
127 | } | 127 | } |
128 | 128 | ||
129 | void save_umask(void) { | 129 | static void save_nonewprivs(void) { |
130 | if (arg_nonewprivs == 0) | ||
131 | return; | ||
132 | |||
133 | FILE *fp = fopen(RUN_NONEWPRIVS_CFG, "wxe"); | ||
134 | if (fp) { | ||
135 | fprintf(fp, "\n"); | ||
136 | SET_PERMS_STREAM(fp, 0, 0, 0644); // assume mode 0644 | ||
137 | fclose(fp); | ||
138 | } | ||
139 | else { | ||
140 | fprintf(stderr, "Error: cannot save nonewprivs state\n"); | ||
141 | exit(1); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void save_umask(void) { | ||
130 | FILE *fp = fopen(RUN_UMASK_FILE, "wxe"); | 146 | FILE *fp = fopen(RUN_UMASK_FILE, "wxe"); |
131 | if (fp) { | 147 | if (fp) { |
132 | fprintf(fp, "%o\n", orig_umask); | 148 | fprintf(fp, "%o\n", orig_umask); |
@@ -597,11 +613,6 @@ int sandbox(void* sandbox_arg) { | |||
597 | fs_logger("install mount namespace"); | 613 | fs_logger("install mount namespace"); |
598 | 614 | ||
599 | //**************************** | 615 | //**************************** |
600 | // save the umask | ||
601 | //**************************** | ||
602 | save_umask(); | ||
603 | |||
604 | //**************************** | ||
605 | // netfilter | 616 | // netfilter |
606 | //**************************** | 617 | //**************************** |
607 | if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter | 618 | if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter |
@@ -750,10 +761,17 @@ int sandbox(void* sandbox_arg) { | |||
750 | need_preload = arg_trace || arg_tracelog; | 761 | need_preload = arg_trace || arg_tracelog; |
751 | arg_seccomp = 1; | 762 | arg_seccomp = 1; |
752 | } | 763 | } |
764 | |||
753 | // trace pre-install | 765 | // trace pre-install |
754 | if (need_preload) | 766 | if (need_preload) |
755 | fs_trace_preload(); | 767 | fs_trace_preload(); |
756 | 768 | ||
769 | // state of nonewprivs | ||
770 | save_nonewprivs(); | ||
771 | |||
772 | // save original umask | ||
773 | save_umask(); | ||
774 | |||
757 | // store hosts file | 775 | // store hosts file |
758 | if (cfg.hosts_file) | 776 | if (cfg.hosts_file) |
759 | fs_store_hosts_file(); | 777 | fs_store_hosts_file(); |