diff options
-rw-r--r-- | src/firejail/dbus.c | 93 | ||||
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/fs.c | 1 | ||||
-rw-r--r-- | src/firejail/main.c | 61 | ||||
-rw-r--r-- | src/firejail/profile.c | 68 |
5 files changed, 206 insertions, 19 deletions
diff --git a/src/firejail/dbus.c b/src/firejail/dbus.c index 5cdd4b372..bf1ae9a1e 100644 --- a/src/firejail/dbus.c +++ b/src/firejail/dbus.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <sys/wait.h> | 24 | #include <sys/wait.h> |
25 | #include <unistd.h> | 25 | #include <unistd.h> |
26 | #include <fcntl.h> | 26 | #include <fcntl.h> |
27 | #include <string.h> | ||
27 | 28 | ||
28 | #define DBUS_SOCKET_PATH_PREFIX "unix:path=" | 29 | #define DBUS_SOCKET_PATH_PREFIX "unix:path=" |
29 | #define DBUS_USER_SOCKET_FORMAT "/run/user/%d/bus" | 30 | #define DBUS_USER_SOCKET_FORMAT "/run/user/%d/bus" |
@@ -33,12 +34,82 @@ | |||
33 | #define DBUS_SESSION_BUS_ADDRESS_ENV "DBUS_SESSION_BUS_ADDRESS" | 34 | #define DBUS_SESSION_BUS_ADDRESS_ENV "DBUS_SESSION_BUS_ADDRESS" |
34 | #define DBUS_USER_PROXY_SOCKET_FORMAT RUN_FIREJAIL_DBUS_DIR "/%d-user" | 35 | #define DBUS_USER_PROXY_SOCKET_FORMAT RUN_FIREJAIL_DBUS_DIR "/%d-user" |
35 | #define DBUS_SYSTEM_PROXY_SOCKET_FORMAT RUN_FIREJAIL_DBUS_DIR "/%d-system" | 36 | #define DBUS_SYSTEM_PROXY_SOCKET_FORMAT RUN_FIREJAIL_DBUS_DIR "/%d-system" |
37 | #define DBUS_MAX_NAME_LENGTH 255 | ||
36 | 38 | ||
37 | static pid_t dbus_proxy_pid = 0; | 39 | static pid_t dbus_proxy_pid = 0; |
38 | static int dbus_proxy_status_fd = -1; | 40 | static int dbus_proxy_status_fd = -1; |
39 | static char *dbus_user_proxy_socket = NULL; | 41 | static char *dbus_user_proxy_socket = NULL; |
40 | static char *dbus_system_proxy_socket = NULL; | 42 | static char *dbus_system_proxy_socket = NULL; |
41 | 43 | ||
44 | int dbus_check_name(const char *name) { | ||
45 | unsigned long length = strlen(name); | ||
46 | if (length == 0 || length > DBUS_MAX_NAME_LENGTH) | ||
47 | return 0; | ||
48 | const char *p = name; | ||
49 | int segments = 1; | ||
50 | int in_segment = 0; | ||
51 | while (*p) { | ||
52 | int alpha = (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'); | ||
53 | int digit = *p >= '0' && *p <= '9'; | ||
54 | if (in_segment) { | ||
55 | if (*p == '.') { | ||
56 | ++segments; | ||
57 | in_segment = 0; | ||
58 | } else if (!alpha && !digit && *p != '_' && *p != '-') { | ||
59 | return 0; | ||
60 | } | ||
61 | } | ||
62 | else { | ||
63 | if (*p == '*') { | ||
64 | return *(p + 1) == '\0'; | ||
65 | } else if (!alpha && *p != '_' && *p != '-') { | ||
66 | return 0; | ||
67 | } | ||
68 | in_segment = 1; | ||
69 | } | ||
70 | ++p; | ||
71 | } | ||
72 | return in_segment && segments >= 2; | ||
73 | } | ||
74 | |||
75 | static void dbus_check_bus_profile(char const *prefix, DbusPolicy policy) { | ||
76 | size_t prefix_length = strlen(prefix); | ||
77 | ProfileEntry *it = cfg.profile; | ||
78 | while (it) { | ||
79 | char *data = it->data; | ||
80 | it = it->next; | ||
81 | if (strncmp(prefix, data, prefix_length) == 0) { | ||
82 | switch (policy) { | ||
83 | case DBUS_POLICY_ALLOW: | ||
84 | // We should never get here, because profile parsing will fail earlier. | ||
85 | fprintf(stderr, | ||
86 | "Error: %s filter rule configured, but the bus is not " | ||
87 | "set to filter.\n", | ||
88 | prefix); | ||
89 | exit(1); | ||
90 | break; | ||
91 | case DBUS_POLICY_FILTER: | ||
92 | // All good. | ||
93 | break; | ||
94 | case DBUS_POLICY_BLOCK: | ||
95 | fwarning("%s filter rule configured, but the bus is blocked.\n", prefix); | ||
96 | fwarning("Ignoring \"%s\" and any other %s filter rules.\n", data, prefix); | ||
97 | break; | ||
98 | default: | ||
99 | fprintf(stderr, "Error: Unknown %s policy.\n", prefix); | ||
100 | exit(1); | ||
101 | break; | ||
102 | } | ||
103 | break; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | void dbus_check_profile(void) { | ||
109 | dbus_check_bus_profile("dbus-user", arg_dbus_user); | ||
110 | dbus_check_bus_profile("dbus-system", arg_dbus_system); | ||
111 | } | ||
112 | |||
42 | static void write_arg(int fd, char const *format, ...) { | 113 | static void write_arg(int fd, char const *format, ...) { |
43 | va_list ap; | 114 | va_list ap; |
44 | va_start(ap, format); | 115 | va_start(ap, format); |
@@ -55,6 +126,24 @@ static void write_arg(int fd, char const *format, ...) { | |||
55 | free(arg); | 126 | free(arg); |
56 | } | 127 | } |
57 | 128 | ||
129 | static void write_profile(int fd, char const *prefix) { | ||
130 | size_t prefix_length = strlen(prefix); | ||
131 | ProfileEntry *it = cfg.profile; | ||
132 | while (it) { | ||
133 | char *data = it->data; | ||
134 | it = it->next; | ||
135 | if (strncmp(prefix, data, prefix_length) != 0) | ||
136 | continue; | ||
137 | data += prefix_length; | ||
138 | int arg_length = 0; | ||
139 | while (data[arg_length] != '\0' && data[arg_length] != ' ') | ||
140 | arg_length++; | ||
141 | if (data[arg_length] != ' ') | ||
142 | continue; | ||
143 | write_arg(fd, "--%.*s=%s", arg_length, data, &data[arg_length + 1]); | ||
144 | } | ||
145 | } | ||
146 | |||
58 | void dbus_proxy_start(void) { | 147 | void dbus_proxy_start(void) { |
59 | int status_pipe[2]; | 148 | int status_pipe[2]; |
60 | if (pipe(status_pipe) == -1) | 149 | if (pipe(status_pipe) == -1) |
@@ -96,7 +185,7 @@ void dbus_proxy_start(void) { | |||
96 | errExit("asprintf"); | 185 | errExit("asprintf"); |
97 | write_arg(args_pipe[1], dbus_user_proxy_socket); | 186 | write_arg(args_pipe[1], dbus_user_proxy_socket); |
98 | write_arg(args_pipe[1], "--filter"); | 187 | write_arg(args_pipe[1], "--filter"); |
99 | // TODO Write filter rules to pipe | 188 | write_profile(args_pipe[1], "dbus-user."); |
100 | } | 189 | } |
101 | 190 | ||
102 | if (arg_dbus_system == DBUS_POLICY_FILTER) { | 191 | if (arg_dbus_system == DBUS_POLICY_FILTER) { |
@@ -105,7 +194,7 @@ void dbus_proxy_start(void) { | |||
105 | errExit("asprintf"); | 194 | errExit("asprintf"); |
106 | write_arg(args_pipe[1], dbus_system_proxy_socket); | 195 | write_arg(args_pipe[1], dbus_system_proxy_socket); |
107 | write_arg(args_pipe[1], "--filter"); | 196 | write_arg(args_pipe[1], "--filter"); |
108 | // TODO Write filter rules to pipe | 197 | write_profile(args_pipe[1], "dbus-system."); |
109 | } | 198 | } |
110 | 199 | ||
111 | if (close(args_pipe[1]) == -1) | 200 | if (close(args_pipe[1]) == -1) |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 36ffd89b6..b811a6cd4 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -846,6 +846,8 @@ void set_x11_run_file(pid_t pid, int display); | |||
846 | void set_profile_run_file(pid_t pid, const char *fname); | 846 | void set_profile_run_file(pid_t pid, const char *fname); |
847 | 847 | ||
848 | // dbus.c | 848 | // dbus.c |
849 | int dbus_check_name(const char *name); | ||
850 | void dbus_check_profile(void); | ||
849 | void dbus_proxy_start(void); | 851 | void dbus_proxy_start(void); |
850 | void dbus_proxy_stop(void); | 852 | void dbus_proxy_stop(void); |
851 | void dbus_apply_policy(void); | 853 | void dbus_apply_policy(void); |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index b642329bf..b906f3047 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -256,6 +256,7 @@ void fs_blacklist(void) { | |||
256 | // whitelist commands handled by fs_whitelist() | 256 | // whitelist commands handled by fs_whitelist() |
257 | if (strncmp(entry->data, "whitelist ", 10) == 0 || | 257 | if (strncmp(entry->data, "whitelist ", 10) == 0 || |
258 | strncmp(entry->data, "nowhitelist ", 12) == 0 || | 258 | strncmp(entry->data, "nowhitelist ", 12) == 0 || |
259 | strncmp(entry->data, "dbus-", 5) == 0 || | ||
259 | *entry->data == '\0') { | 260 | *entry->data == '\0') { |
260 | entry = entry->next; | 261 | entry = entry->next; |
261 | continue; | 262 | continue; |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 9e82a00b5..f59fc26e4 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -2059,9 +2059,11 @@ int main(int argc, char **argv, char **envp) { | |||
2059 | arg_dbus_system = DBUS_POLICY_BLOCK; | 2059 | arg_dbus_system = DBUS_POLICY_BLOCK; |
2060 | } | 2060 | } |
2061 | else if (strncmp("--dbus-user=", argv[i], 12) == 0) { | 2061 | else if (strncmp("--dbus-user=", argv[i], 12) == 0) { |
2062 | if (strcmp("allow", argv[i] + 12) == 0) { | 2062 | if (strcmp("filter", argv[i] + 12) == 0) { |
2063 | arg_dbus_user = DBUS_POLICY_ALLOW; | 2063 | if (arg_dbus_user == DBUS_POLICY_BLOCK) { |
2064 | } else if (strcmp("filter", argv[i] + 12) == 0) { | 2064 | fprintf(stderr, "Error: Cannot relax --dbus-user policy, it is already set to block\n"); |
2065 | exit(1); | ||
2066 | } | ||
2065 | arg_dbus_user = DBUS_POLICY_FILTER; | 2067 | arg_dbus_user = DBUS_POLICY_FILTER; |
2066 | } else if (strcmp("none", argv[i] + 12) == 0) { | 2068 | } else if (strcmp("none", argv[i] + 12) == 0) { |
2067 | arg_dbus_user = DBUS_POLICY_BLOCK; | 2069 | arg_dbus_user = DBUS_POLICY_BLOCK; |
@@ -2070,10 +2072,28 @@ int main(int argc, char **argv, char **envp) { | |||
2070 | exit(1); | 2072 | exit(1); |
2071 | } | 2073 | } |
2072 | } | 2074 | } |
2075 | else if (strncmp(argv[i], "--dbus-user.talk=", 17) == 0) { | ||
2076 | char *line; | ||
2077 | if (asprintf(&line, "dbus-user.talk %s", argv[i] + 17) == -1) | ||
2078 | errExit("asprintf"); | ||
2079 | |||
2080 | profile_check_line(line, 0, NULL); // will exit if something wrong | ||
2081 | profile_add(line); | ||
2082 | } | ||
2083 | else if (strncmp(argv[i], "--dbus-user.own=", 16) == 0) { | ||
2084 | char *line; | ||
2085 | if (asprintf(&line, "dbus-user.own %s", argv[i] + 16) == -1) | ||
2086 | errExit("asprintf"); | ||
2087 | |||
2088 | profile_check_line(line, 0, NULL); // will exit if something wrong | ||
2089 | profile_add(line); | ||
2090 | } | ||
2073 | else if (strncmp("--dbus-system=", argv[i], 14) == 0) { | 2091 | else if (strncmp("--dbus-system=", argv[i], 14) == 0) { |
2074 | if (strcmp("allow", argv[i] + 14) == 0) { | 2092 | if (strcmp("filter", argv[i] + 14) == 0) { |
2075 | arg_dbus_system = DBUS_POLICY_ALLOW; | 2093 | if (arg_dbus_system == DBUS_POLICY_BLOCK) { |
2076 | } else if (strcmp("filter", argv[i] + 14) == 0) { | 2094 | fprintf(stderr, "Error: Cannot relax --dbus-system policy, it is already set to block\n"); |
2095 | exit(1); | ||
2096 | } | ||
2077 | arg_dbus_system = DBUS_POLICY_FILTER; | 2097 | arg_dbus_system = DBUS_POLICY_FILTER; |
2078 | } else if (strcmp("none", argv[i] + 14) == 0) { | 2098 | } else if (strcmp("none", argv[i] + 14) == 0) { |
2079 | arg_dbus_system = DBUS_POLICY_BLOCK; | 2099 | arg_dbus_system = DBUS_POLICY_BLOCK; |
@@ -2082,6 +2102,22 @@ int main(int argc, char **argv, char **envp) { | |||
2082 | exit(1); | 2102 | exit(1); |
2083 | } | 2103 | } |
2084 | } | 2104 | } |
2105 | else if (strncmp(argv[i], "--dbus-system.talk=", 19) == 0) { | ||
2106 | char *line; | ||
2107 | if (asprintf(&line, "dbus-system.talk %s", argv[i] + 19) == -1) | ||
2108 | errExit("asprintf"); | ||
2109 | |||
2110 | profile_check_line(line, 0, NULL); // will exit if something wrong | ||
2111 | profile_add(line); | ||
2112 | } | ||
2113 | else if (strncmp(argv[i], "--dbus-system.own=", 18) == 0) { | ||
2114 | char *line; | ||
2115 | if (asprintf(&line, "dbus-system.own %s", argv[i] + 18) == -1) | ||
2116 | errExit("asprintf"); | ||
2117 | |||
2118 | profile_check_line(line, 0, NULL); // will exit if something wrong | ||
2119 | profile_add(line); | ||
2120 | } | ||
2085 | 2121 | ||
2086 | //************************************* | 2122 | //************************************* |
2087 | // network | 2123 | // network |
@@ -2767,11 +2803,14 @@ int main(int argc, char **argv, char **envp) { | |||
2767 | } | 2803 | } |
2768 | EUID_USER(); | 2804 | EUID_USER(); |
2769 | 2805 | ||
2770 | if (checkcfg(CFG_DBUS) && | 2806 | if (checkcfg(CFG_DBUS)) { |
2771 | (arg_dbus_user == DBUS_POLICY_FILTER || arg_dbus_system == DBUS_POLICY_FILTER)) { | 2807 | dbus_check_profile(); |
2772 | EUID_ROOT(); | 2808 | if (arg_dbus_user == DBUS_POLICY_FILTER || |
2773 | dbus_proxy_start(); | 2809 | arg_dbus_system == DBUS_POLICY_FILTER) { |
2774 | EUID_USER(); | 2810 | EUID_ROOT(); |
2811 | dbus_proxy_start(); | ||
2812 | EUID_USER(); | ||
2813 | } | ||
2775 | } | 2814 | } |
2776 | 2815 | ||
2777 | // clone environment | 2816 | // clone environment |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 14533ce08..9bfd2ff1c 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -438,9 +438,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
438 | } | 438 | } |
439 | else if (strncmp("dbus-user ", ptr, 10) == 0) { | 439 | else if (strncmp("dbus-user ", ptr, 10) == 0) { |
440 | ptr += 10; | 440 | ptr += 10; |
441 | if (strcmp("allow", ptr) == 0) { | 441 | if (strcmp("filter", ptr) == 0) { |
442 | arg_dbus_user = DBUS_POLICY_ALLOW; | 442 | if (arg_dbus_user == DBUS_POLICY_BLOCK) { |
443 | } else if (strcmp("filter", ptr) == 0) { | 443 | fprintf(stderr, "Error: Cannot relax dbus-user policy, it is already set to block\n"); |
444 | exit(1); | ||
445 | } | ||
444 | arg_dbus_user = DBUS_POLICY_FILTER; | 446 | arg_dbus_user = DBUS_POLICY_FILTER; |
445 | } else if (strcmp("none", ptr) == 0) { | 447 | } else if (strcmp("none", ptr) == 0) { |
446 | arg_dbus_user = DBUS_POLICY_BLOCK; | 448 | arg_dbus_user = DBUS_POLICY_BLOCK; |
@@ -450,11 +452,39 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
450 | } | 452 | } |
451 | return 0; | 453 | return 0; |
452 | } | 454 | } |
455 | else if (strncmp(ptr, "dbus-user.talk ", 15) == 0) { | ||
456 | if (arg_dbus_user == DBUS_POLICY_ALLOW) { | ||
457 | fprintf(stderr, "Session DBus filtering (dbus-user filter) is " | ||
458 | "required for dbus-user.talk rules\n"); | ||
459 | exit(1); | ||
460 | } | ||
461 | |||
462 | if (!dbus_check_name(ptr + 15)) { | ||
463 | printf("Invalid dbus-user.talk name: %s\n", ptr + 15); | ||
464 | exit(1); | ||
465 | } | ||
466 | return 1; | ||
467 | } | ||
468 | else if (strncmp(ptr, "dbus-user.own ", 14) == 0) { | ||
469 | if (arg_dbus_user == DBUS_POLICY_ALLOW) { | ||
470 | fprintf(stderr, "Session DBus filtering (dbus-user filter) is " | ||
471 | "required for dbus-user.own rules\n"); | ||
472 | exit(1); | ||
473 | } | ||
474 | |||
475 | if (!dbus_check_name(ptr + 14)) { | ||
476 | fprintf(stderr, "Invalid dbus-user.own name: %s\n", ptr + 14); | ||
477 | exit(1); | ||
478 | } | ||
479 | return 1; | ||
480 | } | ||
453 | else if (strncmp("dbus-system ", ptr, 12) == 0) { | 481 | else if (strncmp("dbus-system ", ptr, 12) == 0) { |
454 | ptr += 12; | 482 | ptr += 12; |
455 | if (strcmp("allow", ptr) == 0) { | 483 | if (strcmp("filter", ptr) == 0) { |
456 | arg_dbus_system = DBUS_POLICY_ALLOW; | 484 | if (arg_dbus_system == DBUS_POLICY_BLOCK) { |
457 | } else if (strcmp("filter", ptr) == 0) { | 485 | fprintf(stderr, "Error: Cannot relax dbus-system policy, it is already set to block\n"); |
486 | exit(1); | ||
487 | } | ||
458 | arg_dbus_system = DBUS_POLICY_FILTER; | 488 | arg_dbus_system = DBUS_POLICY_FILTER; |
459 | } else if (strcmp("none", ptr) == 0) { | 489 | } else if (strcmp("none", ptr) == 0) { |
460 | arg_dbus_system = DBUS_POLICY_BLOCK; | 490 | arg_dbus_system = DBUS_POLICY_BLOCK; |
@@ -464,6 +494,32 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
464 | } | 494 | } |
465 | return 0; | 495 | return 0; |
466 | } | 496 | } |
497 | else if (strncmp(ptr, "dbus-system.talk ", 17) == 0) { | ||
498 | if (arg_dbus_system == DBUS_POLICY_ALLOW) { | ||
499 | fprintf(stderr, "System DBus filtering (dbus-system filter) is " | ||
500 | "required for dbus-system.talk rules\n"); | ||
501 | exit(1); | ||
502 | } | ||
503 | |||
504 | if (!dbus_check_name(ptr + 17)) { | ||
505 | fprintf(stderr, "Invalid dbus-system.talk name: %s\n", ptr + 17); | ||
506 | exit(1); | ||
507 | } | ||
508 | return 1; | ||
509 | } | ||
510 | else if (strncmp(ptr, "dbus-system.own ", 16) == 0) { | ||
511 | if (arg_dbus_system == DBUS_POLICY_ALLOW) { | ||
512 | fprintf(stderr, "System DBus filtering (dbus-system filter) is " | ||
513 | "required for dbus-system.own rules\n"); | ||
514 | exit(1); | ||
515 | } | ||
516 | |||
517 | if (!dbus_check_name(ptr + 16)) { | ||
518 | fprintf(stderr, "Invalid dbus-system.own name: %s\n", ptr + 16); | ||
519 | exit(1); | ||
520 | } | ||
521 | return 1; | ||
522 | } | ||
467 | else if (strcmp(ptr, "nou2f") == 0) { | 523 | else if (strcmp(ptr, "nou2f") == 0) { |
468 | arg_nou2f = 1; | 524 | arg_nou2f = 1; |
469 | return 0; | 525 | return 0; |