diff mbox series

[2/2] sandbox: Use temporary directory for XDG_RUNTIME_DIR

Message ID 20221013132312.294095-2-plautrba@redhat.com (mailing list archive)
State Accepted
Commit ecfcb1d6a8ec
Headers show
Series [1/2] sandbox: Do not try to remove tmpdir twice if uid == 0 | expand

Commit Message

Petr Lautrbach Oct. 13, 2022, 1:23 p.m. UTC
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>
---
 sandbox/sandbox     | 15 ++++++++++++++-
 sandbox/sandbox.8   |  7 +++++--
 sandbox/seunshare.8 |  3 +++
 sandbox/seunshare.c | 45 +++++++++++++++++++++++++++++++++++----------
 4 files changed, 57 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/sandbox/sandbox b/sandbox/sandbox
index ffac70232875..770807345858 100644
--- a/sandbox/sandbox
+++ b/sandbox/sandbox
@@ -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:
diff --git a/sandbox/sandbox.8 b/sandbox/sandbox.8
index d83fee76f335..1ee0ecea96d1 100644
--- a/sandbox/sandbox.8
+++ b/sandbox/sandbox.8
@@ -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
diff --git a/sandbox/seunshare.8 b/sandbox/seunshare.8
index 0da352613485..09cf7feae45d 100644
--- a/sandbox/seunshare.8
+++ b/sandbox/seunshare.8
@@ -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
diff --git a/sandbox/seunshare.c b/sandbox/seunshare.c
index dd1d7ddbdc89..1d38ea92b9ae 100644
--- a/sandbox/seunshare.c
+++ b/sandbox/seunshare.c
@@ -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;