From 48f6f9254dc04350c15a136dd94487400f34dfb5 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 11 Oct 2018 12:38:10 +0200 Subject: rootless: fix an hang on older versions of setresuid/setresgid the issue is caused by the Go Runtime that messes up with the process signals, overriding SIGSETXID and SIGCANCEL which are used internally by glibc. They are used to inform all the threads to update their stored uid/gid information. This causes a hang on the set*id glibc wrappers since the handler installed by glibc is never invoked. Since we are running with only one thread, we don't really need to update other threads or even the current thread as we are not using getuid/getgid before the execvp. Closes: https://github.com/containers/libpod/issues/1625 Signed-off-by: Giuseppe Scrivano --- pkg/rootless/rootless_linux.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'pkg') diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index d78d95453..034a410bd 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -12,6 +12,18 @@ #include #include +static int +syscall_setresuid (uid_t ruid, uid_t euid, uid_t suid) +{ + return (int) syscall (__NR_setresuid, ruid, euid, suid); +} + +static int +syscall_setresgid (gid_t rgid, gid_t egid, gid_t sgid) +{ + return (int) syscall (__NR_setresgid, rgid, egid, sgid); +} + static int syscall_clone (unsigned long flags, void *child_stack) { @@ -107,8 +119,8 @@ reexec_userns_join (int userns) _exit (EXIT_FAILURE); close (userns); - if (setresgid (0, 0, 0) < 0 || - setresuid (0, 0, 0) < 0) + if (syscall_setresgid (0, 0, 0) < 0 || + syscall_setresuid (0, 0, 0) < 0) _exit (EXIT_FAILURE); execvp (argv[0], argv); @@ -146,8 +158,10 @@ reexec_in_user_namespace (int ready) _exit (EXIT_FAILURE); close (ready); - if (setresgid (0, 0, 0) < 0 || - setresuid (0, 0, 0) < 0) + if (syscall_setresgid (0, 0, 0) < 0) + _exit (EXIT_FAILURE); + + if (syscall_setresuid (0, 0, 0) < 0) _exit (EXIT_FAILURE); execvp (argv[0], argv); -- cgit v1.2.3-54-g00ecf From 2933c3b98061534f27626bf99be9d6afc65b37f8 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 11 Oct 2018 12:53:04 +0200 Subject: rootless: report more error messages from the startup phase Signed-off-by: Giuseppe Scrivano --- pkg/rootless/rootless_linux.c | 49 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'pkg') diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 034a410bd..11c3c32f0 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -11,6 +11,7 @@ #include #include #include +#include static int syscall_setresuid (uid_t ruid, uid_t euid, uid_t suid) @@ -106,9 +107,14 @@ reexec_userns_join (int userns) argv = get_cmd_line_args (ppid); if (argv == NULL) - _exit (EXIT_FAILURE); + { + fprintf (stderr, "cannot read argv: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } pid = fork (); + if (pid < 0) + fprintf (stderr, "cannot fork: %s\n", strerror (errno)); if (pid) return pid; @@ -116,12 +122,23 @@ reexec_userns_join (int userns) setenv ("_LIBPOD_ROOTLESS_UID", uid, 1); if (setns (userns, 0) < 0) - _exit (EXIT_FAILURE); + { + fprintf (stderr, "cannot setns: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } close (userns); - if (syscall_setresgid (0, 0, 0) < 0 || - syscall_setresuid (0, 0, 0) < 0) - _exit (EXIT_FAILURE); + if (syscall_setresgid (0, 0, 0) < 0) + { + fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (syscall_setresuid (0, 0, 0) < 0) + { + fprintf (stderr, "cannot setresuid: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } execvp (argv[0], argv); @@ -141,12 +158,17 @@ reexec_in_user_namespace (int ready) sprintf (uid, "%d", geteuid ()); pid = syscall_clone (CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL); + if (pid < 0) + fprintf (stderr, "cannot clone: %s\n", strerror (errno)); if (pid) return pid; argv = get_cmd_line_args (ppid); if (argv == NULL) - _exit (EXIT_FAILURE); + { + fprintf (stderr, "cannot read argv: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } setenv ("_LIBPOD_USERNS_CONFIGURED", "init", 1); setenv ("_LIBPOD_ROOTLESS_UID", uid, 1); @@ -155,14 +177,23 @@ reexec_in_user_namespace (int ready) ret = read (ready, &b, 1) < 0; while (ret < 0 && errno == EINTR); if (ret < 0) - _exit (EXIT_FAILURE); + { + fprintf (stderr, "cannot read from sync pipe: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } close (ready); if (syscall_setresgid (0, 0, 0) < 0) - _exit (EXIT_FAILURE); + { + fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } if (syscall_setresuid (0, 0, 0) < 0) - _exit (EXIT_FAILURE); + { + fprintf (stderr, "cannot setresuid: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } execvp (argv[0], argv); -- cgit v1.2.3-54-g00ecf From 55c9b03bafebac0c388966f6c1834108de42f4a6 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 11 Oct 2018 15:17:18 +0200 Subject: rootless: detect when user namespaces are not enabled Signed-off-by: Giuseppe Scrivano --- pkg/rootless/rootless_linux.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'pkg') diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 11c3c32f0..9eb16c1a5 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -13,6 +13,9 @@ #include #include +static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces"; +static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone"; + static int syscall_setresuid (uid_t ruid, uid_t euid, uid_t suid) { @@ -145,6 +148,25 @@ reexec_userns_join (int userns) _exit (EXIT_FAILURE); } +static void +check_proc_sys_userns_file (const char *path) +{ + FILE *fp; + fp = fopen (path, "r"); + if (fp) + { + char buf[32]; + size_t n_read = fread (buf, 1, sizeof(buf) - 1, fp); + if (n_read > 0) + { + buf[n_read] = '\0'; + if (strtol (buf, NULL, 10) == 0) + fprintf (stderr, "user namespaces are not enabled in %s\n", path); + } + fclose (fp); + } +} + int reexec_in_user_namespace (int ready) { @@ -159,7 +181,12 @@ reexec_in_user_namespace (int ready) pid = syscall_clone (CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL); if (pid < 0) - fprintf (stderr, "cannot clone: %s\n", strerror (errno)); + { + FILE *fp; + fprintf (stderr, "cannot clone: %s\n", strerror (errno)); + check_proc_sys_userns_file (_max_user_namespaces); + check_proc_sys_userns_file (_unprivileged_user_namespaces); + } if (pid) return pid; -- cgit v1.2.3-54-g00ecf