From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qk1-f173.google.com (mail-qk1-f173.google.com [209.85.222.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BB3ED3B7B8C for ; Sun, 28 Jun 2026 22:01:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.173 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782684108; cv=none; b=PniJ5tFX9iqEdAUEh6tmbxe/B54DvYdACgZiJmem0w/ZzdkryKCVOOYcU+Vt4KWauXDt1gN47oTVefbHT0s82OTAWbXE6GDmCMa5DnuxvtTrDHHhbDMBSWRtLOlKE4/M5fg9zFpMHsEL2DP76NvrFfjemjXGEpNHDW0ghW5VJyY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782684108; c=relaxed/simple; bh=LuHUZ5+094V6AcmWHsd/hDM4WrNm+5FITbbJfu4WRYY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HMF3zSgifu/ONGGwVzi2A9bA3crVOJhC24zZq5M4oam+ADu0N55BiTsU2HkOGWLVfNnji9lG/6pHpWQOKYob7LOAOCIStgGw0euhs3SLjRGZhcIpO5T1QS6rdUUqQtq/oem/bmN4R24/eqtjr4QMIho3m4p2HBnZN+lPA674/4I= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=trailofbits.com; spf=pass smtp.mailfrom=trailofbits.com; dkim=pass (2048-bit key) header.d=trailofbits.com header.i=@trailofbits.com header.b=I4HzolM+; arc=none smtp.client-ip=209.85.222.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=trailofbits.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=trailofbits.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=trailofbits.com header.i=@trailofbits.com header.b="I4HzolM+" Received: by mail-qk1-f173.google.com with SMTP id af79cd13be357-922e181f199so246091985a.3 for ; Sun, 28 Jun 2026 15:01:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=trailofbits.com; s=google; t=1782684106; x=1783288906; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HapIXPEwdjpp/Jyui4kmVI5nV4JM4FgWjUEcYk8DlyE=; b=I4HzolM+QUp2EplgJbD1eQmfXhu0l4du6pgZfuTovATgWDKa2g7Cc9/JdlkRGka1v8 +05S3nC2d2CrJauGNLBP7JNTaXGEXxbFJ+FugqFqV+Pq9liyUn597vBweDgEgUz4yPti XF46t8t9sij1MyyCI8GICkWJBMPanZ9y8DMIi1/QcZ/8Ilbbb0kAAJHElK7PGI9+y7q/ He1iI1OyjZjnG4Efl64QYenYbvYTC0oCs6G/pamgHhSUEzd5nQpfykrySogViqdsKjgz OhR/onImXstwpUQSBT7KoCozaBD3Nb6WUVLMeYPN+ScWBVeGXbWLJksJDsypBNDw7wzx gKVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782684106; x=1783288906; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=HapIXPEwdjpp/Jyui4kmVI5nV4JM4FgWjUEcYk8DlyE=; b=h53KIq2Kpj8jRRCV7X4qvfazMZn1UYA7LPm/CGe0XIl0tUz4TKCKXK6LswyXPnCHd/ Fawa+3Bp11kbfEMidpi60UANMRI/d5ayVeuwH9Gz6k7eV1c3/k4h26gqR1i7uq+4I5lB Iex+4kyaFS8YLe00GW4QuaRuIhrhpSVQVj3P83faKu+EEAWRCh6ZHANCG0d3tCTwKfoj Kd6TzqH3IF4IiGdUNyH/t5MDqeljzqeen1PxSDdYWu93s8JLcG6Aej+SoxeqmyPq29IA 6KN8/9xDv0SNfBbjRwNtcbLyJxMfzRzWDzeonuQLJADO+IqFLBxvwhNGnyszzLM9etP0 ArGg== X-Forwarded-Encrypted: i=1; AFNElJ+FP1uZCfDS4usR5TC3Iz3OJeGZ7Hq7p2QK4KSB9PJeFjLmZ3MWhW0A3UO7U4m/nj/rxiDiCvrmd+u6hgQ=@vger.kernel.org X-Gm-Message-State: AOJu0YyhYc67cXeoVRkd2OagwLY6a5vGwDt1mqhlr71bbnVWBssRjPJT drKlDEfT+YZ9RpWKUGvY4A3mSNYbIK8Ev8d0EmUZNvsihZ60PzplN7PMncN49Lz7HIY= X-Gm-Gg: AfdE7cnptLQ+EgD2TbqYq38pCLr6D0kM/NhyFF+AwfxHT1lVbrb7t0oe6zNt5K4D/Ub cpEwk2wjANcOo2fgndr2DBmbXS1nfPV1z0aTNm+2d8ULnkN3whtzQK6hqUYE7XcjYodk3wDRFtr MPaYciWLCtoXY4Gi4sOhycLCnzppZKfiKoq+7xovJk5Kq/bloVYO+QgCRRigwye4Osew2BQU4iU slvcXMnaI2T/6rLZOrrHAlqk5XsDoX9vRA1ygTGE8qIA+Pma5nj1EPUJGXziAGJxklf6v7sq/v4 Rmab8WMfA7EDcWhBwLBAfwaofOOFD89DZUzpHo/B6hIm8h0gBCOWU2BhGHzw03CxWaB9Qe9QvPg 5Omgup1ls00/rxgzZYctc9JK0ZrWp9e56iUv6lUXrLLIwBP7dQzoiYGizAlxAoFQYIJEEeOa+/d 9lQhTKy4sRRLwmn6vi X-Received: by 2002:a05:620a:2414:10b0:92b:6805:919c with SMTP id af79cd13be357-92b68059694mr798726385a.68.1782684105608; Sun, 28 Jun 2026 15:01:45 -0700 (PDT) Received: from localhost ([161.35.96.86]) by smtp.gmail.com with UTF8SMTPSA id af79cd13be357-926000c343bsm1904674285a.28.2026.06.28.15.01.43 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 28 Jun 2026 15:01:44 -0700 (PDT) From: Samuel Moelius 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 Message-ID: <20260628220126.94212-3-sam.moelius@trailofbits.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260628220126.94212-1-sam.moelius@trailofbits.com> References: <202606101323.0DFB06B054@keescook> <20260628220126.94212-1-sam.moelius@trailofbits.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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