Merge pull request #3265 from kris7t/dbus-proxy

Fine-grained DBus sandboxing
This commit is contained in:
Kristóf Marussy 2020-04-07 13:13:56 +02:00 committed by GitHub
commit 07fac581f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 982 additions and 249 deletions

View file

@ -18,41 +18,436 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "firejail.h"
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#ifndef O_PATH
#define O_PATH 010000000
#endif
#define DBUS_SOCKET_PATH_PREFIX "unix:path="
#define DBUS_USER_SOCKET_FORMAT "/run/user/%d/bus"
#define DBUS_USER_SOCKET_FORMAT2 "/run/user/%d/dbus/user_bus_socket"
#define DBUS_SYSTEM_SOCKET "/run/dbus/system_bus_socket"
#define DBUS_SESSION_BUS_ADDRESS_ENV "DBUS_SESSION_BUS_ADDRESS"
#define DBUS_SYSTEM_BUS_ADDRESS_ENV "DBUS_SYSTEM_BUS_ADDRESS"
#define DBUS_USER_DIR_FORMAT RUN_FIREJAIL_DBUS_DIR "/%d"
#define DBUS_USER_PROXY_SOCKET_FORMAT DBUS_USER_DIR_FORMAT "/%d-user"
#define DBUS_SYSTEM_PROXY_SOCKET_FORMAT DBUS_USER_DIR_FORMAT "/%d-system"
#define DBUS_MAX_NAME_LENGTH 255
#define XDG_DBUS_PROXY_PATH "/usr/bin/xdg-dbus-proxy"
static pid_t dbus_proxy_pid = 0;
static int dbus_proxy_status_fd = -1;
static char *dbus_user_proxy_socket = NULL;
static char *dbus_system_proxy_socket = NULL;
int dbus_check_name(const char *name) {
unsigned long length = strlen(name);
if (length == 0 || length > DBUS_MAX_NAME_LENGTH)
return 0;
const char *p = name;
int segments = 1;
int in_segment = 0;
while (*p) {
int alpha = (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z');
int digit = *p >= '0' && *p <= '9';
if (in_segment) {
if (*p == '.') {
++segments;
in_segment = 0;
} else if (!alpha && !digit && *p != '_' && *p != '-') {
return 0;
}
}
else {
if (*p == '*') {
return *(p + 1) == '\0';
} else if (!alpha && *p != '_' && *p != '-') {
return 0;
}
in_segment = 1;
}
++p;
}
return in_segment && segments >= 2;
}
static void dbus_check_bus_profile(char const *prefix, DbusPolicy *policy) {
if (*policy == DBUS_POLICY_FILTER) {
struct stat s;
if (stat(XDG_DBUS_PROXY_PATH, &s) == -1) {
if (errno == ENOENT) {
fprintf(stderr,
"Warning: " XDG_DBUS_PROXY_PATH
" was not found, downgrading %s policy to allow.\n"
"To enable DBus filtering, install the xdg-dbus-proxy "
"program.\n", prefix);
*policy = DBUS_POLICY_ALLOW;
} else {
errExit("stat");
}
} else {
// No need to warn on profile entries.
return;
}
}
size_t prefix_length = strlen(prefix);
ProfileEntry *it = cfg.profile;
int num_matches = 0;
const char *first_match = NULL;
while (it) {
char *data = it->data;
it = it->next;
if (strncmp(prefix, data, prefix_length) == 0) {
++num_matches;
if (first_match == NULL)
first_match = data;
}
}
if (num_matches > 0) {
assert(first_match != NULL);
if (num_matches == 1) {
fprintf(stderr, "Ignoring \"%s\".\n", first_match);
} else if (num_matches == 2) {
fprintf(stderr, "Ignoring \"%s\" and 1 other %s filter rule.\n",
first_match, prefix);
} else {
fprintf(stderr, "Ignoring \"%s\" and %d other %s filter rules.\n",
first_match, num_matches - 1, prefix);
}
}
}
void dbus_check_profile(void) {
dbus_check_bus_profile("dbus-user", &arg_dbus_user);
dbus_check_bus_profile("dbus-system", &arg_dbus_system);
}
static void write_arg(int fd, char const *format, ...) {
va_list ap;
va_start(ap, format);
char *arg;
int length = vasprintf(&arg, format, ap);
va_end(ap);
if (length == -1)
errExit("vasprintf");
length++;
if (arg_debug)
printf("xdg-dbus-proxy arg: %s\n", arg);
if (write(fd, arg, (size_t) length) != (ssize_t) length)
errExit("write");
free(arg);
}
static void write_profile(int fd, char const *prefix) {
size_t prefix_length = strlen(prefix);
ProfileEntry *it = cfg.profile;
while (it) {
char *data = it->data;
it = it->next;
if (strncmp(prefix, data, prefix_length) != 0)
continue;
data += prefix_length;
int arg_length = 0;
while (data[arg_length] != '\0' && data[arg_length] != ' ')
arg_length++;
if (data[arg_length] != ' ')
continue;
write_arg(fd, "--%.*s=%s", arg_length, data, &data[arg_length + 1]);
}
}
static void dbus_create_user_dir(void) {
char *path;
if (asprintf(&path, DBUS_USER_DIR_FORMAT, (int) getuid()) == -1)
errExit("asprintf");
struct stat s;
mode_t mode = 0700;
uid_t uid = getuid();
gid_t gid = getgid();
if (stat(path, &s)) {
if (arg_debug)
printf("Creating %s directory for DBus proxy sockets\n", path);
if (mkdir(path, mode) == -1 && errno != EEXIST)
errExit("mkdir");
if (set_perms(path, uid, gid, mode))
errExit("set_perms");
ASSERT_PERMS(path, uid, gid, mode);
}
free(path);
}
static char *find_user_socket_by_format(char *format) {
char *dbus_user_socket;
if (asprintf(&dbus_user_socket, format, (int) getuid()) == -1)
errExit("asprintf");
struct stat s;
if (stat(dbus_user_socket, &s) == -1) {
if (errno == ENOENT)
goto fail;
return NULL;
errExit("stat");
}
if (!S_ISSOCK(s.st_mode))
goto fail;
return dbus_user_socket;
fail:
free(dbus_user_socket);
return NULL;
}
static char *find_user_socket(void) {
char *socket1 = find_user_socket_by_format(DBUS_USER_SOCKET_FORMAT);
if (socket1 != NULL)
return socket1;
char *socket2 = find_user_socket_by_format(DBUS_USER_SOCKET_FORMAT2);
if (socket2 != NULL)
return socket2;
fprintf(stderr, "DBus user socket was not found.\n");
exit(1);
}
void dbus_proxy_start(void) {
dbus_create_user_dir();
int status_pipe[2];
if (pipe(status_pipe) == -1)
errExit("pipe");
dbus_proxy_status_fd = status_pipe[0];
int args_pipe[2];
if (pipe(args_pipe) == -1)
errExit("pipe");
dbus_proxy_pid = fork();
if (dbus_proxy_pid == -1)
errExit("fork");
if (dbus_proxy_pid == 0) {
int i;
for (i = 3; i < FIREJAIL_MAX_FD; i++) {
if (i != status_pipe[1] && i != args_pipe[0])
close(i); // close open files
}
char *args[4] = {XDG_DBUS_PROXY_PATH, NULL, NULL, NULL};
if (asprintf(&args[1], "--fd=%d", status_pipe[1]) == -1
|| asprintf(&args[2], "--args=%d", args_pipe[0]) == -1)
errExit("asprintf");
if (arg_debug)
printf("starting xdg-dbus-proxy\n");
sbox_exec_v(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE | SBOX_KEEP_FDS, args);
} else {
if (close(status_pipe[1]) == -1 || close(args_pipe[0]) == -1)
errExit("close");
if (arg_dbus_user == DBUS_POLICY_FILTER) {
char *user_env = getenv(DBUS_SESSION_BUS_ADDRESS_ENV);
if (user_env == NULL) {
char *dbus_user_socket = find_user_socket();
write_arg(args_pipe[1], DBUS_SOCKET_PATH_PREFIX "%s",
dbus_user_socket);
free(dbus_user_socket);
} else {
write_arg(args_pipe[1], "%s", user_env);
}
if (asprintf(&dbus_user_proxy_socket, DBUS_USER_PROXY_SOCKET_FORMAT,
(int) getuid(), (int) getpid()) == -1)
errExit("asprintf");
write_arg(args_pipe[1], "%s", dbus_user_proxy_socket);
write_arg(args_pipe[1], "--filter");
write_profile(args_pipe[1], "dbus-user.");
}
if (arg_dbus_system == DBUS_POLICY_FILTER) {
char *system_env = getenv(DBUS_SYSTEM_BUS_ADDRESS_ENV);
if (system_env == NULL) {
write_arg(args_pipe[1],
DBUS_SOCKET_PATH_PREFIX DBUS_SYSTEM_SOCKET);
} else {
write_arg(args_pipe[1], "%s", system_env);
}
if (asprintf(&dbus_system_proxy_socket, DBUS_SYSTEM_PROXY_SOCKET_FORMAT,
(int) getuid(), (int) getpid()) == -1)
errExit("asprintf");
write_arg(args_pipe[1], "%s", dbus_system_proxy_socket);
write_arg(args_pipe[1], "--filter");
write_profile(args_pipe[1], "dbus-system.");
}
if (close(args_pipe[1]) == -1)
errExit("close");
char buf[1];
ssize_t read_bytes = read(status_pipe[0], buf, 1);
switch (read_bytes) {
case -1:
errExit("read");
break;
case 0:
fprintf(stderr, "xdg-dbus-proxy closed pipe unexpectedly\n");
// Wait for the subordinate process to write any errors to stderr and exit.
waitpid(dbus_proxy_pid, NULL, 0);
exit(-1);
break;
case 1:
if (arg_debug)
printf("xdg-dbus-proxy initialized\n");
break;
default:
assert(0);
}
}
}
void dbus_proxy_stop(void) {
if (dbus_proxy_pid == 0)
return;
assert(dbus_proxy_status_fd >= 0);
if (close(dbus_proxy_status_fd) == -1)
errExit("close");
int status;
if (waitpid(dbus_proxy_pid, &status, 0) == -1)
errExit("waitpid");
if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
fwarning("xdg-dbus-proxy returned %s\n", WEXITSTATUS(status));
dbus_proxy_pid = 0;
dbus_proxy_status_fd = -1;
if (dbus_user_proxy_socket != NULL) {
free(dbus_user_proxy_socket);
dbus_user_proxy_socket = NULL;
}
if (dbus_system_proxy_socket != NULL) {
free(dbus_system_proxy_socket);
dbus_system_proxy_socket = NULL;
}
}
static void socket_overlay(char *socket_path, char *proxy_path) {
int fd = safe_fd(proxy_path, O_PATH | O_NOFOLLOW | O_CLOEXEC);
if (fd == -1)
errExit("opening DBus proxy socket");
struct stat s;
if (fstat(fd, &s) == -1)
errExit("fstat");
if (!S_ISSOCK(s.st_mode)) {
errno = ENOTSOCK;
errExit("mounting DBus proxy socket");
}
char *proxy_fd_path;
if (asprintf(&proxy_fd_path, "/proc/self/fd/%d", fd) == -1)
errExit("asprintf");
if (mount(proxy_path, socket_path, NULL, MS_BIND | MS_REC, NULL) == -1)
errExit("mount bind");
free(proxy_fd_path);
close(fd);
}
static char *get_socket_env(const char *name) {
char *value = getenv(name);
if (value == NULL)
return NULL;
if (strncmp(value, DBUS_SOCKET_PATH_PREFIX,
strlen(DBUS_SOCKET_PATH_PREFIX)) == 0)
return value + strlen(DBUS_SOCKET_PATH_PREFIX);
return NULL;
}
static void disable_socket_dir(void) {
struct stat s;
if (stat(RUN_FIREJAIL_DBUS_DIR, &s) == 0)
disable_file_or_dir(RUN_FIREJAIL_DBUS_DIR);
}
void dbus_apply_policy(void) {
EUID_ROOT();
if (arg_dbus_user == DBUS_POLICY_ALLOW && arg_dbus_system == DBUS_POLICY_ALLOW) {
disable_socket_dir();
return;
}
void dbus_disable(void) {
if (!checkcfg(CFG_DBUS)) {
disable_socket_dir();
fwarning("D-Bus handling is disabled in Firejail configuration file\n");
return;
}
char *path;
if (asprintf(&path, "/run/user/%d/bus", getuid()) == -1)
errExit("asprintf");
char *env_var;
if (asprintf(&env_var, "unix:path=%s", path) == -1)
errExit("asprintf");
create_empty_dir_as_root(RUN_DBUS_DIR, 0755);
create_empty_file_as_root(RUN_DBUS_USER_SOCKET, 0700);
create_empty_file_as_root(RUN_DBUS_SYSTEM_SOCKET, 0700);
// set a new environment variable: DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/<UID>/bus
if (setenv("DBUS_SESSION_BUS_ADDRESS", env_var, 1) == -1) {
fprintf(stderr, "Error: cannot modify DBUS_SESSION_BUS_ADDRESS required by --nodbus\n");
exit(1);
if (arg_dbus_user != DBUS_POLICY_ALLOW) {
if (arg_dbus_user == DBUS_POLICY_FILTER) {
assert(dbus_user_proxy_socket != NULL);
socket_overlay(RUN_DBUS_USER_SOCKET, dbus_user_proxy_socket);
free(dbus_user_proxy_socket);
}
char *dbus_user_socket;
if (asprintf(&dbus_user_socket, DBUS_USER_SOCKET_FORMAT,
(int) getuid()) == -1)
errExit("asprintf");
disable_file_or_dir(dbus_user_socket);
char *dbus_user_socket2;
if (asprintf(&dbus_user_socket2, DBUS_USER_SOCKET_FORMAT2,
(int) getuid()) == -1)
errExit("asprintf");
disable_file_or_dir(dbus_user_socket2);
char *user_env = get_socket_env(DBUS_SESSION_BUS_ADDRESS_ENV);
if (user_env != NULL && strcmp(user_env, dbus_user_socket) != 0 &&
strcmp(user_env, dbus_user_socket2) != 0)
disable_file_or_dir(user_env);
free(dbus_user_socket);
free(dbus_user_socket2);
if (setenv(DBUS_SESSION_BUS_ADDRESS_ENV,
DBUS_SOCKET_PATH_PREFIX RUN_DBUS_USER_SOCKET, 1) == -1) {
fprintf(stderr, "Error: cannot modify " DBUS_SESSION_BUS_ADDRESS_ENV
" required by --dbus-user\n");
exit(1);
}
// blacklist the dbus-launch user directory
char *path;
if (asprintf(&path, "%s/.dbus", cfg.homedir) == -1)
errExit("asprintf");
disable_file_or_dir(path);
free(path);
}
// blacklist the path
disable_file_or_dir(path);
free(path);
free(env_var);
if (arg_dbus_system != DBUS_POLICY_ALLOW) {
if (arg_dbus_system == DBUS_POLICY_FILTER) {
assert(dbus_system_proxy_socket != NULL);
socket_overlay(RUN_DBUS_SYSTEM_SOCKET, dbus_system_proxy_socket);
free(dbus_system_proxy_socket);
}
disable_file_or_dir(DBUS_SYSTEM_SOCKET);
// blacklist the dbus-launch user directory
if (asprintf(&path, "%s/.dbus", cfg.homedir) == -1)
errExit("asprintf");
disable_file_or_dir(path);
free(path);
char *system_env = get_socket_env(DBUS_SYSTEM_BUS_ADDRESS_ENV);
if (system_env != NULL && strcmp(system_env, DBUS_SYSTEM_SOCKET) != 0)
disable_file_or_dir(system_env);
// blacklist also system D-Bus socket
disable_file_or_dir("/run/dbus/system_bus_socket");
if (setenv(DBUS_SYSTEM_BUS_ADDRESS_ENV,
DBUS_SOCKET_PATH_PREFIX RUN_DBUS_SYSTEM_SOCKET, 1) == -1) {
fprintf(stderr, "Error: cannot modify " DBUS_SYSTEM_BUS_ADDRESS_ENV
" required by --dbus-system\n");
exit(1);
}
}
// Only disable access to /run/firejail/dbus here, when the sockets have been bind-mounted.
disable_socket_dir();
// look for a possible abstract unix socket

View file

@ -340,9 +340,16 @@ extern int arg_memory_deny_write_execute; // block writable and executable memor
extern int arg_notv; // --notv
extern int arg_nodvd; // --nodvd
extern int arg_nou2f; // --nou2f
extern int arg_nodbus; // -nodbus
extern int arg_deterministic_exit_code; // always exit with first child's exit status
typedef enum {
DBUS_POLICY_ALLOW, // Allow unrestricted access to the bus
DBUS_POLICY_FILTER, // Filter with xdg-dbus-proxy
DBUS_POLICY_BLOCK // Block access
} DbusPolicy;
extern DbusPolicy arg_dbus_user; // --dbus-user
extern DbusPolicy arg_dbus_system; // --dbus-system
extern int login_shell;
extern int parent_to_child_fds[2];
extern int child_to_parent_fds[2];
@ -823,10 +830,13 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc,
#define SBOX_STDIN_FROM_FILE (1 << 6) // open file and redirect it to stdin
#define SBOX_CAPS_HIDEPID (1 << 7) // hidepid caps filter for running firemon
#define SBOX_CAPS_NET_SERVICE (1 << 8) // caps filter for programs running network services
#define SBOX_KEEP_FDS (1 << 9) // keep file descriptors open
#define FIREJAIL_MAX_FD 20 // getdtablesize() is overkill for a firejail process
// run sbox
int sbox_run(unsigned filter, int num, ...);
int sbox_run_v(unsigned filter, char * const arg[]);
void sbox_exec_v(unsigned filter, char * const arg[]);
// run_files.c
void delete_run_files(pid_t pid);
@ -836,7 +846,11 @@ void set_x11_run_file(pid_t pid, int display);
void set_profile_run_file(pid_t pid, const char *fname);
// dbus.c
void dbus_disable(void);
int dbus_check_name(const char *name);
void dbus_check_profile(void);
void dbus_proxy_start(void);
void dbus_proxy_stop(void);
void dbus_apply_policy(void);
// dhcp.c
extern pid_t dhclient4_pid;

View file

@ -256,6 +256,7 @@ void fs_blacklist(void) {
// whitelist commands handled by fs_whitelist()
if (strncmp(entry->data, "whitelist ", 10) == 0 ||
strncmp(entry->data, "nowhitelist ", 12) == 0 ||
strncmp(entry->data, "dbus-", 5) == 0 ||
*entry->data == '\0') {
entry = entry->next;
continue;

View file

@ -144,9 +144,10 @@ int arg_noprofile = 0; // use default.profile if none other found/specified
int arg_memory_deny_write_execute = 0; // block writable and executable memory
int arg_notv = 0; // --notv
int arg_nodvd = 0; // --nodvd
int arg_nodbus = 0; // -nodbus
int arg_nou2f = 0; // --nou2f
int arg_deterministic_exit_code = 0; // always exit with first child's exit status
DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user
DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system
int login_shell = 0;
//**********************************************************************************
@ -180,6 +181,7 @@ static void myexit(int rv) {
// delete sandbox files in shared memory
dbus_proxy_stop();
EUID_ROOT();
delete_run_files(sandbox_pid);
appimage_clear();
@ -2053,8 +2055,70 @@ int main(int argc, char **argv, char **envp) {
arg_nodvd = 1;
else if (strcmp(argv[i], "--nou2f") == 0)
arg_nou2f = 1;
else if (strcmp(argv[i], "--nodbus") == 0)
arg_nodbus = 1;
else if (strcmp(argv[i], "--nodbus") == 0) {
arg_dbus_user = DBUS_POLICY_BLOCK;
arg_dbus_system = DBUS_POLICY_BLOCK;
}
else if (strncmp("--dbus-user=", argv[i], 12) == 0) {
if (strcmp("filter", argv[i] + 12) == 0) {
if (arg_dbus_user == DBUS_POLICY_BLOCK) {
fprintf(stderr, "Error: Cannot relax --dbus-user policy, it is already set to block\n");
exit(1);
}
arg_dbus_user = DBUS_POLICY_FILTER;
} else if (strcmp("none", argv[i] + 12) == 0) {
arg_dbus_user = DBUS_POLICY_BLOCK;
} else {
fprintf(stderr, "Unknown dbus-user policy: %s\n", argv[i] + 12);
exit(1);
}
}
else if (strncmp(argv[i], "--dbus-user.talk=", 17) == 0) {
char *line;
if (asprintf(&line, "dbus-user.talk %s", argv[i] + 17) == -1)
errExit("asprintf");
profile_check_line(line, 0, NULL); // will exit if something wrong
profile_add(line);
}
else if (strncmp(argv[i], "--dbus-user.own=", 16) == 0) {
char *line;
if (asprintf(&line, "dbus-user.own %s", argv[i] + 16) == -1)
errExit("asprintf");
profile_check_line(line, 0, NULL); // will exit if something wrong
profile_add(line);
}
else if (strncmp("--dbus-system=", argv[i], 14) == 0) {
if (strcmp("filter", argv[i] + 14) == 0) {
if (arg_dbus_system == DBUS_POLICY_BLOCK) {
fprintf(stderr, "Error: Cannot relax --dbus-system policy, it is already set to block\n");
exit(1);
}
arg_dbus_system = DBUS_POLICY_FILTER;
} else if (strcmp("none", argv[i] + 14) == 0) {
arg_dbus_system = DBUS_POLICY_BLOCK;
} else {
fprintf(stderr, "Unknown dbus-system policy: %s\n", argv[i] + 14);
exit(1);
}
}
else if (strncmp(argv[i], "--dbus-system.talk=", 19) == 0) {
char *line;
if (asprintf(&line, "dbus-system.talk %s", argv[i] + 19) == -1)
errExit("asprintf");
profile_check_line(line, 0, NULL); // will exit if something wrong
profile_add(line);
}
else if (strncmp(argv[i], "--dbus-system.own=", 18) == 0) {
char *line;
if (asprintf(&line, "dbus-system.own %s", argv[i] + 18) == -1)
errExit("asprintf");
profile_check_line(line, 0, NULL); // will exit if something wrong
profile_add(line);
}
//*************************************
// network
@ -2740,6 +2804,16 @@ int main(int argc, char **argv, char **envp) {
}
EUID_USER();
if (checkcfg(CFG_DBUS)) {
dbus_check_profile();
if (arg_dbus_user == DBUS_POLICY_FILTER ||
arg_dbus_system == DBUS_POLICY_FILTER) {
EUID_ROOT();
dbus_proxy_start();
EUID_USER();
}
}
// clone environment
int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD;

View file

@ -58,6 +58,20 @@ void preproc_build_firejail_dir(void) {
create_empty_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755);
}
if (stat(RUN_FIREJAIL_DBUS_DIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_DBUS_DIR, 0755);
if (arg_debug)
printf("Remounting the " RUN_FIREJAIL_DBUS_DIR
" directory as noexec\n");
if (mount(RUN_FIREJAIL_DBUS_DIR, RUN_FIREJAIL_DBUS_DIR, NULL,
MS_BIND, NULL) == -1)
errExit("mounting " RUN_FIREJAIL_DBUS_DIR);
if (mount(NULL, RUN_FIREJAIL_DBUS_DIR, NULL,
MS_REMOUNT | MS_BIND | MS_NOSUID | MS_NOEXEC | MS_NODEV,
"mode=755,gid=0") == -1)
errExit("remounting " RUN_FIREJAIL_DBUS_DIR);
}
if (stat(RUN_FIREJAIL_APPIMAGE_DIR, &s)) {
create_empty_dir_as_root(RUN_FIREJAIL_APPIMAGE_DIR, 0755);
}

View file

@ -150,7 +150,7 @@ static int check_netoptions(void) {
}
static int check_nodbus(void) {
return arg_nodbus != 0;
return arg_dbus_user != DBUS_POLICY_ALLOW || arg_dbus_system != DBUS_POLICY_ALLOW;
}
static int check_nosound(void) {
@ -432,11 +432,72 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
return 0;
}
else if (strcmp(ptr, "nodbus") == 0) {
arg_nodbus = 1;
arg_dbus_user = DBUS_POLICY_BLOCK;
arg_dbus_system = DBUS_POLICY_BLOCK;
return 0;
}
else if (strncmp("dbus-user ", ptr, 10) == 0) {
ptr += 10;
if (strcmp("filter", ptr) == 0) {
if (arg_dbus_user == DBUS_POLICY_BLOCK) {
fprintf(stderr, "Error: Cannot relax dbus-user policy, it is already set to block\n");
exit(1);
}
arg_dbus_user = DBUS_POLICY_FILTER;
} else if (strcmp("none", ptr) == 0) {
arg_dbus_user = DBUS_POLICY_BLOCK;
} else {
fprintf(stderr, "Unknown dbus-user policy: %s\n", ptr);
exit(1);
}
return 0;
}
else if (strncmp(ptr, "dbus-user.talk ", 15) == 0) {
if (!dbus_check_name(ptr + 15)) {
printf("Invalid dbus-user.talk name: %s\n", ptr + 15);
exit(1);
}
return 1;
}
else if (strncmp(ptr, "dbus-user.own ", 14) == 0) {
if (!dbus_check_name(ptr + 14)) {
fprintf(stderr, "Invalid dbus-user.own name: %s\n", ptr + 14);
exit(1);
}
return 1;
}
else if (strncmp("dbus-system ", ptr, 12) == 0) {
ptr += 12;
if (strcmp("filter", ptr) == 0) {
if (arg_dbus_system == DBUS_POLICY_BLOCK) {
fprintf(stderr, "Error: Cannot relax dbus-system policy, it is already set to block\n");
exit(1);
}
arg_dbus_system = DBUS_POLICY_FILTER;
} else if (strcmp("none", ptr) == 0) {
arg_dbus_system = DBUS_POLICY_BLOCK;
} else {
fprintf(stderr, "Unknown dbus-system policy: %s\n", ptr);
exit(1);
}
return 0;
}
else if (strncmp(ptr, "dbus-system.talk ", 17) == 0) {
if (!dbus_check_name(ptr + 17)) {
fprintf(stderr, "Invalid dbus-system.talk name: %s\n", ptr + 17);
exit(1);
}
return 1;
}
else if (strncmp(ptr, "dbus-system.own ", 16) == 0) {
if (!dbus_check_name(ptr + 16)) {
fprintf(stderr, "Invalid dbus-system.own name: %s\n", ptr + 16);
exit(1);
}
return 1;
}
else if (strcmp(ptr, "nou2f") == 0) {
arg_nou2f = 1;
arg_nou2f = 1;
return 0;
}
else if (strcmp(ptr, "netfilter") == 0) {

View file

@ -932,8 +932,7 @@ int sandbox(void* sandbox_arg) {
//****************************
// Session D-BUS
//****************************
if (arg_nodbus)
dbus_disable();
dbus_apply_policy();
//****************************

View file

@ -23,7 +23,7 @@
#include <unistd.h>
#include <net/if.h>
#include <stdarg.h>
#include <sys/wait.h>
#include <sys/wait.h>
#include "../include/seccomp.h"
#include <fcntl.h>
@ -31,6 +31,210 @@
#define O_PATH 010000000
#endif
static int sbox_do_exec_v(unsigned filtermask, char * const arg[]) {
int env_index = 0;
char *new_environment[256] = { NULL };
// preserve firejail-specific env vars
char *cl = getenv("FIREJAIL_FILE_COPY_LIMIT");
if (cl) {
if (asprintf(&new_environment[env_index++], "FIREJAIL_FILE_COPY_LIMIT=%s", cl) == -1)
errExit("asprintf");
}
clearenv();
if (arg_quiet) // --quiet is passed as an environment variable
new_environment[env_index++] = "FIREJAIL_QUIET=yes";
if (arg_debug) // --debug is passed as an environment variable
new_environment[env_index++] = "FIREJAIL_DEBUG=yes";
if (filtermask & SBOX_STDIN_FROM_FILE) {
int fd;
if((fd = open(SBOX_STDIN_FILE, O_RDONLY)) == -1) {
fprintf(stderr,"Error: cannot open %s\n", SBOX_STDIN_FILE);
exit(1);
}
if (dup2(fd, STDIN_FILENO) == -1)
errExit("dup2");
close(fd);
}
else if ((filtermask & SBOX_ALLOW_STDIN) == 0) {
int fd = open("/dev/null",O_RDWR, 0);
if (fd != -1) {
if (dup2(fd, STDIN_FILENO) == -1)
errExit("dup2");
close(fd);
}
else // the user could run the sandbox without /dev/null
close(STDIN_FILENO);
}
// close all other file descriptors
if ((filtermask & SBOX_KEEP_FDS) == 0) {
int i;
for (i = 3; i < FIREJAIL_MAX_FD; i++)
close(i); // close open files
}
umask(027);
// apply filters
if (filtermask & SBOX_CAPS_NONE) {
caps_drop_all();
} else {
uint64_t set = 0;
if (filtermask & SBOX_CAPS_NETWORK) {
#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
set |= ((uint64_t) 1) << CAP_NET_ADMIN;
set |= ((uint64_t) 1) << CAP_NET_RAW;
#endif
}
if (filtermask & SBOX_CAPS_HIDEPID) {
#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
set |= ((uint64_t) 1) << CAP_SYS_PTRACE;
set |= ((uint64_t) 1) << CAP_SYS_PACCT;
#endif
}
if (filtermask & SBOX_CAPS_NET_SERVICE) {
#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
set |= ((uint64_t) 1) << CAP_NET_BIND_SERVICE;
set |= ((uint64_t) 1) << CAP_NET_BROADCAST;
#endif
}
if (set != 0) { // some SBOX_CAPS_ flag was specified, drop all other capabilities
#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
caps_set(set);
#endif
}
}
if (filtermask & SBOX_SECCOMP) {
struct sock_filter filter[] = {
VALIDATE_ARCHITECTURE,
EXAMINE_SYSCALL,
#if defined(__x86_64__)
#define X32_SYSCALL_BIT 0x40000000
// handle X32 ABI
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, X32_SYSCALL_BIT, 1, 0),
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, 0, 1, 0),
RETURN_ERRNO(EPERM),
#endif
// syscall list
#ifdef SYS_mount
BLACKLIST(SYS_mount), // mount/unmount filesystems
#endif
#ifdef SYS_umount2
BLACKLIST(SYS_umount2),
#endif
#ifdef SYS_ptrace
BLACKLIST(SYS_ptrace), // trace processes
#endif
#ifdef SYS_process_vm_readv
BLACKLIST(SYS_process_vm_readv),
#endif
#ifdef SYS_process_vm_writev
BLACKLIST(SYS_process_vm_writev),
#endif
#ifdef SYS_kexec_file_load
BLACKLIST(SYS_kexec_file_load), // loading a different kernel
#endif
#ifdef SYS_kexec_load
BLACKLIST(SYS_kexec_load),
#endif
#ifdef SYS_name_to_handle_at
BLACKLIST(SYS_name_to_handle_at),
#endif
#ifdef SYS_open_by_handle_at
BLACKLIST(SYS_open_by_handle_at), // open by handle
#endif
#ifdef SYS_init_module
BLACKLIST(SYS_init_module), // kernel module handling
#endif
#ifdef SYS_finit_module // introduced in 2013
BLACKLIST(SYS_finit_module),
#endif
#ifdef SYS_create_module
BLACKLIST(SYS_create_module),
#endif
#ifdef SYS_delete_module
BLACKLIST(SYS_delete_module),
#endif
#ifdef SYS_iopl
BLACKLIST(SYS_iopl), // io permissions
#endif
#ifdef SYS_ioperm
BLACKLIST(SYS_ioperm),
#endif
#ifdef SYS_ioprio_set
BLACKLIST(SYS_ioprio_set),
#endif
#ifdef SYS_ni_syscall // new io permissions call on arm devices
BLACKLIST(SYS_ni_syscall),
#endif
#ifdef SYS_swapon
BLACKLIST(SYS_swapon), // swap on/off
#endif
#ifdef SYS_swapoff
BLACKLIST(SYS_swapoff),
#endif
#ifdef SYS_syslog
BLACKLIST(SYS_syslog), // kernel printk control
#endif
RETURN_ALLOW
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("prctl(NO_NEW_PRIVS)");
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("prctl(PR_SET_SECCOMP)");
}
}
if (filtermask & SBOX_ROOT) {
// elevate privileges in order to get grsecurity working
if (setreuid(0, 0))
errExit("setreuid");
if (setregid(0, 0))
errExit("setregid");
}
else if (filtermask & SBOX_USER)
drop_privs(1);
if (arg[0]) { // get rid of scan-build warning
int fd = open(arg[0], O_PATH | O_CLOEXEC);
if (fd == -1) {
if (errno == ENOENT) {
fprintf(stderr, "Error: %s does not exist\n", arg[0]);
exit(1);
} else {
errExit("open");
}
}
struct stat s;
if (fstat(fd, &s) == -1)
errExit("fstat");
if (s.st_uid != 0 && s.st_gid != 0) {
fprintf(stderr, "Error: %s is not owned by root, refusing to execute\n", arg[0]);
exit(1);
}
if (s.st_mode & 00002) {
fprintf(stderr, "Error: %s is world writable, refusing to execute\n", arg[0]);
exit(1);
}
fexecve(fd, arg, new_environment);
} else {
assert(0);
}
perror("fexecve");
_exit(1);
}
int sbox_run(unsigned filtermask, int num, ...) {
va_list valist;
va_start(valist, num);
@ -39,7 +243,7 @@ int sbox_run(unsigned filtermask, int num, ...) {
char **arg = malloc((num + 1) * sizeof(char *));
int i;
for (i = 0; i < num; i++)
arg[i] = va_arg(valist, char*);
arg[i] = va_arg(valist, char *);
arg[i] = NULL;
va_end(valist);
@ -51,87 +255,6 @@ int sbox_run(unsigned filtermask, int num, ...) {
}
int sbox_run_v(unsigned filtermask, char * const arg[]) {
struct sock_filter filter[] = {
VALIDATE_ARCHITECTURE,
EXAMINE_SYSCALL,
#if defined(__x86_64__)
#define X32_SYSCALL_BIT 0x40000000
// handle X32 ABI
BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0),
BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0),
RETURN_ERRNO(EPERM),
#endif
// syscall list
#ifdef SYS_mount
BLACKLIST(SYS_mount), // mount/unmount filesystems
#endif
#ifdef SYS_umount2
BLACKLIST(SYS_umount2),
#endif
#ifdef SYS_ptrace
BLACKLIST(SYS_ptrace), // trace processes
#endif
#ifdef SYS_process_vm_readv
BLACKLIST(SYS_process_vm_readv),
#endif
#ifdef SYS_process_vm_writev
BLACKLIST(SYS_process_vm_writev),
#endif
#ifdef SYS_kexec_file_load
BLACKLIST(SYS_kexec_file_load), // loading a different kernel
#endif
#ifdef SYS_kexec_load
BLACKLIST(SYS_kexec_load),
#endif
#ifdef SYS_name_to_handle_at
BLACKLIST(SYS_name_to_handle_at),
#endif
#ifdef SYS_open_by_handle_at
BLACKLIST(SYS_open_by_handle_at), // open by handle
#endif
#ifdef SYS_init_module
BLACKLIST(SYS_init_module), // kernel module handling
#endif
#ifdef SYS_finit_module // introduced in 2013
BLACKLIST(SYS_finit_module),
#endif
#ifdef SYS_create_module
BLACKLIST(SYS_create_module),
#endif
#ifdef SYS_delete_module
BLACKLIST(SYS_delete_module),
#endif
#ifdef SYS_iopl
BLACKLIST(SYS_iopl), // io permissions
#endif
#ifdef SYS_ioperm
BLACKLIST(SYS_ioperm),
#endif
#ifdef SYS_ioprio_set
BLACKLIST(SYS_ioprio_set),
#endif
#ifdef SYS_ni_syscall // new io permissions call on arm devices
BLACKLIST(SYS_ni_syscall),
#endif
#ifdef SYS_swapon
BLACKLIST(SYS_swapon), // swap on/off
#endif
#ifdef SYS_swapoff
BLACKLIST(SYS_swapoff),
#endif
#ifdef SYS_syslog
BLACKLIST(SYS_syslog), // kernel printk control
#endif
RETURN_ALLOW
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
EUID_ROOT();
if (arg_debug) {
@ -144,132 +267,14 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) {
printf("\n");
}
// KEEP_FDS only makes sense with sbox_exec_v
assert((filtermask & SBOX_KEEP_FDS) == 0);
pid_t child = fork();
if (child < 0)
errExit("fork");
if (child == 0) {
int env_index = 0;
char *new_environment[256] = { NULL };
// preserve firejail-specific env vars
char *cl = getenv("FIREJAIL_FILE_COPY_LIMIT");
if (cl) {
if (asprintf(&new_environment[env_index++], "FIREJAIL_FILE_COPY_LIMIT=%s", cl) == -1)
errExit("asprintf");
}
clearenv();
if (arg_quiet) // --quiet is passed as an environment variable
new_environment[env_index++] = "FIREJAIL_QUIET=yes";
if (arg_debug) // --debug is passed as an environment variable
new_environment[env_index++] = "FIREJAIL_DEBUG=yes";
if (cfg.seccomp_error_action)
if (asprintf(&new_environment[env_index++], "FIREJAIL_SECCOMP_ERROR_ACTION=%s", cfg.seccomp_error_action) == -1)
errExit("asprintf");
if (filtermask & SBOX_STDIN_FROM_FILE) {
int fd;
if((fd = open(SBOX_STDIN_FILE, O_RDONLY)) == -1) {
fprintf(stderr,"Error: cannot open %s\n", SBOX_STDIN_FILE);
exit(1);
}
if (dup2(fd, STDIN_FILENO) == -1)
errExit("dup2");
close(fd);
}
else if ((filtermask & SBOX_ALLOW_STDIN) == 0) {
int fd = open("/dev/null",O_RDWR, 0);
if (fd != -1) {
if (dup2(fd, STDIN_FILENO) == -1)
errExit("dup2");
close(fd);
}
else // the user could run the sandbox without /dev/null
close(STDIN_FILENO);
}
// close all other file descriptors
int max = 20; // getdtablesize() is overkill for a firejail process
int i = 3;
for (i = 3; i < max; i++)
close(i); // close open files
umask(027);
// apply filters
if (filtermask & SBOX_CAPS_NONE) {
caps_drop_all();
} else {
uint64_t set = 0;
if (filtermask & SBOX_CAPS_NETWORK) {
#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
set |= ((uint64_t) 1) << CAP_NET_ADMIN;
set |= ((uint64_t) 1) << CAP_NET_RAW;
#endif
}
if (filtermask & SBOX_CAPS_HIDEPID) {
#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
set |= ((uint64_t) 1) << CAP_SYS_PTRACE;
set |= ((uint64_t) 1) << CAP_SYS_PACCT;
#endif
}
if (filtermask & SBOX_CAPS_NET_SERVICE) {
#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
set |= ((uint64_t) 1) << CAP_NET_BIND_SERVICE;
set |= ((uint64_t) 1) << CAP_NET_BROADCAST;
#endif
}
if (set != 0) { // some SBOX_CAPS_ flag was specified, drop all other capabilities
#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
caps_set(set);
#endif
}
}
if (filtermask & SBOX_SECCOMP) {
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("prctl(NO_NEW_PRIVS)");
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("prctl(PR_SET_SECCOMP)");
}
}
if (filtermask & SBOX_ROOT) {
// elevate privileges in order to get grsecurity working
if (setreuid(0, 0))
errExit("setreuid");
if (setregid(0, 0))
errExit("setregid");
}
else if (filtermask & SBOX_USER)
drop_privs(1);
if (arg[0]) { // get rid of scan-build warning
int fd = open(arg[0], O_PATH | O_CLOEXEC);
if (fd == -1) {
if (errno == ENOENT) {
fprintf(stderr, "Error: %s does not exist\n", arg[0]);
exit(1);
} else {
errExit("open");
}
}
struct stat s;
if (fstat(fd, &s) == -1)
errExit("fstat");
if (s.st_uid != 0 && s.st_gid != 0) {
fprintf(stderr, "Error: %s is not owned by root, refusing to execute\n", arg[0]);
exit(1);
}
if (s.st_mode & 00002) {
fprintf(stderr, "Error: %s is world writable, refusing to execute\n", arg[0]);
exit(1);
}
fexecve(fd, arg, new_environment);
} else {
assert(0);
}
perror("fexecve");
_exit(1);
sbox_do_exec_v(filtermask, arg);
}
int status;
@ -283,3 +288,19 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) {
return status;
}
void sbox_exec_v(unsigned filtermask, char * const arg[]) {
EUID_ROOT();
if (arg_debug) {
printf("sbox exec: ");
int i = 0;
while (arg[i]) {
printf("%s ", arg[i]);
i++;
}
printf("\n");
}
sbox_do_exec_v(filtermask, arg);
}

View file

@ -53,6 +53,12 @@ static char *usage_str =
#endif
" --cpu=cpu-number,cpu-number - set cpu affinity.\n"
" --cpu.print=name|pid - print the cpus in use.\n"
" --dbus-system=filter|none - set system DBus access policy.\n"
" --dbus-system.own=name - allow ownership of name on the system DBus.\n"
" --dbus-system.talk-name - allow talking to name on the system DBus.\n"
" --dbus-user=filter|none - set session DBus access policy.\n"
" --dbus-user.own=name - allow ownership of name on the session DBus.\n"
" --dbus-user.talk-name - allow talking to name on the session DBus.\n"
" --debug - print sandbox debug messages.\n"
" --debug-blacklists - debug blacklisting.\n"
" --debug-caps - print all recognized capabilities.\n"

View file

@ -30,6 +30,7 @@
#define RUN_FIREJAIL_NETWORK_DIR RUN_FIREJAIL_DIR "/network"
#define RUN_FIREJAIL_BANDWIDTH_DIR RUN_FIREJAIL_DIR "/bandwidth"
#define RUN_FIREJAIL_PROFILE_DIR RUN_FIREJAIL_DIR "/profile"
#define RUN_FIREJAIL_DBUS_DIR RUN_FIREJAIL_DIR "/dbus"
#define RUN_NETWORK_LOCK_FILE RUN_FIREJAIL_DIR "/firejail-network.lock"
#define RUN_DIRECTORY_LOCK_FILE RUN_FIREJAIL_DIR "/firejail-run.lock"
#define RUN_RO_DIR RUN_FIREJAIL_DIR "/firejail.ro.dir"
@ -56,6 +57,9 @@
#define RUN_DHCLIENT_4_LEASES_FILE RUN_DHCLIENT_DIR "/dhclient.leases"
#define RUN_DHCLIENT_4_PID_FILE RUN_DHCLIENT_DIR "/dhclient.pid"
#define RUN_DHCLIENT_6_PID_FILE RUN_DHCLIENT_DIR "/dhclient6.pid"
#define RUN_DBUS_DIR RUN_MNT_DIR "/dbus"
#define RUN_DBUS_USER_SOCKET RUN_DBUS_DIR "/user"
#define RUN_DBUS_SYSTEM_SOCKET RUN_DBUS_DIR "/system"
#define RUN_SECCOMP_DIR RUN_MNT_DIR "/seccomp"
#define RUN_SECCOMP_LIST RUN_SECCOMP_DIR "/seccomp.list" // list of seccomp files installed

View file

@ -447,7 +447,55 @@ xephyr-screen 640x480
.br
x11 xephyr
.SH DBus filtering
Access to the session and system DBus UNIX sockets can be allowed, filtered or
disabled. To disable the abstract sockets (and force applications to use the
filtered UNIX socket) you would need to request a new network namespace using
\-\-net command. Another option is to remove unix from the \-\-protocol set.
.br
.br
Filtering requires installing the xdg-dbus-proxy utility. Filter rules can be
specified for well-known DBus names, but they are also propagated to the owning
unique name, too. The permissions are "sticky" and are kept even if the
corresponding well-know name is released (however, applications rarely release
well-known names in practice). Names may have a .* suffix to match all names
underneath them, including themselves (e.g. "foo.bar.*" matches "foo.bar",
"foo.bar.baz" and "foo.bar.baz.quux", but not "foobar"). For more information,
see xdg-dbus-proxy(1).
.br
.br
Examples:
.TP
\fBdbus-system filter
Enable filtered access to the system DBus. Filters can be specified with the dbus-system.talk and dbus-system.own commands.
.TP
\fBdbus-system none
Disable access to the system DBus. Once access is disabled, it cannot be relaxed to filtering.
.TP
\fBdbus-system.own org.gnome.ghex.*
Allow the application to own the name org.gnome.ghex and all names underneath in on the system DBus.
.TP
\fBdbus-system.talk org.freedesktop.Notifications
Allow the application to talk to the name org.freedesktop.Notifications on the system DBus.
.TP
\fBdbus-user filter
Enable filtered access to the session DBus. Filters can be specified with the dbus-user.talk and dbus-user.own commands.
.TP
\fBdbus-user none
Disable access to the session DBus. Once access is disabled, it cannot be relaxed to filtering.
.TP
\fBdbus-user.own org.gnome.ghex.*
Allow the application to own the name org.gnome.ghex and all names underneath in on the session DBus.
.TP
\fBdbus-user.talk org.freedesktop.Notifications
Allow the application to talk to the name org.freedesktop.Notifications on the session DBus.
.TP
\fBnodbus \fR(deprecated)
Disable D-Bus access (both system and session buses). Equivalent to dbus-system none and dbus-user none.
.SH Resource limits, CPU affinity, Control Groups
These profile entries define the limits on system resources (rlimits) for the processes inside the sandbox.
@ -522,12 +570,6 @@ Disable 3D hardware acceleration.
Disable automatic ~/.config/pulse init, for complex setups such as remote
pulse servers or non-standard socket paths.
.TP
\fBnodbus
Disable D-Bus access. Only the regular UNIX socket is handled by
this command. To disable the abstract socket, you would need to
request a new network namespace using the net command. Another
option is to remove unix from protocol set.
.TP
\fBnodvd
Disable DVD and audio CD devices.
.TP

View file

@ -325,6 +325,112 @@ $ firejail \-\-list
.br
$ firejail \-\-cpu.print=3272
.TP
\fB\-\-dbus-system=filter|none
Set system DBus sandboxing policy.
.br
.br
The \fBfilter\fR policy enables the system DBus filter. This option requires
installing the xdg-dbus-proxy utility. Permissions for well-known can be
specified with the --dbus-system.talk and --dbus-system.own options.
.br
.br
The \fBnone\fR policy disables access to the system DBus.
.br
.br
Only the regular system DBus UNIX socket is handled by this option. To disable
the abstract sockets (and force applications to use the filtered UNIX socket)
you would need to request a new network namespace using \-\-net command. Another
option is to remove unix from the \-\-protocol set.
.br
.br
Example:
.br
$ firejail \-\-dbus-system=none
.TP
\fB\-\-dbus-system.own=name
Allows the application to own the specified well-known name on the system DBus.
The name may have a .* suffix to match all names underneath it, including itself
(e.g. "foo.bar.*" matches "foo.bar", "foo.bar.baz" and "foo.bar.baz.quux", but
not "foobar").
.br
.br
Example:
.br
$ firejail --dbus-system=filter --dbus-system.own=org.gnome.ghex.*
.TP
\fB\-\-dbus-system.talk=name
Allows the application to talk to the specified well-known name on the system DBus.
The name may have a .* suffix to match all names underneath it, including itself
(e.g. "foo.bar.*" matches "foo.bar", "foo.bar.baz" and "foo.bar.baz.quux", but
not "foobar").
.br
.br
Example:
.br
$ firejail --dbus-system=filter --dbus-system.talk=org.freedesktop.Notifications
.TP
\fB\-\-dbus-user=filter|none
Set session DBus sandboxing policy.
.br
.br
The \fBfilter\fR policy enables the session DBus filter. This option requires
installing the xdg-dbus-proxy utility. Permissions for well-known names can be
added with the --dbus-user.talk and --dbus-user.own options.
.br
.br
The \fBnone\fR policy disables access to the session DBus.
.br
.br
Only the regular session DBus UNIX socket is handled by this option. To disable
the abstract sockets (and force applications to use the filtered UNIX socket)
you would need to request a new network namespace using \-\-net command. Another
option is to remove unix from the \-\-protocol set.
.br
.br
Example:
.br
$ firejail \-\-dbus-user=none
.TP
\fB\-\-dbus-user.own=name
Allows the application to own the specified well-known name on the session DBus.
The name may have a .* suffix to match all names underneath it, including itself
(e.g. "foo.bar.*" matches "foo.bar", "foo.bar.baz" and "foo.bar.baz.quux", but
not "foobar").
.br
.br
Example:
.br
$ firejail --dbus-user=filter --dbus-user.own=org.gnome.ghex.*
.TP
\fB\-\-dbus-user.talk=name
Allows the application to talk to the specified well-known name on the session DBus.
The name may have a .* suffix to match all names underneath it, including itself
(e.g. "foo.bar.*" matches "foo.bar", "foo.bar.baz" and "foo.bar.baz.quux", but
not "foobar").
.br
.br
Example:
.br
$ firejail --dbus-user=filter --dbus-user.talk=org.freedesktop.Notifications
.TP
\fB\-\-debug\fR
Print debug messages.
@ -1170,12 +1276,8 @@ $ nc dict.org 2628
220 pan.alephnull.com dictd 1.12.1/rf on Linux 3.14-1-amd64
.br
.TP
\fB\-\-nodbus
Disable D-Bus access (both system and session buses). Only the regular
UNIX sockets are handled by this command. To disable the abstract
sockets you would need to request a new network namespace using
\-\-net command. Another option is to remove unix from \-\-protocol
set.
\fB\-\-nodbus \fR(deprecated)
Disable D-Bus access (both system and session buses). Equivalent to --dbus-system=none --dbus-user=none.
.br
.br