diff --git a/base-linux/run/lx_uid.run b/base-linux/run/lx_uid.run
new file mode 100644
index 0000000000..2512e37157
--- /dev/null
+++ b/base-linux/run/lx_uid.run
@@ -0,0 +1,101 @@
+#
+# \brief Test for assigning custom UIDs and GIDs to Genode processes
+# \author Norman Feske
+# \date 2012-11-21
+#
+
+build "core init test/printf"
+
+assert_spec linux
+
+create_boot_directory
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+#
+# Copy boot modules into run directory
+#
+# We cannot use the predefined 'build_boot_image' function here because
+# this would create mere symlinks. However, we need to enable the setuid
+# and setgid capabilities for core, which won't work if core were a symlink.
+#
+foreach binary { core init } {
+ exec cp -H bin/$binary [run_dir] }
+
+#
+# Allow core to set arbitrary UIDs and GIDs
+#
+exec sudo setcap cap_setuid,cap_setgid=ep [run_dir]/core
+
+#
+# Execute Genode until the point where init_sub_77 is up
+#
+run_genode_until {\[init -> init_77 -> init_sub_77\].*No children to start.*\n} 10
+
+#
+# Obtain the list of Genode user processes starting with the name 'init'
+#
+set ps_output [exec ps -eo uid,gid,cmd | grep Genode | grep init]
+
+puts "Genode user processes:\n$ps_output"
+
+#
+# Validate output of ps
+#
+# We are only interested in the lines for the init instances with the
+# customized UIDs and GIDs.
+#
+if {![regexp {55\s*66 \[Genode\] init_55_66} $ps_output]
+ || ![regexp {77\s*77 \[Genode\] init_77} $ps_output]
+ || ![regexp {77\s*77 \[Genode\] init_77 -> init_sub_77} $ps_output]} {
+ puts stderr "Unexpected output of ps"
+ exit 1
+}
+
+puts "Test succeeded"
+
diff --git a/base-linux/src/core/include/core_linux_syscalls.h b/base-linux/src/core/include/core_linux_syscalls.h
index 6897bb1ccd..2bf00b00d2 100644
--- a/base-linux/src/core/include/core_linux_syscalls.h
+++ b/base-linux/src/core/include/core_linux_syscalls.h
@@ -72,11 +72,6 @@ inline int lx_execve(const char *filename, char *const argv[],
}
-/**
- * Send signal to process
- *
- * This function is used by core to kill processes.
- */
inline int lx_kill(int pid, int signal)
{
return lx_syscall(SYS_kill, pid, signal);
@@ -90,6 +85,18 @@ inline int lx_create_process(int (*entry)(void *), void *stack, void *arg)
}
+inline int lx_setuid(unsigned int uid)
+{
+ return lx_syscall(SYS_setuid, uid);
+}
+
+
+inline int lx_setgid(unsigned int gid)
+{
+ return lx_syscall(SYS_setgid, gid);
+}
+
+
/*********************
** Chroot handling **
*********************/
diff --git a/base-linux/src/core/pd_session_component.cc b/base-linux/src/core/pd_session_component.cc
index 0ec0fc18a0..9c565a4ee0 100644
--- a/base-linux/src/core/pd_session_component.cc
+++ b/base-linux/src/core/pd_session_component.cc
@@ -195,11 +195,25 @@ static bool setup_chroot_environment(char const *chroot_path)
*/
struct Execve_args
{
- char const *filename;
- char const *root;
- char *const *argv;
- char *const *envp;
- int parent_sd;
+ char const *filename;
+ char const *root;
+ char * const *argv;
+ char * const *envp;
+ unsigned int const uid;
+ unsigned int const gid;
+ int const parent_sd;
+
+ Execve_args(char const *filename,
+ char const *root,
+ char * const *argv,
+ char * const *envp,
+ unsigned int uid,
+ unsigned int gid,
+ int parent_sd)
+ :
+ filename(filename), root(root), argv(argv), envp(envp),
+ uid(uid), gid(gid), parent_sd(parent_sd)
+ { }
};
@@ -242,6 +256,25 @@ static int _exec_child(Execve_args *arg)
}
}
+ /*
+ * Set UID and GID
+ *
+ * We must set the GID prior setting the UID because setting the GID won't
+ * be possible anymore once we set the UID to non-root.
+ */
+ if (arg->gid) {
+ int const ret = lx_setgid(arg->gid);
+ if (ret)
+ PWRN("Could not set PID %d (%s) to GID %u (error %d)",
+ lx_getpid(), arg->filename, arg->gid, ret);
+ }
+ if (arg->uid) {
+ int const ret = lx_setuid(arg->uid);
+ if (ret)
+ PWRN("Could not set PID %d (%s) to UID %u (error %d)",
+ lx_getpid(), arg->filename, arg->uid, ret);
+ }
+
return lx_execve(arg->filename, arg->argv, arg->envp);
}
@@ -289,6 +322,15 @@ Pd_session_component::Pd_session_component(Rpc_entrypoint *ep, const char *args)
bool const is_chroot = (Genode::strcmp(_root, "") != 0);
+ /*
+ * If a UID is specified but no GID, we use the UID as GID. This way, a
+ * configuration error where the UID is defined but the GID is left
+ * undefined won't result in the execution of the new process with the
+ * root user's GID.
+ */
+ if (_gid == 0)
+ _gid = _uid;
+
/*
* Print Linux-specific session arguments if specified
*
@@ -375,7 +417,8 @@ void Pd_session_component::start(Capability binary)
* Argument frame as passed to 'clone'. Because, we can only pass a single
* pointer, all arguments are embedded within the 'execve_args' struct.
*/
- Execve_args arg = { filename.buf, _root, argv_buf, env, _parent.dst().socket };
+ Execve_args arg(filename.buf, _root, argv_buf, env, _uid, _gid,
+ _parent.dst().socket);
_pid = lx_create_process((int (*)(void *))_exec_child,
stack + STACK_SIZE - sizeof(umword_t), &arg);
diff --git a/os/src/test/chroot_loader/target.mk b/os/src/test/chroot_loader/target.mk
index b59705e964..0c2900720e 100644
--- a/os/src/test/chroot_loader/target.mk
+++ b/os/src/test/chroot_loader/target.mk
@@ -1,3 +1,4 @@
-TARGET = test-chroot_loader
-SRC_CC = main.cc
-LIBS += cxx env
+TARGET = test-chroot_loader
+REQUIRES += linux
+SRC_CC = main.cc
+LIBS += cxx env