Skip to content

Commit f777d11

Browse files
committed
Merge tag 'vfs-6.17-rc6.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: "fuse: - Prevent opening of non-regular backing files. Fuse doesn't support non-regular files anyway. - Check whether copy_file_range() returns a larger size than requested. - Prevent overflow in copy_file_range() as fuse currently only supports 32-bit sized copies. - Cache the blocksize value if the server returned a new value as inode->i_blkbits isn't modified directly anymore. - Fix i_blkbits handling for iomap partial writes. By default i_blkbits is set to PAGE_SIZE which causes iomap to mark the whole folio as uptodate even on a partial write. But fuseblk filesystems support choosing a blocksize smaller than PAGE_SIZE risking data corruption. Simply enforce PAGE_SIZE as blocksize for fuseblk's internal inode for now. - Prevent out-of-bounds acces in fuse_dev_write() when the number of bytes to be retrieved is truncated to the fc->max_pages limit. virtiofs: - Fix page faults for DAX page addresses. Misc: - Tighten file handle decoding from userns. Check that the decoded dentry itself has a valid idmapping in the user namespace. - Fix mount-notify selftests. - Fix some indentation errors. - Add an FMODE_ flag to indicate IOCB_HAS_METADATA availability. This will be moved to an FOP_* flag with a bit more rework needed for that to happen not suitable for a fix. - Don't silently ignore metadata for sync read/write. - Don't pointlessly log warning when reading coredump sysctls" * tag 'vfs-6.17-rc6.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: fuse: virtio_fs: fix page fault for DAX page address selftests/fs/mount-notify: Fix compilation failure. fhandle: use more consistent rules for decoding file handle from userns fuse: Block access to folio overlimit fuse: fix fuseblk i_blkbits for iomap partial writes fuse: reflect cached blocksize if blocksize was changed fuse: prevent overflow in copy_file_range return value fuse: check if copy_file_range() returns larger than requested size fuse: do not allow mapping a non-regular backing file coredump: don't pointlessly check and spew warnings fs: fix indentation style block: don't silently ignore metadata for sync read/write fs: add a FMODE_ flag to indicate IOCB_HAS_METADATA availability Please enter a commit message to explain why this merge is necessary, especially if it merges an updated upstream into a topic branch.
2 parents 76eeb9b + e1bf212 commit f777d11

File tree

16 files changed

+86
-31
lines changed

16 files changed

+86
-31
lines changed

block/fops.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/init.h>
88
#include <linux/mm.h>
99
#include <linux/blkdev.h>
10+
#include <linux/blk-integrity.h>
1011
#include <linux/buffer_head.h>
1112
#include <linux/mpage.h>
1213
#include <linux/uio.h>
@@ -54,7 +55,6 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
5455
struct bio bio;
5556
ssize_t ret;
5657

57-
WARN_ON_ONCE(iocb->ki_flags & IOCB_HAS_METADATA);
5858
if (nr_pages <= DIO_INLINE_BIO_VECS)
5959
vecs = inline_vecs;
6060
else {
@@ -131,7 +131,7 @@ static void blkdev_bio_end_io(struct bio *bio)
131131
if (bio->bi_status && !dio->bio.bi_status)
132132
dio->bio.bi_status = bio->bi_status;
133133

134-
if (!is_sync && (dio->iocb->ki_flags & IOCB_HAS_METADATA))
134+
if (bio_integrity(bio))
135135
bio_integrity_unmap_user(bio);
136136

137137
if (atomic_dec_and_test(&dio->ref)) {
@@ -233,7 +233,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
233233
}
234234
bio->bi_opf |= REQ_NOWAIT;
235235
}
236-
if (!is_sync && (iocb->ki_flags & IOCB_HAS_METADATA)) {
236+
if (iocb->ki_flags & IOCB_HAS_METADATA) {
237237
ret = bio_integrity_map_iter(bio, iocb->private);
238238
if (unlikely(ret))
239239
goto fail;
@@ -301,7 +301,7 @@ static void blkdev_bio_end_io_async(struct bio *bio)
301301
ret = blk_status_to_errno(bio->bi_status);
302302
}
303303

304-
if (iocb->ki_flags & IOCB_HAS_METADATA)
304+
if (bio_integrity(bio))
305305
bio_integrity_unmap_user(bio);
306306

307307
iocb->ki_complete(iocb, ret);
@@ -422,7 +422,8 @@ static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
422422
}
423423

