From 22542eca18e5807b72ddc78999f5101e33f17a53 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 21:55:02 +0200 Subject: getopt32: remove opt_complementary function old new delta vgetopt32 1318 1392 +74 runsvdir_main 703 713 +10 bb_make_directory 423 425 +2 collect_cpu 546 545 -1 opt_chars 3 - -3 opt_complementary 4 - -4 tftpd_main 567 562 -5 ntp_init 476 471 -5 zcip_main 1266 1256 -10 xxd_main 428 418 -10 whois_main 140 130 -10 who_main 463 453 -10 which_main 212 202 -10 wget_main 2535 2525 -10 watchdog_main 291 281 -10 watch_main 222 212 -10 vlock_main 399 389 -10 uuencode_main 332 322 -10 uudecode_main 316 306 -10 unlink_main 45 35 -10 udhcpd_main 1482 1472 -10 udhcpc_main 2762 2752 -10 tune2fs_main 290 280 -10 tunctl_main 366 356 -10 truncate_main 218 208 -10 tr_main 518 508 -10 time_main 1134 1124 -10 tftp_main 286 276 -10 telnetd_main 1873 1863 -10 tcpudpsvd_main 1785 1775 -10 taskset_main 521 511 -10 tar_main 1009 999 -10 tail_main 1644 1634 -10 syslogd_main 1967 1957 -10 switch_root_main 368 358 -10 svlogd_main 1454 1444 -10 sv 1296 1286 -10 stat_main 104 94 -10 start_stop_daemon_main 1028 1018 -10 split_main 542 532 -10 sort_main 796 786 -10 slattach_main 624 614 -10 shuf_main 504 494 -10 setsid_main 96 86 -10 setserial_main 1132 1122 -10 setfont_main 388 378 -10 setconsole_main 78 68 -10 sendmail_main 1209 1199 -10 sed_main 677 667 -10 script_main 1077 1067 -10 run_parts_main 325 315 -10 rtcwake_main 454 444 -10 rm_main 175 165 -10 reformime_main 119 109 -10 readlink_main 123 113 -10 rdate_main 246 236 -10 pwdx_main 189 179 -10 pstree_main 317 307 -10 pscan_main 663 653 -10 popmaildir_main 818 808 -10 pmap_main 80 70 -10 nc_main 1042 1032 -10 mv_main 558 548 -10 mountpoint_main 477 467 -10 mount_main 1264 1254 -10 modprobe_main 768 758 -10 modinfo_main 333 323 -10 mktemp_main 200 190 -10 mkswap_main 324 314 -10 mkfs_vfat_main 1489 1479 -10 microcom_main 715 705 -10 md5_sha1_sum_main 521 511 -10 man_main 867 857 -10 makedevs_main 1052 1042 -10 ls_main 563 553 -10 losetup_main 432 422 -10 loadfont_main 89 79 -10 ln_main 524 514 -10 link_main 75 65 -10 ipcalc_main 544 534 -10 iostat_main 2397 2387 -10 install_main 768 758 -10 id_main 480 470 -10 i2cset_main 1239 1229 -10 i2cget_main 380 370 -10 i2cdump_main 1482 1472 -10 i2cdetect_main 682 672 -10 hwclock_main 406 396 -10 httpd_main 741 731 -10 grep_main 837 827 -10 getty_main 1559 1549 -10 fuser_main 297 287 -10 ftpgetput_main 345 335 -10 ftpd_main 2232 2222 -10 fstrim_main 251 241 -10 fsfreeze_main 77 67 -10 fsck_minix_main 2921 2911 -10 flock_main 314 304 -10 flashcp_main 740 730 -10 flash_eraseall_main 833 823 -10 fdformat_main 532 522 -10 expand_main 680 670 -10 eject_main 335 325 -10 dumpleases_main 630 620 -10 du_main 314 304 -10 dos2unix_main 441 431 -10 diff_main 1350 1340 -10 df_main 1064 1054 -10 date_main 1095 1085 -10 cut_main 961 951 -10 cryptpw_main 228 218 -10 crontab_main 575 565 -10 crond_main 1149 1139 -10 cp_main 370 360 -10 common_traceroute_main 3834 3824 -10 common_ping_main 1767 1757 -10 comm_main 239 229 -10 cmp_main 655 645 -10 chrt_main 379 369 -10 chpst_main 704 694 -10 chpasswd_main 308 298 -10 chown_main 171 161 -10 chmod_main 158 148 -10 cat_main 428 418 -10 bzip2_main 120 110 -10 blkdiscard_main 264 254 -10 base64_main 221 211 -10 arping_main 1665 1655 -10 ar_main 556 546 -10 adjtimex_main 406 396 -10 adduser_main 882 872 -10 addgroup_main 411 401 -10 acpid_main 1198 1188 -10 optstring 11 - -11 opt_string 18 - -18 OPT_STR 25 - -25 ubi_tools_main 1288 1258 -30 ls_options 31 - -31 ------------------------------------------------------------------------------ (add/remove: 0/6 grow/shrink: 3/129 up/down: 86/-1383) Total: -1297 bytes text data bss dec hex filename 915428 485 6876 922789 e14a5 busybox_old 914629 485 6872 921986 e1182 busybox_unstripped Signed-off-by: Denys Vlasenko --- util-linux/switch_root.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'util-linux/switch_root.c') diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index 32708934e..fb6057a02 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c @@ -97,9 +97,8 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) struct statfs stfs; dev_t rootdev; - // Parse args (-c console) - opt_complementary = "-2"; // minimum 2 params - getopt32(argv, "+c:", &console); // '+': stop at first non-option + // Parse args (-c console). '+': stop at first non-option + getopt32(argv, "^+" "c:" "\0" "-2" /* minimum 2 args */, &console); argv += optind; newroot = *argv++; -- cgit v1.2.3-55-g6feb From 200bcc851acbe1ba30fe90b5cf918f88370a5d15 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Aug 2017 19:30:01 +0200 Subject: 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 --- include/libbb.h | 9 ++++ klibc-utils/run-init.c | 27 ++++++++++ libbb/capability.c | 47 ++++++++++++++++++ util-linux/setpriv.c | 55 ++------------------- util-linux/switch_root.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 212 insertions(+), 52 deletions(-) create mode 100644 klibc-utils/run-init.c (limited to 'util-linux/switch_root.c') 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; unsigned cap_name_to_number(const char *cap) FAST_FUNC; void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC; +void drop_capability(int cap_ordinal) FAST_FUNC; +/* Structures inside "struct caps" are Linux-specific and libcap-specific: */ +#define DEFINE_STRUCT_CAPS \ +struct caps { \ + struct __user_cap_header_struct header; \ + unsigned u32s; \ + struct __user_cap_data_struct data[2]; \ +} +void getcaps(void *caps) FAST_FUNC; unsigned cap_name_to_number(const char *name) FAST_FUNC; void 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 @@ +/* + * run-init implementation for busybox + * + * Copyright (c) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config RUN_INIT +//config: bool "run-init" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: The run-init utility is used from initramfs to select a new +//config: root device. Under initramfs, you have to use this instead of +//config: pivot_root. +//config: +//config: Booting with initramfs extracts a gzipped cpio archive into rootfs +//config: (which is a variant of ramfs/tmpfs). Because rootfs can't be moved +//config: or unmounted, pivot_root will not work from initramfs. Instead, +//config: run-init deletes everything out of rootfs (including itself), +//config: does a mount --move that overmounts rootfs with the new root, and +//config: then execs the specified init program. +//config: +//config: util-linux has a similar tool, switch-root. +//config: run-init differs by also having a "-d CAPS_TO_DROP" option. + +/* 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 @@ //kbuild:lib-$(CONFIG_PLATFORM_LINUX) += capability.o #include +// #include +// This header is in libcap, but the functions are in libc. +// Comment in the header says this above capset/capget: +/* system calls - look to libc for function to system call mapping */ +extern int capset(cap_user_header_t header, cap_user_data_t data); +extern int capget(cap_user_header_t header, const cap_user_data_t data); +// so for bbox, let's just repeat the declarations. +// This way, libcap needs not be installed in build environment. #include "libbb.h" static const char *const capabilities[] = { @@ -77,3 +85,42 @@ void FAST_FUNC printf_cap(const char *pfx, unsigned cap_no) } printf("%scap_%u", pfx, cap_no); } + +DEFINE_STRUCT_CAPS; + +void FAST_FUNC getcaps(void *arg) +{ + static const uint8_t versions[] = { + _LINUX_CAPABILITY_U32S_3, /* = 2 (fits into byte) */ + _LINUX_CAPABILITY_U32S_2, /* = 2 */ + _LINUX_CAPABILITY_U32S_1, /* = 1 */ + }; + int i; + struct caps *caps = arg; + + caps->header.pid = 0; + for (i = 0; i < ARRAY_SIZE(versions); i++) { + caps->header.version = versions[i]; + if (capget(&caps->header, NULL) == 0) + goto got_it; + } + bb_simple_perror_msg_and_die("capget"); + got_it: + + switch (caps->header.version) { + case _LINUX_CAPABILITY_VERSION_1: + caps->u32s = _LINUX_CAPABILITY_U32S_1; + break; + case _LINUX_CAPABILITY_VERSION_2: + caps->u32s = _LINUX_CAPABILITY_U32S_2; + break; + case _LINUX_CAPABILITY_VERSION_3: + caps->u32s = _LINUX_CAPABILITY_U32S_3; + break; + default: + bb_error_msg_and_die("unsupported capability version"); + } + + if (capget(&caps->header, caps->data) != 0) + bb_simple_perror_msg_and_die("capget"); +} 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 { }; #if ENABLE_FEATURE_SETPRIV_CAPABILITIES -struct caps { - struct __user_cap_header_struct header; - cap_user_data_t data; - int u32s; -}; - -static void getcaps(struct caps *caps) -{ - static const uint8_t versions[] = { - _LINUX_CAPABILITY_U32S_3, /* = 2 (fits into byte) */ - _LINUX_CAPABILITY_U32S_2, /* = 2 */ - _LINUX_CAPABILITY_U32S_1, /* = 1 */ - }; - int i; - - caps->header.pid = 0; - for (i = 0; i < ARRAY_SIZE(versions); i++) { - caps->header.version = versions[i]; - if (capget(&caps->header, NULL) == 0) - goto got_it; - } - bb_simple_perror_msg_and_die("capget"); - got_it: - - switch (caps->header.version) { - case _LINUX_CAPABILITY_VERSION_1: - caps->u32s = _LINUX_CAPABILITY_U32S_1; - break; - case _LINUX_CAPABILITY_VERSION_2: - caps->u32s = _LINUX_CAPABILITY_U32S_2; - break; - case _LINUX_CAPABILITY_VERSION_3: - caps->u32s = _LINUX_CAPABILITY_U32S_3; - break; - default: - bb_error_msg_and_die("unsupported capability version"); - } - - caps->data = xmalloc(sizeof(caps->data[0]) * caps->u32s); - if (capget(&caps->header, caps->data) < 0) - bb_simple_perror_msg_and_die("capget"); -} +DEFINE_STRUCT_CAPS; static unsigned parse_cap(const char *cap) { @@ -195,7 +154,7 @@ static void set_inh_caps(char *capstring) cap = parse_cap(capstring); if (CAP_TO_INDEX(cap) >= caps.u32s) - bb_error_msg_and_die("invalid capability cap"); + bb_error_msg_and_die("invalid capability '%s'", capstring); if (capstring[0] == '+') caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap); @@ -204,11 +163,8 @@ static void set_inh_caps(char *capstring) capstring = strtok(NULL, ","); } - if ((capset(&caps.header, caps.data)) < 0) + if (capset(&caps.header, caps.data) != 0) bb_perror_msg_and_die("capset"); - - if (ENABLE_FEATURE_CLEAN_UP) - free(caps.data); } static void set_ambient_caps(char *string) @@ -322,10 +278,9 @@ static int dump(void) bb_putchar('\n'); # endif - if (ENABLE_FEATURE_CLEAN_UP) { - IF_FEATURE_SETPRIV_CAPABILITIES(free(caps.data);) + if (ENABLE_FEATURE_CLEAN_UP) free(gids); - } + return EXIT_SUCCESS; } #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 @@ //config: list of active mount points. That's why. //applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_RUN_INIT( APPLET_ODDNAME(run-init, switch_root, BB_DIR_SBIN, BB_SUID_DROP, run_init)) //kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o +//kbuild:lib-$(CONFIG_RUN_INIT) += switch_root.o //usage:#define switch_root_trivial_usage -//usage: "[-c /dev/console] NEW_ROOT NEW_INIT [ARGS]" +//usage: "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" //usage:#define switch_root_full_usage "\n\n" //usage: "Free initramfs and switch to another root fs:\n" //usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" //usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" //usage: "\n -c DEV Reopen stdio to DEV after switch" +//usage:#define run_init_trivial_usage +//usage: "[-d CAP,CAP...] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" +//usage:#define run_init_full_usage "\n\n" +//usage: "Free initramfs and switch to another root fs:\n" +//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" +//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" +//usage: "\n -c DEV Reopen stdio to DEV after switch" +//usage: "\n -d CAPS Drop capabilities" + #include #include +#if ENABLE_RUN_INIT +# include +# include +// #include +// This header is in libcap, but the functions are in libc. +// Comment in the header says this above capset/capget: +/* system calls - look to libc for function to system call mapping */ +extern int capset(cap_user_header_t header, cap_user_data_t data); +extern int capget(cap_user_header_t header, const cap_user_data_t data); +// so for bbox, let's just repeat the declarations. +// This way, libcap needs not be installed in build environment. +#endif + #include "libbb.h" + // Make up for header deficiencies #ifndef RAMFS_MAGIC # define RAMFS_MAGIC ((unsigned)0x858458f6) @@ -89,6 +115,84 @@ static void delete_contents(const char *directory, dev_t rootdev) } } +#if ENABLE_RUN_INIT +DEFINE_STRUCT_CAPS; + +static void drop_capset(int cap_idx) +{ + struct caps caps; + + /* Get the current capability mask */ + getcaps(&caps); + + /* Drop the bit */ + caps.data[CAP_TO_INDEX(cap_idx)].inheritable &= ~CAP_TO_MASK(cap_idx); + + /* And drop the capability. */ + if (capset(&caps.header, caps.data) != 0) + bb_perror_msg_and_die("capset"); +} + +static void drop_bounding_set(int cap_idx) +{ + int ret; + + ret = prctl(PR_CAPBSET_READ, cap_idx, 0, 0, 0); + if (ret < 0) + bb_perror_msg_and_die("prctl: %s", "PR_CAPBSET_READ"); + + if (ret == 1) { + ret = prctl(PR_CAPBSET_DROP, cap_idx, 0, 0, 0); + if (ret != 0) + bb_perror_msg_and_die("prctl: %s", "PR_CAPBSET_DROP"); + } +} + +static void drop_usermodehelper(const char *filename, int cap_idx) +{ + unsigned lo, hi; + char buf[sizeof(int)*3 * 2 + 8]; + int fd; + int ret; + + ret = open_read_close(filename, buf, sizeof(buf) - 1); + if (ret < 0) + return; /* assuming files do not exist */ + + buf[ret] = '\0'; + ret = sscanf(buf, "%u %u", &lo, &hi); + if (ret != 2) + bb_perror_msg_and_die("can't parse file '%s'", filename); + + if (cap_idx < 32) + lo &= ~(1 << cap_idx); + else + hi &= ~(1 << (cap_idx - 32)); + + fd = xopen(filename, O_WRONLY); + fdprintf(fd, "%u %u", lo, hi); + close(fd); +} + +static void drop_capabilities(char *string) +{ + char *cap; + + cap = strtok(string, ","); + while (cap) { + unsigned cap_idx; + + cap_idx = cap_name_to_number(cap); + drop_usermodehelper("/proc/sys/kernel/usermodehelper/bset", cap_idx); + drop_usermodehelper("/proc/sys/kernel/usermodehelper/inheritable", cap_idx); + drop_bounding_set(cap_idx); + drop_capset(cap_idx); + bb_error_msg("dropped capability: %s", cap); + cap = strtok(NULL, ","); + } +} +#endif + int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int switch_root_main(int argc UNUSED_PARAM, char **argv) { @@ -98,7 +202,25 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) dev_t rootdev; // Parse args (-c console). '+': stop at first non-option - getopt32(argv, "^+" "c:" "\0" "-2" /* minimum 2 args */, &console); + if (ENABLE_SWITCH_ROOT && (!ENABLE_RUN_INIT || applet_name[0] == 's')) { + getopt32(argv, "^+" + "c:" + "\0" "-2" /* minimum 2 args */, + &console + ); + } else { +#if ENABLE_RUN_INIT + char *cap_list = NULL; + getopt32(argv, "^+" + "c:d:" + "\0" "-2" /* minimum 2 args */, + &console, + &cap_list + ); + if (cap_list) + drop_capabilities(cap_list); +#endif + } argv += optind; newroot = *argv++; -- cgit v1.2.3-55-g6feb From bbc26c6934fac218e19c7897f2dc2e6084e963b0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 22 Aug 2017 10:37:30 +0200 Subject: run-init: implement -n "dry run" function old new delta switch_root_main 637 706 +69 packed_usage 31743 31757 +14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 83/0) Total: 83 bytes text data bss dec hex filename 915247 563 5844 921654 e1036 busybox_old 915303 563 5844 921710 e106e busybox_unstripped Signed-off-by: Denys Vlasenko --- selinux/setfiles.c | 2 +- util-linux/switch_root.c | 77 +++++++++++++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 35 deletions(-) (limited to 'util-linux/switch_root.c') diff --git a/selinux/setfiles.c b/selinux/setfiles.c index fca698296..8da47d274 100644 --- a/selinux/setfiles.c +++ b/selinux/setfiles.c @@ -679,7 +679,7 @@ int setfiles_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); xstat(argv[0], &sb); if (!S_ISREG(sb.st_mode)) { - bb_error_msg_and_die("spec file %s is not a regular file", argv[0]); + bb_error_msg_and_die("'%s' is not a regular file", argv[0]); } /* Load the file contexts configuration and check it. */ rc = matchpathcon_init(argv[0]); diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index fe9ab68d0..16abcb634 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c @@ -24,6 +24,8 @@ //config: * Because the Linux kernel uses rootfs internally as the starting //config: and ending point for searching through the kernel's doubly linked //config: list of active mount points. That's why. +//config: +// RUN_INIT config item is in klibc-utils //applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) // APPLET_ODDNAME:name main location suid_type help @@ -32,23 +34,6 @@ //kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o //kbuild:lib-$(CONFIG_RUN_INIT) += switch_root.o -//usage:#define switch_root_trivial_usage -//usage: "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" -//usage:#define switch_root_full_usage "\n\n" -//usage: "Free initramfs and switch to another root fs:\n" -//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" -//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" -//usage: "\n -c DEV Reopen stdio to DEV after switch" - -//usage:#define run_init_trivial_usage -//usage: "[-d CAP,CAP...] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" -//usage:#define run_init_full_usage "\n\n" -//usage: "Free initramfs and switch to another root fs:\n" -//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" -//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" -//usage: "\n -c DEV Reopen stdio to DEV after switch" -//usage: "\n -d CAPS Drop capabilities" - #include #include #if ENABLE_RUN_INIT @@ -122,13 +107,8 @@ static void drop_capset(int cap_idx) { struct caps caps; - /* Get the current capability mask */ getcaps(&caps); - - /* Drop the bit */ caps.data[CAP_TO_INDEX(cap_idx)].inheritable &= ~CAP_TO_MASK(cap_idx); - - /* And drop the capability. */ if (capset(&caps.header, caps.data) != 0) bb_perror_msg_and_die("capset"); } @@ -199,10 +179,18 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) char *newroot, *console = NULL; struct stat st; struct statfs stfs; + unsigned dry_run = 0; dev_t rootdev; - // Parse args (-c console). '+': stop at first non-option + // Parse args. '+': stop at first non-option if (ENABLE_SWITCH_ROOT && (!ENABLE_RUN_INIT || applet_name[0] == 's')) { +//usage:#define switch_root_trivial_usage +//usage: "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" +//usage:#define switch_root_full_usage "\n\n" +//usage: "Free initramfs and switch to another root fs:\n" +//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" +//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" +//usage: "\n -c DEV Reopen stdio to DEV after switch" getopt32(argv, "^+" "c:" "\0" "-2" /* minimum 2 args */, @@ -210,13 +198,23 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) ); } else { #if ENABLE_RUN_INIT +//usage:#define run_init_trivial_usage +//usage: "[-d CAP,CAP...] [-n] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" +//usage:#define run_init_full_usage "\n\n" +//usage: "Free initramfs and switch to another root fs:\n" +//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" +//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" +//usage: "\n -c DEV Reopen stdio to DEV after switch" +//usage: "\n -d CAPS Drop capabilities" +//usage: "\n -n Dry run" char *cap_list = NULL; - getopt32(argv, "^+" - "c:d:" + dry_run = getopt32(argv, "^+" + "c:d:n" "\0" "-2" /* minimum 2 args */, &console, &cap_list ); + dry_run >>= 2; // -n if (cap_list) drop_capabilities(cap_list); #endif @@ -239,7 +237,7 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) // we mean it. I could make this a CONFIG option, but I would get email // from all the people who WILL destroy their filesystems. if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) { - bb_error_msg_and_die("/init is not a regular file"); + bb_error_msg_and_die("'%s' is not a regular file", "/init"); } statfs("/", &stfs); // this never fails if ((unsigned)stfs.f_type != RAMFS_MAGIC @@ -248,13 +246,15 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die("root filesystem is not ramfs/tmpfs"); } - // Zap everything out of rootdev - delete_contents("/", rootdev); + if (!dry_run) { + // Zap everything out of rootdev + delete_contents("/", rootdev); - // Overmount / with newdir and chroot into it - if (mount(".", "/", NULL, MS_MOVE, NULL)) { - // For example, fails when newroot is not a mountpoint - bb_perror_msg_and_die("error moving root"); + // Overmount / with newdir and chroot into it + if (mount(".", "/", NULL, MS_MOVE, NULL)) { + // For example, fails when newroot is not a mountpoint + bb_perror_msg_and_die("error moving root"); + } } xchroot("."); // The chdir is needed to recalculate "." and ".." links @@ -270,8 +270,17 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) } } - // Exec real init - execv(argv[0], argv); + if (dry_run) { + // Does NEW_INIT look like it can be executed? + //xstat(argv[0], &st); + //if (!S_ISREG(st.st_mode)) + // bb_perror_msg_and_die("'%s' is not a regular file", argv[0]); + if (access(argv[0], X_OK) == 0) + return 0; + } else { + // Exec NEW_INIT + execv(argv[0], argv); + } bb_perror_msg_and_die("can't execute '%s'", argv[0]); } -- cgit v1.2.3-55-g6feb From 7d834c9bb436edd594ebacc48d2b9ea7d3364dbd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 22 Aug 2017 11:40:27 +0200 Subject: run-init: if doing dry run, do not require pid==1 Signed-off-by: Denys Vlasenko --- util-linux/switch_root.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'util-linux/switch_root.c') diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index 16abcb634..080b05e45 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c @@ -227,9 +227,12 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) xstat("/", &st); rootdev = st.st_dev; xstat(".", &st); - if (st.st_dev == rootdev || getpid() != 1) { + if (st.st_dev == rootdev) { // Show usage, it says new root must be a mountpoint - // and we must be PID 1 + bb_show_usage(); + } + if (!dry_run && getpid() != 1) { + // Show usage, it says we must be PID 1 bb_show_usage(); } -- cgit v1.2.3-55-g6feb