Commit 2ef5971f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'vfs-6.10-rc4.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:
 "Misc:
   - Restore debugfs behavior of ignoring unknown mount options
   - Fix kernel doc for netfs_wait_for_oustanding_io()
   - Fix struct statx comment after new addition for this cycle
   - Fix a check in find_next_fd()

  iomap:
   - Fix data zeroing behavior when an extent spans the block that
     contains i_size
   - Restore i_size increasing in iomap_write_end() for now to avoid
     stale data exposure on xfs with a realtime device

  Cachefiles:
   - Remove unneeded fdtable.h include
   - Improve trace output for cachefiles_obj_{get,put}_ondemand_fd()
   - Remove requests from the request list to prevent accessing already
     freed requests
   - Fix UAF when issuing restore command while the daemon is still
     alive by adding an additional reference count to requests
   - Fix UAF by grabbing a reference during xarray lookup with xa_lock()
     held
   - Simplify error handling in cachefiles_ondemand_daemon_read()
   - Add consistency checks read and open requests to avoid crashes
   - Add a spinlock to protect ondemand_id variable which is used to
     determine whether an anonymous cachefiles fd has already been
     closed
   - Make on-demand reads killable allowing to handle broken cachefiles
     daemon better
   - Flush all requests after the kernel has been marked dead via
     CACHEFILES_DEAD to avoid hung-tasks
   - Ensure that closed requests are marked as such to avoid reusing
     them with a reopen request
   - Defer fd_install() until after copy_to_user() succeeded and thereby
     get rid of having to use close_fd()
   - Ensure that anonymous cachefiles on-demand fds are reused while
     they are valid to avoid pinning already freed cookies"

* tag 'vfs-6.10-rc4.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  iomap: Fix iomap_adjust_read_range for plen calculation
  iomap: keep on increasing i_size in iomap_write_end()
  cachefiles: remove unneeded include of <linux/fdtable.h>
  fs/file: fix the check in find_next_fd()
  cachefiles: make on-demand read killable
  cachefiles: flush all requests after setting CACHEFILES_DEAD
  cachefiles: Set object to close if ondemand_id < 0 in copen
  cachefiles: defer exposing anon_fd until after copy_to_user() succeeds
  cachefiles: never get a new anonymous fd if ondemand_id is valid
  cachefiles: add spin_lock for cachefiles_ondemand_info
  cachefiles: add consistency check for copen/cread
  cachefiles: remove err_put_fd label in cachefiles_ondemand_daemon_read()
  cachefiles: fix slab-use-after-free in cachefiles_ondemand_daemon_read()
  cachefiles: fix slab-use-after-free in cachefiles_ondemand_get_fd()
  cachefiles: remove requests from xarray during flushing requests
  cachefiles: add output string to cachefiles_obj_[get|put]_ondemand_fd
  statx: Update offset commentary for struct statx
  netfs: fix kernel doc for nets_wait_for_outstanding_io()
  debugfs: continue to ignore unknown mount options
