aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-08-21 19:30:01 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-08-21 19:30:01 +0200
commit200bcc851acbe1ba30fe90b5cf918f88370a5d15 (patch)
tree50f4d5ac42869548b78b00470d7b80b50a28157a
parent44b3f2ffbc01c0a9fcfb5d60af3e292f505ac67c (diff)
downloadbusybox-w32-200bcc851acbe1ba30fe90b5cf918f88370a5d15.tar.gz
busybox-w32-200bcc851acbe1ba30fe90b5cf918f88370a5d15.tar.bz2
busybox-w32-200bcc851acbe1ba30fe90b5cf918f88370a5d15.zip
run-init: new applet
function old new delta switch_root_main 354 637 +283 drop_usermodehelper - 157 +157 cap_name_to_number - 77 +77 packed_usage 31707 31743 +36 applet_names 2665 2674 +9 applet_main 1544 1548 +4 applet_install_loc 193 194 +1 setpriv_main 933 928 -5 getcaps 131 122 -9 parse_cap 117 29 -88 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 5/3 up/down: 567/-102) Total: 465 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--include/libbb.h9
-rw-r--r--klibc-utils/run-init.c27
-rw-r--r--libbb/capability.c47
-rw-r--r--util-linux/setpriv.c55
-rw-r--r--util-linux/switch_root.c126
5 files changed, 212 insertions, 52 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 9535f5fb3..95a7470a8 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1475,6 +1475,15 @@ const char *get_shell_name(void) FAST_FUNC;
1475 1475
1476unsigned cap_name_to_number(const char *cap) FAST_FUNC; 1476unsigned cap_name_to_number(const char *cap) FAST_FUNC;
1477void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC; 1477void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC;
1478void drop_capability(int cap_ordinal) FAST_FUNC;
1479/* Structures inside "struct caps" are Linux-specific and libcap-specific: */
1480#define DEFINE_STRUCT_CAPS \
1481struct caps { \
1482 struct __user_cap_header_struct header; \
1483 unsigned u32s; \
1484 struct __user_cap_data_struct data[2]; \
1485}
1486void getcaps(void *caps) FAST_FUNC;
1478 1487
1479unsigned cap_name_to_number(const char *name) FAST_FUNC; 1488unsigned cap_name_to_number(const char *name) FAST_FUNC;
1480void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC; 1489void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC;
diff --git a/klibc-utils/run-init.c b/klibc-utils/run-init.c
new file mode 100644
index 000000000..a70d1bfbf
--- /dev/null
+++ b/klibc-utils/run-init.c
@@ -0,0 +1,27 @@
1/*
2 * run-init implementation for busybox
3 *
4 * Copyright (c) 2017 Denys Vlasenko <vda.linux@gmail.com>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8//config:config RUN_INIT
9//config: bool "run-init"
10//config: default y
11//config: select PLATFORM_LINUX
12//config: help
13//config: The run-init utility is used from initramfs to select a new
14//config: root device. Under initramfs, you have to use this instead of
15//config: pivot_root.
16//config:
17//config: Booting with initramfs extracts a gzipped cpio archive into rootfs
18//config: (which is a variant of ramfs/tmpfs). Because rootfs can't be moved
19//config: or unmounted, pivot_root will not work from initramfs. Instead,
20//config: run-init deletes everything out of rootfs (including itself),
21//config: does a mount --move that overmounts rootfs with the new root, and
22//config: then execs the specified init program.
23//config:
24//config: util-linux has a similar tool, switch-root.
25//config: run-init differs by also having a "-d CAPS_TO_DROP" option.
26
27/* applet and kbuild hooks are in switch_root.c */
diff --git a/libbb/capability.c b/libbb/capability.c
index 692024f2f..f60062bfc 100644
--- a/libbb/capability.c
+++ b/libbb/capability.c
@@ -6,6 +6,14 @@
6//kbuild:lib-$(CONFIG_PLATFORM_LINUX) += capability.o 6//kbuild:lib-$(CONFIG_PLATFORM_LINUX) += capability.o
7 7
8#include <linux/capability.h> 8#include <linux/capability.h>
9// #include <sys/capability.h>
10// This header is in libcap, but the functions are in libc.
11// Comment in the header says this above capset/capget:
12/* system calls - look to libc for function to system call mapping */
13extern int capset(cap_user_header_t header, cap_user_data_t data);
14extern int capget(cap_user_header_t header, const cap_user_data_t data);
15// so for bbox, let's just repeat the declarations.
16// This way, libcap needs not be installed in build environment.
9#include "libbb.h" 17#include "libbb.h"
10 18
11static const char *const capabilities[] = { 19static const char *const capabilities[] = {
@@ -77,3 +85,42 @@ void FAST_FUNC printf_cap(const char *pfx, unsigned cap_no)
77 } 85 }
78 printf("%scap_%u", pfx, cap_no); 86 printf("%scap_%u", pfx, cap_no);
79} 87}
88
89DEFINE_STRUCT_CAPS;
90
91void FAST_FUNC getcaps(void *arg)
92{
93 static const uint8_t versions[] = {
94 _LINUX_CAPABILITY_U32S_3, /* = 2 (fits into byte) */
95 _LINUX_CAPABILITY_U32S_2, /* = 2 */
96 _LINUX_CAPABILITY_U32S_1, /* = 1 */
97 };
98 int i;
99 struct caps *caps = arg;
100
101 caps->header.pid = 0;
102 for (i = 0; i < ARRAY_SIZE(versions); i++) {
103 caps->header.version = versions[i];
104 if (capget(&caps->header, NULL) == 0)
105 goto got_it;
106 }
107 bb_simple_perror_msg_and_die("capget");
108 got_it:
109
110 switch (caps->header.version) {
111 case _LINUX_CAPABILITY_VERSION_1:
112 caps->u32s = _LINUX_CAPABILITY_U32S_1;
113 break;
114 case _LINUX_CAPABILITY_VERSION_2:
115 caps->u32s = _LINUX_CAPABILITY_U32S_2;
116 break;
117 case _LINUX_CAPABILITY_VERSION_3:
118 caps->u32s = _LINUX_CAPABILITY_U32S_3;
119 break;
120 default:
121 bb_error_msg_and_die("unsupported capability version");
122 }
123
124 if (capget(&caps->header, caps->data) != 0)
125 bb_simple_perror_msg_and_die("capget");
126}
diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c
index 9f2793949..12ab1bd66 100644
--- a/util-linux/setpriv.c
+++ b/util-linux/setpriv.c
@@ -124,48 +124,7 @@ enum {
124}; 124};
125 125
126#if ENABLE_FEATURE_SETPRIV_CAPABILITIES 126#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
127struct caps { 127DEFINE_STRUCT_CAPS;
128 struct __user_cap_header_struct header;
129 cap_user_data_t data;
130 int u32s;
131};
132
133static void getcaps(struct caps *caps)
134{
135 static const uint8_t versions[] = {
136 _LINUX_CAPABILITY_U32S_3, /* = 2 (fits into byte) */
137 _LINUX_CAPABILITY_U32S_2, /* = 2 */
138 _LINUX_CAPABILITY_U32S_1, /* = 1 */
139 };
140 int i;
141
142 caps->header.pid = 0;
143 for (i = 0; i < ARRAY_SIZE(versions); i++) {
144 caps->header.version = versions[i];
145 if (capget(&caps->header, NULL) == 0)
146 goto got_it;
147 }
148 bb_simple_perror_msg_and_die("capget");
149 got_it:
150
151 switch (caps->header.version) {
152 case _LINUX_CAPABILITY_VERSION_1:
153 caps->u32s = _LINUX_CAPABILITY_U32S_1;
154 break;
155 case _LINUX_CAPABILITY_VERSION_2:
156 caps->u32s = _LINUX_CAPABILITY_U32S_2;
157 break;
158 case _LINUX_CAPABILITY_VERSION_3:
159 caps->u32s = _LINUX_CAPABILITY_U32S_3;
160 break;
161 default:
162 bb_error_msg_and_die("unsupported capability version");
163 }
164
165 caps->data = xmalloc(sizeof(caps->data[0]) * caps->u32s);
166 if (capget(&caps->header, caps->data) < 0)
167 bb_simple_perror_msg_and_die("capget");
168}
169 128
170static unsigned parse_cap(const char *cap) 129static unsigned parse_cap(const char *cap)
171{ 130{
@@ -195,7 +154,7 @@ static void set_inh_caps(char *capstring)
195 154
196 cap = parse_cap(capstring); 155 cap = parse_cap(capstring);
197 if (CAP_TO_INDEX(cap) >= caps.u32s) 156 if (CAP_TO_INDEX(cap) >= caps.u32s)
198 bb_error_msg_and_die("invalid capability cap"); 157 bb_error_msg_and_die("invalid capability '%s'", capstring);
199 158
200 if (capstring[0] == '+') 159 if (capstring[0] == '+')
201 caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap); 160 caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap);
@@ -204,11 +163,8 @@ static void set_inh_caps(char *capstring)
204 capstring = strtok(NULL, ","); 163 capstring = strtok(NULL, ",");
205 } 164 }
206 165
207 if ((capset(&caps.header, caps.data)) < 0) 166 if (capset(&caps.header, caps.data) != 0)
208 bb_perror_msg_and_die("capset"); 167 bb_perror_msg_and_die("capset");
209
210 if (ENABLE_FEATURE_CLEAN_UP)
211 free(caps.data);
212} 168}
213 169
214static void set_ambient_caps(char *string) 170static void set_ambient_caps(char *string)
@@ -322,10 +278,9 @@ static int dump(void)
322 bb_putchar('\n'); 278 bb_putchar('\n');
323# endif 279# endif
324 280
325 if (ENABLE_FEATURE_CLEAN_UP) { 281 if (ENABLE_FEATURE_CLEAN_UP)
326 IF_FEATURE_SETPRIV_CAPABILITIES(free(caps.data);)
327 free(gids); 282 free(gids);
328 } 283
329 return EXIT_SUCCESS; 284 return EXIT_SUCCESS;
330} 285}
331#endif /* FEATURE_SETPRIV_DUMP */ 286#endif /* FEATURE_SETPRIV_DUMP */
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
index fb6057a02..fe9ab68d0 100644
--- a/util-linux/switch_root.c
+++ b/util-linux/switch_root.c
@@ -26,20 +26,46 @@
26//config: list of active mount points. That's why. 26//config: list of active mount points. That's why.
27 27
28//applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) 28//applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP))
29// APPLET_ODDNAME:name main location suid_type help
30//applet:IF_RUN_INIT( APPLET_ODDNAME(run-init, switch_root, BB_DIR_SBIN, BB_SUID_DROP, run_init))
29 31
30//kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o 32//kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o
33//kbuild:lib-$(CONFIG_RUN_INIT) += switch_root.o
31 34
32//usage:#define switch_root_trivial_usage 35//usage:#define switch_root_trivial_usage
33//usage: "[-c /dev/console] NEW_ROOT NEW_INIT [ARGS]" 36//usage: "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]"
34//usage:#define switch_root_full_usage "\n\n" 37//usage:#define switch_root_full_usage "\n\n"
35//usage: "Free initramfs and switch to another root fs:\n" 38//usage: "Free initramfs and switch to another root fs:\n"
36//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" 39//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n"
37//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" 40//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n"
38//usage: "\n -c DEV Reopen stdio to DEV after switch" 41//usage: "\n -c DEV Reopen stdio to DEV after switch"
39 42
43//usage:#define run_init_trivial_usage
44//usage: "[-d CAP,CAP...] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]"
45//usage:#define run_init_full_usage "\n\n"
46//usage: "Free initramfs and switch to another root fs:\n"
47//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n"
48//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n"
49//usage: "\n -c DEV Reopen stdio to DEV after switch"
50//usage: "\n -d CAPS Drop capabilities"
51
40#include <sys/vfs.h> 52#include <sys/vfs.h>
41#include <sys/mount.h> 53#include <sys/mount.h>
54#if ENABLE_RUN_INIT
55# include <sys/prctl.h>
56# include <linux/capability.h>
57// #include <sys/capability.h>
58// This header is in libcap, but the functions are in libc.
59// Comment in the header says this above capset/capget:
60/* system calls - look to libc for function to system call mapping */
61extern int capset(cap_user_header_t header, cap_user_data_t data);
62extern int capget(cap_user_header_t header, const cap_user_data_t data);
63// so for bbox, let's just repeat the declarations.
64// This way, libcap needs not be installed in build environment.
65#endif
66
42#include "libbb.h" 67#include "libbb.h"
68
43// Make up for header deficiencies 69// Make up for header deficiencies
44#ifndef RAMFS_MAGIC 70#ifndef RAMFS_MAGIC
45# define RAMFS_MAGIC ((unsigned)0x858458f6) 71# define RAMFS_MAGIC ((unsigned)0x858458f6)
@@ -89,6 +115,84 @@ static void delete_contents(const char *directory, dev_t rootdev)
89 } 115 }
90} 116}
91 117
118#if ENABLE_RUN_INIT
119DEFINE_STRUCT_CAPS;
120
121static void drop_capset(int cap_idx)
122{
123 struct caps caps;
124
125 /* Get the current capability mask */
126 getcaps(&caps);
127
128 /* Drop the bit */
129 caps.data[CAP_TO_INDEX(cap_idx)].inheritable &= ~CAP_TO_MASK(cap_idx);
130
131 /* And drop the capability. */
132 if (capset(&caps.header, caps.data) != 0)
133 bb_perror_msg_and_die("capset");
134}
135
136static void drop_bounding_set(int cap_idx)
137{
138 int ret;
139
140 ret = prctl(PR_CAPBSET_READ, cap_idx, 0, 0, 0);
141 if (ret < 0)
142 bb_perror_msg_and_die("prctl: %s", "PR_CAPBSET_READ");
143
144 if (ret == 1) {
145 ret = prctl(PR_CAPBSET_DROP, cap_idx, 0, 0, 0);
146 if (ret != 0)
147 bb_perror_msg_and_die("prctl: %s", "PR_CAPBSET_DROP");
148 }
149}
150
151static void drop_usermodehelper(const char *filename, int cap_idx)
152{
153 unsigned lo, hi;
154 char buf[sizeof(int)*3 * 2 + 8];
155 int fd;
156 int ret;
157
158 ret = open_read_close(filename, buf, sizeof(buf) - 1);
159 if (ret < 0)
160 return; /* assuming files do not exist */
161
162 buf[ret] = '\0';
163 ret = sscanf(buf, "%u %u", &lo, &hi);
164 if (ret != 2)
165 bb_perror_msg_and_die("can't parse file '%s'", filename);
166
167 if (cap_idx < 32)
168 lo &= ~(1 << cap_idx);
169 else
170 hi &= ~(1 << (cap_idx - 32));
171
172 fd = xopen(filename, O_WRONLY);
173 fdprintf(fd, "%u %u", lo, hi);
174 close(fd);
175}
176
177static void drop_capabilities(char *string)
178{
179 char *cap;
180
181 cap = strtok(string, ",");
182 while (cap) {
183 unsigned cap_idx;
184
185 cap_idx = cap_name_to_number(cap);
186 drop_usermodehelper("/proc/sys/kernel/usermodehelper/bset", cap_idx);
187 drop_usermodehelper("/proc/sys/kernel/usermodehelper/inheritable", cap_idx);
188 drop_bounding_set(cap_idx);
189 drop_capset(cap_idx);
190 bb_error_msg("dropped capability: %s", cap);
191 cap = strtok(NULL, ",");
192 }
193}
194#endif
195
92int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 196int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
93int switch_root_main(int argc UNUSED_PARAM, char **argv) 197int switch_root_main(int argc UNUSED_PARAM, char **argv)
94{ 198{
@@ -98,7 +202,25 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
98 dev_t rootdev; 202 dev_t rootdev;
99 203
100 // Parse args (-c console). '+': stop at first non-option 204 // Parse args (-c console). '+': stop at first non-option
101 getopt32(argv, "^+" "c:" "\0" "-2" /* minimum 2 args */, &console); 205 if (ENABLE_SWITCH_ROOT && (!ENABLE_RUN_INIT || applet_name[0] == 's')) {
206 getopt32(argv, "^+"
207 "c:"
208 "\0" "-2" /* minimum 2 args */,
209 &console
210 );
211 } else {
212#if ENABLE_RUN_INIT
213 char *cap_list = NULL;
214 getopt32(argv, "^+"
215 "c:d:"
216 "\0" "-2" /* minimum 2 args */,
217 &console,
218 &cap_list
219 );
220 if (cap_list)
221 drop_capabilities(cap_list);
222#endif
223 }
102 argv += optind; 224 argv += optind;
103 newroot = *argv++; 225 newroot = *argv++;
104 226