aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kris7topher@gmail.com>2020-02-28 20:59:15 +0100
committerLibravatar Kristóf Marussy <kris7topher@gmail.com>2020-04-06 21:26:41 +0200
commit31df60f61d2c286674d7a062797fba494d1fd47c (patch)
tree2f85182069cff035bf73aeff0338e8fa6643897f /src
parentAdd xdg-dbus-proxy support (diff)
downloadfirejail-31df60f61d2c286674d7a062797fba494d1fd47c.tar.gz
firejail-31df60f61d2c286674d7a062797fba494d1fd47c.tar.zst
firejail-31df60f61d2c286674d7a062797fba494d1fd47c.zip
Add dbus filter options
The options --dbus-user.talk, --dbus-user.own, --dbus-system.talk, and --dbus-system.own control which names can be accessed and owned on the user and system buses.
Diffstat (limited to 'src')
-rw-r--r--src/firejail/dbus.c93
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/fs.c1
-rw-r--r--src/firejail/main.c61
-rw-r--r--src/firejail/profile.c68
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
37static pid_t dbus_proxy_pid = 0; 39static pid_t dbus_proxy_pid = 0;
38static int dbus_proxy_status_fd = -1; 40static int dbus_proxy_status_fd = -1;
39static char *dbus_user_proxy_socket = NULL; 41static char *dbus_user_proxy_socket = NULL;
40static char *dbus_system_proxy_socket = NULL; 42static char *dbus_system_proxy_socket = NULL;
41 43
44int 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
75static 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
108void 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
42static void write_arg(int fd, char const *format, ...) { 113static 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
129static 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
58void dbus_proxy_start(void) { 147void 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);
846void set_profile_run_file(pid_t pid, const char *fname); 846void set_profile_run_file(pid_t pid, const char *fname);
847 847
848// dbus.c 848// dbus.c
849int dbus_check_name(const char *name);
850void dbus_check_profile(void);
849void dbus_proxy_start(void); 851void dbus_proxy_start(void);
850void dbus_proxy_stop(void); 852void dbus_proxy_stop(void);
851void dbus_apply_policy(void); 853void 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;