parents 83a7eefe f5ceb1bb
...@@ -133,7 +133,7 @@ static int cachefiles_daemon_open(struct inode *inode, struct file *file) ...@@ -133,7 +133,7 @@ static int cachefiles_daemon_open(struct inode *inode, struct file *file)
return 0; return 0;
} }
static void cachefiles_flush_reqs(struct cachefiles_cache *cache) void cachefiles_flush_reqs(struct cachefiles_cache *cache)
{ {
struct xarray *xa = &cache->reqs; struct xarray *xa = &cache->reqs;
struct cachefiles_req *req; struct cachefiles_req *req;
...@@ -159,6 +159,7 @@ static void cachefiles_flush_reqs(struct cachefiles_cache *cache) ...@@ -159,6 +159,7 @@ static void cachefiles_flush_reqs(struct cachefiles_cache *cache)
xa_for_each(xa, index, req) { xa_for_each(xa, index, req) {
req->error = -EIO; req->error = -EIO;
complete(&req->done); complete(&req->done);
__xa_erase(xa, index);
} }
xa_unlock(xa); xa_unlock(xa);
......
...@@ -55,6 +55,7 @@ struct cachefiles_ondemand_info { ...@@ -55,6 +55,7 @@ struct cachefiles_ondemand_info {
int ondemand_id; int ondemand_id;
enum cachefiles_object_state state; enum cachefiles_object_state state;
struct cachefiles_object *object; struct cachefiles_object *object;
spinlock_t lock;
}; };
/* /*
...@@ -138,6 +139,7 @@ static inline bool cachefiles_in_ondemand_mode(struct cachefiles_cache *cache) ...@@ -138,6 +139,7 @@ static inline bool cachefiles_in_ondemand_mode(struct cachefiles_cache *cache)
struct cachefiles_req { struct cachefiles_req {
struct cachefiles_object *object; struct cachefiles_object *object;
struct completion done; struct completion done;
refcount_t ref;
int error; int error;
struct cachefiles_msg msg; struct cachefiles_msg msg;
}; };
...@@ -186,6 +188,7 @@ extern int cachefiles_has_space(struct cachefiles_cache *cache, ...@@ -186,6 +188,7 @@ extern int cachefiles_has_space(struct cachefiles_cache *cache,
* daemon.c * daemon.c
*/ */
extern const struct file_operations cachefiles_daemon_fops; extern const struct file_operations cachefiles_daemon_fops;
extern void cachefiles_flush_reqs(struct cachefiles_cache *cache);
extern void cachefiles_get_unbind_pincount(struct cachefiles_cache *cache); extern void cachefiles_get_unbind_pincount(struct cachefiles_cache *cache);
extern void cachefiles_put_unbind_pincount(struct cachefiles_cache *cache); extern void cachefiles_put_unbind_pincount(struct cachefiles_cache *cache);
...@@ -424,6 +427,8 @@ do { \ ...@@ -424,6 +427,8 @@ do { \
pr_err("I/O Error: " FMT"\n", ##__VA_ARGS__); \ pr_err("I/O Error: " FMT"\n", ##__VA_ARGS__); \
fscache_io_error((___cache)->cache); \ fscache_io_error((___cache)->cache); \
set_bit(CACHEFILES_DEAD, &(___cache)->flags); \ set_bit(CACHEFILES_DEAD, &(___cache)->flags); \
if (cachefiles_in_ondemand_mode(___cache)) \
cachefiles_flush_reqs(___cache); \
} while (0) } while (0)
#define cachefiles_io_error_obj(object, FMT, ...) \ #define cachefiles_io_error_obj(object, FMT, ...) \
......
This diff is collapsed.
...@@ -107,8 +107,16 @@ static int debugfs_parse_param(struct fs_context *fc, struct fs_parameter *param ...@@ -107,8 +107,16 @@ static int debugfs_parse_param(struct fs_context *fc, struct fs_parameter *param
int opt; int opt;
opt = fs_parse(fc, debugfs_param_specs, param, &result); opt = fs_parse(fc, debugfs_param_specs, param, &result);
if (opt < 0) if (opt < 0) {
/*
* We might like to report bad mount options here; but
* traditionally debugfs has ignored all mount options
*/
if (opt == -ENOPARAM)
return 0;
return opt; return opt;
}
switch (opt) { switch (opt) {
case Opt_uid: case Opt_uid:
......
...@@ -486,12 +486,12 @@ struct files_struct init_files = { ...@@ -486,12 +486,12 @@ struct files_struct init_files = {
static unsigned int find_next_fd(struct fdtable *fdt, unsigned int start) static unsigned int find_next_fd(struct fdtable *fdt, unsigned int start)
{ {
unsigned int maxfd = fdt->max_fds; unsigned int maxfd = fdt->max_fds; /* always multiple of BITS_PER_LONG */
unsigned int maxbit = maxfd / BITS_PER_LONG; unsigned int maxbit = maxfd / BITS_PER_LONG;
unsigned int bitbit = start / BITS_PER_LONG; unsigned int bitbit = start / BITS_PER_LONG;
bitbit = find_next_zero_bit(fdt->full_fds_bits, maxbit, bitbit) * BITS_PER_LONG; bitbit = find_next_zero_bit(fdt->full_fds_bits, maxbit, bitbit) * BITS_PER_LONG;
if (bitbit > maxfd) if (bitbit >= maxfd)
return maxfd; return maxfd;
if (bitbit > start) if (bitbit > start)
start = bitbit; start = bitbit;
......
...@@ -241,6 +241,7 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio, ...@@ -241,6 +241,7 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio,
unsigned block_size = (1 << block_bits); unsigned block_size = (1 << block_bits);
size_t poff = offset_in_folio(folio, *pos); size_t poff = offset_in_folio(folio, *pos);
size_t plen = min_t(loff_t, folio_size(folio) - poff, length); size_t plen = min_t(loff_t, folio_size(folio) - poff, length);
size_t orig_plen = plen;
unsigned first = poff >> block_bits; unsigned first = poff >> block_bits;
unsigned last = (poff + plen - 1) >> block_bits; unsigned last = (poff + plen - 1) >> block_bits;
...@@ -277,7 +278,7 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio, ...@@ -277,7 +278,7 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio,
* handle both halves separately so that we properly zero data in the * handle both halves separately so that we properly zero data in the
* page cache for blocks that are entirely outside of i_size. * page cache for blocks that are entirely outside of i_size.
*/ */
if (orig_pos <= isize && orig_pos + length > isize) { if (orig_pos <= isize && orig_pos + orig_plen > isize) {
unsigned end = offset_in_folio(folio, isize - 1) >> block_bits; unsigned end = offset_in_folio(folio, isize - 1) >> block_bits;
if (first <= end && last > end) if (first <= end && last > end)
...@@ -877,22 +878,37 @@ static bool iomap_write_end(struct iomap_iter *iter, loff_t pos, size_t len, ...@@ -877,22 +878,37 @@ static bool iomap_write_end(struct iomap_iter *iter, loff_t pos, size_t len,
size_t copied, struct folio *folio) size_t copied, struct folio *folio)
{ {
const struct iomap *srcmap = iomap_iter_srcmap(iter); const struct iomap *srcmap = iomap_iter_srcmap(iter);
loff_t old_size = iter->inode->i_size;
size_t written;
if (srcmap->type == IOMAP_INLINE) { if (srcmap->type == IOMAP_INLINE) {
iomap_write_end_inline(iter, folio, pos, copied); iomap_write_end_inline(iter, folio, pos, copied);
return true; written = copied;
} else if (srcmap->flags & IOMAP_F_BUFFER_HEAD) {
written = block_write_end(NULL, iter->inode->i_mapping, pos,
len, copied, &folio->page, NULL);
WARN_ON_ONCE(written != copied && written != 0);
} else {
written = __iomap_write_end(iter->inode, pos, len, copied,
folio) ? copied : 0;
} }
if (srcmap->flags & IOMAP_F_BUFFER_HEAD) { /*
size_t bh_written; * Update the in-memory inode size after copying the data into the page
* cache. It's up to the file system to write the updated size to disk,
bh_written = block_write_end(NULL, iter->inode->i_mapping, pos, * preferably after I/O completion so that no stale data is exposed.
len, copied, &folio->page, NULL); * Only once that's done can we unlock and release the folio.
WARN_ON_ONCE(bh_written != copied && bh_written != 0); */
return bh_written == copied; if (pos + written > old_size) {
i_size_write(iter->inode, pos + written);
iter->iomap.flags |= IOMAP_F_SIZE_CHANGED;
} }
__iomap_put_folio(iter, pos, written, folio);
return __iomap_write_end(iter->inode, pos, len, copied, folio); if (old_size < pos)
pagecache_isize_extended(iter->inode, old_size, pos);
return written == copied;
} }
static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i) static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i)
...@@ -907,7 +923,6 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i) ...@@ -907,7 +923,6 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i)
do { do {
struct folio *folio; struct folio *folio;
loff_t old_size;
size_t offset; /* Offset into folio */ size_t offset; /* Offset into folio */
size_t bytes; /* Bytes to write to folio */ size_t bytes; /* Bytes to write to folio */
size_t copied; /* Bytes copied from user */ size_t copied; /* Bytes copied from user */
...@@ -959,23 +974,6 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i) ...@@ -959,23 +974,6 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i)
written = iomap_write_end(iter, pos, bytes, copied, folio) ? written = iomap_write_end(iter, pos, bytes, copied, folio) ?
copied : 0; copied : 0;
/*
* Update the in-memory inode size after copying the data into
* the page cache. It's up to the file system to write the
* updated size to disk, preferably after I/O completion so that
* no stale data is exposed. Only once that's done can we
* unlock and release the folio.
*/
old_size = iter->inode->i_size;
if (pos + written > old_size) {
i_size_write(iter->inode, pos + written);
iter->iomap.flags |= IOMAP_F_SIZE_CHANGED;
}
__iomap_put_folio(iter, pos, written, folio);
if (old_size < pos)
pagecache_isize_extended(iter->inode, old_size, pos);
cond_resched(); cond_resched();
if (unlikely(written == 0)) { if (unlikely(written == 0)) {
/* /*
...@@ -1346,7 +1344,6 @@ static loff_t iomap_unshare_iter(struct iomap_iter *iter) ...@@ -1346,7 +1344,6 @@ static loff_t iomap_unshare_iter(struct iomap_iter *iter)
bytes = folio_size(folio) - offset; bytes = folio_size(folio) - offset;
ret = iomap_write_end(iter, pos, bytes, bytes, folio); ret = iomap_write_end(iter, pos, bytes, bytes, folio);
__iomap_put_folio(iter, pos, bytes, folio);
if (WARN_ON_ONCE(!ret)) if (WARN_ON_ONCE(!ret))
return -EIO; return -EIO;
...@@ -1412,7 +1409,6 @@ static loff_t iomap_zero_iter(struct iomap_iter *iter, bool *did_zero) ...@@ -1412,7 +1409,6 @@ static loff_t iomap_zero_iter(struct iomap_iter *iter, bool *did_zero)
folio_mark_accessed(folio); folio_mark_accessed(folio);
ret = iomap_write_end(iter, pos, bytes, bytes, folio); ret = iomap_write_end(iter, pos, bytes, bytes, folio);
__iomap_put_folio(iter, pos, bytes, folio);
if (WARN_ON_ONCE(!ret)) if (WARN_ON_ONCE(!ret))
return -EIO; return -EIO;
......
...@@ -521,7 +521,7 @@ static inline struct fscache_cookie *netfs_i_cookie(struct netfs_inode *ctx) ...@@ -521,7 +521,7 @@ static inline struct fscache_cookie *netfs_i_cookie(struct netfs_inode *ctx)
/** /**
* netfs_wait_for_outstanding_io - Wait for outstanding I/O to complete * netfs_wait_for_outstanding_io - Wait for outstanding I/O to complete
* @ctx: The netfs inode to wait on * @inode: The netfs inode to wait on
* *
* Wait for outstanding I/O requests of any type to complete. This is intended * Wait for outstanding I/O requests of any type to complete. This is intended
* to be called from inode eviction routines. This makes sure that any * to be called from inode eviction routines. This makes sure that any
......
...@@ -33,6 +33,8 @@ enum cachefiles_obj_ref_trace { ...@@ -33,6 +33,8 @@ enum cachefiles_obj_ref_trace {
cachefiles_obj_see_withdrawal, cachefiles_obj_see_withdrawal,
cachefiles_obj_get_ondemand_fd, cachefiles_obj_get_ondemand_fd,
cachefiles_obj_put_ondemand_fd, cachefiles_obj_put_ondemand_fd,
cachefiles_obj_get_read_req,
cachefiles_obj_put_read_req,
}; };
enum fscache_why_object_killed { enum fscache_why_object_killed {
...@@ -127,7 +129,11 @@ enum cachefiles_error_trace { ...@@ -127,7 +129,11 @@ enum cachefiles_error_trace {
EM(cachefiles_obj_see_lookup_cookie, "SEE lookup_cookie") \ EM(cachefiles_obj_see_lookup_cookie, "SEE lookup_cookie") \
EM(cachefiles_obj_see_lookup_failed, "SEE lookup_failed") \ EM(cachefiles_obj_see_lookup_failed, "SEE lookup_failed") \
EM(cachefiles_obj_see_withdraw_cookie, "SEE withdraw_cookie") \ EM(cachefiles_obj_see_withdraw_cookie, "SEE withdraw_cookie") \
E_(cachefiles_obj_see_withdrawal, "SEE withdrawal") EM(cachefiles_obj_see_withdrawal, "SEE withdrawal") \
EM(cachefiles_obj_get_ondemand_fd, "GET ondemand_fd") \
EM(cachefiles_obj_put_ondemand_fd, "PUT ondemand_fd") \
EM(cachefiles_obj_get_read_req, "GET read_req") \
E_(cachefiles_obj_put_read_req, "PUT read_req")
#define cachefiles_coherency_traces \ #define cachefiles_coherency_traces \
EM(cachefiles_coherency_check_aux, "BAD aux ") \ EM(cachefiles_coherency_check_aux, "BAD aux ") \
......
...@@ -126,8 +126,8 @@ struct statx { ...@@ -126,8 +126,8 @@ struct statx {
__u64 stx_mnt_id; __u64 stx_mnt_id;
__u32 stx_dio_mem_align; /* Memory buffer alignment for direct I/O */ __u32 stx_dio_mem_align; /* Memory buffer alignment for direct I/O */
__u32 stx_dio_offset_align; /* File offset alignment for direct I/O */ __u32 stx_dio_offset_align; /* File offset alignment for direct I/O */
__u64 stx_subvol; /* Subvolume identifier */
/* 0xa0 */ /* 0xa0 */
__u64 stx_subvol; /* Subvolume identifier */
__u64 __spare3[11]; /* Spare space for future expansion */ __u64 __spare3[11]; /* Spare space for future expansion */
/* 0x100 */ /* 0x100 */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment