Skip to content

Commit 31ad74b

Browse files
Zizhi Wobrauner
authored andcommitted
cachefiles: Fix NULL pointer dereference in object->file
At present, the object->file has the NULL pointer dereference problem in ondemand-mode. The root cause is that the allocated fd and object->file lifetime are inconsistent, and the user-space invocation to anon_fd uses object->file. Following is the process that triggers the issue: [write fd] [umount] cachefiles_ondemand_fd_write_iter fscache_cookie_state_machine cachefiles_withdraw_cookie if (!file) return -ENOBUFS cachefiles_clean_up_object cachefiles_unmark_inode_in_use fput(object->file) object->file = NULL // file NULL pointer dereference! __cachefiles_write(..., file, ...) Fix this issue by add an additional reference count to the object->file before write/llseek, and decrement after it finished. Fixes: c838305 ("cachefiles: notify the user daemon when looking up cookie") Signed-off-by: Zizhi Wo <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: David Howells <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 09ecf8f commit 31ad74b

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

fs/cachefiles/interface.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,8 @@ static void cachefiles_commit_object(struct cachefiles_object *object,
327327
static void cachefiles_clean_up_object(struct cachefiles_object *object,
328328
struct cachefiles_cache *cache)
329329
{
330+
struct file *file;
331+
330332
if (test_bit(FSCACHE_COOKIE_RETIRED, &object->cookie->flags)) {
331333
if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
332334
cachefiles_see_object(object, cachefiles_obj_see_clean_delete);
@@ -342,10 +344,14 @@ static void cachefiles_clean_up_object(struct cachefiles_object *object,
342344
}
343345

344346
cachefiles_unmark_inode_in_use(object, object->file);
345-
if (object->file) {
346-
fput(object->file);
347-
object->file = NULL;
348-
}
347+
348+
spin_lock(&object->lock);
349+
file = object->file;
350+
object->file = NULL;
351+
spin_unlock(&object->lock);
352+
353+
if (file)
354+
fput(file);
349355
}
350356

351357
/*

fs/cachefiles/ondemand.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,26 @@ static ssize_t cachefiles_ondemand_fd_write_iter(struct kiocb *kiocb,
6060
{
6161
struct cachefiles_object *object = kiocb->ki_filp->private_data;
6262
struct cachefiles_cache *cache = object->volume->cache;
63-
struct file *file = object->file;
63+
struct file *file;
6464
size_t len = iter->count, aligned_len = len;
6565
loff_t pos = kiocb->ki_pos;
6666
const struct cred *saved_cred;
6767
int ret;
6868

69-
if (!file)
69+
spin_lock(&object->lock);
70+
file = object->file;
71+
if (!file) {
72+
spin_unlock(&object->lock);
7073
return -ENOBUFS;
74+
}
75+
get_file(file);
76+
spin_unlock(&object->lock);
7177

7278
cachefiles_begin_secure(cache, &saved_cred);
7379
ret = __cachefiles_prepare_write(object, file, &pos, &aligned_len, len, true);
7480
cachefiles_end_secure(cache, saved_cred);
7581
if (ret < 0)
76-
return ret;
82+
goto out;
7783

7884
trace_cachefiles_ondemand_fd_write(object, file_inode(file), pos, len);
7985
ret = __cachefiles_write(object, file, pos, iter, NULL, NULL);
@@ -82,19 +88,31 @@ static ssize_t cachefiles_ondemand_fd_write_iter(struct kiocb *kiocb,
8288
kiocb->ki_pos += ret;
8389
}
8490

91+
out:
92+
fput(file);
8593
return ret;
8694
}
8795

8896
static loff_t cachefiles_ondemand_fd_llseek(struct file *filp, loff_t pos,
8997
int whence)
9098
{
9199
struct cachefiles_object *object = filp->private_data;
92-
struct file *file = object->file;
100+
struct file *file;
101+
loff_t ret;
93102

94-
if (!file)
103+
spin_lock(&object->lock);
104+
file = object->file;
105+
if (!file) {
106+
spin_unlock(&object->lock);
95107
return -ENOBUFS;
108+
}
109+
get_file(file);
110+
spin_unlock(&object->lock);
96111

97-
return vfs_llseek(file, pos, whence);
112+
ret = vfs_llseek(file, pos, whence);
113+
fput(file);
114+
115+
return ret;
98116
}
99117

100118
static long cachefiles_ondemand_fd_ioctl(struct file *filp, unsigned int ioctl,

0 commit comments

Comments
 (0)