From 52cf6045c0ce521228ea893748189fca8dc42199 Mon Sep 17 00:00:00 2001 From: Ron Nazarov Date: Wed, 27 Nov 2024 00:41:20 +0000 Subject: [PATCH] Add support for Linux namespaces 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 | 13 ++++++++++++ dgamelaunch.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/configure.ac b/configure.ac index 5008dc9..8935a2d 100644 --- a/configure.ac +++ b/configure.ac @@ -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"]) diff --git a/dgamelaunch.c b/dgamelaunch.c index 2a6dfd8..3165280 100644 --- a/dgamelaunch.c +++ b/dgamelaunch.c @@ -80,6 +80,11 @@ # include #endif +#ifdef USE_NAMESPACES +# include +# include +#endif + #include #include #include @@ -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) { -- 2.47.3