Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Unreleased

- Instrument diod `t0010` first `access=<uid>` mount (stderr/dmesg/diod log), pin `version=9p2000.L`, pre-create export, `Defaults !requiretty`, and force a fresh patched build stamp so CI can triage residual non-root mount failures.
- Fix non-root `ACCESS_SINGLE` mounts across diod sharness: `scripts/v9fs-mount-9p` + trash on `/tmp`; t0010 runasuser now expected PASS including root-negatives.
- Run diod sharness as non-root user `v9fs` (so ACCESS_SINGLE / `--runas` negatives work); per-test `timeout` via automake `LOG_COMPILER` instead of one outer suite timeout.
- Refresh diod XFAIL baseline for tip `v7.2` (access/umount residuals); tee `make check` so timeout still yields a parseable suite log for XFAIL eval.
- Build-in `NET_9P_FD` (and `UNIX`) on published Images so diod-regression `trans=unix` mounts work; arm64 defconfig left FD as `=m` while virtio was forced `=y`.
Expand Down
20 changes: 11 additions & 9 deletions diod/xfail.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@
#
# <testfile> :: <description>
#
# Example:
# t0010-v9fs-runasuser.t :: root cannot read file
#
# Keep this list minimal and update it intentionally when behavior changes.
#
# Note: t0010 "root cannot …" / uname=root negatives are NOT XFAIL'd here;
# the suite must run as non-root user `v9fs` so those assertions are meaningful.
# t0010 runasuser ACCESS_SINGLE / root-negative assertions are expected to PASS
# when the suite runs as non-root `v9fs` with v9fs-mount-9p.

# allsquash identity mapping gaps under guest harness
t0011-v9fs-allsquash.t :: root can create a directory, mode 755
t0011-v9fs-allsquash.t :: nobody can create a directory, mode 755
t0011-v9fs-allsquash.t :: nobody cannot create a file in nobody directory
t0011-v9fs-allsquash.t :: user can create a file in rootdir
t0011-v9fs-allsquash.t :: user can create a file in nobodydir
t0011-v9fs-allsquash.t :: user can chmod 777 nobody directory
t0011-v9fs-allsquash.t :: exited with status 1
t0011-v9fs-allsquash :: automake error/timeout

# posixacl / setfacl residuals on tip
t0013-v9fs-acl.t :: create a test file and setfacl -m u:root:r
t0013-v9fs-acl.t :: getfacl confirms ACL is set
t0013-v9fs-acl.t :: it is set on the server too
t0013-v9fs-acl.t :: getfacl confirms ACL is unset
t0013-v9fs-acl.t :: it is unset on the server too
t0013-v9fs-acl.t :: create a test directory and setfacl -d -m u:root:r
t0013-v9fs-acl.t :: getfacl confirms ACL is set
t0013-v9fs-acl.t :: it is set on the server too
t0013-v9fs-acl.t :: getfacl confirms ACL is unset
t0013-v9fs-acl.t :: it is unset on the server too
t0013-v9fs-acl.t :: exited with status 1
t0013-v9fs-acl :: automake error/timeout
37 changes: 35 additions & 2 deletions scripts/v9fs-build-initrd
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ echo "init: bootver=${bootver}"

