From: sashiko-bot@kernel.org
To: "John Groves" <john@jagalactic.com>
Cc: nvdimm@lists.linux.dev, linux-cxl@vger.kernel.org
Subject: Re: [PATCH V11 6/9] famfs_fuse: Plumb dax iomap and fuse read/write/mmap
Date: Mon, 20 Jul 2026 03:57:03 +0000 [thread overview]
Message-ID: <20260720035703.D96F01F000E9@smtp.kernel.org> (raw)
In-Reply-To: <0100019f7da1cf3d-bb04c043-a09f-4925-bf63-eb92452871e5-000000@email.amazonses.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] famfs_fuse_write_iter and famfs_fuse_read_iter completely bypass mandatory VFS locking, security privilege stripping, and POSIX semantics.
- [High] famfs_fuse_mmap fails to set the VM_MIXEDMAP flag, guaranteeing a BUG_ON() crash during DAX page faults.
- [High] Explicitly returning -EIO for splice operations on famfs files breaks standard system calls like sendfile() and splice().
- [High] 32-bit architectures suffer from silent data truncation due to the use of size_t and off_t for 64-bit file offsets and sizes.
- [Medium] Concurrent, lockless modification of `meta->error` in `famfs_file_bad()` creates a data race.
--
--- Patch [6]: [PATCH V11 6/9] famfs_fuse: Plumb dax iomap and fuse read/write/mmap ---
commit 26226f89d9106affa50e5f7fc0a4be4656c4531c
Author: John Groves <john@groves.net>
famfs_fuse: Plumb dax iomap and fuse read/write/mmap
This commit adds read, write, and mmap support for famfs files using the
dev_dax_iomap interface. It handles file offset resolution and page faults
via DAX upcalls.
> diff --git a/fs/fuse/famfs.c b/fs/fuse/famfs.c
> index a2a7dd631dc0f..ac56317944d93 100644
> --- a/fs/fuse/famfs.c
> +++ b/fs/fuse/famfs.c
[ ... ]
> +static int
> +famfs_fileofs_to_daxofs(struct inode *inode, struct iomap *iomap,
> + loff_t file_offset, off_t len, unsigned int flags)
> +{
[Severity: High]
Does defining the len parameter as off_t truncate the mapping length on 32-bit
systems?
[ ... ]
> +const struct vm_operations_struct famfs_file_vm_ops = {
> + .fault = famfs_filemap_fault,
> + .huge_fault = famfs_filemap_huge_fault,
> + .map_pages = filemap_map_pages,
[Severity: High]
Is it correct to assign a page-cache-specific mapping function here? Since
DAX mappings bypass the page cache, using filemap_map_pages might lead to
unexpected behavior.
> + .page_mkwrite = famfs_filemap_mkwrite,
> + .pfn_mkwrite = famfs_filemap_mkwrite,
> +};
[ ... ]
> +static int
> +famfs_file_bad(struct inode *inode)
> +{
> + struct fuse_inode *fi = get_fuse_inode(inode);
> + struct famfs_file_meta *meta = fi->famfs_meta;
> + size_t i_size = i_size_read(inode);
> +
> + if (!meta) {
> + pr_err("%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);
> + meta->error = true;
[Severity: Medium]
Can concurrent I/O operations cause a data race on meta->error? Since read
and write paths can execute without the inode lock, multiple threads might
modify this flag simultaneously.
> + return -ENXIO;
> + }
[ ... ]
> +static ssize_t
> +famfs_fuse_rw_prep(struct kiocb *iocb, struct iov_iter *ubuf)
> +{
> + struct inode *inode = iocb->ki_filp->f_mapping->host;
> + size_t i_size = i_size_read(inode);
[Severity: High]
Might reading i_size_read() into a size_t truncate the 64-bit value on 32-bit
platforms? This would break I/O bounds checking for files larger than 4GB.
This also applies to the file_size field in the famfs_file_meta structure if
it is similarly defined as size_t.
> + size_t count = iov_iter_count(ubuf);
> + size_t max_count;
> + ssize_t rc;
[ ... ]
> +ssize_t
> +famfs_fuse_read_iter(struct kiocb *iocb, struct iov_iter *to)
> +{
> + ssize_t rc;
> +
> + rc = famfs_fuse_rw_prep(iocb, to);
> + if (rc)
> + return rc;
> +
> + if (!iov_iter_count(to))
> + return 0;
> +
> + rc = dax_iomap_rw(iocb, to, &famfs_iomap_ops);
[Severity: Critical]
Does this read path need to acquire inode_lock_shared()? The standard VFS
read paths typically acquire it before calling dax_iomap_rw().
> +
> + file_accessed(iocb->ki_filp);
> + return rc;
> +}
> +
> +ssize_t
> +famfs_fuse_write_iter(struct kiocb *iocb, struct iov_iter *from)
> +{
> + ssize_t rc;
> +
> + rc = famfs_fuse_rw_prep(iocb, from);
> + if (rc)
> + return rc;
> +
> + if (!iov_iter_count(from))
> + return 0;
> +
> + return dax_iomap_rw(iocb, from, &famfs_iomap_ops);
> +}
[Severity: Critical]
Does this write path omit mandatory VFS security and integrity checks?
Calling dax_iomap_rw() directly without acquiring inode_lock() bypasses
generic_write_checks() and file_remove_privs(), which could allow
unprivileged modification of setuid/setgid files and bypass O_APPEND
restrictions.
> +int
> +famfs_fuse_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> + struct inode *inode = file_inode(file);
> + ssize_t rc;
> +
> + rc = famfs_file_bad(inode);
> + if (rc)
> + return rc;
> +
> + file_accessed(file);
> + vma->vm_ops = &famfs_file_vm_ops;
> + vm_flags_set(vma, VM_HUGEPAGE);
[Severity: High]
Could this trigger a kernel panic during DAX page faults? The
vmf_insert_mixed() path expects VM_MIXEDMAP or VM_PFNMAP to be set on the
vma, but VM_MIXEDMAP appears to be omitted here.
> + return 0;
> +}
[ ... ]
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index b4e7b6a645870..2435a79cbb4a3 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
[ ... ]
> @@ -1896,9 +1900,13 @@ static ssize_t fuse_splice_read(struct file *in, loff_t *ppos,
> unsigned int flags)
> {
> struct fuse_file *ff = in->private_data;
> + struct inode *inode = file_inode(in);
> + struct fuse_inode *fi = get_fuse_inode(inode);
>
> /* FOPEN_DIRECT_IO overrides FOPEN_PASSTHROUGH */
> - if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))
> + if (fuse_file_famfs(fi))
> + return -EIO; /* famfs does not use the page cache... */
[Severity: High]
Will returning -EIO break standard system calls like splice() and sendfile()
for famfs files? Should this fall back to iter_file_splice_read() or
copy_splice_read() instead?
> + else if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))
> return fuse_passthrough_splice_read(in, ppos, pipe, len, flags);
> else
> return filemap_splice_read(in, ppos, pipe, len, flags);
> @@ -1908,9 +1916,13 @@ static ssize_t fuse_splice_write(struct pipe_inode_info *pipe, struct file *out,
> loff_t *ppos, size_t len, unsigned int flags)
> {
> struct fuse_file *ff = out->private_data;
> + struct inode *inode = file_inode(out);
> + struct fuse_inode *fi = get_fuse_inode(inode);
>
> /* FOPEN_DIRECT_IO overrides FOPEN_PASSTHROUGH */
> - if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))
> + if (fuse_file_famfs(fi))
> + return -EIO; /* famfs does not use the page cache... */
[Severity: High]
Does hardcoding -EIO here also break splice writes? Falling back to
iter_file_splice_write() might be required to keep standard system calls
functioning.
> + else if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))
> return fuse_passthrough_splice_write(pipe, out, ppos, len, flags);
> else
> return iter_file_splice_write(pipe, out, ppos, len, flags);
--
Sashiko AI review · https://sashiko.dev/#/patchset/0100019f7d9fbe81-6cb16662-2522-47ea-a152-fab0ee3d9b35-000000@email.amazonses.com?part=6
next prev parent reply other threads:[~2026-07-20 3:57 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20260720034358.68714-1-john@jagalactic.com>
2026-07-20 3:44 ` [PATCH V11 0/9] famfs: port into fuse John Groves
2026-07-20 3:45 ` [PATCH V11 1/9] famfs_fuse: Update macro s/FUSE_IS_DAX/FUSE_IS_VIRTIO_DAX/ John Groves
2026-07-20 3:45 ` [PATCH V11 2/9] famfs_fuse: Basic fuse kernel ABI enablement for famfs John Groves
2026-07-20 3:56 ` sashiko-bot
2026-07-20 3:45 ` [PATCH V11 3/9] famfs_fuse: Plumb the GET_FMAP message/response John Groves
2026-07-20 3:56 ` sashiko-bot
2026-07-20 3:46 ` [PATCH V11 4/9] famfs_fuse: Create files with famfs fmaps John Groves
2026-07-20 3:59 ` sashiko-bot
2026-07-20 3:46 ` [PATCH V11 5/9] famfs_fuse: register fs-dax daxdevs via FUSE_DEV_IOC_DAXDEV_OPEN John Groves
2026-07-20 4:02 ` sashiko-bot
2026-07-20 3:46 ` [PATCH V11 6/9] famfs_fuse: Plumb dax iomap and fuse read/write/mmap John Groves
2026-07-20 3:57 ` sashiko-bot [this message]
2026-07-20 3:46 ` [PATCH V11 7/9] famfs_fuse: fail I/O on invalid or errored daxdevs John Groves
2026-07-20 4:00 ` sashiko-bot
2026-07-20 3:46 ` [PATCH V11 8/9] famfs_fuse: Add DAX address_space_operations with noop_dirty_folio John Groves
2026-07-20 4:04 ` sashiko-bot
2026-07-20 3:47 ` [PATCH V11 9/9] famfs_fuse: Add documentation John Groves
2026-07-20 4:09 ` sashiko-bot
2026-07-20 10:07 ` [PATCH V11 0/9] famfs: port into fuse Amir Goldstein
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=20260720035703.D96F01F000E9@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox