From 7f564c55ebbc28d17d65ee0fbf5f716f01ffab9d Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Tue, 13 Dec 2016 13:50:04 +0100 Subject: [PATCH] Build and load binder/ashmem kernel modules on service start As both kernel modules are not part of the standard Ubuntu kernel we need to build and load them at runtime. We bundle this together with the container manager start and reuse the classic snap scripts to do the actual build in a proper environment. --- scripts/classic | 63 ++++++++++++++++++++++++++++++++++++ scripts/classic-create | 61 ++++++++++++++++++++++++++++++++++ scripts/classic-reset | 19 +++++++++++ scripts/container-manager.sh | 54 +++++++++++++++++++++++++++++++ snapcraft.yaml | 9 ++++++ 5 files changed, 206 insertions(+) create mode 100755 scripts/classic create mode 100755 scripts/classic-create create mode 100755 scripts/classic-reset diff --git a/scripts/classic b/scripts/classic new file mode 100755 index 0000000..ab5ca89 --- /dev/null +++ b/scripts/classic @@ -0,0 +1,63 @@ +#!/bin/sh + +set -e + +ROOT=$SNAP_COMMON/classic + +# $1: source +# $2: target +# $3: if not empty, bind mount will be read-only +# note that we do NOT clean these up at the end, as the user might start many +# classic shells in parallel; we could start all of them in their own mount +# namespace, but that would make the classic shell less useful for +# developing/debugging the snappy host +do_bindmount() { + if ! mountpoint -q "$ROOT/$2"; then + if [ -d "$1" -a ! -L "$1" ]; then + mkdir -p "$ROOT/$2" + fi + mount --make-rprivate --rbind -o rbind "$1" "$ROOT/$2" + if [ -n "${3:-}" ]; then + mount --rbind -o remount,ro "$1" "$ROOT/$2" + fi + fi +} + +if [ "$(id -u)" != "0" ]; then + echo "needs to run as root" + exit 1 +fi + +if [ ! -d $ROOT ]; then + # IMPORTANT: do not run the classic.create as this will run it with + # snap-confine again and this will cause havoc with current + # snap-confine + $SNAP/bin/create +fi + +# FIXME: confinement will prevent this +do_bindmount /home /home +do_bindmount /run /run +do_bindmount /proc /proc +do_bindmount /sys /sys +do_bindmount /dev /dev +do_bindmount / /snappy + +SUDO_USER=root + +# fix LP: #1619455 +cp -a /var/lib/extrausers/* $ROOT/var/lib/extrausers/ +cp -a /etc/sudoers.d/* $ROOT/etc/sudoers.d/ + +# assemble command line +DEVPTS="mount -o mode=666,ptmxmode=666 -t devpts devpts /dev/pts" +SUDOCMD="sudo debian_chroot=classic -u ${SUDO_USER} -i $@" +# FIXME: workaround for https://bugs.launchpad.net/snappy/+bug/1611493 +SCRIPT="script --quiet --return --command \"$SUDOCMD\" /dev/null" + +CMD="$DEVPTS; $SCRIPT" + +systemd-run --quiet --scope --unit=classic-$$.scope --description="Classic shell" chroot "$ROOT" sh -c "$CMD" + +# kill leftover processes after exiting, if it's still around +systemctl stop classic-$$.scope 2>/dev/null || true diff --git a/scripts/classic-create b/scripts/classic-create new file mode 100755 index 0000000..10b8efa --- /dev/null +++ b/scripts/classic-create @@ -0,0 +1,61 @@ +#!/bin/sh + +set -eu + +ROOT=$SNAP_COMMON/classic + +if [ -d $ROOT ]; then + echo "classic already enabled" + exit 1 +fi + +if [ $(id -u) -ne 0 ]; then + echo "This script needs to be called as root" >&2 + exit 1 +fi + +CORE="" +if [ -e /snap/core/current ]; then + CORE="core" +elif [ -e /snap/ubuntu-core/current ]; then + CORE="ubuntu-core" +else + echo "Cannot find core snap" + exit 1 +fi + +# FIXME: confinement will prevent this +echo "Creating classic environment" +VERSION="$(/bin/readlink /snap/${CORE}/current)" +SNAPROOT="/var/lib/snapd/snaps/${CORE}_${VERSION}.snap" +/usr/bin/unsquashfs -d $ROOT $SNAPROOT +mkdir $ROOT/snappy + +# enable +sudo chroot $ROOT /var/lib/classic/enable.sh + +# copy important config +for f in hostname timezone localtime; do + cp -a /etc/writable/$f $ROOT/etc/writable +done +for f in hosts; do + cp -a /etc/$f $ROOT/etc/ +done + + +# don't start services in the chroot on apt-get install +cat < "$ROOT/usr/sbin/policy-rc.d" +#!/bin/sh +while true; do + case "\$1" in + -*) shift ;; + makedev) exit 0;; + x11-common) exit 0;; + *) exit 101;; + esac +done +EOF +chmod 755 "$ROOT/usr/sbin/policy-rc.d" + +# workaround bug in livecd-rootfs +chmod 1777 "$ROOT/tmp" diff --git a/scripts/classic-reset b/scripts/classic-reset new file mode 100755 index 0000000..62c4329 --- /dev/null +++ b/scripts/classic-reset @@ -0,0 +1,19 @@ +#!/bin/sh + +set -eu + +ROOT=$SNAP_COMMON/classic + +if [ "$(id -u)" != "0" ]; then + echo "needs to run as root" + exit 1 +fi + +for d in /home /run /proc /sys /dev /var/lib/extrausers /etc/sudoers /etc/sudoers.d /snappy; do + if mountpoint -q "$ROOT/$d"; then + umount "$ROOT/$d" + fi +done + +# cleanup +rm -rf $ROOT diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index 8dd9fe8..90f867d 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -1,4 +1,5 @@ #!/bin/sh +set -x # We need to put the rootfs somewhere where we can modify some # parts of the content on first boot (namely file permissions). @@ -21,6 +22,50 @@ if [ ! -e $SYSTEM_IMG ]; then exit 1 fi +build_kernel_modules() { + kversion=$1 + + rm -rf $SNAP_COMMON/kernel-* + + $SNAP/bin/classic-create || true + + rm -rf $SNAP_COMMON/classic/build + mkdir -p $SNAP_COMMON/classic/build + cp -rav $SNAP/ashmem $SNAP_COMMON/classic/build/ + cp -rav $SNAP/binder $SNAP_COMMON/classic/build/ + + cat< $SNAP_COMMON/classic/build/run.sh +#!/bin/sh +set -ex +apt update +apt install -y --force-yes linux-headers-$kversion build-essential +cd /build/ashmem +make +cd /build/binder +make +EOF + + chmod +x $SNAP_COMMON/classic/build/run.sh + $SNAP/bin/classic /build/run.sh + + mkdir -p $SNAP_COMMON/kernel-$kversion + cp $SNAP_COMMON/classic/build/ashmem/ashmem_linux.ko \ + $SNAP_COMMON/kernel-$kversion/ + cp $SNAP_COMMON/classic/build/binder/binder_linux.ko \ + $SNAP_COMMON/kernel-$kversion/ +} + +load_kernel_modules() { + kversion=`uname -r` + rmmod ashmem_linux binder_linux || true + echo "Loading kernel modules for version $kversion.." + insmod $SNAP_COMMON/kernel-$kversion/binder_linux.ko + insmod $SNAP_COMMON/kernel-$kversion/ashmem_linux.ko + sleep 0.5 + chmod 666 /dev/binder + chmod 666 /dev/ashmem +} + start() { # Extract ramdisk content instead of trying to bind mount the # cpio image file to allow modifications. @@ -52,6 +97,13 @@ start() { # possible. See snapcraft.yaml for further details. $SNAP/bin/anbox-bridge.sh start + kversion=`uname -r` + if [ ! -e $SNAP_COMMON/kernel-$kversion ]; then + build_kernel_modules $kversion + fi + + load_kernel_modules + exec $SNAP/usr/sbin/aa-exec -p unconfined -- $SNAP/bin/anbox-wrapper.sh container-manager } @@ -63,6 +115,8 @@ stop() { umount $ROOTFS_PATH $SNAP/bin/anbox-bridge.sh stop + + rmmod ashmem_linux binder_linux || true } case "$1" in diff --git a/snapcraft.yaml b/snapcraft.yaml index 376defc..972822a 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -29,6 +29,9 @@ parts: files: system.img: system.img ramdisk.img: ramdisk.img + kernel-modules: + plugin: dump + source: kernel anbox-common: plugin: copy source: . @@ -36,10 +39,16 @@ parts: scripts/snap-wrapper.sh: bin/anbox-wrapper.sh scripts/container-manager.sh: bin/container-manager.sh scripts/anbox-bridge.sh: bin/anbox-bridge.sh + scripts/classic: bin/classic + scripts/classic-create: bin/classic-create + scripts/classic-reset: bin/classic-reset snap: - bin/anbox-bridge.sh - bin/anbox-wrapper.sh - bin/container-manager.sh + - bin/classic + - bin/classic-create + - bin/classic-reset apparmor: plugin: nil stage-packages: