From 6d109ecba3110b2d7798074348964b07fcd4f5b0 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 30 Jan 2019 10:19:15 -0800 Subject: [PATCH] fs_mgr: overlayfs support legacy devices (marlin) Expand the tests to deal with the boot environment for marlin. Recognize that older overlayfs drivers do not report to /sys/module and the parsing /proc/filesystem is another place to interrogate this. Suppress adb push and pull noise during testing. Resolve APEX failures. Add some cleanup to test script. NB: Running test to completion is difficult because marlin's USB driver is flakey enough through the multitude of reboots and may not reconnect. The tester will have to notice when a reboot is stalling and manually disconnect and reconnect the USB connection to trigger discovery and to continue through the test sequences. To make this easier, report when we are waiting for the device to make it easier to babysit. Test: system/core/fs_mgr/tests/adb-remount-test.sh Bug: 120448575 Bug: 123079041 Change-Id: I5fc5f01b4e4788ac57541cb5235f7ac4e4284d71 --- fs_mgr/fs_mgr_overlayfs.cpp | 19 +++- fs_mgr/tests/adb-remount-test.sh | 181 ++++++++++++++++++++++++++----- 2 files changed, 167 insertions(+), 33 deletions(-) diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index c7d2cb9fd..0c2b3d3cb 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -67,6 +67,13 @@ bool fs_mgr_access(const std::string& path) { return ret; } +// determine if a filesystem is available +bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) { + std::string filesystems; + if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false; + return filesystems.find("\t" + filesystem + "\n") != std::string::npos; +} + } // namespace #if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs @@ -625,8 +632,12 @@ const std::string kMkExt4("/system/bin/mke2fs"); // Only a suggestion for _first_ try during mounting std::string fs_mgr_overlayfs_scratch_mount_type() { - if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_access("/sys/fs/f2fs")) return "f2fs"; - if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_access("/sys/fs/ext4")) return "ext4"; + if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("f2fs")) { + return "f2fs"; + } + if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("ext4")) { + return "ext4"; + } return "auto"; } @@ -657,7 +668,7 @@ bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std: if (mnt_type == "f2fs") { command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint); } else if (mnt_type == "ext4") { - command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; + command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; } else { errno = ESRCH; LERROR << mnt_type << " has no mkfs cookbook"; @@ -1002,7 +1013,7 @@ OverlayfsValidResult fs_mgr_overlayfs_valid() { if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) { return OverlayfsValidResult::kOverrideCredsRequired; } - if (!fs_mgr_access("/sys/module/overlay")) { + if (!fs_mgr_overlayfs_filesystem_available("overlay")) { return OverlayfsValidResult::kNotSupported; } struct utsname uts; diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh index 4d9bc610f..8298bf290 100755 --- a/fs_mgr/tests/adb-remount-test.sh +++ b/fs_mgr/tests/adb-remount-test.sh @@ -1,4 +1,15 @@ #! /bin/bash +# +# Divided into four section: +# +## USAGE +## Helper Variables +## Helper Functions +## MAINLINE + +## +## USAGE +## USAGE="USAGE: `basename ${0}` [-s ] @@ -17,20 +28,26 @@ if [ X"${1}" = X"--help" -o X"${1}" = X"-h" -o X"${1}" = X"-?" ]; then exit 0 fi -# Helper Variables +## +## Helper Variables +## SPACE=" " # A _real_ embedded tab character TAB="`echo | tr '\n' '\t'`" # A _real_ embedded escape character ESCAPE="`echo | tr '\n' '\033'`" +# A _real_ embedded carriage return character +CR="`echo | tr '\n' '\r'`" GREEN="${ESCAPE}[38;5;40m" RED="${ESCAPE}[38;5;196m" ORANGE="${ESCAPE}[38;5;255:165:0m" BLUE="${ESCAPE}[35m" NORMAL="${ESCAPE}[0m" -# Helper functions +## +## Helper Functions +## [ "USAGE: inFastboot @@ -68,6 +85,8 @@ adb_sh() { args="${args}${i}" elif [ X"${i}" != X"${i#* }" ]; then args="${args}'${i}'" + elif [ X"${i}" != X"${i#*${TAB}}" ]; then + args="${args}'${i}'" else args="${args}${i}" fi @@ -130,16 +149,62 @@ adb_cat() { Returns: true if the reboot command succeeded" ] adb_reboot() { - adb reboot remount-test && + adb reboot remount-test || true sleep 2 } +[ "USAGE: format_duration [|s|m|h|d] + +human readable output whole seconds, whole minutes or mm:ss" ] +format_duration() { + if [ -z "${1}" ]; then + echo unknown + return + fi + duration="${1}" + if [ X"${duration}" != X"${duration%s}" ]; then + duration=${duration%s} + elif [ X"${duration}" != X"${duration%m}" ]; then + duration=`expr ${duration%m} \* 60` + elif [ X"${duration}" != X"${duration%h}" ]; then + duration=`expr ${duration%h} \* 3600` + elif [ X"${duration}" != X"${duration%d}" ]; then + duration=`expr ${duration%d} \* 86400` + fi + seconds=`expr ${duration} % 60` + minutes=`expr \( ${duration} / 60 \) % 60` + hours=`expr ${duration} / 3600` + if [ 0 -eq ${minutes} -a 0 -eq ${hours} ]; then + if [ 1 -eq ${duration} ]; then + echo 1 second + return + fi + echo ${duration} seconds + return + elif [ 60 -eq ${duration} ]; then + echo 1 minute + return + elif [ 0 -eq ${seconds} -a 0 -eq ${hours} ]; then + echo ${minutes} minutes + return + fi + if [ 0 -eq ${hours} ]; then + echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10` + return + fi + echo ${hours}:`expr ${minutes} / 10``expr ${minutes} % 10`:`expr ${seconds} / 10``expr ${seconds} % 10` +} + [ "USAGE: adb_wait [timeout] Returns: waits until the device has returned for adb or optional timeout" ] adb_wait() { if [ -n "${1}" ]; then + echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} "${CR}" timeout --preserve-status --signal=KILL ${1} adb wait-for-device + retval=${?} + echo -n " ${CR}" + return ${retval} else adb wait-for-device fi @@ -152,10 +217,14 @@ fastboot_wait() { # fastboot has no wait-for-device, but it does an automatic # wait and requires (even a nonsensical) command to do so. if [ -n "${1}" ]; then - timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device + echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} "${CR}" + timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device >/dev/null 2>/dev/null + retval=${?} + echo -n " ${CR}" + ( exit ${retval} ) else - fastboot wait-for-device >/dev/null - fi >/dev/null 2>/dev/null || + fastboot wait-for-device >/dev/null 2>/dev/null + fi || inFastboot } @@ -310,9 +379,14 @@ skip_administrative_mounts() { -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \ -e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \ -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \ + -e "^rootfs / rootfs rw," \ -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) " } +## +## MAINLINE +## + if [ X"-s" = X"${1}" -a -n "${2}" ]; then export ANDROID_SERIAL="${2}" shift 2 @@ -320,7 +394,7 @@ fi inFastboot && die "device in fastboot mode" if ! inAdb; then - echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode ... waiting 2 minutes" + echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode" adb_wait 2m fi inAdb || die "specified device not in adb mode" @@ -331,19 +405,38 @@ if ! adb_su getenforce /dev/null; then enforcing=false fi -# Do something +# Do something. D=`get_property ro.serialno` [ -n "${D}" ] || D=`get_property ro.boot.serialno` [ -z "${D}" ] || ANDROID_SERIAL=${D} +USB_SERIAL= +[ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial | + grep usb | + xargs grep -l ${ANDROID_SERIAL}` +USB_ADDRESS= +if [ -n "${USB_SERIAL}" ]; then + USB_ADDRESS=${USB_SERIAL%/serial} + USB_ADDRESS=usb${USB_ADDRESS##*/} +fi +[ -z "${ANDROID_SERIAL}${USB_ADDRESS}" ] || + echo "${BLUE}[ INFO ]${NORMAL}" ${ANDROID_SERIAL} ${USB_ADDRESS} >&2 BUILD_DESCRIPTION=`get_property ro.build.description` -echo "${BLUE}[ INFO ]${NORMAL} ${ANDROID_SERIAL} ${BUILD_DESCRIPTION}" >&2 +[ -z "${BUILD_DESCRIPTION}" ] || + echo "${BLUE}[ INFO ]${NORMAL} ${BUILD_DESCRIPTION}" >&2 + +VERITY_WAS_ENABLED=false +if [ "orange" = "`get_property ro.boot.verifiedbootstate`" -a \ + "2" = "`get_property partition.system.verified`" ]; then + VERITY_WAS_ENABLED=true +fi echo "${GREEN}[ RUN ]${NORMAL} Testing kernel support for overlayfs" >&2 overlayfs_supported=true; adb_wait || die "wait for device failed" -adb_sh ls -d /sys/module/overlay /dev/null && +adb_sh ls -d /sys/module/overlay /dev/null 2>/dev/null || + adb_sh grep "nodev${TAB}overlay" /proc/filesystems /dev/null 2>/dev/null && echo "${GREEN}[ OK ]${NORMAL} overlay module present" >&2 || ( echo "${ORANGE}[ WARNING ]${NORMAL} overlay module not present" >&2 && @@ -391,9 +484,9 @@ if ${reboot}; then echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2 adb_reboot && adb_wait 2m || - die "lost device after reboot after wipe" + die "lost device after reboot after wipe (USB stack broken?)" adb_root || - die "lost device after elevation to root after wipe" + die "lost device after elevation to root after wipe (USB stack broken?)" fi D=`adb_sh df -k &1` adb_reboot && adb_wait 2m || - die "lost device after reboot requested" + die "lost device after reboot requested (USB stack broken?)" adb_root || - die "lost device after elevation to root" + die "lost device after elevation to root (USB stack broken?)" rebooted=true # re-disable verity to see the setup remarks expected T=`adb_date` @@ -544,7 +637,7 @@ if ${overlayfs_needed}; then echo "${D}" | grep "^overlay .* /system\$" >/dev/null || die "overlay takeover after remount" !(adb_sh grep "^overlay " /proc/mounts &2 @@ -569,17 +662,22 @@ B="`adb_cat /vendor/hello`" || die "vendor hello" check_eq "${A}" "${B}" /vendor before reboot -# download libc.so, append some gargage, push back, and check if the file is updated. +# Download libc.so, append some gargage, push back, and check if the file +# is updated. tempdir="`mktemp -d`" cleanup() { rm -rf ${tempdir} } -adb pull /system/lib/bootstrap/libc.so ${tempdir} || die "pull libc.so from device" +adb pull /system/lib/bootstrap/libc.so ${tempdir} >/dev/null || + die "pull libc.so from device" garbage="`hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random`" echo ${garbage} >> ${tempdir}/libc.so -adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so || die "push libc.so to device" -adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice || die "pull libc.so from device" -diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ" +adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so >/dev/null || + die "push libc.so to device" +adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null || + die "pull libc.so from device" +diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || + die "libc.so differ" echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2 @@ -605,7 +703,7 @@ B="`adb_cat /system/hello`" || die "re-read /system/hello after reboot" check_eq "${A}" "${B}" /system after reboot echo "${GREEN}[ OK ]${NORMAL} /system content remains after reboot" >&2 -# Only root can read vendor if sepolicy permissions are as expected +# Only root can read vendor if sepolicy permissions are as expected. if ${enforcing}; then adb_unroot B="`adb_cat /vendor/hello`" && @@ -619,9 +717,9 @@ adb_root && check_eq "${A}" "${B}" vendor after reboot echo "${GREEN}[ OK ]${NORMAL} /vendor content remains after reboot" >&2 -# check if the updated libc.so is persistent after reboot +# Check if the updated libc.so is persistent after reboot. adb_root && - adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice || + adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null || die "pull libc.so from device" diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ" rm -r ${tempdir} @@ -677,7 +775,7 @@ else fi fastboot reboot || die "can not reboot out of fastboot" - echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes" + echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot" adb_wait 2m || die "did not reboot after flash" if ${overlayfs_needed}; then @@ -719,9 +817,26 @@ fi echo "${GREEN}[ RUN ]${NORMAL} remove test content (cleanup)" >&2 T=`adb_date` -adb remount && +H=`adb remount 2>&1` +err=${?} +L= +D="${H%?Now reboot your device for settings to take effect}" +if [ X"${H}" != X"${D}" ]; then + echo "${ORANGE}[ WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)" + L=`adb_logcat -b all -v nsec -t ${T} 2>&1` + adb_reboot && + adb_wait 2m && + adb_root || + die "failed to reboot" + T=`adb_date` + H=`adb remount 2>&1` + err=${?} +fi +echo "${H}" +[ ${err} = 0 ] && ( adb_sh rm /vendor/hello /dev/null || true ) && adb_sh rm /system/hello &2 +echo "${GREEN}[ RUN ]${NORMAL} test raw remount commands" >&2 -# prerequisite is a prepped device from above +# Prerequisite is a prepped device from above. adb_reboot && adb_wait 2m || - die "lost device after reboot to ro state" + die "lost device after reboot to ro state (USB stack broken?)" adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null && die "/vendor is not read-only" adb_su mount -o rw,remount /vendor || @@ -782,4 +897,12 @@ adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null || die "/vendor is not read-write" echo "${GREEN}[ OK ]${NORMAL} mount -o rw,remount command works" >&2 +if $VERITY_WAS_ENABLED && $overlayfs_supported; then + adb_root && + adb enable-verity && + adb_reboot && + adb_wait 2m || + die "failed to restore verity" >&2 +fi + echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2