diff --git a/tool/rump b/tool/rump new file mode 100755 index 000000000..2166a0d18 --- /dev/null +++ b/tool/rump @@ -0,0 +1,433 @@ +#!/bin/bash +# +# \brief Manage rumpkernel tools +# \author Josef Soentgen +# \date 2014-04-29 +# + + +# +# Needed by glibc, otherwise loading modules as libraries for the +# rumpkernel does not work +# +export LD_DYNAMIC_WEAK=1 + + +msg() { + [ $ARG_VERBOSE -ge 0 ] && printf -- "${1}\n" +} + + +debug() { + [ $ARG_VERBOSE -ge 2 ] && printf -- "\t${1}\n" > /dev/stderr +} + + +trap_exit() { + if [ "$RUMP_SERVER" ]; then + if [ $ARG_CRYPT_DEV -ne 0 ] && [ "$ARG_CRYPT_KEY" != "" ]; then + rump_client "cgdconfig" "-u cgd0" + fi + rump_client "halt" + fi + + [ -d "$RUMP_TMP" ] && rm -rf $RUMP_TMP +} + + +trap_abort() { + trap_exit + [ -d "$RUMP_TMP" ] && rm -rf $RUMP_TMP +} + + +# +# Start the rumpkernel +# +# \param libs list of libraries (modules) the rumpkernel should +# load on start-up +# \param disks list of drivespecs the rumpkernel should attach +# +rump_server() { + local libs="$1" + local disks="$2" + + $DRY_RUN $RUMP_PATH/rump_server $libs $disks $RUMP_SERVER + if [ $? -ne 0 ]; then + msg "could not start rump server." + unset RUMP_SERVER + exit 1 + fi +} + + +# +# Run a rumpkernel client +# +# \param cmd commando to execute within the rumpkernel +# \param args arguments for the commando +# +rump_client() { + local cmd="$1" + local args="$2" + + debug "$RUMP_PATH/$cmd $args" + + $DRY_RUN $RUMP_PATH/$cmd $args + if [ $? -ne 0 ]; then + echo "executing '$(basename $cmd) $args' failed." + # XXX kill all processes that are still haning around + # exit 1 + fi +} + + +# +# Encrypt or decrypt device +# +# If the key parameter is not blank decrypt the device. Otherwise +# generate a new key to encrypt. +# +# \param key key to encrypt +# +do_crypt_dev() { + local key="$1" + local args= + + if [ "$key" = "" ]; then + args="-g -k storedkey -o /cgd0.conf aes-cbc 256" + else + args="cgd0 $RUMP_DISK_DEV /cgd0.conf" + fi + + rump_client "cgdconfig" "$args" +} + + +# +# Format file system +# +# \param fs file system type +# \param dev raw device +# +do_format_fs() { + local fs="$1" + local dev="$2" + local prog= + local args= + + case $fs in + ffs) prog="newfs";; + ext2fs) prog="newfs_ext2fs"; args="-I";; + *) msg "unsupported fs given."; return;; + esac + + args="$args $dev" + rump_client "$prog" "$args" +} + + +# +# List files in the file system +# +# \param mntpt mount point of file system in the rumpkernel namespace +# +do_list_fs() { + local mntpt="$1" + + rump_client "ls" "-lRah $mntpt" +} + + +# +# Mount fs +# +# \param fs type of file system +# \param dev device to mount +# \param mntpt mount point +# +do_mount_fs() { + local fs="$1" + local dev="$2" + local mntpt="$3" + + args="$dev $mntpt" + + # XXX maybe check if $mntpt exists + rump_client "mkdir" "$mntpt" + + rump_client "mount_$fs" "$args" +} + + +# +# Umount fs +# +# \param mntpt mount point +# +do_umount_fs() { + local mntpt="$1" + + rump_client "umount" "$mntpt" +} + + +# +# Populate fs +# +# \param top_dir root directory +# +do_populate_fs() { + local top_dir="$(readlink -f $1)" + local dirs="$(find $top_dir -mindepth 1 -type d|sed 's:'$top_dir'/::g')" + local files="$(find $top_dir -type f|sed 's:'$top_dir'/::g')" + + # + # First create the directories and copy the files thereafter + # + for dir in ${dirs[*]}; do + rump_client "mkdir" "-p /mnt/$dir" + done + + for file in ${files[*]}; do + target_dir="$(dirname ${file})" + + rump_client "cp" "${RUMP_HOST_DIR}/${file} /mnt/${target_dir}" + done +} + + +# +# Create cgdconfig(8) file from given key +# +# \param config_file name of the output file +# \param key key string +# +create_cgd_config() { + local config_file=$1 + local key=$2 + + if [ "$key" != "" ]; then + $TOOL_DIR/rump_cgdconf -k $key > $config_file + else + echo > $config_file + fi + + chmod 600 $config_file +} + + +# +# Create temporary directory +# +# If the dir parameter is not set, create a temp directory automagically. +# +# \param dir path to the directory +# +create_temp_dir() { + local dir="$1" + + if [ "$dir" != "" ]; then + RUMP_TMP="$dir" + mkdir $RUMP_TMP + else + RUMP_TMP=$(mktemp -d -t genode-rump.XXXXXX 2>&1) + [ $? -ne 0 ] && { echo 'could not create temp dir'; exit 1; } + fi +} + + +# +# Print usage +# +print_usage() { + local help="$1" + + printf "usage: $PROG_NAME [-cfhlnvH] [-d dev] [-F fs] [-k key] " + printf "[-p dir] [-t dir] \n" + if [ "$help" != "" ]; then + printf "\t-c use cgd(4) to en/decrypt image\n" + printf "\t-f format image (see -F)\n" + printf "\t-h print this help screen\n" + printf "\t-l list files in disk_image\n" + printf "\t-n dry run, print commands w/o executing\n" + printf "\t-v verbose mode, may be used multiple times\n" + printf "\t-d dev device which is used for formatting within " + printf "the rumpkernel\n" + printf "\t [e.g. /blk_device or /dev/rcgd0a]\n" + printf "\t-F fs specify file system [ffs, ext2fs]\n" + printf "\t-k key use given key to access cgd(4) device\n" + printf "\t-p dir populate the image with the content of " + printf "dir\n" + printf "\t-t dir temp directory for storing rump tool " + printf "files [/tmp/genode-rump.XXXXXX]\n" + fi +} + + +# +# Parse commandline arguments +# +parse_arguments() { + args=$(getopt cd:fhk:lnp:t:vHF: ${*}) + [ $? != 0 ] && exit 1 + if [ $# -lt 1 ] + then + print_usage + exit 1 + fi + set -- $args + while [ $# -ge 0 ]; do + case "$1" in + -c) ARG_CRYPT_DEV=1; shift;; + -d) ARG_DISK_DEV="$2"; shift; shift;; + -f) ARG_FORMAT_DEV=1; shift;; + -F) ARG_FORMAT_FS="$2"; shift; shift;; + -h) print_usage "help"; exit 0;; + -k) ARG_CRYPT_KEY="$2"; shift; shift;; + -l) ARG_LIST_FS=1; shift;; + -n) ARG_DRY_RUN=1; shift;; + -p) ARG_POPULATE_FS="$2"; shift; shift;; + -t) ARG_TMP_DIR="$2"; shift; shift;; + -v) ARG_VERBOSE=$(($ARG_VERBOSE + 1)); shift;; + --) shift; break;; + esac + done + + if [ $# -lt 1 ]; then + msg "aborting, disk image missing." + exit 1 + fi + + ARG_DISK_IMAGE="$1" + if [ ! -f "$ARG_DISK_IMAGE" ]; then + msg "aborting, could not open '$ARG_DISK_IMAGE'." + exit 1 + fi + + if [ $ARG_LIST_FS -eq 1 ] && [ $ARG_FORMAT_DEV -eq 1 ]; then + msg "aborting, -f and -l are mutually exclusive." + exit 1 + fi + + if [ "$ARG_CRYPT_KEY" != "" ] && [ "$ARG_DISK_DEV" = "" ]; then + ARG_DISK_DEV="/dev/cgd0a" + fi + + [ "$ARG_DISK_DEV" != "" ] && RUMP_FORMAT_DISK_DEV="$ARG_DISK_DEV" + + [ $ARG_DRY_RUN -eq 1 ] && DRY_RUN=echo + + if [ $ARG_FORMAT_DEV -eq 1 ] && [ "$ARG_FORMAT_FS" = "" ]; then + msg "aborting, filesystem type not specified." + exit 1 + fi +} + + +main() { + local disk_dev= + + parse_arguments "$@" + + create_temp_dir "$ARG_TMP_DIR" + + export RUMP_SERVER="unix://$RUMP_TMP/server_socket" + + # + # First we prepare the actions... + # + if [ "$ARG_FORMAT_FS" != "" ]; then + RUMP_LIBS="$RUMP_LIBS -lrumpfs_$ARG_FORMAT_FS" + # XXX + [ "$ARG_FORMAT_FS" = "ext2fs" ] && RUMP_LIBS="$RUMP_LIBS -lrumpfs_ffs" + fi + + if [ $ARG_FORMAT_DEV -eq 1 ]; then + # only add the disk image as raw device if do not + # already have another device + [ "$ARG_DISK_DEV" = "" ] && disk_dev="$disk_dev -d key=$RUMP_DISK_DEV,hostpath=$ARG_DISK_IMAGE,size=host,type=chr" + else + [ "$ARG_DISK_DEV" = "" ] && disk_dev="$disk_dev -d key=$RUMP_DISK_DEV,hostpath=$ARG_DISK_IMAGE,size=host,type=blk" + fi + + if [ $ARG_CRYPT_DEV -eq 1 ]; then + RUMP_LIBS="$RUMP_LIBS -lrumpkern_crypto -lrumpdev_cgd -lrumpdev_rnd" + disk_dev="-d key=$RUMP_DISK_DEV,hostpath=$ARG_DISK_IMAGE,size=host,type=blk" + + cgd_config="$RUMP_TMP/cgd0.conf" + create_cgd_config "$cgd_config" "$ARG_CRYPT_KEY" + disk_dev="$disk_dev -d key=/cgd0.conf,hostpath=$cgd_config,size=host,type=reg" + fi + + if [ "$ARG_POPULATE_FS" != "" ]; then + disk_dev="$disk_dev -d key=$RUMP_HOST_DIR,hostpath=$ARG_POPULATE_FS,size=host,type=dirs" + fi + + # + # ... and start the rump server... + # + rump_server "$RUMP_LIBS" "$disk_dev" + + # + # ... then we execute the actions. + # + if [ $ARG_CRYPT_DEV -eq 1 ]; then + do_crypt_dev "$ARG_CRYPT_KEY" + + if [ "$ARG_CRYPT_KEY" = "" ]; then + $TOOL_DIR/rump_cgdconf -f "$cgd_config" + fi + fi + + if [ $ARG_FORMAT_DEV -eq 1 ]; then + do_format_fs "$ARG_FORMAT_FS" "$RUMP_FORMAT_DISK_DEV" + fi + + if [ "$ARG_POPULATE_FS" != "" ]; then + do_mount_fs "$ARG_FORMAT_FS" "$RUMP_FORMAT_DISK_DEV" "/mnt" + do_populate_fs "$ARG_POPULATE_FS" "/mnt" + do_umount_fs "/mnt" + fi + + if [ $ARG_LIST_FS -eq 1 ]; then + do_mount_fs "$ARG_FORMAT_FS" "$RUMP_FORMAT_DISK_DEV" "/mnt" + do_list_fs "/mnt" + do_umount_fs "/mnt" + fi + + exit 0 +} + + +PROG_NAME=$(basename $0) +ARG_CRYPT_DEV=0 +ARG_FORMAT_DEV=0 +ARG_DRY_RUN=0 +ARG_FORMAT_FS="" +ARG_LIST_FS=0 +ARG_TMP_DIR="" +ARG_VERBOSE=0 + +DRY_RUN="" + +TOOL_DIR=$(dirname $(readlink -f $0)) +GENODE_DIR=$(readlink -f $TOOL_DIR/..) + +RUMP_TMP="" +RUMP_DIR="/usr/local/genode-rump" +RUMP_PATH="$RUMP_DIR/bin" +RUMP_LIBS="-lrumpdev -lrumpdev_disk -lrumpvfs" +RUMP_SERVER="" +RUMP_DISK_DEV=/disk_image +RUMP_FORMAT_DISK_DEV="$RUMP_DISK_DEV" +RUMP_HOST_DIR=/host + +trap "trap_abort" INT TERM +trap "trap_exit" EXIT + +main "$@" + +exit 0 + +# End of file diff --git a/tool/rump_cgdconf b/tool/rump_cgdconf new file mode 100755 index 000000000..7fe07cc20 --- /dev/null +++ b/tool/rump_cgdconf @@ -0,0 +1,113 @@ +#!/bin/sh +# +# \brief Create cgdconfig(8) configuration file from key or extract the key +# from the specified configuration file +# \author Josef Soentgen +# \date 2014-04-29 +# +# +# Note: This script is merely just a awk(1) wrapper and only generates a +# aes-cbc 256 storedkey configuration and expects the given key to +# be a proper base64 encoded key generated by cgdconfig(8). +# + + +# +# Print usage +# +print_usage() { + local help=$1 + printf "usage: $PROG_NAME [-h] <-f file|-k key>\n" + if [ "$help" != "" ]; then + printf "\t-h show this help screen\n" + printf "\t-k key generate config file from key and print " + printf "to stdout\n" + printf "\t-f file extract key from config file and print " + printf "to stdout\n" + fi +} + + +# +# Parse arguments given on the commandline +# +parse_arguments() { + local args="$(getopt hf:k: ${*})" + + [ $? != 0 ] && exit 1 + if [ $# -lt 1 ] + then + print_usage + exit 1 + fi + set -- $args + while [ $# -ge 0 ]; do + case "$1" in + -h) + print_usage "help" + exit 0;; + -k) ARG_KEY="$2"; shift; shift;; + -f) ARG_FILE="$2"; shift; shift;; + --) shift; break;; + esac + done +} + + +# +# Extract the key string from the configuration file +# +extract_key() { + local cgd_file="$1" + + awk 'BEGIN { found=0 } + { + if (found == 1) key=key $1 + if ($1 == "keygen") { found=1; key=$4 } + } + END { sub(/;$/, "", key); print key }' $cgd_file +} + + +# +# Generate a proper cgd(8) configuration file from the given key +# +generate_conf() { + local key="$1" + + printf "$key" | awk '{ key=$0 } + END { + printf("algorithm aes-cbc;\n") + printf("iv-method encblkno1;\n") + printf("keylength 256;\n") + printf("verify_method none;\n") + printf("keygen storedkey key ") + printf("%s \\\n", substr(key, 1, 30)) + printf(" %s;\n", substr(key, 31)) + }' +} + + +main() { + parse_arguments "$@" + + if [ "$ARG_FILE" != "" ]; then + extract_key "$ARG_FILE" + fi + + if [ "$ARG_KEY" != "" ]; then + generate_conf "$ARG_KEY" + fi +} + + +PROG_NAME=$(basename $0) + +ARG_FILE= +ARG_KEY= + +main "$@" + +exit 0 + +# End of file