sandbox: Use temporary directory for XDG_RUNTIME_DIR

XDG_RUNTIME_DIR (/run/user/$UID) is used for user-specific data files
such as sockets, named pipes and so on. Therefore, it should not be
available to sandboxed processes.

Usage:
    # ls -a $XDG_RUNTIME_DIR
    .  ..  bus  pipewire-0  systemd
    # sandbox -R /root/sandbox/user -- sh -c "ls -a $XDG_RUNTIME_DIR"
    .  ..

Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
This commit is contained in:
Petr Lautrbach 2022-10-13 15:23:12 +02:00 committed by James Carter
parent 0fb988c86b
commit ecfcb1d6a8
4 changed files with 57 additions and 13 deletions

View file

@ -209,6 +209,7 @@ class Sandbox:
self.__level = None
self.__homedir = None
self.__tmpdir = None
self.__runuserdir = None
def __validate_mount(self):
if self.__options.level:
@ -357,6 +358,11 @@ sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-
action="callback", callback=self.__validdir,
help=_("alternate /tmp directory to use for mounting"))
parser.add_option("-R", "--runuserdir", dest="runuserdir",
type="string",
action="callback", callback=self.__validdir,
help=_("alternate XDG_RUNTIME_DIR - /run/user/$UID - directory to use for mounting"))
parser.add_option("-w", "--windowsize", dest="windowsize",
type="string", default=DEFAULT_WINDOWSIZE,
help="size of the sandbox window")
@ -401,10 +407,12 @@ sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-
self.__options.X_ind = True
self.__homedir = self.__options.homedir
self.__tmpdir = self.__options.tmpdir
self.__runuserdir = self.__options.runuserdir
else:
if self.__options.level:
self.__homedir = self.__options.homedir
self.__tmpdir = self.__options.tmpdir
self.__runuserdir = self.__options.runuserdir
if len(cmds) == 0:
self.usage(_("Command required"))
@ -442,9 +450,14 @@ sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-
self.__tmpdir = self.__options.tmpdir
else:
self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox_tmp_")
if self.__options.runuserdir:
self.__runuserdir = self.__options.runuserdir
else:
self.__runuserdir = mkdtemp(dir="/tmp", prefix=".sandbox_runuser_")
self.__copyfiles()
selinux.chcon(self.__homedir, self.__filecon, recursive=True)
selinux.chcon(self.__tmpdir, self.__filecon, recursive=True)
selinux.chcon(self.__runuserdir, self.__filecon, recursive=True)
selinux.setfscreatecon(None)
def __execute(self):
@ -453,7 +466,7 @@ sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-
if self.__options.usecaps:
cmds.append('-C')
if self.__mount:
cmds += ["-t", self.__tmpdir, "-h", self.__homedir]
cmds += ["-t", self.__tmpdir, "-h", self.__homedir, "-r", self.__runuserdir]
if self.__options.X_ind:
if self.__options.dpi:

View file

@ -3,11 +3,11 @@
sandbox \- Run cmd under an SELinux sandbox
.SH SYNOPSIS
.B sandbox
[\-C] [\-s] [ \-d DPI ] [\-l level ] [[\-M | \-X] \-H homedir \-T tempdir ] [\-I includefile ] [ \-W windowmanager ] [ \-w windowsize ] [[\-i file ]...] [ \-t type ] cmd
[\-C] [\-s] [ \-d DPI ] [\-l level ] [[\-M | \-X] \-H homedir \-T tempdir ] [ \-R runuserdir ] [\-I includefile ] [ \-W windowmanager ] [ \-w windowsize ] [[\-i file ]...] [ \-t type ] cmd
.br
.B sandbox
[\-C] [\-s] [ \-d DPI ] [\-l level ] [[\-M | \-X] \-H homedir \-T tempdir ] [\-I includefile ] [ \-W windowmanager ] [ \-w windowsize ] [[\-i file ]...] [ \-t type ] \-S
[\-C] [\-s] [ \-d DPI ] [\-l level ] [[\-M | \-X] \-H homedir \-T tempdir ] [ \-R runuserdir ] [\-I includefile ] [ \-W windowmanager ] [ \-w windowsize ] [[\-i file ]...] [ \-t type ] \-S
.br
.SH DESCRIPTION
.PP
@ -67,6 +67,9 @@ sandbox_net_client_t \- All network ports
\fB\-T\fR \fB\-\-tmpdir\fR
Use alternate temporary directory to mount on /tmp. Defaults to tmpfs. Requires \-X or \-M.
.TP
\fB\-R\fR \fB\-\-runuserdir\fR
Use alternate temporary directory to mount on XDG_RUNTIME_DIR (/run/user/$UID).
.TP
\fB\-S\fR \fB\-\-session\fR
Run a full desktop session, Requires level, and home and tmpdir.
.TP

View file

