The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Samuel Moelius <sam.moelius@trailofbits.com>
To: kees@kernel.org
Cc: brauner@kernel.org, iwasbaeyz@gmail.com,
	linux-kernel@vger.kernel.org, rmk+kernel@armlinux.org.uk,
	sam.moelius@trailofbits.com, viro@zeniv.linux.org.uk
Subject: [PATCH v2 2/2] selftests: filesystems: add ADFS mount validation test
Date: Sun, 28 Jun 2026 22:01:26 +0000	[thread overview]
Message-ID: <20260628220126.94212-3-sam.moelius@trailofbits.com> (raw)
In-Reply-To: <20260628220126.94212-1-sam.moelius@trailofbits.com>

Add a selftest for ADFS disc record validation.  The test generates a
minimal one-zone ADFS image whose declared disc size is exactly one
filesystem block, mounts it read-only, and verifies that statfs succeeds.

It also generates an otherwise-identical image whose declared disc size
is smaller than one filesystem block, and verifies that the kernel rejects
the mount.  This covers the malformed image rejected by the preceding ADFS
fix without deliberately triggering the old statfs divide-by-zero.

Assisted-by: Codex:gpt-5.5-cyber-preview
---
 tools/testing/selftests/Makefile              |   1 +
 .../selftests/filesystems/adfs/Makefile       |   5 +
 .../filesystems/adfs/adfs_mount_check.sh      | 113 ++++++++++++++++++
 .../testing/selftests/filesystems/adfs/config |   2 +
 4 files changed, 121 insertions(+)
 create mode 100644 tools/testing/selftests/filesystems/adfs/Makefile
 create mode 100755 tools/testing/selftests/filesystems/adfs/adfs_mount_check.sh
 create mode 100644 tools/testing/selftests/filesystems/adfs/config

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 8d4db2241cc2..093cc43a2053 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -31,6 +31,7 @@ TARGETS += efivarfs
 TARGETS += exec
 TARGETS += fchmodat2
 TARGETS += filesystems
+TARGETS += filesystems/adfs
 TARGETS += filesystems/binderfs
 TARGETS += filesystems/epoll
 TARGETS += filesystems/fat