if mount -t 9p -o "trans=virtio,version=${bootver},cache=loose" hostshare /mnt/9; then
echo "init: mounted hostshare at /mnt/9"
# Ensure the Debian chroot has real /proc /sys /dev (image dirs alone are not enough).
mkdir -p /mnt/9/proc /mnt/9/sys /mnt/9/dev
mount -t proc proc /mnt/9/proc 2>/dev/null || mount --bind /proc /mnt/9/proc || true
mount -t sysfs sysfs /mnt/9/sys 2>/dev/null || mount --bind /sys /mnt/9/sys || true
mount --bind /dev /mnt/9/dev 2>/dev/null || true
if [ -x /mnt/9/usr/sbin/chroot ] && [ -x /mnt/9/usr/bin/bash ]; then
echo "init: chroot -> /mnt/9, running container bash+ls"
rc=0
Expand Down Expand Up @@ -92,9 +97,13 @@ if mount -t 9p -o "trans=virtio,version=${bootver},cache=loose" hostshare /mnt/9
# Run as non-root so --runas=$(id -u) / access=$(id -u) match diod intent.
# Per-test timeout (LOG_COMPILER) so a hung script FAILs that test instead of
# stalling the whole suite under a single outer timeout.
# Install per-test timeout wrapper into /tmp (writable, not on 9p).
cp -f /home/v9fs-test/test/scripts/v9fs-diod-test-timeout /tmp/v9fs-diod-test-timeout
chmod 755 /tmp/v9fs-diod-test-timeout

set +e
sudo -u v9fs -H make -C t check \
LOG_COMPILER=timeout \
timeout 1500 sudo -u v9fs -H stdbuf -oL -eL make -C t check \
LOG_COMPILER=/tmp/v9fs-diod-test-timeout \
AM_LOG_FLAGS=300 \
TESTS="\
t0010-v9fs-runasuser.t \
Expand All @@ -106,6 +115,16 @@ if mount -t 9p -o "trans=virtio,version=${bootver},cache=loose" hostshare /mnt/9
" 2>&1 | tee "$make_out"
make_rc="${PIPESTATUS[0]}"
set -e
if [ -r /proc/self/mountinfo ]; then
while read -r _ _ _ _ mnt _; do
case "$mnt" in
/tmp/*) umount -l "$mnt" 2>/dev/null || true ;;
esac
done < /proc/self/mountinfo
fi
pkill -x diod 2>/dev/null || true
pkill -x test_diodrun 2>/dev/null || true
sleep 1

# Prefer automake combined log; synthesize from tee if missing.
suite="$build/t/test-suite.log"
Expand All @@ -116,13 +135,27 @@ if mount -t 9p -o "trans=virtio,version=${bootver},cache=loose" hostshare /mnt/9
fi
cp -f "$suite" /home/v9fs-test/test/logs/diod-test-suite.log 2>/dev/null || true

# Scoop t0010 mount instrumentation + diod server logs for CI artifacts.
cp -f /home/v9fs-test/test/logs/diod-t0010-mount-debug.txt \
/home/v9fs-test/test/logs/ 2>/dev/null || true
find "$build/t" -maxdepth 3 \( -name '*.diod.log' -o -name 'diod-t0010-mount-debug.txt' \) \
-exec cp -f {} /home/v9fs-test/test/logs/ \; 2>/dev/null || true
cp -f /tmp/diod-t0010-mount.stderr /tmp/diod-t0010.diod.log \
/home/v9fs-test/test/logs/ 2>/dev/null || true

# Evaluate failures against the harness XFAIL baseline so we can track them
# without failing the overall CI stage unless a regression appears.
eval_out="/home/v9fs-test/test/logs/diod-xfail"
xfail="/home/v9fs-test/test/diod/xfail.txt"
/home/v9fs-test/test/scripts/v9fs-diod-regression-eval "$suite" "$xfail" "$eval_out"
eval_rc="$?"

# timeout(1) exits 124; signals often yield 143/137. Never treat an
# aborted suite with zero FAIL lines as an XFAIL pass.
if [ "$make_rc" -eq 124 ] || [ "$make_rc" -ge 128 ]; then
echo "diod-regression: make aborted rc=$make_rc (timeout/signal)"
exit "$make_rc"
fi
if [ "$eval_rc" = "0" ]; then
exit 0
fi
Expand Down
23 changes: 23 additions & 0 deletions scripts/v9fs-diod-test-timeout
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Per-test wrapper: line-buffered timeout around sharness, then drop leftover
# unix 9p mounts / diod so test_diodrun --socktest cannot wedge make check.
set -u
secs="${1:-300}"
shift
set +e
# stdbuf so breadcrumbs appear before a subsequent D-state hang.
stdbuf -oL -eL timeout --foreground -k 10 "$secs" stdbuf -oL -eL "$@"
rc=$?
set -e
if [ -r /proc/self/mountinfo ]; then
while read -r _ _ _ _ mnt _; do
case "$mnt" in
/tmp/sharness-trash/*)
umount -l "$mnt" 2>/dev/null || true
;;
esac
done < /proc/self/mountinfo
fi
pkill -x diod 2>/dev/null || true
sleep 1
exit "$rc"
121 changes: 121 additions & 0 deletions scripts/v9fs-mount-9p.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Minimal 9p mount helper for diod sharness under ACCESS_SINGLE.
* util-linux mount(8) post-checks as euid 0 and fails when access=<uid>.
* This calls mount(2) directly with no post-check.
*
* If options contain access=<uid>, setfsuid to that uid before mount so the
* kernel session matches the ACCESS_SINGLE user (mounter may be root via sudo).
*
* Usage: v9fs-mount-9p [-n] -t 9p -o OPTS SOURCE MNT
* -n is accepted and ignored (compatibility with sharness mountcmd).
*/