@ -18,6 +18,9 @@ Alternate homedir to be used by the application. Homedir must be owned by the u
\fB\-t\ tmpdir
Use alternate temporary directory to mount on /tmp. tmpdir must be owned by the user.
.TP
\fB\-r\ runuserdir
Use alternate temporary directory to mount on XDG_RUNTIME_DIR (/run/user/$UID). runuserdir must be owned by the user.
.TP
\fB\-C --capabilities\fR
Allow apps executed within the namespace to use capabilities. Default is no capabilities.
.TP

View file

@ -52,7 +52,7 @@
#define BUF_SIZE 1024
#define DEFAULT_PATH "/usr/bin:/bin"
#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z CONTEXT ] -- executable [args] ")
#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -r runuserdir ] [ -Z CONTEXT ] -- executable [args] ")
static int verbose = 0;
static int child = 0;
@ -623,15 +623,20 @@ int main(int argc, char **argv) {
char *homedir_s = NULL; /* homedir spec'd by user in argv[] */
char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */
char *tmpdir_r = NULL; /* tmpdir created by seunshare */
char *runuserdir_s = NULL; /* /var/run/user/UID spec'd by user in argv[] */
char *runuserdir_r = NULL; /* /var/run/user/UID created by seunshare */
struct stat st_curhomedir;
struct stat st_homedir;
struct stat st_tmpdir_s;
struct stat st_tmpdir_r;
struct stat st_runuserdir_s;
struct stat st_runuserdir_r;
const struct option long_options[] = {
{"homedir", 1, 0, 'h'},
{"tmpdir", 1, 0, 't'},
{"runuserdir", 1, 0, 'r'},
{"kill", 1, 0, 'k'},
{"verbose", 1, 0, 'v'},
{"context", 1, 0, 'Z'},
@ -665,7 +670,7 @@ int main(int argc, char **argv) {
}
while (1) {
clflag = getopt_long(argc, argv, "Ccvh:t:Z:", long_options, NULL);
clflag = getopt_long(argc, argv, "Ccvh:r:t:Z:", long_options, NULL);
if (clflag == -1)
break;
@ -679,6 +684,9 @@ int main(int argc, char **argv) {
case 'h':
homedir_s = optarg;
break;
case 'r':
runuserdir_s = optarg;
break;
case 'v':
verbose++;
break;
@ -729,6 +737,10 @@ int main(int argc, char **argv) {
if (tmpdir_s && (
verify_directory(tmpdir_s, NULL, &st_tmpdir_s) < 0 ||
check_owner_uid(uid, tmpdir_s, &st_tmpdir_s))) return -1;
if (runuserdir_s && (
verify_directory(runuserdir_s, NULL, &st_runuserdir_s) < 0 ||
check_owner_uid(uid, runuserdir_s, &st_runuserdir_s))) return -1;
if ((uid_t)setfsuid(0) != uid) return -1;
/* create runtime tmpdir */
@ -737,6 +749,12 @@ int main(int argc, char **argv) {
fprintf(stderr, _("Failed to create runtime temporary directory\n"));
return -1;
}
/* create runtime runuserdir */
if (runuserdir_s && (runuserdir_r = create_tmpdir(runuserdir_s, &st_runuserdir_s,
&st_runuserdir_r, pwd, execcon)) == NULL) {
fprintf(stderr, _("Failed to create runtime $XDG_RUNTIME_DIR directory\n"));
return -1;
}
/* spawn child process */
child = fork();
@ -775,7 +793,21 @@ int main(int argc, char **argv) {
if (check_owner_uid(uid, resolved_path, &st_curhomedir) < 0)
goto childerr;
/* mount homedir and tmpdir, in this order */
if ((RUNTIME_DIR = getenv("XDG_RUNTIME_DIR")) != NULL) {
if ((RUNTIME_DIR = strdup(RUNTIME_DIR)) == NULL) {
perror(_("Out of memory"));
goto childerr;
}
} else {
if (asprintf(&RUNTIME_DIR, "/run/user/%d", uid) == -1) {
perror(_("Out of memory\n"));
goto childerr;
}
}
/* mount homedir, runuserdir and tmpdir, in this order */
if (runuserdir_s && seunshare_mount(runuserdir_s, RUNTIME_DIR,
&st_runuserdir_s) != 0) goto childerr;
if (homedir_s && seunshare_mount(homedir_s, resolved_path,
&st_homedir) != 0) goto childerr;
if (tmpdir_s && seunshare_mount(tmpdir_r, "/tmp",
@ -799,13 +831,6 @@ int main(int argc, char **argv) {
}
}
if ((RUNTIME_DIR = getenv("XDG_RUNTIME_DIR")) != NULL) {
if ((RUNTIME_DIR = strdup(RUNTIME_DIR)) == NULL) {
perror(_("Out of memory"));
goto childerr;
}
}
if ((rc = clearenv()) != 0) {
perror(_("Failed to clear environment"));
goto childerr;