aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/firejail/dbus.c225
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/main.c10
-rw-r--r--src/firejail/preproc.c4
-rw-r--r--src/include/rundefs.h1
5 files changed, 214 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
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index d35e0d155..36ffd89b6 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
849void dbus_proxy_start(void);
850void dbus_proxy_stop(void);
849void dbus_apply_policy(void); 851void dbus_apply_policy(void);
850 852
851// dhcp.c 853// dhcp.c
diff --git a/src/firejail/main.c b/src/firejail/main.c
index fd2c6cb62..9e82a00b5 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -2767,6 +2767,13 @@ int main(int argc, char **argv, char **envp) {
2767 } 2767 }
2768 EUID_USER(); 2768 EUID_USER();
2769 2769
2770 if (checkcfg(CFG_DBUS) &&
2771 (arg_dbus_user == DBUS_POLICY_FILTER || arg_dbus_system == DBUS_POLICY_FILTER)) {
2772 EUID_ROOT();
2773 dbus_proxy_start();
2774 EUID_USER();
2775 }
2776
2770 // clone environment 2777 // clone environment
2771 int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD; 2778 int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD;
2772 2779
@@ -2977,6 +2984,9 @@ printf("**********************************\n");
2977 // end of signal-safe code 2984 // end of signal-safe code
2978 //***************************** 2985 //*****************************
2979 2986
2987 // stop dbus proxy (if any)
2988 dbus_proxy_stop();
2989
2980 // free globals 2990 // free globals
2981 if (cfg.profile) { 2991 if (cfg.profile) {
2982 ProfileEntry *prf = cfg.profile; 2992 ProfileEntry *prf = cfg.profile;
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c
index 7f23a9f6f..61573b220 100644
--- a/src/firejail/preproc.c
+++ b/src/firejail/preproc.c
@@ -58,6 +58,10 @@ void preproc_build_firejail_dir(void) {
58 create_empty_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755); 58 create_empty_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755);
59 } 59 }
60 60
61 if (stat(RUN_FIREJAIL_DBUS_DIR, &s)) {
62 create_empty_dir_as_root(RUN_FIREJAIL_DBUS_DIR, 01777);
63 }
64
61 if (stat(RUN_FIREJAIL_APPIMAGE_DIR, &s)) { 65 if (stat(RUN_FIREJAIL_APPIMAGE_DIR, &s)) {
62 create_empty_dir_as_root(RUN_FIREJAIL_APPIMAGE_DIR, 0755); 66 create_empty_dir_as_root(RUN_FIREJAIL_APPIMAGE_DIR, 0755);
63 } 67 }
diff --git a/src/include/rundefs.h b/src/include/rundefs.h
index 32f5ff12c..528d9e901 100644
--- a/src/include/rundefs.h
+++ b/src/include/rundefs.h
@@ -30,6 +30,7 @@
30#define RUN_FIREJAIL_NETWORK_DIR RUN_FIREJAIL_DIR "/network" 30#define RUN_FIREJAIL_NETWORK_DIR RUN_FIREJAIL_DIR "/network"
31#define RUN_FIREJAIL_BANDWIDTH_DIR RUN_FIREJAIL_DIR "/bandwidth" 31#define RUN_FIREJAIL_BANDWIDTH_DIR RUN_FIREJAIL_DIR "/bandwidth"
32#define RUN_FIREJAIL_PROFILE_DIR RUN_FIREJAIL_DIR "/profile" 32#define RUN_FIREJAIL_PROFILE_DIR RUN_FIREJAIL_DIR "/profile"
33#define RUN_FIREJAIL_DBUS_DIR RUN_FIREJAIL_DIR "/dbus"
33#define RUN_NETWORK_LOCK_FILE RUN_FIREJAIL_DIR "/firejail-network.lock" 34#define RUN_NETWORK_LOCK_FILE RUN_FIREJAIL_DIR "/firejail-network.lock"
34#define RUN_DIRECTORY_LOCK_FILE RUN_FIREJAIL_DIR "/firejail-run.lock" 35#define RUN_DIRECTORY_LOCK_FILE RUN_FIREJAIL_DIR "/firejail-run.lock"
35#define RUN_RO_DIR RUN_FIREJAIL_DIR "/firejail.ro.dir" 36#define RUN_RO_DIR RUN_FIREJAIL_DIR "/firejail.ro.dir"