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.
This commit is contained in:
Simon Fels 2016-12-13 13:50:04 +01:00
commit 7f564c55eb
5 changed files with 206 additions and 0 deletions

63
scripts/classic Executable file
View file

@ -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

61
scripts/classic-create Executable file
View file

@ -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 <<EOF > "$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"

19
scripts/classic-reset Executable file
View file

@ -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

View file

@ -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<<EOF > $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

View file

@ -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: