Skip to content

Commit 83ab4b4

Browse files
committed
Merge tag 'vfs-6.10-rc8.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: "cachefiles: - Export an existing and add a new cachefile helper to be used in filesystems to fix reference count bugs - Use the newly added fscache_ty_get_volume() helper to get a reference count on an fscache_volume to handle volumes that are about to be removed cleanly - After withdrawing a fscache_cache via FSCACHE_CACHE_IS_WITHDRAWN wait for all ongoing cookie lookups to complete and for the object count to reach zero - Propagate errors from vfs_getxattr() to avoid an infinite loop in cachefiles_check_volume_xattr() because it keeps seeing ESTALE - Don't send new requests when an object is dropped by raising CACHEFILES_ONDEMAND_OJBSTATE_DROPPING - Cancel all requests for an object that is about to be dropped - Wait for the ondemand_boject_worker to finish before dropping a cachefiles object to prevent use-after-free - Use cyclic allocation for message ids to better handle id recycling - Add missing lock protection when iterating through the xarray when polling netfs: - Use standard logging helpers for debug logging VFS: - Fix potential use-after-free in file locks during trace_posix_lock_inode(). The tracepoint could fire while another task raced it and freed the lock that was requested to be traced - Only increment the nr_dentry_negative counter for dentries that are present on the superblock LRU. Currently, DCACHE_LRU_LIST list is used to detect this case. However, the flag is also raised in combination with DCACHE_SHRINK_LIST to indicate that dentry->d_lru is used. So checking only DCACHE_LRU_LIST will lead to wrong nr_dentry_negative count. Fix the check to not count dentries that are on a shrink related list Misc: - hfsplus: fix an uninitialized value issue in copy_name - minix: fix minixfs_rename with HIGHMEM. It still uses kunmap() even though we switched it to kmap_local_page() a while ago" * tag 'vfs-6.10-rc8.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: minixfs: Fix minixfs_rename with HIGHMEM hfsplus: fix uninit-value in copy_name vfs: don't mod negative dentry count when on shrinker list filelock: fix potential use-after-free in posix_lock_inode cachefiles: add missing lock protection when polling cachefiles: cyclic allocation of msg_id to avoid reuse cachefiles: wait for ondemand_object_worker to finish when dropping object cachefiles: cancel all requests for the object that is being dropped cachefiles: stop sending new request when dropping object cachefiles: propagate errors from vfs_getxattr() to avoid infinite loop cachefiles: fix slab-use-after-free in cachefiles_withdraw_cookie() cachefiles: fix slab-use-after-free in fscache_withdraw_volume() netfs, fscache: export fscache_put_volume() and add fscache_try_get_volume() netfs: Switch debug logging to pr_debug()
2 parents 9d9a2f2 + 3d1bec2 commit 83ab4b4

27 files changed

+213
-133
lines changed

fs/cachefiles/cache.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/slab.h>
99
#include <linux/statfs.h>
1010
#include <linux/namei.h>
11+
#include <trace/events/fscache.h>
1112
#include "internal.h"
1213

