From 2aacc6912b78e7d3158f072cd9c1b3c5d0bddc22 Mon Sep 17 00:00:00 2001 From: William Manley Date: Wed, 31 Aug 2016 17:15:48 +0100 Subject: [PATCH] ostree-prepare-root: Fix running with musl musl libc's implementation of `realpath` works by opening the path and then doing a lookup in `/proc/self/fd` to find the canonical path. This fails if `/proc` is not mounted. This causes problems for us if `ostree-prepare-root` is `init` as `/proc` won't be mounted. We have to mount `/proc` anyway for `/proc/cmdline` so this fix just expands the scope over which `/proc` is mounted to include both our `realpath` calls. See also: * http://www.openwall.com/lists/musl/2016/06/08/2 and * http://git.musl-libc.org/cgit/musl/tree/src/misc/realpath.c?id=e738b8cbe64b6dd3ed9f47b6d4cd7eb2c422b38d Closes: #485 Approved by: cgwalters --- src/switchroot/ostree-prepare-root.c | 37 +++++++++++++++------------- tests/test-switchroot.sh | 9 ++++++- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index ea7333b5..ce48a91e 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -80,26 +80,10 @@ parse_ostree_cmdline (void) char *cmdline = NULL; const char *iter; char *ret = NULL; - int tmp_errno; cmdline = read_proc_cmdline (); if (!cmdline) - { - // Mount proc - if (mount ("proc", "/proc", "proc", 0, NULL) < 0) - err (EXIT_FAILURE, "failed to mount proc on /proc"); - - cmdline = read_proc_cmdline (); - tmp_errno = errno; - - /* Leave the filesystem in the state that we found it: */ - if (umount ("/proc")) - err (EXIT_FAILURE, "failed to umount proc from /proc"); - - errno = tmp_errno; - if (!cmdline) - err (EXIT_FAILURE, "failed to read /proc/cmdline"); - } + err (EXIT_FAILURE, "failed to read /proc/cmdline"); iter = cmdline; while (iter != NULL) @@ -178,17 +162,36 @@ main(int argc, char *argv[]) char *deploy_path = NULL; char srcpath[PATH_MAX]; struct stat stbuf; + int we_mounted_proc = 0; if (argc < 2) root_arg = "/"; else root_arg = argv[1]; + if (stat ("/proc/cmdline", &stbuf) < 0) + { + if (errno != ENOENT) + err (EXIT_FAILURE, "stat(\"/proc/cmdline\") failed"); + /* We need /proc mounted for /proc/cmdline and realpath (on musl) to + * work: */ + if (mount ("proc", "/proc", "proc", 0, NULL) < 0) + err (EXIT_FAILURE, "failed to mount proc on /proc"); + we_mounted_proc = 1; + } + root_mountpoint = realpath (root_arg, NULL); if (root_mountpoint == NULL) err (EXIT_FAILURE, "realpath(\"%s\")", root_arg); deploy_path = resolve_deploy_path (root_mountpoint); + if (we_mounted_proc) + { + /* Leave the filesystem in the state that we found it: */ + if (umount ("/proc")) + err (EXIT_FAILURE, "failed to umount proc from /proc"); + } + /* Work-around for a kernel bug: for some reason the kernel * refuses switching root if any file systems are mounted * MS_SHARED. Hence remount them MS_PRIVATE here as a diff --git a/tests/test-switchroot.sh b/tests/test-switchroot.sh index 96c849e5..fd5a30d0 100755 --- a/tests/test-switchroot.sh +++ b/tests/test-switchroot.sh @@ -4,7 +4,14 @@ this_script="${BASH_SOURCE:-$(readlink -f "$0")}" setup_bootfs() { mkdir -p "$1/proc" "$1/bin" - echo "quiet ostree=/ostree/boot.0 ro" >"$1/proc/cmdline" + + # We need the real /proc mounted here so musl's realpath will work, but we + # want to be able to override /proc/cmdline, so bind mount. + mount -t proc proc "$1/proc" + + echo "quiet ostree=/ostree/boot.0 ro" >"$1/override_cmdline" + mount --bind "$1/override_cmdline" "$1/proc/cmdline" + touch "$1/this_is_bootfs" cp "$(dirname "$this_script")/../ostree-prepare-root" "$1/bin" }