2023-06-15 14:33:49 +08:00
|
|
|
From acb72212eb41ca862b8bc29b0106a46a83297fcb Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: David Gibson <david@gibson.dropbear.id.au>
|
|
|
|
|
Date: Wed, 29 Mar 2023 13:36:15 +1100
|
|
|
|
|
Subject: [PATCH] unshare: Move implementation of --keep-caps option to library
|
|
|
|
|
function
|
|
|
|
|
|
|
|
|
|
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 | 2 ++
|
|
|
|
|
lib/caputils.c | 38 ++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
sys-utils/unshare.c | 38 ++------------------------------------
|
|
|
|
|
3 files changed, 42 insertions(+), 36 deletions(-)
|
|
|
|
|
|
|
|
|
|
diff --git a/include/caputils.h b/include/caputils.h
|
2023-07-18 16:39:47 +08:00
|
|
|
index 852903a6e..8fc214e7f 100644
|
2023-06-15 14:33:49 +08:00
|
|
|
--- a/include/caputils.h
|
|
|
|
|
+++ b/include/caputils.h
|
|
|
|
|
@@ -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 */
|
|
|
|
|
diff --git a/lib/caputils.c b/lib/caputils.c
|
2023-07-18 16:39:47 +08:00
|
|
|
index 987533a34..3041c3078 100644
|
2023-06-15 14:33:49 +08:00
|
|
|
--- a/lib/caputils.c
|
|
|
|
|
+++ b/lib/caputils.c
|
|
|
|
|
@@ -24,6 +24,7 @@
|
|
|
|
|
#include "caputils.h"
|
|
|
|
|
#include "pathnames.h"
|
2023-07-18 16:39:47 +08:00
|
|
|
#include "procfs.h"
|
2023-06-15 14:33:49 +08:00
|
|
|
+#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[])
|
|
|
|
|
{
|
|
|
|
|
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
|
2023-07-18 16:39:47 +08:00
|
|
|
index 2aa239eff..13aefa96c 100644
|
2023-06-15 14:33:49 +08:00
|
|
|
--- a/sys-utils/unshare.c
|
|
|
|
|
+++ b/sys-utils/unshare.c
|
2023-07-18 16:39:47 +08:00
|
|
|
@@ -1089,42 +1089,8 @@ int main(int argc, char *argv[])
|
2023-06-15 14:33:49 +08:00
|
|
|
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);
|
|
|
|
|
--
|
|
|
|
|
2.33.0
|
|
|
|
|
|