424424
nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1);
425-
if (likely(nr_pages <= BIO_MAX_VECS)) {
425+
if (likely(nr_pages <= BIO_MAX_VECS &&
426+
!(iocb->ki_flags & IOCB_HAS_METADATA))) {
426427
if (is_sync_kiocb(iocb))
427428
return __blkdev_direct_IO_simple(iocb, iter, bdev,
428429
nr_pages);
@@ -687,6 +688,8 @@ static int blkdev_open(struct inode *inode, struct file *filp)
687688

688689
if (bdev_can_atomic_write(bdev))
689690
filp->f_mode |= FMODE_CAN_ATOMIC_WRITE;
691+
if (blk_get_integrity(bdev->bd_disk))
692+
filp->f_mode |= FMODE_HAS_METADATA;
690693

691694
ret = bdev_open(bdev, mode, filp->private_data, NULL, filp);
692695
if (ret)

fs/coredump.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,11 +1466,15 @@ static int proc_dostring_coredump(const struct ctl_table *table, int write,
14661466
ssize_t retval;
14671467
char old_core_pattern[CORENAME_MAX_SIZE];
14681468

1469+
if (write)
1470+
return proc_dostring(table, write, buffer, lenp, ppos);
1471+
14691472
retval = strscpy(old_core_pattern, core_pattern, CORENAME_MAX_SIZE);
14701473

14711474
error = proc_dostring(table, write, buffer, lenp, ppos);
14721475
if (error)
14731476
return error;
1477+
14741478
if (!check_coredump_socket()) {
14751479
strscpy(core_pattern, old_core_pattern, retval + 1);
14761480
return -EINVAL;

fs/exec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2048,7 +2048,7 @@ static int proc_dointvec_minmax_coredump(const struct ctl_table *table, int writ
20482048
{
20492049
int error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
20502050

2051-
if (!error)
2051+
if (!error && !write)
20522052
validate_coredump_safety();
20532053
return error;
20542054
}

fs/fhandle.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,14 @@ static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
207207
if (!ctx->flags)
208208
return 1;
209209

210+
/*
211+
* Verify that the decoded dentry itself has a valid id mapping.
212+
* In case the decoded dentry is the mountfd root itself, this
213+
* verifies that the mountfd inode itself has a valid id mapping.
214+
*/
215+
if (!privileged_wrt_inode_uidgid(user_ns, idmap, d_inode(dentry)))
216+
return 0;
217+
210218
/*
211219
* It's racy as we're not taking rename_lock but we're able to ignore
212220
* permissions and we just need an approximation whether we were able

fs/fuse/dev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1893,7 +1893,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
18931893

18941894
index = outarg->offset >> PAGE_SHIFT;
18951895

1896-
while (num) {
1896+
while (num && ap->num_folios < num_pages) {
18971897
struct folio *folio;
18981898
unsigned int folio_offset;
18991899
unsigned int nr_bytes;

fs/fuse/dir.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,7 @@ static void fuse_fillattr(struct mnt_idmap *idmap, struct inode *inode,
11991199
if (attr->blksize != 0)
12001200
blkbits = ilog2(attr->blksize);
12011201
else
1202-
blkbits = inode->i_sb->s_blocksize_bits;
1202+
blkbits = fc->blkbits;
12031203

12041204
stat->blksize = 1 << blkbits;
12051205
}
@@ -1377,6 +1377,7 @@ static int fuse_update_get_attr(struct mnt_idmap *idmap, struct inode *inode,
13771377
generic_fillattr(idmap, request_mask, inode, stat);
13781378
stat->mode = fi->orig_i_mode;
13791379
stat->ino = fi->orig_ino;
1380+
stat->blksize = 1 << fi->cached_i_blkbits;
13801381
if (test_bit(FUSE_I_BTIME, &fi->state)) {
13811382
stat->btime = fi->i_btime;
13821383
stat->result_mask |= STATX_BTIME;

fs/fuse/file.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2960,7 +2960,7 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in,
29602960
.nodeid_out = ff_out->nodeid,
29612961
.fh_out = ff_out->fh,
29622962
.off_out = pos_out,
2963-
.len = len,
2963+
.len = min_t(size_t, len, UINT_MAX & PAGE_MASK),
29642964
.flags = flags
29652965
};
29662966
struct fuse_write_out outarg;
@@ -3026,6 +3026,9 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in,
30263026
fc->no_copy_file_range = 1;
30273027
err = -EOPNOTSUPP;
30283028
}
3029+
if (!err && outarg.size > len)
3030+
err = -EIO;
3031+
30293032
if (err)
30303033
goto out;
30313034

fs/fuse/fuse_i.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ struct fuse_inode {
210210
/** Reference to backing file in passthrough mode */
211211
struct fuse_backing *fb;
212212
#endif
213+
214+
/*
215+
* The underlying inode->i_blkbits value will not be modified,
216+
* so preserve the blocksize specified by the server.
217+
*/
218+
u8 cached_i_blkbits;
213219
};
214220

215221
/** FUSE inode state bits */
@@ -969,6 +975,14 @@ struct fuse_conn {
969975
/* Request timeout (in jiffies). 0 = no timeout */
970976
unsigned int req_timeout;
971977
} timeout;
978+
979+
/*
980+
* This is a workaround until fuse uses iomap for reads.
981+
* For fuseblk servers, this represents the blocksize passed in at
982+
* mount time and for regular fuse servers, this is equivalent to
983+
* inode->i_blkbits.
984+
*/
985+
u8 blkbits;
972986
};
973987

974988
/*

fs/fuse/inode.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,11 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
289289
}
290290
}
291291

292+
if (attr->blksize)
293+
fi->cached_i_blkbits = ilog2(attr->blksize);
294+
else
295+
fi->cached_i_blkbits = fc->blkbits;
296+
292297
/*
293298
* Don't set the sticky bit in i_mode, unless we want the VFS
294299
* to check permissions. This prevents failures due to the
@@ -1805,10 +1810,21 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
18051810
err = -EINVAL;
18061811
if (!sb_set_blocksize(sb, ctx->blksize))
18071812
goto err;
1813+
/*
1814+
* This is a workaround until fuse hooks into iomap for reads.
1815+
* Use PAGE_SIZE for the blocksize else if the writeback cache
1816+
* is enabled, buffered writes go through iomap and a read may
1817+
* overwrite partially written data if blocksize < PAGE_SIZE
1818+
*/
1819+
fc->blkbits = sb->s_blocksize_bits;
1820+
if (ctx->blksize != PAGE_SIZE &&
1821+
!sb_set_blocksize(sb, PAGE_SIZE))
1822+
goto err;
18081823
#endif
18091824
} else {
18101825
sb->s_blocksize = PAGE_SIZE;
18111826
sb->s_blocksize_bits = PAGE_SHIFT;
1827+
fc->blkbits = sb->s_blocksize_bits;
18121828
}
18131829

18141830
sb->s_subtype = ctx->subtype;

fs/fuse/passthrough.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
237237
if (!file)
238238
goto out;
239239

240+
/* read/write/splice/mmap passthrough only relevant for regular files */
241+
res = d_is_dir(file->f_path.dentry) ? -EISDIR : -EINVAL;
242+
if (!d_is_reg(file->f_path.dentry))
243+
goto out_fput;
244+
240245
backing_sb = file_inode(file)->i_sb;
241246
res = -ELOOP;
242247
if (backing_sb->s_stack_depth >= fc->max_stack_depth)

0 commit comments

Comments
 (0)