]>
Commit | Line | Data |
---|---|---|
d7832d2c KS |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
3 | /*** | |
4 | This file is part of systemd. | |
5 | ||
6 | Copyright 2010 Lennart Poettering | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
5430f7f2 LP |
9 | under the terms of the GNU Lesser General Public License as published by |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
d7832d2c KS |
11 | (at your option) any later version. |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
5430f7f2 | 16 | Lesser General Public License for more details. |
d7832d2c | 17 | |
5430f7f2 | 18 | You should have received a copy of the GNU Lesser General Public License |
d7832d2c KS |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
20 | ***/ | |
21 | ||
22 | #include <assert.h> | |
23 | #include <string.h> | |
24 | #include <unistd.h> | |
25 | #include <errno.h> | |
26 | #include <stdio.h> | |
27 | #include <sys/types.h> | |
28 | #include <stdarg.h> | |
29 | #include <ctype.h> | |
30 | #include <sys/capability.h> | |
31 | #include <sys/prctl.h> | |
32 | ||
33 | #include "macro.h" | |
34 | #include "capability.h" | |
35 | #include "util.h" | |
36 | #include "log.h" | |
a5c32cff | 37 | #include "fileio.h" |
d7832d2c KS |
38 | |
39 | int have_effective_cap(int value) { | |
40 | cap_t cap; | |
41 | cap_flag_value_t fv; | |
42 | int r; | |
43 | ||
ec8927ca LP |
44 | cap = cap_get_proc(); |
45 | if (!cap) | |
d7832d2c KS |
46 | return -errno; |
47 | ||
48 | if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) | |
49 | r = -errno; | |
50 | else | |
51 | r = fv == CAP_SET; | |
52 | ||
53 | cap_free(cap); | |
54 | return r; | |
55 | } | |
56 | ||
57 | unsigned long cap_last_cap(void) { | |
ec202eae SL |
58 | static thread_local unsigned long saved; |
59 | static thread_local bool valid = false; | |
d7832d2c KS |
60 | unsigned long p; |
61 | ||
62 | if (valid) | |
63 | return saved; | |
64 | ||
65 | p = (unsigned long) CAP_LAST_CAP; | |
66 | ||
67 | if (prctl(PR_CAPBSET_READ, p) < 0) { | |
68 | ||
69 | /* Hmm, look downwards, until we find one that | |
70 | * works */ | |
71 | for (p--; p > 0; p --) | |
72 | if (prctl(PR_CAPBSET_READ, p) >= 0) | |
73 | break; | |
74 | ||
75 | } else { | |
76 | ||
77 | /* Hmm, look upwards, until we find one that doesn't | |
78 | * work */ | |
79 | for (;; p++) | |
80 | if (prctl(PR_CAPBSET_READ, p+1) < 0) | |
81 | break; | |
82 | } | |
83 | ||
84 | saved = p; | |
85 | valid = true; | |
86 | ||
87 | return p; | |
88 | } | |
ec8927ca LP |
89 | |
90 | int capability_bounding_set_drop(uint64_t drop, bool right_now) { | |
91 | unsigned long i; | |
92 | cap_t after_cap = NULL, temp_cap = NULL; | |
93 | cap_flag_value_t fv; | |
94 | int r; | |
95 | ||
96 | /* If we are run as PID 1 we will lack CAP_SETPCAP by default | |
97 | * in the effective set (yes, the kernel drops that when | |
98 | * executing init!), so get it back temporarily so that we can | |
99 | * call PR_CAPBSET_DROP. */ | |
100 | ||
101 | after_cap = cap_get_proc(); | |
102 | if (!after_cap) | |
103 | return -errno; | |
104 | ||
105 | if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) { | |
106 | cap_free(after_cap); | |
107 | return -errno; | |
108 | } | |
109 | ||
110 | if (fv != CAP_SET) { | |
111 | static const cap_value_t v = CAP_SETPCAP; | |
112 | ||
113 | temp_cap = cap_dup(after_cap); | |
114 | if (!temp_cap) { | |
115 | r = -errno; | |
116 | goto finish; | |
117 | } | |
118 | ||
119 | if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { | |
120 | r = -errno; | |
121 | goto finish; | |
122 | } | |
123 | ||
124 | if (cap_set_proc(temp_cap) < 0) { | |
125 | r = -errno; | |
126 | goto finish; | |
127 | } | |
128 | } | |
129 | ||
130 | for (i = 0; i <= cap_last_cap(); i++) { | |
131 | ||
132 | if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { | |
133 | cap_value_t v; | |
134 | ||
135 | /* Drop it from the bounding set */ | |
136 | if (prctl(PR_CAPBSET_DROP, i) < 0) { | |
137 | r = -errno; | |
138 | goto finish; | |
139 | } | |
693eb9a2 | 140 | v = (cap_value_t) i; |
ec8927ca LP |
141 | |
142 | /* Also drop it from the inheritable set, so | |
143 | * that anything we exec() loses the | |
144 | * capability for good. */ | |
145 | if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) { | |
146 | r = -errno; | |
147 | goto finish; | |
148 | } | |
149 | ||
150 | /* If we shall apply this right now drop it | |
151 | * also from our own capability sets. */ | |
152 | if (right_now) { | |
153 | if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 || | |
154 | cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) { | |
155 | r = -errno; | |
156 | goto finish; | |
157 | } | |
158 | } | |
159 | } | |
160 | } | |
161 | ||
162 | r = 0; | |
163 | ||
164 | finish: | |
165 | if (temp_cap) | |
166 | cap_free(temp_cap); | |
167 | ||
168 | if (after_cap) { | |
169 | cap_set_proc(after_cap); | |
170 | cap_free(after_cap); | |
171 | } | |
172 | ||
173 | return r; | |
174 | } | |
939b8f14 LP |
175 | |
176 | static int drop_from_file(const char *fn, uint64_t drop) { | |
177 | int r, k; | |
178 | uint32_t hi, lo; | |
179 | uint64_t current, after; | |
180 | char *p; | |
181 | ||
182 | r = read_one_line_file(fn, &p); | |
183 | if (r < 0) | |
184 | return r; | |
185 | ||
186 | assert_cc(sizeof(hi) == sizeof(unsigned)); | |
187 | assert_cc(sizeof(lo) == sizeof(unsigned)); | |
188 | ||
189 | k = sscanf(p, "%u %u", &lo, &hi); | |
190 | free(p); | |
191 | ||
192 | if (k != 2) | |
193 | return -EIO; | |
194 | ||
195 | current = (uint64_t) lo | ((uint64_t) hi << 32ULL); | |
196 | after = current & ~drop; | |
197 | ||
198 | if (current == after) | |
199 | return 0; | |
200 | ||
201 | lo = (unsigned) (after & 0xFFFFFFFFULL); | |
202 | hi = (unsigned) ((after >> 32ULL) & 0xFFFFFFFFULL); | |
203 | ||
204 | if (asprintf(&p, "%u %u", lo, hi) < 0) | |
205 | return -ENOMEM; | |
206 | ||
574d5f2d | 207 | r = write_string_file(fn, p); |
939b8f14 LP |
208 | free(p); |
209 | ||
210 | return r; | |
211 | } | |
212 | ||
213 | int capability_bounding_set_drop_usermode(uint64_t drop) { | |
214 | int r; | |
215 | ||
216 | r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop); | |
217 | if (r < 0) | |
218 | return r; | |
219 | ||
220 | r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop); | |
221 | if (r < 0) | |
222 | return r; | |
223 | ||
224 | return r; | |
225 | } |