]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
unshare: Move implementation of --keep-caps option to library function
authorDavid Gibson <david@gibson.dropbear.id.au>
Wed, 29 Mar 2023 02:36:15 +0000 (13:36 +1100)
committerDavid Gibson <david@gibson.dropbear.id.au>
Wed, 29 Mar 2023 02:36:15 +0000 (13:36 +1100)
unshare.c open codes some logic to copy the permitted capability set to the
ambient set in order to implement the --keep-caps option.  Move this logic
to lib/caputils.c so that we can reuse it in nsenter.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
include/caputils.h
lib/caputils.c
sys-utils/unshare.c

index 852903a6ee5e22fa5c787daec2a23787ee274494..8fc214e7fc5b4697422263553ef984924781e2db 100644 (file)
@@ -31,4 +31,6 @@ extern int capget(cap_user_header_t header, const cap_user_data_t data);
 
 extern int cap_last_cap(void);
 
+extern void cap_permitted_to_ambient(void);
+
 #endif /* CAPUTILS_H */
index 987533a34392e9443852430d969327f0f91bc120..3041c3078341048ee5ef0adf38139311187e5f74 100644 (file)
@@ -24,6 +24,7 @@
 #include "caputils.h"
 #include "pathnames.h"
 #include "procfs.h"
+#include "nls.h"
 
 static int test_cap(unsigned int cap)
 {
@@ -87,6 +88,43 @@ int cap_last_cap(void)
        return cap;
 }
 
+void cap_permitted_to_ambient(void)
+{
+       /* We use capabilities system calls to propagate the permitted
+        * capabilities into the ambient set because we may have
+        * already forked so be in async-signal-safe context. */
+       struct __user_cap_header_struct header = {
+               .version = _LINUX_CAPABILITY_VERSION_3,
+               .pid = 0,
+       };
+       struct __user_cap_data_struct payload[_LINUX_CAPABILITY_U32S_3] = {{ 0 }};
+       uint64_t effective, cap;
+
+       if (capget(&header, payload) < 0)
+               err(EXIT_FAILURE, _("capget failed"));
+
+       /* In order the make capabilities ambient, we first need to ensure
+        * that they are all inheritable. */
+       payload[0].inheritable = payload[0].permitted;
+       payload[1].inheritable = payload[1].permitted;
+
+       if (capset(&header, payload) < 0)
+               err(EXIT_FAILURE, _("capset failed"));
+
+       effective = ((uint64_t)payload[1].effective << 32) |  (uint64_t)payload[0].effective;
+
+       for (cap = 0; cap < (sizeof(effective) * 8); cap++) {
+               /* This is the same check as cap_valid(), but using
+                * the runtime value for the last valid cap. */
+               if (cap > (uint64_t) cap_last_cap())
+                       continue;
+
+               if ((effective & (1 << cap))
+                   && prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0)
+                       err(EXIT_FAILURE, _("prctl(PR_CAP_AMBIENT) failed"));
+       }
+}
+
 #ifdef TEST_PROGRAM_CAPUTILS
 int main(int argc, char *argv[])
 {
index 2aa239eff006494f3acc03781b0c7180bd8c6539..13aefa96c42338d70b902cd341b16df44fd3a43e 100644 (file)
@@ -1089,42 +1089,8 @@ int main(int argc, char *argv[])
        if (force_uid && setuid(uid) < 0)       /* change UID */
                err(EXIT_FAILURE, _("setuid failed"));
 
-       /* We use capabilities system calls to propagate the permitted
-        * capabilities into the ambient set because we have already
-        * forked so are in async-signal-safe context. */
-       if (keepcaps && (unshare_flags & CLONE_NEWUSER)) {
-               struct __user_cap_header_struct header = {
-                       .version = _LINUX_CAPABILITY_VERSION_3,
-                       .pid = 0,
-               };
-
-               struct __user_cap_data_struct payload[_LINUX_CAPABILITY_U32S_3] = {{ 0 }};
-               uint64_t effective, cap;
-
-               if (capget(&header, payload) < 0)
-                       err(EXIT_FAILURE, _("capget failed"));
-
-               /* In order the make capabilities ambient, we first need to ensure
-                * that they are all inheritable. */
-               payload[0].inheritable = payload[0].permitted;
-               payload[1].inheritable = payload[1].permitted;
-
-               if (capset(&header, payload) < 0)
-                       err(EXIT_FAILURE, _("capset failed"));
-
-               effective = ((uint64_t)payload[1].effective << 32) |  (uint64_t)payload[0].effective;
-
-               for (cap = 0; cap < (sizeof(effective) * 8); cap++) {
-                       /* This is the same check as cap_valid(), but using
-                        * the runtime value for the last valid cap. */
-                       if (cap > (uint64_t) cap_last_cap())
-                               continue;
-
-                       if ((effective & (1 << cap))
-                           && prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0)
-                                       err(EXIT_FAILURE, _("prctl(PR_CAP_AMBIENT) failed"));
-                }
-        }
+       if (keepcaps && (unshare_flags & CLONE_NEWUSER))
+               cap_permitted_to_ambient();
 
        if (optind < argc) {
                execvp(argv[optind], argv + optind);