]> skyeroc.xyz Git - dgamelaunch/commitdiff
Add support for Linux namespaces
authorRon Nazarov <ron@noisytoot.org>
Wed, 27 Nov 2024 00:41:20 +0000 (00:41 +0000)
committerRon Nazarov <ron@noisytoot.org>
Wed, 27 Nov 2024 00:41:20 +0000 (00:41 +0000)
If compiled with --enable-namespaces, dgamelaunch will now create new
user and network namespaces before chrooting.  This means that it
works without root (if unprivileged user namespaces are enabled) and
cannot access the network.

Without namespaces:
-chroot
-setgroups/setgid/setuid to shed_gid/shed_uid

With namespaces:
-unshare to create a new user and network namespace
-write to /proc/self/{uid,gid}_map to set uid/gid to shed_uid/shed_gid
-chroot
-drop all capabilities

configure.ac
dgamelaunch.c

index 5008dc927749847f7f3e235f11bbd87b7f59a23d..8935a2ded09bdb69b8ed3c40876c02168bb4643b 100644 (file)
@@ -165,6 +165,19 @@ if test "$enable_shmem" = yes; then
 fi
 
 
+AC_ARG_ENABLE(namespaces,
+[AS_HELP_STRING([--enable-namespaces],[Use Linux namespaces.])],
+[enable_namespaces=yes], [])
+
+if test "$enable_namespaces" = yes; then
+   AC_CHECK_HEADERS([sched.h], [], [AC_MSG_ERROR([sched.h not found.])], [])
+   AC_CHECK_HEADERS([sys/capability.h], [], [AC_MSG_ERROR([sys/capability.h not found.])], [])
+   AC_CHECK_LIB(cap, cap_get_proc, [LIBS+=" -lcap"], [AC_MSG_ERROR([Cannot find libcap.])])
+   AC_MSG_RESULT([Enabled Linux namespace support.])
+   AC_DEFINE(USE_NAMESPACES,1,[Use Linux namespaces])
+fi
+
+
 AC_ARG_WITH(config-file,
 [AS_HELP_STRING([--with-config-file=PATH],[Define the path to the default configuration file.])],
 [configfile=$withval], [configfile="/etc/dgamelaunch.conf"])
index 2a6dfd88bbf131dde0a0a9d9bfd3c8097dbca175..3165280e0fb6889df130a836b9c73f0d2ec80a19 100644 (file)
 # include <pty.h>
 #endif
 
+#ifdef USE_NAMESPACES
+# include <sched.h>
+# include <sys/capability.h>
+#endif
+
 #include <fcntl.h>
 #include <pwd.h>
 #include <grp.h>
@@ -2949,6 +2954,32 @@ runmenuloop(struct dg_menu *menu)
     }
 }
 
+#ifdef USE_NAMESPACES
+void
+write_proc_maps(uid_t uid, gid_t gid)
+{
+  FILE *fp;
+
+  fp = fopen("/proc/self/setgroups", "w");
+  if (fp) {
+    fprintf(fp, "deny");
+    fclose(fp);
+  } else perror("fopen setgroups");
+
+  fp = fopen("/proc/self/uid_map", "w");
+  if (fp) {
+    fprintf(fp, "%d %d 1", globalconfig.shed_uid, uid);
+    fclose(fp);
+  } else perror("fopen uid_map");
+
+  fp = fopen("/proc/self/gid_map", "w");
+  if (fp) {
+    fprintf(fp, "%d %d 1", globalconfig.shed_gid, gid);
+    fclose(fp);
+  } else perror("fopen gid_map");
+}
+#endif
+
 int
 main (int argc, char** argv)
 {
@@ -3114,7 +3145,21 @@ main (int argc, char** argv)
 #endif
 #endif
 
+#ifdef USE_NAMESPACES
+  {
+    uid_t uid = geteuid();
+    gid_t gid = getegid();
+    if (unshare(CLONE_NEWUSER | CLONE_NEWNET)) {
+      perror("unshare");
+      graceful_exit(14);
+    }
+    write_proc_maps(uid, gid);
+  }
+#endif
+
+#ifndef USE_NAMESPACES
   if (geteuid () != globalconfig.shed_uid)
+#endif
     {
       /* chroot */
       if (chroot (globalconfig.chroot))
@@ -3134,6 +3179,15 @@ main (int argc, char** argv)
         }
 
       /* shed privs. this is done immediately after chroot. */
+#ifdef USE_NAMESPACES
+      {
+        /* drop all capabilities */
+        cap_t cap = cap_get_proc();
+        cap_clear(cap);
+        cap_set_proc(cap);
+        cap_free(cap);
+      }
+#else
       if (setgroups (1, &globalconfig.shed_gid) == -1)
        {
          perror ("setgroups");
@@ -3151,6 +3205,7 @@ main (int argc, char** argv)
          perror ("setuid");
          graceful_exit (6);
        }
+#endif
     }
 
   if (globalconfig.locale) {