1314
/*
@@ -312,26 +313,67 @@ static void cachefiles_withdraw_objects(struct cachefiles_cache *cache)
312313
}
313314

314315
/*
315-
* Withdraw volumes.
316+
* Withdraw fscache volumes.
317+
*/
318+
static void cachefiles_withdraw_fscache_volumes(struct cachefiles_cache *cache)
319+
{
320+
struct list_head *cur;
321+
struct cachefiles_volume *volume;
322+
struct fscache_volume *vcookie;
323+
324+
_enter("");
325+
retry:
326+
spin_lock(&cache->object_list_lock);
327+
list_for_each(cur, &cache->volumes) {
328+
volume = list_entry(cur, struct cachefiles_volume, cache_link);
329+
330+
if (atomic_read(&volume->vcookie->n_accesses) == 0)
331+
continue;
332+
333+
vcookie = fscache_try_get_volume(volume->vcookie,
334+
fscache_volume_get_withdraw);
335+
if (vcookie) {
336+
spin_unlock(&cache->object_list_lock);
337+
fscache_withdraw_volume(vcookie);
338+
fscache_put_volume(vcookie, fscache_volume_put_withdraw);
339+
goto retry;
340+
}
341+
}
342+
spin_unlock(&cache->object_list_lock);
343+
344+
_leave("");
345+
}
346+
347+
/*
348+
* Withdraw cachefiles volumes.
316349
*/
317350
static void cachefiles_withdraw_volumes(struct cachefiles_cache *cache)
318351
{
319352
_enter("");
320353

321354
for (;;) {
355+
struct fscache_volume *vcookie = NULL;
322356
struct cachefiles_volume *volume = NULL;
323357

324358
spin_lock(&cache->object_list_lock);
325359
if (!list_empty(&cache->volumes)) {
326360
volume = list_first_entry(&cache->volumes,
327361
struct cachefiles_volume, cache_link);
362+
vcookie = fscache_try_get_volume(volume->vcookie,
363+
fscache_volume_get_withdraw);
364+
if (!vcookie) {
365+
spin_unlock(&cache->object_list_lock);
366+
cpu_relax();
367+
continue;
368+
}
328369
list_del_init(&volume->cache_link);
329370
}
330371
spin_unlock(&cache->object_list_lock);
331372
if (!volume)
332373
break;
333374

334375
cachefiles_withdraw_volume(volume);
376+
fscache_put_volume(vcookie, fscache_volume_put_withdraw);
335377
}
336378

337379
_leave("");
@@ -371,6 +413,7 @@ void cachefiles_withdraw_cache(struct cachefiles_cache *cache)
371413
pr_info("File cache on %s unregistering\n", fscache->name);
372414

373415
fscache_withdraw_cache(fscache);
416+
cachefiles_withdraw_fscache_volumes(cache);
374417

375418
/* we now have to destroy all the active objects pertaining to this
376419
* cache - which we do by passing them off to thread pool to be

fs/cachefiles/daemon.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,14 +366,14 @@ static __poll_t cachefiles_daemon_poll(struct file *file,
366366

367367
if (cachefiles_in_ondemand_mode(cache)) {
368368
if (!xa_empty(&cache->reqs)) {
369-
rcu_read_lock();
369+
xas_lock(&xas);
370370
xas_for_each_marked(&xas, req, ULONG_MAX, CACHEFILES_REQ_NEW) {
371371
if (!cachefiles_ondemand_is_reopening_read(req)) {
372372
mask |= EPOLLIN;
373373
break;
374374
}
375375
}
376-
rcu_read_unlock();
376+
xas_unlock(&xas);
377377
}
378378
} else {
379379
if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags))

fs/cachefiles/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ enum cachefiles_object_state {
4848
CACHEFILES_ONDEMAND_OBJSTATE_CLOSE, /* Anonymous fd closed by daemon or initial state */
4949
CACHEFILES_ONDEMAND_OBJSTATE_OPEN, /* Anonymous fd associated with object is available */
5050
CACHEFILES_ONDEMAND_OBJSTATE_REOPENING, /* Object that was closed and is being reopened. */
51+
CACHEFILES_ONDEMAND_OBJSTATE_DROPPING, /* Object is being dropped. */
5152
};
5253