#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/types.h>

/* setfsuid(2) is Linux-only; declare if headers omit it. */
extern int setfsuid(uid_t fsuid);

static void
usage(const char *prog)
{
fprintf(stderr,
"usage: %s [-n] -t 9p -o OPTS SOURCE MNT\n", prog);
exit(2);
}

static uid_t
parse_access_uid(const char *opts)
{
const char *p = opts;

while (p && *p) {
if (!strncmp(p, "access=", 7)) {
p += 7;
if (*p >= '0' && *p <= '9')
return (uid_t)strtoul(p, NULL, 10);
return (uid_t)-1;
}
p = strchr(p, ',');
if (p)
p++;
}
return (uid_t)-1;
}

int
main(int argc, char **argv)
{
const char *opts = NULL;
const char *source = NULL;
const char *target = NULL;
unsigned long flags = 0;
uid_t access_uid;
int i;

for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-n"))
continue;
if (!strcmp(argv[i], "-t") || !strncmp(argv[i], "-t", 2)) {
const char *fstype = argv[i][2] ? argv[i] + 2 : NULL;
if (!fstype) {
if (++i >= argc)
usage(argv[0]);
fstype = argv[i];
}
if (strcmp(fstype, "9p") != 0)
usage(argv[0]);
continue;
}
if (!strcmp(argv[i], "-o") || !strncmp(argv[i], "-o", 2)) {
opts = argv[i][2] ? argv[i] + 2 : NULL;
if (!opts) {
if (++i >= argc)
usage(argv[0]);
opts = argv[i];
}
continue;
}
if (!source)
source = argv[i];
else if (!target)
target = argv[i];
else
usage(argv[0]);
}

if (!opts || !source || !target)
usage(argv[0]);

if (geteuid() != 0) {
fprintf(stderr, "%s: must run as root (use sudo)\n", argv[0]);
return 1;
}

access_uid = parse_access_uid(opts);
if (access_uid != (uid_t)-1) {
/* Keep CAP_SYS_ADMIN as root euid; match ACCESS_SINGLE for VFS.
* setfsuid returns the previous fsuid (not -1) even on success.
*/
setfsuid(access_uid);
if ((uid_t)setfsuid(access_uid) != access_uid) {
fprintf(stderr, "%s: setfsuid(%u) did not stick\n",
argv[0], (unsigned)access_uid);
return 1;
}
}

if (mount(source, target, "9p", flags, opts) < 0) {
fprintf(stderr, "%s: mount %s -> %s (%s): %s\n",
argv[0], source, target, opts, strerror(errno));
return 1;
}

return 0;
}
Loading
Loading