Commit c31894c7 authored by Zizhi Wo's avatar Zizhi Wo
Browse files

cachefiles: Fix NULL pointer dereference in object->file

mainline inclusion
from mainline-v6.13-rc1
commit 31ad74b20227ce6b40910ff78b1c604e42975cf1
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IB5UKT

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31ad74b20227ce6b40910ff78b1c604e42975cf1



--------------------------------

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: c8383054 ("cachefiles: notify the user daemon when looking up cookie")
Conflicts:
	fs/cachefiles/ondemand.c
[Context conflict for __cachefiles_prepare_write parameters, not related to
this patch.]
Signed-off-by: default avatarZizhi Wo <wozizhi@huawei.com>
Link: https://lore.kernel.org/r/20241107110649.3980193-5-wozizhi@huawei.com


Reviewed-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 5602ffe8
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -337,6 +337,8 @@ static void cachefiles_commit_object(struct cachefiles_object *object,
static void cachefiles_clean_up_object(struct cachefiles_object *object,
				       struct cachefiles_cache *cache)
{
	struct file *file;

	if (test_bit(FSCACHE_COOKIE_RETIRED, &object->cookie->flags)) {
		if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
			cachefiles_see_object(object, cachefiles_obj_see_clean_delete);
@@ -352,10 +354,14 @@ static void cachefiles_clean_up_object(struct cachefiles_object *object,
	}

	cachefiles_unmark_inode_in_use(object, object->file);
	if (object->file) {
		fput(object->file);

	spin_lock(&object->lock);
	file = object->file;
	object->file = NULL;
	}
	spin_unlock(&object->lock);

	if (file)
		fput(file);
}

/*
+24 −7
Original line number Diff line number Diff line
@@ -61,26 +61,33 @@ static ssize_t cachefiles_ondemand_fd_write_iter(struct kiocb *kiocb,
{
	struct cachefiles_object *object = kiocb->ki_filp->private_data;
	struct cachefiles_cache *cache = object->volume->cache;
	struct file *file = object->file;
	struct file *file;
	size_t len = iter->count;
	loff_t pos = kiocb->ki_pos;
	const struct cred *saved_cred;
	int ret;

	if (!file)
	spin_lock(&object->lock);
	file = object->file;
	if (!file) {
		spin_unlock(&object->lock);
		return -ENOBUFS;
	}
	get_file(file);
	spin_unlock(&object->lock);

	cachefiles_begin_secure(cache, &saved_cred);
	ret = __cachefiles_prepare_write(object, file, &pos, &len, true);
	cachefiles_end_secure(cache, saved_cred);
	if (ret < 0)
		return ret;
		goto out;

	trace_cachefiles_ondemand_fd_write(object, file_inode(file), pos, len);
	ret = __cachefiles_write(object, file, pos, iter, NULL, NULL);
	if (!ret)
		ret = len;

out:
	fput(file);
	return ret;
}

@@ -88,12 +95,22 @@ static loff_t cachefiles_ondemand_fd_llseek(struct file *filp, loff_t pos,
					    int whence)
{
	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;
	}
	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,