3 * Copyright © 2021 Christian Brauner <christian.brauner@ubuntu.com>.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2, as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <sys/types.h>
33 #include "lxccontainer.h"
34 #include "attach_options.h"
41 __u32
*cap_bset_bits
= NULL
;
44 static int capabilities_allow(void *payload
)
46 for (__u32 cap
= 0; cap
<= last_cap
; cap
++) {
49 if (!is_set(cap
, cap_bset_bits
))
53 bret
= cap_get_bound(cap
) == CAP_SET
;
55 bret
= cap_get_bound(cap
) != CAP_SET
;
57 lxc_error("Capability %d unexpectedly raised or lowered\n", cap
);
65 static int capabilities_deny(void *payload
)
67 for (__u32 cap
= 0; cap
<= last_cap
; cap
++) {
70 if (!is_set(cap
, cap_bset_bits
))
74 bret
= cap_get_bound(cap
) != CAP_SET
;
76 bret
= cap_get_bound(cap
) == CAP_SET
;
78 lxc_error("Capability %d unexpectedly raised or lowered\n", cap
);
86 static int run(int (*test
)(void *), bool allow
)
88 int fd_log
= -EBADF
, fret
= -1;
89 lxc_attach_options_t attach_options
= LXC_ATTACH_OPTIONS_DEFAULT
;
92 struct lxc_container
*c
;
94 char template[sizeof(P_tmpdir
"/capabilities_XXXXXX")];
96 (void)strlcpy(template, P_tmpdir
"/capabilities_XXXXXX", sizeof(template));
98 fd_log
= lxc_make_tmpfile(template, false);
100 lxc_error("%s", "Failed to create temporary log file for container \"capabilities\"");
104 log
.name
= "capabilities";
107 log
.prefix
= "capabilities";
111 if (lxc_log_init(&log
))
114 c
= lxc_container_new("capabilities", NULL
);
116 lxc_error("%s\n", "Failed to create container \"capabilities\"");
120 if (c
->is_defined(c
)) {
121 lxc_error("%s\n", "Container \"capabilities\" is defined");
125 if (!c
->createl(c
, "busybox", NULL
, NULL
, 0, NULL
)) {
126 lxc_error("%s\n", "Failed to create busybox container \"capabilities\"");
130 if (!c
->is_defined(c
)) {
131 lxc_error("%s\n", "Container \"capabilities\" is not defined");
132 goto on_error_destroy
;
135 if (!c
->clear_config_item(c
, "lxc.cap.drop")) {
136 lxc_error("%s\n", "Failed to clear config item \"lxc.cap.drop\"");
137 goto on_error_destroy
;
140 if (!c
->clear_config_item(c
, "lxc.cap.keep")) {
141 lxc_error("%s\n", "Failed to clear config item \"lxc.cap.drop\"");
142 goto on_error_destroy
;
146 if (!c
->set_config_item(c
, "lxc.cap.keep", "mknod")) {
147 lxc_error("%s\n", "Failed to set config item \"lxc.cap.keep=mknod\"");
148 goto on_error_destroy
;
151 if (!c
->set_config_item(c
, "lxc.cap.drop", "mknod")) {
152 lxc_error("%s\n", "Failed to set config item \"lxc.cap.drop=mknod\"");
153 goto on_error_destroy
;
157 if (!c
->want_daemonize(c
, true)) {
158 lxc_error("%s\n", "Failed to mark container \"capabilities\" daemonized");
159 goto on_error_destroy
;
162 if (!c
->startl(c
, 0, NULL
)) {
163 lxc_error("%s\n", "Failed to start container \"capabilities\" daemonized");
164 goto on_error_destroy
;
167 ret
= c
->attach(c
, test
, NULL
, &attach_options
, &pid
);
169 lxc_error("%s\n", "Failed to run function in container \"capabilities\"");
173 ret
= wait_for_pid(pid
);
175 lxc_error("%s\n", "Function \"capabilities\" failed");
182 if (c
->is_running(c
) && !c
->stop(c
))
183 lxc_error("%s\n", "Failed to stop container \"capabilities\"");
187 lxc_error("%s\n", "Failed to destroy container \"capabilities\"");
190 lxc_container_put(c
);
192 if (fret
== EXIT_SUCCESS
) {
193 lxc_debug("All capability %s tests passed\n", allow
? "allow" : "deny");
197 fd
= open(template, O_RDONLY
);
201 while ((buflen
= read(fd
, buf
, 1024)) > 0) {
202 buflen
= write(STDERR_FILENO
, buf
, buflen
);
209 (void)unlink(template);
214 static void __attribute__((constructor
)) capabilities_init(void)
219 ret
= lxc_caps_last_cap(&last_cap
);
220 if (ret
|| last_cap
> 200)
223 nr_u32
= BITS_TO_LONGS(last_cap
);
224 cap_bset_bits
= zalloc(nr_u32
* sizeof(__u32
));
228 for (__u32 cap_bit
= 0; cap_bit
<= last_cap
; cap_bit
++) {
229 if (prctl(PR_CAPBSET_READ
, prctl_arg(cap_bit
)) == 0)
232 set_bit(cap_bit
, cap_bset_bits
);
236 static void __attribute__((destructor
)) capabilities_exit(void)
241 int main(int argc
, char *argv
[])
243 if (run(capabilities_allow
, true))
246 if (run(capabilities_deny
, false))
252 #else /* !HAVE_LIBCAP */
254 int main(int argc
, char *argv
[])
256 lxc_debug("%s\n", "Capabilities not supported. Skipping.");