aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2020-08-17 16:40:52 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2020-08-17 16:40:52 +0200
commit7d0800682ab3a74e3d463836cd2ca5cd697d542c (patch)
treec1099688e259a1d03ffc633778de2ce836f03db4 /src
parenthardening: run plugins with dumpable flag cleared (diff)
downloadfirejail-7d0800682ab3a74e3d463836cd2ca5cd697d542c.tar.gz
firejail-7d0800682ab3a74e3d463836cd2ca5cd697d542c.tar.zst
firejail-7d0800682ab3a74e3d463836cd2ca5cd697d542c.zip
various x11 xorg enhancements
1) copy xauth binary into the sandbox and set mode to 0711, so it runs with cleared dumpable flag for unprivileged users 2) run xauth in an sbox sandbox 3) generate Xauthority file in runtime directory instead of /tmp; this way xauth is able to connect to the X11 socket even if the abstract socket doesn't exist, for example because a new network namespace was instantiated
Diffstat (limited to 'src')
-rw-r--r--src/firejail/x11.c173
-rw-r--r--src/include/rundefs.h5
2 files changed, 72 insertions, 106 deletions
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 98ac184d9..1ecb688af 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -34,7 +34,7 @@
34 34
35#include <fcntl.h> 35#include <fcntl.h>
36#ifndef O_PATH 36#ifndef O_PATH
37# define O_PATH 010000000 37#define O_PATH 010000000
38#endif 38#endif
39 39
40 40
@@ -1129,28 +1129,17 @@ void x11_start(int argc, char **argv) {
1129} 1129}
1130#endif 1130#endif
1131 1131
1132// Porting notes: 1132
1133//
1134// 1. merge #1100 from zackw:
1135// Attempting to run xauth -f directly on a file in /run/firejail/mnt/ directory fails on Debian 8
1136// with this message:
1137// xauth: timeout in locking authority file /run/firejail/mnt/sec.Xauthority-Qt5Mu4
1138// Failed to create untrusted X cookie: xauth: exit 1
1139// For this reason we run xauth on a file in a tmpfs filesystem mounted on /tmp. This was
1140// a partial merge.
1141//
1142// 2. Since we cannot deal with the TOCTOU condition when mounting .Xauthority in user home
1143// directory, we need to make sure /usr/bin/xauth executable is the real thing, and not
1144// something picked up on $PATH.
1145//
1146// 3. If for any reason xauth command fails, we exit the sandbox. On Debian 8 this happens
1147// when using a network namespace. Somehow, xauth tries to connect to the abstract socket,
1148// and it fails because of the network namespace - it should try to connect to the regular
1149// Unix socket! If we ignore the fail condition, the program will be started on X server without
1150// the security extension loaded.
1151void x11_xorg(void) { 1133void x11_xorg(void) {
1152#ifdef HAVE_X11 1134#ifdef HAVE_X11
1153 1135
1136 // get DISPLAY env
1137 char *display = getenv("DISPLAY");
1138 if (!display) {
1139 fputs("Error: --x11=xorg requires an 'outer' X11 server to use.\n", stderr);
1140 exit(1);
1141 }
1142
1154 // check xauth utility is present in the system 1143 // check xauth utility is present in the system
1155 struct stat s; 1144 struct stat s;
1156 if (stat("/usr/bin/xauth", &s) == -1) { 1145 if (stat("/usr/bin/xauth", &s) == -1) {
@@ -1160,26 +1149,27 @@ void x11_xorg(void) {
1160 fprintf(stderr, " Fedora: sudo dnf install xorg-x11-xauth\n"); 1149 fprintf(stderr, " Fedora: sudo dnf install xorg-x11-xauth\n");
1161 exit(1); 1150 exit(1);
1162 } 1151 }
1163 if (s.st_uid != 0 && s.st_gid != 0) { 1152 if ((s.st_uid != 0 && s.st_gid != 0) || (s.st_mode & S_IWOTH)) {
1164 fprintf(stderr, "Error: invalid /usr/bin/xauth executable\n"); 1153 fprintf(stderr, "Error: invalid /usr/bin/xauth executable\n");
1165 exit(1); 1154 exit(1);
1166 } 1155 }
1167 1156 if (s.st_size > 1024 * 1024) {
1168 // get DISPLAY env 1157 fprintf(stderr, "Error: /usr/bin/xauth executable is too large\n");
1169 char *display = getenv("DISPLAY");
1170 if (!display) {
1171 fputs("Error: --x11=xorg requires an 'outer' X11 server to use.\n", stderr);
1172 exit(1); 1158 exit(1);
1173 } 1159 }
1174 1160 // copy /usr/bin/xauth in the sandbox and set mode to 0711
1175 // temporarily mount a tempfs on top of /tmp directory 1161 // users are not able to trace the running xauth this way
1176 if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=1777,gid=0") < 0)
1177 errExit("mounting /tmp");
1178
1179 // create the temporary .Xauthority file
1180 if (arg_debug) 1162 if (arg_debug)
1181 printf("Generating a new .Xauthority file\n"); 1163 printf("Copying /usr/bin/xauth to %s\n", RUN_XAUTH_FILE);
1182 char tmpfname[] = "/tmp/.tmpXauth-XXXXXX"; 1164 if (copy_file("/usr/bin/xauth", RUN_XAUTH_FILE, 0, 0, 0711)) {
1165 fprintf(stderr, "Error: cannot copy /usr/bin/xauth executable\n");
1166 exit(1);
1167 }
1168
1169 fmessage("Generating a new .Xauthority file\n");
1170 mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid());
1171 // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR
1172 char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX";
1183 int fd = mkstemp(tmpfname); 1173 int fd = mkstemp(tmpfname);
1184 if (fd == -1) { 1174 if (fd == -1) {
1185 fprintf(stderr, "Error: cannot create .Xauthority file\n"); 1175 fprintf(stderr, "Error: cannot create .Xauthority file\n");
@@ -1189,64 +1179,17 @@ void x11_xorg(void) {
1189 errExit("chown"); 1179 errExit("chown");
1190 close(fd); 1180 close(fd);
1191 1181
1192 pid_t child = fork(); 1182 // run xauth
1193 if (child < 0)
1194 errExit("fork");
1195 if (child == 0) {
1196 drop_privs(1);
1197 clearenv();
1198#ifdef HAVE_GCOV
1199 __gcov_flush();
1200#endif
1201 if (arg_debug) {
1202 execlp("/usr/bin/xauth", "/usr/bin/xauth", "-v", "-f", tmpfname,
1203 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL);
1204 }
1205 else {
1206 execlp("/usr/bin/xauth", "/usr/bin/xauth", "-f", tmpfname,
1207 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL);
1208 }
1209
1210 _exit(127);
1211 }
1212
1213 // wait for the xauth process to finish
1214 int status;
1215 if (waitpid(child, &status, 0) != child)
1216 errExit("waitpid");
1217 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1218 /* success */
1219 }
1220 else if (WIFEXITED(status)) {
1221 fprintf(stderr, "Failed to create untrusted X cookie: xauth: exit %d\n",
1222 WEXITSTATUS(status));
1223 exit(1);
1224 }
1225 else if (WIFSIGNALED(status)) {
1226 fprintf(stderr, "Failed to create untrusted X cookie: xauth: %s\n",
1227 strsignal(WTERMSIG(status)));
1228 exit(1);
1229 }
1230 else {
1231 fprintf(stderr, "Failed to create untrusted X cookie: "
1232 "xauth: un-decodable exit status %04x\n", status);
1233 exit(1);
1234 }
1235
1236 // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted
1237 // automatically when the sandbox is closed (rename doesn't work)
1238 if (arg_debug) 1183 if (arg_debug)
1239 printf("Copying the new .Xauthority file\n"); 1184 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 8, RUN_XAUTH_FILE, "-v", "-f", tmpfname,
1240 copy_file_from_user_to_root(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600); 1185 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted");
1241 1186 else
1242 /* coverity[toctou] */ 1187 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname,
1243 unlink(tmpfname); 1188 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted");
1244 umount("/tmp"); 1189 // remove xauth copy
1245 1190 unlink(RUN_XAUTH_FILE);
1246 // mount RUN_XAUTHORITY_SEC_FILE noexec, nodev, nosuid
1247 fs_remount(RUN_XAUTHORITY_SEC_FILE, MOUNT_NOEXEC, 0);
1248 1191
1249 // Ensure there is already a file in the usual location, so that bind-mount below will work. 1192 // ensure there is already a file ~/.Xauthority, so that bind-mount below will work.
1250 char *dest; 1193 char *dest;
1251 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) 1194 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1)
1252 errExit("asprintf"); 1195 errExit("asprintf");
@@ -1257,13 +1200,12 @@ void x11_xorg(void) {
1257 exit(1); 1200 exit(1);
1258 } 1201 }
1259 } 1202 }
1260 1203 // get a file descriptor for ~/.Xauthority
1261 // get a file descriptor for .Xauthority 1204 int dst = safe_fd(dest, O_PATH|O_NOFOLLOW|O_CLOEXEC);
1262 fd = safe_fd(dest, O_PATH|O_NOFOLLOW|O_CLOEXEC); 1205 if (dst == -1)
1263 if (fd == -1)
1264 errExit("safe_fd"); 1206 errExit("safe_fd");
1265 // check if the actual mount destination is a user owned regular file 1207 // check if the actual mount destination is a user owned regular file
1266 if (fstat(fd, &s) == -1) 1208 if (fstat(dst, &s) == -1)
1267 errExit("fstat"); 1209 errExit("fstat");
1268 if (!S_ISREG(s.st_mode) || s.st_uid != getuid()) { 1210 if (!S_ISREG(s.st_mode) || s.st_uid != getuid()) {
1269 if (S_ISLNK(s.st_mode)) 1211 if (S_ISLNK(s.st_mode))
@@ -1274,31 +1216,49 @@ void x11_xorg(void) {
1274 } 1216 }
1275 // preserve a read-only mount 1217 // preserve a read-only mount
1276 struct statvfs vfs; 1218 struct statvfs vfs;
1277 if (fstatvfs(fd, &vfs) == -1) 1219 if (fstatvfs(dst, &vfs) == -1)
1278 errExit("fstatvfs"); 1220 errExit("fstatvfs");
1279 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY) 1221 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY)
1280 fs_remount(RUN_XAUTHORITY_SEC_FILE, MOUNT_READONLY, 0); 1222 fs_remount(RUN_XAUTHORITY_SEC_DIR, MOUNT_READONLY, 0);
1223
1224 // always mounting the new Xauthority file noexec,nodev,nosuid
1225 fs_remount(RUN_XAUTHORITY_SEC_DIR, MOUNT_NOEXEC, 0);
1226
1227 // get a file descriptor for the new Xauthority file
1228 int src = safe_fd(tmpfname, O_PATH|O_NOFOLLOW|O_CLOEXEC);
1229 if (src == -1)
1230 errExit("safe_fd");
1231 if (fstat(src, &s) == -1)
1232 errExit("fstat");
1233 if (!S_ISREG(s.st_mode)) {
1234 errno = EPERM;
1235 errExit("mounting Xauthority file");
1236 }
1281 1237
1282 // mount via the link in /proc/self/fd 1238 // mount via the link in /proc/self/fd
1283 if (arg_debug) 1239 if (arg_debug)
1284 printf("Mounting %s on %s\n", RUN_XAUTHORITY_SEC_FILE, dest); 1240 printf("Mounting %s on %s\n", tmpfname, dest);
1285 char *proc; 1241 char *proc_src, *proc_dst;
1286 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 1242 if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1)
1243 errExit("asprintf");
1244 if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1)
1287 errExit("asprintf"); 1245 errExit("asprintf");
1288 if (mount(RUN_XAUTHORITY_SEC_FILE, proc, "none", MS_BIND, "mode=0600") == -1) { 1246 if (mount(proc_src, proc_dst, NULL, MS_BIND, NULL) == -1) {
1289 fprintf(stderr, "Error: cannot mount the new .Xauthority file\n"); 1247 fprintf(stderr, "Error: cannot mount the new .Xauthority file\n");
1290 exit(1); 1248 exit(1);
1291 } 1249 }
1292 free(proc);
1293 close(fd);
1294 // check /proc/self/mountinfo to confirm the mount is ok 1250 // check /proc/self/mountinfo to confirm the mount is ok
1295 MountData *mptr = get_last_mount(); 1251 MountData *mptr = get_last_mount();
1296 if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) 1252 if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
1297 errLogExit("invalid .Xauthority mount"); 1253 errLogExit("invalid .Xauthority mount");
1254 free(proc_src);
1255 free(proc_dst);
1256 close(src);
1257 close(dst);
1298 1258
1299 ASSERT_PERMS(dest, getuid(), getgid(), 0600); 1259 ASSERT_PERMS(dest, getuid(), getgid(), 0600);
1300 1260
1301 // blacklist .Xauthority file if it is not masked already 1261 // blacklist user .Xauthority file if it is not masked already
1302 char *envar = getenv("XAUTHORITY"); 1262 char *envar = getenv("XAUTHORITY");
1303 if (envar) { 1263 if (envar) {
1304 char *rp = realpath(envar, NULL); 1264 char *rp = realpath(envar, NULL);
@@ -1312,6 +1272,11 @@ void x11_xorg(void) {
1312 if (setenv("XAUTHORITY", dest, 1) < 0) 1272 if (setenv("XAUTHORITY", dest, 1) < 0)
1313 errExit("setenv"); 1273 errExit("setenv");
1314 free(dest); 1274 free(dest);
1275
1276 // mask RUN_XAUTHORITY_SEC_DIR
1277 if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
1278 errExit("mounting tmpfs");
1279 fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR);
1315#endif 1280#endif
1316} 1281}
1317 1282
diff --git a/src/include/rundefs.h b/src/include/rundefs.h
index f8bcdec52..d56623907 100644
--- a/src/include/rundefs.h
+++ b/src/include/rundefs.h
@@ -99,8 +99,9 @@
99#define RUN_WHITELIST_SHARE_DIR RUN_MNT_DIR "/orig-share" 99#define RUN_WHITELIST_SHARE_DIR RUN_MNT_DIR "/orig-share"
100#define RUN_WHITELIST_MODULE_DIR RUN_MNT_DIR "/orig-module" 100#define RUN_WHITELIST_MODULE_DIR RUN_MNT_DIR "/orig-module"
101 101
102#define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" 102#define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" // private options
103#define RUN_XAUTHORITY_SEC_FILE RUN_MNT_DIR "/sec.Xauthority" 103#define RUN_XAUTH_FILE RUN_MNT_DIR "/xauth" // x11=xorg
104#define RUN_XAUTHORITY_SEC_DIR RUN_MNT_DIR "/.sec.Xauthority" // x11=xorg
104#define RUN_ASOUNDRC_FILE RUN_MNT_DIR "/.asoundrc" 105#define RUN_ASOUNDRC_FILE RUN_MNT_DIR "/.asoundrc"
105#define RUN_HOSTNAME_FILE RUN_MNT_DIR "/hostname" 106#define RUN_HOSTNAME_FILE RUN_MNT_DIR "/hostname"
106#define RUN_HOSTS_FILE RUN_MNT_DIR "/hosts" 107#define RUN_HOSTS_FILE RUN_MNT_DIR "/hosts"