diff --git a/external/nsexec/uidmapshift.c b/external/nsexec/uidmapshift.c new file mode 100644 index 0000000000000000000000000000000000000000..089b7b545c22f34ef5ff955cc3bf69322420b033 --- /dev/null +++ b/external/nsexec/uidmapshift.c @@ -0,0 +1,160 @@ +/* + * Copyright © 2012-2016 Canonical, Inc + * + * Author: Serge Hallyn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + */ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define min(a,b) (a) < (b) ? (a) : (b) +#define max(a,b) (a) > (b) ? (a) : (b) + +static int verbose = 0; +static int convert_uids = 0; +static int convert_gids = 0; +static uid_t srcid; +static uid_t dstid; +static uid_t range; +static uid_t range_uid_max = 0; +static uid_t range_uid_min = ~0; +static gid_t range_gid_max = 0; +static gid_t range_gid_min = ~0; + +void usage(void) +{ + extern const char *__progname; + printf("Usage: %s [OPTIONS] directory [src dst range]\n\n", __progname); + printf(" -u, --uid convert uids in directory\n"); + printf(" -g, --gid convert gids in directory\n"); + printf(" -b, --both convert uids and gids in directory\n"); + printf(" -r, --range find min,max uid/gid used in directory\n"); + printf(" -v, --verbose increate verbosity\n\n"); + printf("Note this program always recursively walks all of directory.\n"); + printf("If -u,-g, or -b is given, then [src dst range] are required to convert the \n"); + printf("ids within the range [src..src+range] to [dst..dst+range].\n\n"); + printf("Examples:\n"); + printf(" %s -r /path/to/directory # show min/max uid/gid\n", __progname); + printf(" %s -b /path/to/directory 0 100000 500 # map uids and gids up\n", __progname); + printf(" %s -u /path/to/directory 100000 0 500 # map the uids back down\n", __progname); +} + +int ftw_callback(const char *fpath, const struct stat *st, + int typeflag, struct FTW *ftw) +{ + uid_t new_uid = -1; + uid_t new_gid = -1; + int ret; + + range_uid_max = max(range_uid_max, st->st_uid); + range_uid_min = min(range_uid_min, st->st_uid); + range_gid_max = max(range_gid_max, st->st_gid); + range_gid_min = min(range_gid_min, st->st_gid); + + if (convert_uids && st->st_uid >= srcid && st->st_uid < srcid+range) + new_uid = (st->st_uid-srcid) + dstid; + if (convert_gids && st->st_gid >= srcid && st->st_gid < srcid+range) + new_gid = (st->st_gid-srcid) + dstid; + if (new_uid != -1 || new_gid != -1) { + ret = lchown(&fpath[ftw->base], new_uid, new_gid); + if (ret) { + fprintf(stderr, "failed to chown %d:%d %s\n", + new_uid, new_gid, fpath); + /* well, let's keep going */ + } else { + if (!S_ISLNK(st->st_mode)) { + if (verbose > 1) + fprintf(stderr, "resetting mode to %o on %s\n", + st->st_mode, fpath); + ret = chmod(&fpath[ftw->base], st->st_mode); + if (ret) { + fprintf(stderr, "failed to reset mode %o on %s\n", + st->st_mode, fpath); + /* well, let's keep going */ + } + } + if (verbose) + printf("u:%07d=%07d g:%07d=%07d m:%#07o %s %s\n", + st->st_uid, new_uid, + st->st_gid, new_gid, + st->st_mode, fpath, &fpath[ftw->base]); + } + } + return 0; +} + +int main(int argc, char *argv[]) +{ + const char *base; + int show_range = 0; + int opt,ret; + + static const struct option long_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "uids", no_argument, NULL, 'u' }, + { "gids", no_argument, NULL, 'g' }, + { "both", no_argument, NULL, 'b' }, + { "range", no_argument, NULL, 'r' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } + }; + + while ((opt = getopt_long(argc, argv, "hugbrv", long_opts, NULL)) >= 0) { + switch (opt) { + case 'h': usage(); exit(EXIT_SUCCESS); + case 'u': convert_uids = 1; break; + case 'g': convert_gids = 1; break; + case 'b': convert_uids = convert_gids = 1; break; + case 'r': show_range = 1; break; + case 'v': verbose++; break; + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + exit(EXIT_FAILURE); + } + + base = argv[0]; + if (convert_uids || convert_gids) { + if (argc < 4) { + usage(); + exit(EXIT_FAILURE); + } + srcid = atoi(argv[1]); + dstid = atoi(argv[2]); + range = atoi(argv[3]); + } + + ret = nftw(base, ftw_callback, 1000, FTW_PHYS|FTW_CHDIR); + if (ret < 0) { + fprintf(stderr, "Failed to walk path %s %s\n", base, strerror(errno)); + usage(); + return EXIT_FAILURE; + } + + if (show_range) { + printf("UIDs %d - %d\n" + "GIDs %d - %d\n", + range_uid_min, range_uid_max, + range_gid_min, range_gid_max); + } + + return EXIT_SUCCESS; +} diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index 90f867d30d335fa9672bdaed568b043101e9c1ab..163bab4679f4598dd8c95fc73fc0ab28b2ff04e1 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -8,17 +8,11 @@ set -x DATA_PATH=$SNAP_COMMON/var/lib/anbox ROOTFS_PATH=$DATA_PATH/rootfs -RAMDISK_PATH=$DATA_PATH/ramdisk -INITRD=$SNAP/ramdisk.img -SYSTEM_IMG=$SNAP/system.img +ANDROID_IMG=$SNAP/android.img +CONTAINER_BASE_UID=100000 -if [ ! -e $INITRD ]; then - echo "ERROR: boot ramdisk does not exist" - exit 1 -fi - -if [ ! -e $SYSTEM_IMG ]; then - echo "ERROR: system image does not exist" +if [ ! -e $ANDROID_IMG ]; then + echo "ERROR: android image does not exist" exit 1 fi @@ -67,24 +61,14 @@ load_kernel_modules() { } start() { - # Extract ramdisk content instead of trying to bind mount the - # cpio image file to allow modifications. - rm -Rf $RAMDISK_PATH - mkdir -p $RAMDISK_PATH - cd $RAMDISK_PATH - cat $INITRD | gzip -d | cpio -i - - # FIXME those things should be fixed in the build process - chmod +x $RAMDISK_PATH/anbox-init.sh - # Setup the read-only rootfs mkdir -p $ROOTFS_PATH - mount -o bind,ro $RAMDISK_PATH $ROOTFS_PATH - mount -o loop,ro $SYSTEM_IMG $ROOTFS_PATH/system + mount -o loop,ro $ANDROID_IMG $ROOTFS_PATH # but certain top-level directories need to be in a writable space for dir in cache data; do mkdir -p $DATA_PATH/android-$dir + chown $CONTAINER_BASE_UID:$CONTAINER_BASE_UID $DATA_PATH/android-$dir mount -o bind $DATA_PATH/android-$dir $ROOTFS_PATH/$dir done @@ -104,6 +88,9 @@ start() { load_kernel_modules + # Ensure FUSE support for user namespaces is enabled + echo Y > /sys/module/fuse/parameters/userns_mounts + exec $SNAP/usr/sbin/aa-exec -p unconfined -- $SNAP/bin/anbox-wrapper.sh container-manager } @@ -111,7 +98,6 @@ stop() { for dir in cache data; do umount $ROOTFS_PATH/$dir done - umount $ROOTFS_PATH/system umount $ROOTFS_PATH $SNAP/bin/anbox-bridge.sh stop diff --git a/scripts/create-package.sh b/scripts/create-package.sh index a94b28f26bf5b6a2dc4c9b049a8629c705985596..d5a33b07135b4d23cf5cf7983790809ba397f6bf 100755 --- a/scripts/create-package.sh +++ b/scripts/create-package.sh @@ -1,45 +1,34 @@ #!/bin/bash -TOPDIR=`echo $ANDROID_BUILD_TOP` -OUTDIR=`echo $ANDROID_PRODUCT_OUT` -CURDIR=`pwd` -TARGET=rootfs +set -ex -if [ -d $TARGET ] ; then - rm -rf $TARGET +ramdisk=$1 +system=$2 + +if [ -z "$ramdisk" ] || [ -z "$system" ]; then + echo "Usage: $0 " + exit 1 fi -mkdir $TARGET -cp -r $OUTDIR/root/* $TARGET/ -cp -r $OUTDIR/system/* $TARGET/system/ +workdir=`mktemp -d` +rootfs=$workdir/rootfs -mkdir $TARGET/cache +mkdir -p $rootfs -find out -name filesystem_config.txt -exec cp {} $TARGET \; -if [ ! -e $TARGET/filesystem_config.txt ] ; then - echo "ERROR: Filesystem config is not available. You have to run" - echo "ERROR: $ make target-files-package" - echo "ERROR: to generate it as part of the Android build." - rm -rf $TARGET - exit 1 -fi +# Extract ramdisk and preserve ownership of files +(cd $rootfs ; cat $ramdisk | gzip -d | sudo cpio -i) -if [ -z "$TOPDIR" ] || [ "$CURDIR" != "$TOPDIR" ] ; then - echo "ERROR: You have to execute this script from the ANDROID_BUILD_TOP" - echo "ERROR: directory." - exit 1 -fi +mkdir $workdir/system +sudo mount -o loop,ro $system $workdir/system +sudo cp -ar $workdir/system/* $rootfs/system +sudo umount $workdir/system -cp anbox/scripts/anbox-init.sh $TARGET/ -chmod +x $TARGET/anbox-init.sh +gcc -o $workdir/uidmapshift external/nsexec/uidmapshift.c +sudo $workdir/uidmapshift -b $rootfs 0 100000 65536 -chmod 755 $TARGET/init.* -chmod 755 $TARGET/default.prop -chmod 755 $TARGET/system/build.prop -chmod +x $TARGET/anbox-init.sh +# FIXME +sudo chmod +x $rootfs/anbox-init.sh -TARBALL_NAME=anbox-rootfs-`date +%Y%m%d%H%M`.tar -tar cf $TARBALL_NAME $TARGET -rm -rf $TARGET +sudo mksquashfs $rootfs android.img -comp xz -no-xattrs -echo "Created $TARBALL_NAME" +sudo rm -rf $workdir