aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/dbus.c
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kris7topher@gmail.com>2020-02-27 19:55:52 +0100
committerLibravatar Kristóf Marussy <kris7topher@gmail.com>2020-04-06 21:26:41 +0200
commit0afb43a5607574fa946fdfd65f3a4cfa25cfa018 (patch)
treea09eb41b57cbecfccf6e284817d0043f0bbe0ab4 /src/firejail/dbus.c
parentAdd sbox_exec_v and SBOX_KEEP_FDS (diff)
downloadfirejail-0afb43a5607574fa946fdfd65f3a4cfa25cfa018.tar.gz
firejail-0afb43a5607574fa946fdfd65f3a4cfa25cfa018.tar.zst
firejail-0afb43a5607574fa946fdfd65f3a4cfa25cfa018.zip
Add xdg-dbus-proxy support
* The proxy is forked off outside the sandbox namespace to protect the fds of the original buses from the sandboxed process. * The /run/firejail/dbus directory (with the sticky bit set) holds the proxy sockets. The sockets are <parent pid>-user and <parent pid>-system for the user and system buses, respectively. Each socket is owned by the sandbox user. * The sockets are bind-mounted over their expected locations and the /run/firejail/dbus directory is subsequently hidden from the sandbox. * Upon sandbox exit, the xdg-dbus-proxy instance is terminated and the sockets are cleaned up. * Filter rules will be added in a future commit.
Diffstat (limited to 'src/firejail/dbus.c')
-rw-r--r--src/firejail/dbus.c225
1 files changed, 197 insertions, 28 deletions
diff --git a/src/firejail/dbus.c b/src/firejail/dbus.c
index 241b8fc44..5cdd4b372 100644
--- a/src/firejail/dbus.c
+++ b/src/firejail/dbus.c
@@ -18,52 +18,221 @@
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>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <unistd.h>
26#include <fcntl.h>
21 27
22static void dbus_block_user(void) { 28#define DBUS_SOCKET_PATH_PREFIX "unix:path="
23 char *path; 29#define DBUS_USER_SOCKET_FORMAT "/run/user/%d/bus"
24 if (asprintf(&path, "/run/user/%d/bus", getuid()) == -1) 30#define DBUS_USER_SOCKET_PATH_FORMAT DBUS_SOCKET_PATH_PREFIX DBUS_USER_SOCKET_FORMAT
25 errExit("asprintf"); 31#define DBUS_SYSTEM_SOCKET "/run/dbus/system_bus_socket"
26 char *env_var; 32#define DBUS_SYSTEM_SOCKET_PATH DBUS_SOCKET_PATH_PREFIX DBUS_SYSTEM_SOCKET
27 if (asprintf(&env_var, "unix:path=%s", path) == -1) 33#define DBUS_SESSION_BUS_ADDRESS_ENV "DBUS_SESSION_BUS_ADDRESS"
28 errExit("asprintf"); 34#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
37static pid_t dbus_proxy_pid = 0;
38static int dbus_proxy_status_fd = -1;
39static char *dbus_user_proxy_socket = NULL;
40static char *dbus_system_proxy_socket = NULL;
41
42static void write_arg(int fd, char const *format, ...) {
43 va_list ap;
44 va_start(ap, format);
45 char *arg;
46 int length = vasprintf(&arg, format, ap);
47 va_end(ap);
48 if (length == -1)
49 errExit("vasprintf");
50 length++;
51 if (arg_debug)
52 printf("xdg-dbus-proxy arg: %s\n", arg);
53 if (write(fd, arg, (size_t) length) != (ssize_t) length)
54 errExit("write");
55 free(arg);
56}
57
58void dbus_proxy_start(void) {
59 int status_pipe[2];
60 if (pipe(status_pipe) == -1)
61 errExit("pipe");
62 dbus_proxy_status_fd = status_pipe[0];
63
64 int args_pipe[2];
65 if (pipe(args_pipe) == -1)
66 errExit("pipe");
29 67
30 // set a new environment variable: DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/<UID>/bus 68 dbus_proxy_pid = fork();
31 if (setenv("DBUS_SESSION_BUS_ADDRESS", env_var, 1) == -1) { 69 if (dbus_proxy_pid == -1)
32 fprintf(stderr, "Error: cannot modify DBUS_SESSION_BUS_ADDRESS required by --nodbus\n"); 70 errExit("fork");
33 exit(1); 71 if (dbus_proxy_pid == 0) {
72 int i;
73 for (i = 3; i < FIREJAIL_MAX_FD; i++) {
74 if (i != status_pipe[1] && i != args_pipe[0])
75 close(i); // close open files
76 }
77 char *args[4] = {"/usr/bin/xdg-dbus-proxy", NULL, NULL, NULL};
78 if (asprintf(&args[1], "--fd=%d", status_pipe[1]) == -1
79 || asprintf(&args[2], "--args=%d", args_pipe[0]) == -1)
80 errExit("asprintf");
81 if (arg_debug)
82 printf("starting xdg-dbus-proxy\n");
83 sbox_exec_v(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE | SBOX_KEEP_FDS, args);
84 } else {
85 if (close(status_pipe[1]) == -1 || close(args_pipe[0]) == -1)
86 errExit("close");
87
88 if (arg_dbus_user == DBUS_POLICY_FILTER) {
89 char *dbus_user_path_env = getenv(DBUS_SESSION_BUS_ADDRESS_ENV);
90 if (dbus_user_path_env == NULL) {
91 write_arg(args_pipe[1], DBUS_USER_SOCKET_PATH_FORMAT, getuid());
92 } else {
93 write_arg(args_pipe[1], dbus_user_path_env);
94 }
95 if (asprintf(&dbus_user_proxy_socket, DBUS_USER_PROXY_SOCKET_FORMAT, (int) getpid()) == -1)
96 errExit("asprintf");
97 write_arg(args_pipe[1], dbus_user_proxy_socket);
98 write_arg(args_pipe[1], "--filter");
99 // TODO Write filter rules to pipe
100 }
101
102 if (arg_dbus_system == DBUS_POLICY_FILTER) {
103 write_arg(args_pipe[1], DBUS_SYSTEM_SOCKET_PATH);
104 if (asprintf(&dbus_system_proxy_socket, DBUS_SYSTEM_PROXY_SOCKET_FORMAT, (int) getpid()) == -1)
105 errExit("asprintf");
106 write_arg(args_pipe[1], dbus_system_proxy_socket);
107 write_arg(args_pipe[1], "--filter");
108 // TODO Write filter rules to pipe
109 }
110
111 if (close(args_pipe[1]) == -1)
112 errExit("close");
113 char buf[1];
114 ssize_t read_bytes = read(status_pipe[0], buf, 1);
115 switch (read_bytes) {
116 case -1:
117 errExit("read");
118 break;
119 case 0:
120 fprintf(stderr, "xdg-dbus-proxy closed pipe unexpectedly\n");
121 // Wait for the subordinate process to write any errors to stderr and exit.
122 waitpid(dbus_proxy_pid, NULL, 0);
123 exit(-1);
124 break;
125 case 1:
126 if (arg_debug)
127 printf("xdg-dbus-proxy initialized\n");
128 break;
129 default:
130 assert(0);
131 }
34 } 132 }
133}
35 134
36 // blacklist the path 135void dbus_proxy_stop(void) {
37 disable_file_or_dir(path); 136 if (dbus_proxy_pid == 0)
38 free(path); 137 return;
39 free(env_var); 138 assert(dbus_proxy_status_fd >= 0);
139 if (close(dbus_proxy_status_fd) == -1)
140 errExit("close");
141 int status;
142 if (waitpid(dbus_proxy_pid, &status, 0) == -1)
143 errExit("waitpid");
144 if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
145 fwarning("xdg-dbus-proxy returned %s\n", WEXITSTATUS(status));
146 dbus_proxy_pid = 0;
147 dbus_proxy_status_fd = -1;
148 if (dbus_user_proxy_socket != NULL) {
149 free(dbus_user_proxy_socket);
150 dbus_user_proxy_socket = NULL;
151 }
152 if (dbus_system_proxy_socket != NULL) {
153 free(dbus_system_proxy_socket);
154 dbus_system_proxy_socket = NULL;
155 }
156}
40 157
41 // blacklist the dbus-launch user directory 158static void socket_overlay(char *socket_path, char *proxy_path) {
42 if (asprintf(&path, "%s/.dbus", cfg.homedir) == -1) 159 if (mount(proxy_path, socket_path, NULL, MS_BIND, NULL) == -1)
43 errExit("asprintf"); 160 errExit("mount");
44 disable_file_or_dir(path);
45 free(path);
46} 161}
47 162
48static void dbus_block_system() { 163static void disable_socket_dir(void) {
49 // blacklist also system D-Bus socket 164 struct stat s;
50 disable_file_or_dir("/run/dbus/system_bus_socket"); 165 if (stat(RUN_FIREJAIL_DBUS_DIR, &s) == 0)
166 disable_file_or_dir(RUN_FIREJAIL_DBUS_DIR);
51} 167}
52 168
53void dbus_apply_policy(void) { 169void dbus_apply_policy(void) {
54 if (arg_dbus_user == DBUS_POLICY_ALLOW && arg_dbus_system == DBUS_POLICY_ALLOW) 170 EUID_ROOT();
171
172 if (arg_dbus_user == DBUS_POLICY_ALLOW && arg_dbus_system == DBUS_POLICY_ALLOW) {
173 disable_socket_dir();
55 return; 174 return;
175 }
56 176
57 if (!checkcfg(CFG_DBUS)) { 177 if (!checkcfg(CFG_DBUS)) {
178 disable_socket_dir();
58 fwarning("D-Bus handling is disabled in Firejail configuration file\n"); 179 fwarning("D-Bus handling is disabled in Firejail configuration file\n");
59 return; 180 return;
60 } 181 }
61 182
62 if (arg_dbus_user != DBUS_POLICY_ALLOW) 183 char *dbus_new_user_socket_path;
63 dbus_block_user(); 184 if (asprintf(&dbus_new_user_socket_path, DBUS_USER_SOCKET_PATH_FORMAT, getuid()) == -1)
185 errExit("asprintf");
186 char *dbus_new_user_socket = dbus_new_user_socket_path + strlen(DBUS_SOCKET_PATH_PREFIX);
187 char *dbus_user_path_env = getenv(DBUS_SESSION_BUS_ADDRESS_ENV);
188 char *dbus_orig_user_socket_path;
189 if (dbus_user_path_env != NULL
190 && strncmp(DBUS_SOCKET_PATH_PREFIX, dbus_user_path_env, strlen(DBUS_SOCKET_PATH_PREFIX)) == 0) {
191 dbus_orig_user_socket_path = dbus_user_path_env;
192 } else {
193 dbus_orig_user_socket_path = dbus_new_user_socket_path;
194 }
195 char *dbus_orig_user_socket = dbus_user_path_env + strlen(DBUS_SOCKET_PATH_PREFIX);
196
197 if (arg_dbus_user != DBUS_POLICY_ALLOW) {
198 if (arg_dbus_user == DBUS_POLICY_FILTER) {
199 assert(dbus_user_proxy_socket != NULL);
200 socket_overlay(dbus_new_user_socket, dbus_user_proxy_socket);
201 free(dbus_user_proxy_socket);
202 } else { // arg_dbus_user == DBUS_POLICY_BLOCK
203 disable_file_or_dir(dbus_new_user_socket);
204 }
205
206 if (strcmp(dbus_orig_user_socket, dbus_new_user_socket) != 0)
207 disable_file_or_dir(dbus_orig_user_socket);
208
209 // set a new environment variable:
210 // DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/<UID>/bus
211 if (setenv(DBUS_SESSION_BUS_ADDRESS_ENV, dbus_new_user_socket_path, 1) == -1) {
212 fprintf(stderr, "Error: cannot modify " DBUS_SESSION_BUS_ADDRESS_ENV " required by --dbus-user\n");
213 exit(1);
214 }
215
216 // blacklist the dbus-launch user directory
217 char *path;
218 if (asprintf(&path, "%s/.dbus", cfg.homedir) == -1)
219 errExit("asprintf");
220 disable_file_or_dir(path);
221 free(path);
222 }
223
224 free(dbus_new_user_socket_path);
225
226 if (arg_dbus_system == DBUS_POLICY_FILTER) {
227 assert(dbus_system_proxy_socket != NULL);
228 socket_overlay(DBUS_SYSTEM_SOCKET, dbus_system_proxy_socket);
229 free(dbus_system_proxy_socket);
230 } else if (arg_dbus_system == DBUS_POLICY_BLOCK) {
231 disable_file_or_dir(DBUS_SYSTEM_SOCKET);
232 }
64 233
65 if (arg_dbus_system != DBUS_POLICY_ALLOW) 234 // Only disable access to /run/firejail/dbus here, when the sockets have been bind-mounted.
66 dbus_block_system(); 235 disable_socket_dir();
67 236
68 // look for a possible abstract unix socket 237 // look for a possible abstract unix socket
69 238