diff --git a/tools/testing/selftests/filesystems/adfs/Makefile b/tools/testing/selftests/filesystems/adfs/Makefile
new file mode 100644
index 000000000000..4b38cd45a945
--- /dev/null
+++ b/tools/testing/selftests/filesystems/adfs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+TEST_PROGS := adfs_mount_check.sh
+
+include ../../lib.mk
diff --git a/tools/testing/selftests/filesystems/adfs/adfs_mount_check.sh b/tools/testing/selftests/filesystems/adfs/adfs_mount_check.sh
new file mode 100755
index 000000000000..48fa777bebcc
--- /dev/null
+++ b/tools/testing/selftests/filesystems/adfs/adfs_mount_check.sh
@@ -0,0 +1,113 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Generate minimal ADFS images and verify that mount-time disc record
+# validation accepts an image with one filesystem block and rejects an image
+# whose declared disc size is smaller than one filesystem block.
+
+set -euo pipefail
+
+ksft_skip=4
+tmp_dir="$(mktemp -d /tmp/adfs_mount_check.XXXXXX)"
+mnt_dir="${tmp_dir}/mnt"
+good_img="${tmp_dir}/adfs-good.img"
+bad_img="${tmp_dir}/adfs-bad.img"
+
+cleanup()
+{
+	if command -v mountpoint >/dev/null 2>&1 && mountpoint -q "${mnt_dir}"; then
+		umount "${mnt_dir}" || true
+	fi
+	rm -rf "${tmp_dir}"
+}
+trap cleanup EXIT
+
+skip_all()
+{
+	echo "1..0 # SKIP $*"
+	exit "${ksft_skip}"
+}
+
+fail()
+{
+	echo "not ok $1 - $2"
+	exit 1
+}
+
+require_cmd()
+{
+	command -v "$1" >/dev/null 2>&1 || skip_all "missing $1"
+}
+
+adfs_available()
+{
+	grep -qw adfs /proc/filesystems
+}
+
+make_image()
+{
+	local img="$1"
+	local checksum="$2"
+	local disc_size="$3"
+
+	truncate -s 1M "${img}"
+
+	# One-zone ADFS map header.
+	printf '%b' "${checksum}" | dd of="${img}" bs=1 seek=0 \
+		conv=notrunc status=none
+	printf '%b' '\x00\x00\xff' | dd of="${img}" bs=1 seek=1 \
+		conv=notrunc status=none
+
+	# Disc record fields up to, but not including, disc_size.
+	printf '%b' '\x09\x01\x01\x00\x0c\x09\x00\x00' | dd of="${img}" \
+		bs=1 seek=4 conv=notrunc status=none
+	printf '%b' '\x00\x01\x00\x00\x00\x02\x00\x00' | dd of="${img}" \
+		bs=1 seek=12 conv=notrunc status=none
+
+	printf '%b' "${disc_size}" | dd of="${img}" bs=1 seek=20 \
+		conv=notrunc status=none
+}
+
+if [ "$(id -u)" -ne 0 ]; then
+	skip_all "must be run as root"
+fi
+
+require_cmd dd
+require_cmd grep
+require_cmd mount
+require_cmd mountpoint
+require_cmd stat
+require_cmd truncate
+require_cmd umount
+
+if ! adfs_available; then
+	modprobe adfs 2>/dev/null || true
+fi
+adfs_available || skip_all "adfs filesystem support is unavailable"
+
+mkdir -p "${mnt_dir}"
+
+echo "1..2"
+
+# A one-zone ADFS image whose declared disc size is exactly one 512-byte
+# filesystem block.  The first byte is the ADFS map checksum.
+make_image "${good_img}" '\xe4' '\x00\x02\x00\x00'
+
+if ! mount -t adfs -o ro,loop "${good_img}" "${mnt_dir}" >/dev/null 2>&1; then
+	fail 1 "good image mount failed"
+fi
+if ! stat -f "${mnt_dir}" >/dev/null 2>&1; then
+	fail 1 "good image statfs failed"
+fi
+umount "${mnt_dir}"
+echo "ok 1 - good ADFS image mounted and statfs succeeded"
+
+# Same minimal image, but with disc_size == 1.  This is smaller than the
+# 512-byte filesystem block size encoded by log2secsize and must be rejected.
+make_image "${bad_img}" '\xe5' '\x01\x00\x00\x00'
+
+if mount -t adfs -o ro,loop "${bad_img}" "${mnt_dir}" >/dev/null 2>&1; then
+	umount "${mnt_dir}"
+	fail 2 "bad image mounted"
+fi
+echo "ok 2 - undersized ADFS image rejected"
diff --git a/tools/testing/selftests/filesystems/adfs/config b/tools/testing/selftests/filesystems/adfs/config
new file mode 100644
index 000000000000..7d3cf42f8c99
--- /dev/null
+++ b/tools/testing/selftests/filesystems/adfs/config
@@ -0,0 +1,2 @@
+CONFIG_ADFS_FS=m
+CONFIG_BLK_DEV_LOOP=m
-- 
2.43.0


      parent reply	other threads:[~2026-06-28 22:01 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-05 18:37 [PATCH] adfs: reject disc records smaller than one filesystem block Samuel Moelius
2026-06-10 20:24 ` Kees Cook
2026-06-28 22:01   ` [PATCH v2 0/2] " Samuel Moelius
2026-06-28 22:01     ` [PATCH v2 1/2] " Samuel Moelius
2026-06-28 23:16       ` Russell King
2026-06-28 22:01     ` Samuel Moelius [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260628220126.94212-3-sam.moelius@trailofbits.com \
    --to=sam.moelius@trailofbits.com \
    --cc=brauner@kernel.org \
    --cc=iwasbaeyz@gmail.com \
    --cc=kees@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rmk+kernel@armlinux.org.uk \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox