1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
Index: docs/capng_lock.3
===================================================================
--- a/docs/capng_lock.3 (revision 55)
+++ b/docs/capng_lock.3 (working copy)
@@ -8,12 +8,13 @@
.SH "DESCRIPTION"
-capng_lock will take steps to prevent children of the current process to regain full privileges if the uid is 0. This should be called while possessing the CAP_SETPCAP capability in the kernel. This function will do the following if permitted by the kernel: Set the NOROOT option on for PR_SET_SECUREBITS, set the NOROOT_LOCKED option to on for PR_SET_SECUREBITS, set the PR_NO_SETUID_FIXUP option on for PR_SET_SECUREBITS, and set the PR_NO_SETUID_FIXUP_LOCKED option on for PR_SET_SECUREBITS.
+capng_lock will take steps to prevent children of the current process from gaining privileges by executing setuid programs. This should be called while possessing the CAP_SETPCAP capability in the kernel.
+This function will do the following if permitted by the kernel: If the kernel supports PR_SET_NO_NEW_PRIVS, it will use it. Otherwise it will set the NOROOT option on for PR_SET_SECUREBITS, set the NOROOT_LOCKED option to on for PR_SET_SECUREBITS, set the PR_NO_SETUID_FIXUP option on for PR_SET_SECUREBITS, and set the PR_NO_SETUID_FIXUP_LOCKED option on for PR_SET_SECUREBITS. If both fail, it will return an error.
.SH "RETURN VALUE"
-This returns 0 on success and a negative number on failure. -1 means a failure setting any of the PR_SET_SECUREBITS options.
+This returns 0 on success and a negative number on failure. -1 means a failure to use PR_SET_NO_NEW_PRIVS and a failure setting any of the PR_SET_SECUREBITS options.
.SH "SEE ALSO"
Index: src/cap-ng.c
===================================================================
--- a/src/cap-ng.c (revision 55)
+++ b/src/cap-ng.c (working copy)
@@ -49,6 +49,7 @@
* 2.6.24 kernel XATTR_NAME_CAPS
* 2.6.25 kernel PR_CAPBSET_DROP, CAPABILITY_VERSION_2
* 2.6.26 kernel PR_SET_SECUREBITS, SECURE_*_LOCKED, VERSION_3
+ * 3.5 kernel PR_SET_NO_NEW_PRIVS
*/
/* External syscall prototypes */
@@ -126,6 +127,14 @@
#define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */
#endif
+/* prctl values that we use */
+#ifndef PR_SET_SECUREBITS
+#define PR_SET_SECUREBITS 28
+#endif
+#ifndef PR_SET_NO_NEW_PRIVS
+#define PR_SET_NO_NEW_PRIVS 38
+#endif
+
// States: new, allocated, initted, updated, applied
typedef enum { CAPNG_NEW, CAPNG_ERROR, CAPNG_ALLOCATED, CAPNG_INIT,
CAPNG_UPDATED, CAPNG_APPLIED } capng_states_t;
@@ -703,15 +712,22 @@
int capng_lock(void)
{
-#ifdef PR_SET_SECUREBITS
- int rc = prctl(PR_SET_SECUREBITS,
- 1 << SECURE_NOROOT |
- 1 << SECURE_NOROOT_LOCKED |
- 1 << SECURE_NO_SETUID_FIXUP |
- 1 << SECURE_NO_SETUID_FIXUP_LOCKED, 0, 0, 0);
+ int rc;
+
+ // On Linux 3.5 and up, we can directly prevent ourselves and
+ // our descendents from gaining privileges.
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0)
+ return 0;
+
+ // This kernel is too old or otherwise doesn't support
+ // PR_SET_NO_NEW_PRIVS. Fall back to using securebits.
+ rc = prctl(PR_SET_SECUREBITS,
+ 1 << SECURE_NOROOT |
+ 1 << SECURE_NOROOT_LOCKED |
+ 1 << SECURE_NO_SETUID_FIXUP |
+ 1 << SECURE_NO_SETUID_FIXUP_LOCKED, 0, 0, 0);
if (rc)
return -1;
-#endif
return 0;
}
|