diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-21 19:30:01 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-21 19:30:01 +0200 |
commit | 200bcc851acbe1ba30fe90b5cf918f88370a5d15 (patch) | |
tree | 50f4d5ac42869548b78b00470d7b80b50a28157a /util-linux/switch_root.c | |
parent | 44b3f2ffbc01c0a9fcfb5d60af3e292f505ac67c (diff) | |
download | busybox-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>
Diffstat (limited to 'util-linux/switch_root.c')
-rw-r--r-- | util-linux/switch_root.c | 126 |
1 files changed, 124 insertions, 2 deletions
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 */ | ||
61 | extern int capset(cap_user_header_t header, cap_user_data_t data); | ||
62 | extern 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 | ||
119 | DEFINE_STRUCT_CAPS; | ||
120 | |||
121 | static 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 | |||
136 | static 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 | |||
151 | static 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 | |||
177 | static 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 | |||
92 | int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 196 | int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
93 | int switch_root_main(int argc UNUSED_PARAM, char **argv) | 197 | int 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 | ||