]>
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) { | |
5ce70e5b | 40 | _cleanup_cap_free_ cap_t cap; |
d7832d2c | 41 | cap_flag_value_t fv; |
d7832d2c | 42 | |
ec8927ca LP |
43 | cap = cap_get_proc(); |
44 | if (!cap) | |
d7832d2c KS |
45 | return -errno; |
46 | ||
47 | if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) | |
5ce70e5b | 48 | return -errno; |
d7832d2c | 49 | else |
5ce70e5b | 50 | return fv == CAP_SET; |
d7832d2c KS |
51 | } |
52 | ||
53 | unsigned long cap_last_cap(void) { | |
ec202eae SL |
54 | static thread_local unsigned long saved; |
55 | static thread_local bool valid = false; | |
d7832d2c KS |
56 | unsigned long p; |
57 | ||
58 | if (valid) | |
59 | return saved; | |
60 | ||
61 | p = (unsigned long) CAP_LAST_CAP; | |
62 | ||
63 | if (prctl(PR_CAPBSET_READ, p) < 0) { | |
64 | ||
65 | /* Hmm, look downwards, until we find one that | |
66 | * works */ | |
67 | for (p--; p > 0; p --) | |
68 | if (prctl(PR_CAPBSET_READ, p) >= 0) | |
69 | break; | |
70 | ||
71 | } else { | |
72 | ||
73 | /* Hmm, look upwards, until we find one that doesn't | |
74 | * work */ | |
75 | for (;; p++) | |
76 | if (prctl(PR_CAPBSET_READ, p+1) < 0) | |
77 | break; | |
78 | } | |
79 | ||
80 | saved = p; | |
81 | valid = true; | |
82 | ||
83 | return p; | |
84 | } | |
ec8927ca LP |
85 | |
86 | int capability_bounding_set_drop(uint64_t drop, bool right_now) { | |
87 | unsigned long i; | |
5ce70e5b | 88 | _cleanup_cap_free_ cap_t after_cap = NULL, temp_cap = NULL; |
ec8927ca LP |
89 | cap_flag_value_t fv; |
90 | int r; | |
91 | ||
92 | /* If we are run as PID 1 we will lack CAP_SETPCAP by default | |
93 | * in the effective set (yes, the kernel drops that when | |
94 | * executing init!), so get it back temporarily so that we can | |
95 | * call PR_CAPBSET_DROP. */ | |
96 | ||
97 | after_cap = cap_get_proc(); | |
98 | if (!after_cap) | |
99 | return -errno; | |
100 | ||
5ce70e5b | 101 | if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) |
ec8927ca | 102 | return -errno; |
ec8927ca LP |
103 | |
104 | if (fv != CAP_SET) { | |
105 | static const cap_value_t v = CAP_SETPCAP; | |
106 | ||
107 | temp_cap = cap_dup(after_cap); | |
108 | if (!temp_cap) { | |
109 | r = -errno; | |
110 | goto finish; | |
111 | } | |
112 | ||
113 | if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { | |
114 | r = -errno; | |
115 | goto finish; | |
116 | } | |
117 | ||
118 | if (cap_set_proc(temp_cap) < 0) { | |
119 | r = -errno; | |
120 | goto finish; | |
121 | } | |
122 | } | |
123 | ||
124 | for (i = 0; i <= cap_last_cap(); i++) { | |
125 | ||
126 | if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { | |
127 | cap_value_t v; | |
128 | ||
129 | /* Drop it from the bounding set */ | |
130 | if (prctl(PR_CAPBSET_DROP, i) < 0) { | |
131 | r = -errno; | |
132 | goto finish; | |
133 | } | |
693eb9a2 | 134 | v = (cap_value_t) i; |
ec8927ca LP |
135 | |
136 | /* Also drop it from the inheritable set, so | |
137 | * that anything we exec() loses the | |
138 | * capability for good. */ | |
139 | if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) { | |
140 | r = -errno; | |
141 | goto finish; | |
142 | } | |
143 | ||
144 | /* If we shall apply this right now drop it | |
145 | * also from our own capability sets. */ | |
146 | if (right_now) { | |
147 | if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 || | |
148 | cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) { | |
149 | r = -errno; | |
150 | goto finish; | |
151 | } | |
152 | } | |
153 | } | |
154 | } | |
155 | ||
156 | r = 0; | |
157 | ||
158 | finish: | |
a349eb10 LP |
159 | if (cap_set_proc(after_cap) < 0) |
160 | return -errno; | |
ec8927ca LP |
161 | |
162 | return r; | |
163 | } | |
939b8f14 LP |
164 | |
165 | static int drop_from_file(const char *fn, uint64_t drop) { | |
166 | int r, k; | |
167 | uint32_t hi, lo; | |
168 | uint64_t current, after; | |
169 | char *p; | |
170 | ||
171 | r = read_one_line_file(fn, &p); | |
172 | if (r < 0) | |
173 | return r; | |
174 | ||
175 | assert_cc(sizeof(hi) == sizeof(unsigned)); | |
176 | assert_cc(sizeof(lo) == sizeof(unsigned)); | |
177 | ||
178 | k = sscanf(p, "%u %u", &lo, &hi); | |
179 | free(p); | |
180 | ||
181 | if (k != 2) | |
182 | return -EIO; | |
183 | ||
184 | current = (uint64_t) lo | ((uint64_t) hi << 32ULL); | |
185 | after = current & ~drop; | |
186 | ||
187 | if (current == after) | |
188 | return 0; | |
189 | ||
190 | lo = (unsigned) (after & 0xFFFFFFFFULL); | |
191 | hi = (unsigned) ((after >> 32ULL) & 0xFFFFFFFFULL); | |
192 | ||
193 | if (asprintf(&p, "%u %u", lo, hi) < 0) | |
194 | return -ENOMEM; | |
195 | ||
574d5f2d | 196 | r = write_string_file(fn, p); |
939b8f14 LP |
197 | free(p); |
198 | ||
199 | return r; | |
200 | } | |
201 | ||
202 | int capability_bounding_set_drop_usermode(uint64_t drop) { | |
203 | int r; | |
204 | ||
205 | r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop); | |
206 | if (r < 0) | |
207 | return r; | |
208 | ||
209 | r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop); | |
210 | if (r < 0) | |
211 | return r; | |
212 | ||
213 | return r; | |
214 | } |