aboutsummaryrefslogtreecommitdiffstats
path: root/main/libcap-ng/apply.patch
blob: 5fb9f189c095b7d0f31a8fb8bc60181584d81638 (plain) (blame)
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
From fda0224fea4f01b77bd07ac195b3baaaf1a28fca Mon Sep 17 00:00:00 2001
From: Steve Grubb <sgrubb@redhat.com>
Date: Fri, 20 Nov 2020 14:01:33 -0500
Subject: [PATCH] In capng_apply, allow continuing in spite of errors

In capng_apply, if we blow up trying to adjust the bounding set without
proper permissions, continue into the capabilities in case they called
with SELECT_BOTH and they don't bother checking the return code. This
will at least leave the application in a potentially safer state.
---
 src/cap-ng.c | 56 +++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 42 insertions(+), 14 deletions(-)

diff --git a/src/cap-ng.c b/src/cap-ng.c
index a9de370..1474326 100644
--- a/src/cap-ng.c
+++ b/src/cap-ng.c
@@ -680,6 +680,8 @@ int capng_updatev(capng_act_t action, capng_type_t type,
 
 int capng_apply(capng_select_t set)
 {
+	int rc = 0;
+
 	// Before updating, we expect that the data is initialized to something
 	if (m.state < CAPNG_INIT)
 		return -1;
@@ -695,52 +697,78 @@ int capng_apply(capng_select_t set)
 			for (i=0; i <= last_cap; i++) {
 				if (capng_have_capability(CAPNG_BOUNDING_SET,
 								 i) == 0) {
-				    if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) <0)
-					return -2;
+				    if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) <0) {
+					rc = -2;
+					goto try_caps;
+				    }
 				}
 			}
 			m.state = CAPNG_APPLIED;
-			if (get_bounding_set() < 0)
-				return -3;
+			if (get_bounding_set() < 0) {
+				rc = -3;
+				goto try_caps;
+			}
 		} else {
 			memcpy(&m, &state, sizeof(m)); /* restore state */
-			return -4;
+			rc = -4;
+			goto try_caps;
 		}
 #endif
 	}
+
+	// Try caps is here so that if someone had SELECT_BOTH and we blew up
+	// doing the bounding set, we at least try to set any capabilities
+	// before returning in case the caller also doesn't bother checking
+	// the return code.
+try_caps:
 	if (set & CAPNG_SELECT_CAPS) {
 		if (capset((cap_user_header_t)&m.hdr,
 				(cap_user_data_t)&m.data) == 0)
 			m.state = CAPNG_APPLIED;
 		else
-			return -5;
+			rc = -5;
 	}
-	// Put ambient last so that inheritable and permitted are set
+
+	// Most programs do not and should not mess with ambient capabilities.
+	// Instead of returning here if rc is set, we'll let it try to
+	// do something with ambient capabilities in hopes that it's lowering
+	// capabilities. Again, this is for people that don't check their
+	// return codes.
+	//
+	// Do ambient last so that inheritable and permitted are set by the
+	// time we get here.
 	if (set & CAPNG_SELECT_AMBIENT) {
 #ifdef PR_CAP_AMBIENT
 		if (capng_have_capabilities(CAPNG_SELECT_AMBIENT) ==
 								CAPNG_NONE) {
 			if (prctl(PR_CAP_AMBIENT,
-				   PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0)
-				return -6;
+				   PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0) {
+				rc = -6;
+				goto out;
+			}
 		} else {
 			unsigned int i;
 
 			// Clear them all
 			if (prctl(PR_CAP_AMBIENT,
-				   PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0)
-				return -7;
+				   PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0) {
+				rc = -7;
+				goto out;
+			}
 			for (i=0; i <= last_cap; i++) {
 				if (capng_have_capability(CAPNG_AMBIENT, i))
 					if (prctl(PR_CAP_AMBIENT,
-					    PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0)
-						return -8;
+					    PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0){
+						rc = -8;
+						goto out;
+					}
 			}
 		}
 		m.state = CAPNG_APPLIED;
 #endif
 	}
-	return 0;
+out:
+	return rc;
 }
 
 #ifdef VFS_CAP_U32