5354
struct cachefiles_ondemand_info {
@@ -128,6 +129,7 @@ struct cachefiles_cache {
128129
unsigned long req_id_next;
129130
struct xarray ondemand_ids; /* xarray for ondemand_id allocation */
130131
u32 ondemand_id_next;
132+
u32 msg_id_next;
131133
};
132134

133135
static inline bool cachefiles_in_ondemand_mode(struct cachefiles_cache *cache)
@@ -335,6 +337,7 @@ cachefiles_ondemand_set_object_##_state(struct cachefiles_object *object) \
335337
CACHEFILES_OBJECT_STATE_FUNCS(open, OPEN);
336338
CACHEFILES_OBJECT_STATE_FUNCS(close, CLOSE);
337339
CACHEFILES_OBJECT_STATE_FUNCS(reopening, REOPENING);
340+
CACHEFILES_OBJECT_STATE_FUNCS(dropping, DROPPING);
338341

339342
static inline bool cachefiles_ondemand_is_reopening_read(struct cachefiles_req *req)
340343
{

fs/cachefiles/ondemand.c

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,8 @@ static int cachefiles_ondemand_send_req(struct cachefiles_object *object,
517517
*/
518518
xas_lock(&xas);
519519

520-
if (test_bit(CACHEFILES_DEAD, &cache->flags)) {
520+
if (test_bit(CACHEFILES_DEAD, &cache->flags) ||
521+
cachefiles_ondemand_object_is_dropping(object)) {
521522
xas_unlock(&xas);
522523
ret = -EIO;
523524
goto out;
@@ -527,20 +528,32 @@ static int cachefiles_ondemand_send_req(struct cachefiles_object *object,
527528
smp_mb();
528529

529530
if (opcode == CACHEFILES_OP_CLOSE &&
530-
!cachefiles_ondemand_object_is_open(object)) {
531+
!cachefiles_ondemand_object_is_open(object)) {
531532
WARN_ON_ONCE(object->ondemand->ondemand_id == 0);
532533
xas_unlock(&xas);
533534
ret = -EIO;
534535
goto out;
535536
}
536537

537-
xas.xa_index = 0;
538+
/*
539+
* Cyclically find a free xas to avoid msg_id reuse that would
540+
* cause the daemon to successfully copen a stale msg_id.
541+
*/
542+
xas.xa_index = cache->msg_id_next;
538543
xas_find_marked(&xas, UINT_MAX, XA_FREE_MARK);
544+
if (xas.xa_node == XAS_RESTART) {
545+
xas.xa_index = 0;
546+
xas_find_marked(&xas, cache->msg_id_next - 1, XA_FREE_MARK);
547+
}
539548
if (xas.xa_node == XAS_RESTART)
540549
xas_set_err(&xas, -EBUSY);
550+
541551
xas_store(&xas, req);
542-
xas_clear_mark(&xas, XA_FREE_MARK);
543-
xas_set_mark(&xas, CACHEFILES_REQ_NEW);
552+
if (xas_valid(&xas)) {
553+
cache->msg_id_next = xas.xa_index + 1;
554+
xas_clear_mark(&xas, XA_FREE_MARK);
555+
xas_set_mark(&xas, CACHEFILES_REQ_NEW);
556+
}
544557
xas_unlock(&xas);
545558
} while (xas_nomem(&xas, GFP_KERNEL));
546559

@@ -568,7 +581,8 @@ static int cachefiles_ondemand_send_req(struct cachefiles_object *object,
568581
* If error occurs after creating the anonymous fd,
569582
* cachefiles_ondemand_fd_release() will set object to close.
570583
*/
571-
if (opcode == CACHEFILES_OP_OPEN)
584+
if (opcode == CACHEFILES_OP_OPEN &&
585+
!cachefiles_ondemand_object_is_dropping(object))
572586
cachefiles_ondemand_set_object_close(object);
573587
kfree(req);
574588
return ret;
@@ -667,8 +681,34 @@ int cachefiles_ondemand_init_object(struct cachefiles_object *object)
667681

668682
void cachefiles_ondemand_clean_object(struct cachefiles_object *object)
669683
{
684+
unsigned long index;
685+
struct cachefiles_req *req;
686+
struct cachefiles_cache *cache;
687+
688+
if (!object->ondemand)
689+
return;
690+
670691
cachefiles_ondemand_send_req(object, CACHEFILES_OP_CLOSE, 0,
671692
cachefiles_ondemand_init_close_req, NULL);
693+
694+
if (!object->ondemand->ondemand_id)
695+
return;
696+
697+
/* Cancel all requests for the object that is being dropped. */
698+
cache = object->volume->cache;
699+
xa_lock(&cache->reqs);
700+
cachefiles_ondemand_set_object_dropping(object);
701+
xa_for_each(&cache->reqs, index, req) {
702+
if (req->object == object) {
703+
req->error = -EIO;
704+
complete(&req->done);
705+
__xa_erase(&cache->reqs, index);
706+
}
707+
}
708+
xa_unlock(&cache->reqs);
709+
710+
/* Wait for ondemand_object_worker() to finish to avoid UAF. */
711+
cancel_work_sync(&object->ondemand->ondemand_work);
672712
}
673713

674714
int cachefiles_ondemand_init_obj_info(struct cachefiles_object *object,

fs/cachefiles/volume.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ void cachefiles_free_volume(struct fscache_volume *vcookie)
133133

134134
void cachefiles_withdraw_volume(struct cachefiles_volume *volume)
135135
{
136-
fscache_withdraw_volume(volume->vcookie);
137136
cachefiles_set_volume_xattr(volume);
138137
__cachefiles_free_volume(volume);
139138
}

fs/cachefiles/xattr.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ int cachefiles_check_auxdata(struct cachefiles_object *object, struct file *file
110110
if (xlen == 0)
111111
xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, tlen);
112112
if (xlen != tlen) {
113-
if (xlen < 0)
113+
if (xlen < 0) {
114+
ret = xlen;
114115
trace_cachefiles_vfs_error(object, file_inode(file), xlen,
115116
cachefiles_trace_getxattr_error);
117+
}
116118
if (xlen == -EIO)
117119
cachefiles_io_error_obj(
118120
object,
@@ -252,6 +254,7 @@ int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
252254
xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, len);
253255
if (xlen != len) {
254256
if (xlen < 0) {
257+
ret = xlen;
255258
trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,
256259
cachefiles_trace_getxattr_error);
257260
if (xlen == -EIO)

fs/dcache.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,11 @@ static inline void __d_clear_type_and_inode(struct dentry *dentry)
355355
flags &= ~DCACHE_ENTRY_TYPE;
356356
WRITE_ONCE(dentry->d_flags, flags);
357357
dentry->d_inode = NULL;
358-
if (flags & DCACHE_LRU_LIST)
358+
/*
359+
* The negative counter only tracks dentries on the LRU. Don't inc if
360+
* d_lru is on another list.
361+
*/
362+
if ((flags & (DCACHE_LRU_LIST|DCACHE_SHRINK_LIST)) == DCACHE_LRU_LIST)
359363
this_cpu_inc(nr_dentry_negative);
360364
}
361365

@@ -1844,9 +1848,11 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
18441848

18451849
spin_lock(&dentry->d_lock);
18461850
/*
1847-
* Decrement negative dentry count if it was in the LRU list.
1851+
* The negative counter only tracks dentries on the LRU. Don't dec if
1852+
* d_lru is on another list.
18481853
*/
1849-
if (dentry->d_flags & DCACHE_LRU_LIST)
1854+
if ((dentry->d_flags &
1855+
(DCACHE_LRU_LIST|DCACHE_SHRINK_LIST)) == DCACHE_LRU_LIST)
18501856
this_cpu_dec(nr_dentry_negative);
18511857
hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
18521858
raw_write_seqcount_begin(&dentry->d_seq);

fs/hfsplus/xattr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
696696
return err;
697697
}
698698

699-
strbuf = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN +
699+
strbuf = kzalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN +
700700
XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL);
701701
if (!strbuf) {
702702
res = -ENOMEM;

fs/locks.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1367,9 +1367,9 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
13671367
locks_wake_up_blocks(&left->c);
13681368
}
13691369
out:
1370+
trace_posix_lock_inode(inode, request, error);
13701371
spin_unlock(&ctx->flc_lock);
13711372
percpu_up_read(&file_rwsem);
1372-
trace_posix_lock_inode(inode, request, error);
13731373
/*
13741374
* Free any unused locks.
13751375
*/

fs/minix/namei.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,7 @@ static int minix_rename(struct mnt_idmap *idmap,
213213
if (!new_de)
214214
goto out_dir;
215215
err = minix_set_link(new_de, new_page, old_inode);
216-
kunmap(new_page);
217-
put_page(new_page);
216+
unmap_and_put_page(new_page, new_de);
218217
if (err)
219218
goto out_dir;
220219
inode_set_ctime_current(new_inode);

0 commit comments

Comments
 (0)