From f6e421a0897c1f8579b1e62956da338e350a7f2a Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Wed, 12 Jul 2017 09:28:01 +0200 Subject: [PATCH] Add support to mount rootfs image via squashfuse --- src/anbox/cmds/container_manager.cpp | 78 +++++++++++++++++++++------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/src/anbox/cmds/container_manager.cpp b/src/anbox/cmds/container_manager.cpp index a71f07b..3356fd7 100644 --- a/src/anbox/cmds/container_manager.cpp +++ b/src/anbox/cmds/container_manager.cpp @@ -23,6 +23,7 @@ #include "anbox/config.h" #include "core/posix/signal.h" +#include "core/posix/exec.h" #include #include @@ -121,30 +122,67 @@ bool anbox::cmds::ContainerManager::setup_mounts() { if (!fs::exists(android_rootfs_dir)) fs::create_directory(android_rootfs_dir); - std::shared_ptr loop_device; + // We prefer using the kernel for mounting the squashfs image but + // for some cases (unprivileged containers) where no loop support + // is available we do the mount instead via squashfuse which will + // work entirely in userspace. + if (fs::exists("/dev/loop-control")) { + std::shared_ptr loop_device; - try { - loop_device = common::LoopDeviceAllocator::new_device(); - } catch (const std::exception& e) { - ERROR("Could not create loopback device: %s", e.what()); - return false; - } catch (...) { - ERROR("Could not create loopback device"); + try { + loop_device = common::LoopDeviceAllocator::new_device(); + } catch (const std::exception& e) { + ERROR("Could not create loopback device: %s", e.what()); + return false; + } catch (...) { + ERROR("Could not create loopback device"); + return false; + } + + if (!loop_device->attach_file(android_img_path)) { + ERROR("Failed to attach Android rootfs image to loopback device"); + return false; + } + + auto m = common::MountEntry::create(loop_device, android_rootfs_dir, "squashfs", MS_MGC_VAL | MS_RDONLY | MS_PRIVATE); + if (!m) { + ERROR("Failed to mount Android rootfs"); + return false; + } + mounts_.push_back(m); + } else if (fs::exists("/dev/fuse") && !utils::find_program_on_path("squashfuse").empty()) { + std::vector args = { + "-t", "fuse.squashfuse", + // Allow other users than root to access the rootfs + "-o", "allow_other", + android_img_path.string(), + android_rootfs_dir, + }; + + // Easiest is here to go with the standard mount program as that + // will handle everything for us which is relevant to get the + // squashfs via squashfuse properly mount without having to + // reimplement all the details. Once the mount call comes back + // without an error we can expect the image to be mounted. + auto child = core::posix::exec("/bin/mount", args, {}, core::posix::StandardStream::empty, []() {}); + const auto result = child.wait_for(core::posix::wait::Flags::untraced); + if (result.status != core::posix::wait::Result::Status::exited || + result.detail.if_exited.status != core::posix::exit::Status::success) { + ERROR("Failed to mount squashfs Android image"); + return false; + } + + auto m = common::MountEntry::create(android_rootfs_dir); + if (!m) { + ERROR("Failed to create mount entry for Android rootfs"); + return false; + } + mounts_.push_back(m); + } else { + ERROR("No loop device or FUSE support found. Can't setup Android rootfs!"); return false; } - if (!loop_device->attach_file(android_img_path)) { - ERROR("Failed to attach Android rootfs image to loopback device"); - return false; - } - - auto m = common::MountEntry::create(loop_device, android_rootfs_dir, "squashfs", MS_MGC_VAL | MS_RDONLY | MS_PRIVATE); - if (!m) { - ERROR("Failed to mount Android rootfs"); - return false; - } - mounts_.push_back(m); - for (const auto &dir_name : std::vector{"cache", "data"}) { auto target_dir_path = fs::path(android_rootfs_dir) / dir_name; auto src_dir_path = SystemConfiguration::instance().data_dir() / dir_name;