mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-07 18:40:10 +00:00
cachefiles: Fix NULL pointer dereference in object->file
commit31ad74b202upstream. 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:c838305450("cachefiles: notify the user daemon when looking up cookie") Signed-off-by: Zizhi Wo <wozizhi@huawei.com> Link: https://lore.kernel.org/r/20241107110649.3980193-5-wozizhi@huawei.com Reviewed-by: David Howells <dhowells@redhat.com> Signed-off-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Bin Lan <lanbincn@qq.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
893b28374a
commit
785408bbaf
@@ -327,6 +327,8 @@ static void cachefiles_commit_object(struct cachefiles_object *object,
|
|||||||
static void cachefiles_clean_up_object(struct cachefiles_object *object,
|
static void cachefiles_clean_up_object(struct cachefiles_object *object,
|
||||||
struct cachefiles_cache *cache)
|
struct cachefiles_cache *cache)
|
||||||
{
|
{
|
||||||
|
struct file *file;
|
||||||
|
|
||||||
if (test_bit(FSCACHE_COOKIE_RETIRED, &object->cookie->flags)) {
|
if (test_bit(FSCACHE_COOKIE_RETIRED, &object->cookie->flags)) {
|
||||||
if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
|
if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
|
||||||
cachefiles_see_object(object, cachefiles_obj_see_clean_delete);
|
cachefiles_see_object(object, cachefiles_obj_see_clean_delete);
|
||||||
@@ -342,10 +344,14 @@ static void cachefiles_clean_up_object(struct cachefiles_object *object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cachefiles_unmark_inode_in_use(object, object->file);
|
cachefiles_unmark_inode_in_use(object, object->file);
|
||||||
if (object->file) {
|
|
||||||
fput(object->file);
|
spin_lock(&object->lock);
|
||||||
|
file = object->file;
|
||||||
object->file = NULL;
|
object->file = NULL;
|
||||||
}
|
spin_unlock(&object->lock);
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
fput(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -61,20 +61,26 @@ static ssize_t cachefiles_ondemand_fd_write_iter(struct kiocb *kiocb,
|
|||||||
{
|
{
|
||||||
struct cachefiles_object *object = kiocb->ki_filp->private_data;
|
struct cachefiles_object *object = kiocb->ki_filp->private_data;
|
||||||
struct cachefiles_cache *cache = object->volume->cache;
|
struct cachefiles_cache *cache = object->volume->cache;
|
||||||
struct file *file = object->file;
|
struct file *file;
|
||||||
size_t len = iter->count;
|
size_t len = iter->count;
|
||||||
loff_t pos = kiocb->ki_pos;
|
loff_t pos = kiocb->ki_pos;
|
||||||
const struct cred *saved_cred;
|
const struct cred *saved_cred;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!file)
|
spin_lock(&object->lock);
|
||||||
|
file = object->file;
|
||||||
|
if (!file) {
|
||||||
|
spin_unlock(&object->lock);
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
get_file(file);
|
||||||
|
spin_unlock(&object->lock);
|
||||||
|
|
||||||
cachefiles_begin_secure(cache, &saved_cred);
|
cachefiles_begin_secure(cache, &saved_cred);
|
||||||
ret = __cachefiles_prepare_write(object, file, &pos, &len, true);
|
ret = __cachefiles_prepare_write(object, file, &pos, &len, true);
|
||||||
cachefiles_end_secure(cache, saved_cred);
|
cachefiles_end_secure(cache, saved_cred);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
trace_cachefiles_ondemand_fd_write(object, file_inode(file), pos, len);
|
trace_cachefiles_ondemand_fd_write(object, file_inode(file), pos, len);
|
||||||
ret = __cachefiles_write(object, file, pos, iter, NULL, NULL);
|
ret = __cachefiles_write(object, file, pos, iter, NULL, NULL);
|
||||||
@@ -83,6 +89,8 @@ static ssize_t cachefiles_ondemand_fd_write_iter(struct kiocb *kiocb,
|
|||||||
kiocb->ki_pos += ret;
|
kiocb->ki_pos += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
fput(file);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,12 +98,22 @@ static loff_t cachefiles_ondemand_fd_llseek(struct file *filp, loff_t pos,
|
|||||||
int whence)
|
int whence)
|
||||||
{
|
{
|
||||||
struct cachefiles_object *object = filp->private_data;
|
struct cachefiles_object *object = filp->private_data;
|
||||||
struct file *file = object->file;
|
struct file *file;
|
||||||
|
loff_t ret;
|
||||||
|
|
||||||
if (!file)
|
spin_lock(&object->lock);
|
||||||
|
file = object->file;
|
||||||
|
if (!file) {
|
||||||
|
spin_unlock(&object->lock);
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
get_file(file);
|
||||||
|
spin_unlock(&object->lock);
|
||||||
|
|
||||||
return vfs_llseek(file, pos, whence);
|
ret = vfs_llseek(file, pos, whence);
|
||||||
|
fput(file);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long cachefiles_ondemand_fd_ioctl(struct file *filp, unsigned int ioctl,
|
static long cachefiles_ondemand_fd_ioctl(struct file *filp, unsigned int ioctl,
|
||||||
|
|||||||
Reference in New Issue
Block a user