From: sashiko-bot@kernel.org
To: "John Groves" <john@jagalactic.com>
Cc: linux-cxl@vger.kernel.org, nvdimm@lists.linux.dev
Subject: Re: [PATCH V12 07/12] famfs: MAP_CREATE ioctl and fmap ingest (ABI 44)
Date: Mon, 03 Aug 2026 02:42:26 +0000 [thread overview]
Message-ID: <20260803024226.6339E1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <0100019fc5746312-6cfe9a07-a658-4aba-b1e9-5233b0ddfcf4-000000@email.amazonses.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [Critical] The FAMFSIOC_MAP_CREATE ioctl lacks a privilege check, allowing unprivileged users to map arbitrary physical DAX memory.
- [High] 64-bit file size and extent lengths are silently truncated to size_t on 32-bit architectures.
- [High] Missing overflow checks on extent lengths and physical offsets.
- [High] Race condition in state publication leads to permanent file corruption (Denial of Service).
- [High] Persistent memory allocations for file metadata lack __GFP_ACCOUNT, bypassing memcg limits.
- [Low] Format string type mismatch for size_t arguments causes compiler warnings.
Pre-existing issues:
- [High] NULL pointer dereference in famfs_meta_to_dax_offset_interleaved.
--
--- Patch [7]: [PATCH V12 07/12] famfs: MAP_CREATE ioctl and fmap ingest (ABI 44) ---
commit 7c28fdf850baa1b17b165378da6b0515248fad98
Author: John Groves <John@Groves.net>
famfs: MAP_CREATE ioctl and fmap ingest (ABI 44)
This commit adds the famfs file ioctl handler, including the
FAMFSIOC_MAP_CREATE ioctl to ingest user-provided mapping extent messages.
It parses both simple and interleaved wire formats into a famfs_file_meta
structure that is published on the inode.
> diff --git a/fs/famfs/famfs_internal.h b/fs/famfs/famfs_internal.h
> --- a/fs/famfs/famfs_internal.h
> +++ b/fs/famfs/famfs_internal.h
> @@ -15,8 +15,52 @@
> #include <linux/bits.h>
> #include <linux/build_bug.h>
>
> +#include <linux/famfs_ioctl.h>
> +
> extern const struct file_operations famfs_file_operations;
[ ... ]
> +struct famfs_file_meta {
> + bool error;
> + enum famfs_file_type file_type;
> + size_t file_size;
[Severity: High]
Will this type choice truncate the 64-bit file size to 32 bits on 32-bit
architectures? If fmh.file_size exceeds 4GB, the upper 32 bits will be
lost, which could silently corrupt the file size and allow validation
checks to be bypassed.
> + enum famfs_ioc_ext_type fm_extent_type;
> + u64 dev_bitmap; /* referenced daxdev indices */
> + union { /* This will make code a bit more readable */
> + struct {
> + size_t fm_nextents;
> + struct famfs_meta_simple_ext *se;
> + };
> + struct {
> + size_t fm_niext;
> + struct famfs_meta_interleaved_ext *ie;
> + };
> + };
> +};
> diff --git a/fs/famfs/famfs_file.c b/fs/famfs/famfs_file.c
> --- a/fs/famfs/famfs_file.c
> +++ b/fs/famfs/famfs_file.c
[ ... ]
> @@ -60,6 +81,250 @@
> +static int
> +famfs_file_init_dax(struct file *file, void __user *arg)
> +{
[ ... ]
> + fmap_buf = kvmalloc(fmh.fmap_size, GFP_KERNEL);
[Severity: High]
Should these metadata allocations use the __GFP_ACCOUNT flag?
This allocation scales with user input. Without __GFP_ACCOUNT, an
unprivileged user mapping up to 4MB of metadata per file could bypass
memory cgroup limits and potentially trigger a host-wide out-of-memory
condition.
> + if (!fmap_buf)
> + return -ENOMEM;
> +
> + if (copy_from_user(fmap_buf, arg, fmh.fmap_size)) {
> + rc = -EFAULT;
> + goto out;
> + }
> + next_offset = sizeof(fmh); /* start of the extent list */
> +
> + meta = kzalloc_obj(*meta, GFP_KERNEL);
> + if (!meta) {
> + rc = -ENOMEM;
> + goto out;
> + }
> +
> + meta->error = false;
> + meta->file_type = fmh.file_type;
> + meta->file_size = fmh.file_size;
> + meta->fm_extent_type = fmh.ext_type;
> +
> + switch (fmh.ext_type) {
> + case FAMFS_IOC_EXT_SIMPLE: {
> + struct famfs_ioc_simple_ext *se_in = fmap_buf + next_offset;
[ ... ]
> + for (i = 0; i < fmh.nextents; i++) {
> + meta->se[i].dev_index = se_in[i].se_devindex;
> + meta->se[i].ext_offset = se_in[i].se_offset;
> + meta->se[i].ext_len = se_in[i].se_len;
> +
> + if (meta->se[i].dev_index >= FAMFS_MAX_DAXDEVS) {
> + rc = -EINVAL;
> + goto out;
> + }
> + meta->dev_bitmap |= BIT_ULL(meta->se[i].dev_index);
> + errs += famfs_check_ext_alignment(&meta->se[i]);
> + extent_total += meta->se[i].ext_len;
[Severity: High]
Is there a potential integer overflow when accumulating extent_total here?
If the sum of ext_len wraps around, it might pass the extent_total check below
even if the extents do not actually cover the file size. Could ext_offset +
ext_len also overflow U64_MAX and cause out-of-bounds physical memory
accesses when constructing the iomap?
> + }
> + break;
> + }
[ ... ]
> + /* Publish the famfs metadata on inode->i_private */
> + inode_lock(inode);
> + if (inode->i_private) {
> + rc = -EEXIST; /* file already has famfs metadata */
> + } else {
> + inode->i_private = meta;
> + i_size_write(inode, meta->file_size);
[Severity: High]
Could a concurrent reader observe the published metadata but a stale i_size?
Because inode->i_private is assigned before i_size_write(), a lockless
reader could call famfs_file_invalid() in the middle of this window. It
would see a size mismatch and incorrectly set meta->error = true, which
permanently marks the file as corrupted.
> + inode->i_flags |= S_DAX;
> + meta = NULL; /* owned by the inode now */
> + rc = 0;
> + }
> + inode_unlock(inode);
> +
> +out:
> + kvfree(fmap_buf);
> + if (meta)
> + famfs_meta_free(meta);
> + return rc;
> +}
> +
> +/**
> + * famfs_file_ioctl() - Top-level famfs file ioctl handler
> + * @file: the file
> + * @cmd: ioctl opcode
> + * @arg: ioctl opcode argument (if any)
> + */
> +static long
> +famfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> +{
> + struct inode *inode = file_inode(file);
> + struct famfs_fs_info *fsi = inode->i_sb->s_fs_info;
> + long rc;
> +
> + if (fsi->deverror && (cmd != FAMFSIOC_NOP))
> + return -ENODEV;
> +
> + switch (cmd) {
> + case FAMFSIOC_NOP:
> + rc = 0;
> + break;
> +
> + case FAMFSIOC_MAP_CREATE:
> + rc = famfs_file_init_dax(file, (void __user *)arg);
[Severity: Critical]
Does this ioctl command require a privilege check like capable(CAP_SYS_ADMIN)?
Without it, it appears any unprivileged user who can open the file could map
arbitrary physical DAX memory directly into their processes.
> + break;
> +
> + default:
> + rc = -ENOTTY;
> + break;
> + }
> +
> + return rc;
> +}
[ ... ]
> @@ -93,9 +397,25 @@ const struct vm_operations_struct famfs_file_vm_ops = {
> static ssize_t
> famfs_file_invalid(struct inode *inode)
> {
> + struct famfs_file_meta *meta = inode->i_private;
> + size_t i_size = i_size_read(inode);
> +
> + if (!meta) {
> + pr_debug("%s: un-initialized famfs file\n", __func__);
> + return -EIO;
> + }
> + if (meta->error) {
> + pr_debug("%s: previously detected metadata errors\n", __func__);
> + return -EIO;
> + }
> + if (i_size != meta->file_size) {
> + pr_warn("%s: i_size overwritten from %ld to %ld\n",
> + __func__, meta->file_size, i_size);
[Severity: Low]
Should this format string use %zu instead of %ld for size_t variables?
This can cause compiler warnings and misformatted logs on 32-bit platforms.
> + meta->error = true;
> + return -ENXIO;
> + }
[ ... ]
[Severity: High]
This is a pre-existing issue, but can famfs_meta_to_dax_offset_interleaved()
dereference a NULL pointer if called on an uninitialized file?
fs/famfs/famfs_file.c:famfs_meta_to_dax_offset_interleaved() {
...
struct famfs_file_meta *meta = inode->i_private;
...
if (meta->fm_extent_type != FAMFS_IOC_EXT_INTERLEAVE) {
pr_debug("%s: bad extent type\n", __func__);
goto err_out;
}
if (fsi->deverror || famfs_file_invalid(inode))
goto err_out;
...
}
The meta pointer is dereferenced to check fm_extent_type before the call to
famfs_file_invalid(), which is where the check for a NULL meta pointer
actually happens. If the file is uninitialized (inode->i_private is NULL),
this will cause a panic.
--
Sashiko AI review · https://sashiko.dev/#/patchset/0100019fc572ca94-ec363dd7-3a77-484b-b4b7-f2503a0931a6-000000@email.amazonses.com?part=7
next prev parent reply other threads:[~2026-08-03 2:42 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20260803022730.75731-1-john@jagalactic.com>
2026-08-03 2:27 ` [PATCH V12 00/12] famfs: the Fabric-Attached Memory File System (standalone) John Groves
2026-08-03 2:28 ` [PATCH V12 01/12] dax: replace exported dax_dev_get() with non-allocating dax_dev_find() John Groves
2026-08-03 2:43 ` sashiko-bot
2026-08-03 19:13 ` Alison Schofield
2026-08-05 20:21 ` John Groves
2026-08-03 2:28 ` [PATCH V12 02/12] famfs: Module operations, fs_context, and mount John Groves
2026-08-03 2:49 ` sashiko-bot
2026-08-06 4:37 ` Darrick J. Wong
2026-08-06 13:22 ` John Groves
2026-08-03 2:28 ` [PATCH V12 03/12] famfs: Add daxdev table and dax notify_failure support John Groves
2026-08-03 2:45 ` sashiko-bot
2026-08-06 5:05 ` Darrick J. Wong
2026-08-06 13:36 ` John Groves
2026-08-03 2:28 ` [PATCH V12 04/12] famfs: Introduce inode_operations and super_operations John Groves
2026-08-03 2:42 ` sashiko-bot
2026-08-06 5:12 ` Darrick J. Wong
2026-08-06 16:31 ` John Groves
2026-08-03 2:29 ` [PATCH V12 05/12] famfs: Introduce file_operations read/write John Groves
2026-08-03 2:42 ` sashiko-bot
2026-08-06 5:14 ` Darrick J. Wong
2026-08-06 20:03 ` John Groves
2026-08-03 2:29 ` [PATCH V12 06/12] famfs: Introduce mmap and VM fault handling John Groves
2026-08-03 2:46 ` sashiko-bot
2026-08-06 5:16 ` Darrick J. Wong
2026-08-06 20:40 ` John Groves
2026-08-03 2:29 ` [PATCH V12 07/12] famfs: MAP_CREATE ioctl and fmap ingest (ABI 44) John Groves
2026-08-03 2:42 ` sashiko-bot [this message]
2026-08-06 5:24 ` Darrick J. Wong
2026-08-06 20:53 ` John Groves
2026-08-07 22:17 ` John Groves
2026-08-03 2:29 ` [PATCH V12 08/12] famfs: iomap_begin and file-to-dax offset resolution John Groves
2026-08-03 2:44 ` sashiko-bot
2026-08-06 5:28 ` Darrick J. Wong
2026-08-06 22:14 ` John Groves
2026-08-03 2:29 ` [PATCH V12 09/12] famfs: Register secondary daxdevs by path (FAMFSIOC_DAXDEV_OPEN) John Groves
2026-08-03 2:42 ` sashiko-bot
2026-08-06 5:29 ` Darrick J. Wong
2026-08-06 22:22 ` John Groves
2026-08-03 2:29 ` [PATCH V12 10/12] famfs: Add runtime operation-permission (opts) framework John Groves
2026-08-03 2:42 ` sashiko-bot
2026-08-06 5:31 ` Darrick J. Wong
2026-08-06 22:30 ` John Groves
2026-08-03 2:30 ` [PATCH V12 11/12] famfs: Report device capacity via statfs so df works John Groves
2026-08-03 2:58 ` sashiko-bot
2026-08-06 5:33 ` Darrick J. Wong
2026-08-07 13:47 ` John Groves
2026-08-03 2:30 ` [PATCH V12 12/12] famfs: Add documentation John Groves
2026-08-06 5:38 ` Darrick J. Wong
2026-08-07 15:05 ` John Groves
2026-08-03 8:52 ` [PATCH V12 00/12] famfs: the Fabric-Attached Memory File System (standalone) Amir Goldstein
2026-08-06 5:19 ` Matthew Wilcox
2026-08-06 5:34 ` Darrick J. Wong
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=20260803024226.6339E1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=john@jagalactic.com \
--cc=linux-cxl@vger.kernel.org \
--cc=nvdimm@lists.linux.dev \
--cc=sashiko-reviews@lists.linux.dev \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.