aboutsummaryrefslogtreecommitdiff
path: root/util-linux/switch_root.c
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 /util-linux/switch_root.c
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>
Diffstat (limited to 'util-linux/switch_root.c')
-rw-r--r--util-linux/switch_root.c126
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 */
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