Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: feature: Firejail as a service #3315

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions firejail.socket
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=Socket for Firejail

[Socket]
ListenStream=/run/firejail/firejail.socket
Accept=yes
PassCredentials=yes
PassSecurity=yes

[Install]
WantedBy=multi-user.target
2 changes: 2 additions & 0 deletions [email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[Service]
ExecStart=/usr/bin/firejail --socket-activation
142 changes: 140 additions & 2 deletions src/firejail/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#include <time.h>
#include <net/if.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <fcntl.h>
#ifndef O_PATH
Expand Down Expand Up @@ -979,6 +981,136 @@ static int check_postexec(const char *list) {
return 0;
}

static int read_args(int *argcp, char **argv)
{
struct msghdr msghdr;
struct iovec iovec;
struct ucred *ucred;
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
} control;
size_t len;
char *buf, *ptr;
int orig_argc = *argcp, i;

memset(&control, 0, sizeof(control));
memset(&msghdr, 0, sizeof(msghdr));

buf = calloc(MAX_ARGS * PATH_MAX + 1, 1);
if (!buf)
errExit("calloc");

iovec.iov_base = buf;
iovec.iov_len = MAX_ARGS * PATH_MAX;
msghdr.msg_iov = &iovec;
msghdr.msg_iovlen = 1;
msghdr.msg_control = &control;
msghdr.msg_controllen = sizeof(control);

len = recvmsg(3, &msghdr, 0);
if (len == -1 || len == 0 ||
msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
control.cmsghdr.cmsg_level != SOL_SOCKET ||
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred)))
errExit("recvmsg");

ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);

firejail_uid = ucred->uid;
firejail_gid = ucred->gid;
if (setresgid(firejail_gid, firejail_gid, -1) == -1)
errExit("setresgid");

if (setresuid(firejail_gid, firejail_uid, -1) == -1)
errExit("setresuid");

// Prepare argc and argv
*argcp = *(int *)buf;

if (*argcp <= 0 || *argcp > MAX_ARGS)
errExit("argc");
//printf("argc %d\n", *argcp);

ptr = &buf[sizeof(int)];
for (i = 0; i < *argcp; i++) {
if (i > 0)
argv[i] = ptr;
ptr += strlen(ptr) + 1;
//printf("argv[%d]: %s, len %zd\n", i, argv[i], strlen(argv[i]));
}
for (i = *argcp; i < orig_argc; i++)
argv[i] = 0;
return 0;
}

static int send_args(int argc, char **argv)
{
struct msghdr msghdr;
struct iovec *iovecs;
struct ucred *ucred;
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
} control;
size_t len;
char *args;
int fd, r, i, j;
struct sockaddr_un sa;
int iov_argc;

memset(&sa, 0, sizeof(sa));
memset(&control, 0, sizeof(control));
memset(&msghdr, 0, sizeof(msghdr));
fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd < 0)
errExit("socket");

sa.sun_family = AF_UNIX;
strncpy(sa.sun_path, "/run/firejail/firejail.socket", sizeof(sa.sun_path) - 1);
r = connect(fd, &sa, sizeof(struct sockaddr_un));
if (r < 0)
errExit("connect");

iovecs = calloc(sizeof(struct iovec), argc);
if (!iovecs)
errExit("calloc");

// Send argc and argv strings, except for --send-socket
iov_argc = argc - 1;
iovecs[0].iov_base = &iov_argc;
iovecs[0].iov_len = sizeof(int);

j = 1;
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "--send-socket") == 0)
continue;
iovecs[j].iov_base = argv[i];
iovecs[j].iov_len = strlen(argv[i]) + 1;
j++;
}

msghdr.msg_iov = iovecs;
msghdr.msg_iovlen = j;
msghdr.msg_control = &control;
msghdr.msg_controllen = sizeof(control);

control.cmsghdr.cmsg_level = SOL_SOCKET;
control.cmsghdr.cmsg_type = SCM_CREDENTIALS;
control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));;

ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
ucred->uid = getuid();
ucred->gid = getgid();
ucred->pid = getpid();

len = sendmsg(fd, &msghdr, 0);
if (len == -1 || len == 0)
errExit("sendmsg");
return 0;
}

//*******************************************
// Main program
//*******************************************
Expand All @@ -991,8 +1123,11 @@ int main(int argc, char **argv) {
int custom_profile = 0; // custom profile loaded
int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot)

// drop permissions by default and rise them when required
EUID_INIT();
if (argc == 2 && strcmp(argv[1], "--socket-activation") == 0)
read_args(&argc, argv);
else
// drop permissions by default and rise them when required
EUID_INIT();
EUID_USER();

// sanitize the umask
Expand All @@ -1013,6 +1148,9 @@ int main(int argc, char **argv) {
if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0))
arg_quiet = 1;

if (check_arg(argc, argv, "--send-socket", 1))
return send_args(argc, argv);

// cleanup at exit
EUID_ROOT();
atexit(clear_atexit);
Expand Down