Commit fd4287e8 authored by Rishabh Dave's avatar Rishabh Dave Committed by Long Li
Browse files

ceph: prevent use-after-free in encode_cap_msg()

stable inclusion
from stable-v5.15.148
commit 70e329b440762390258a6fe8c0de93c9fdd56c77
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9E2GN
CVE: CVE-2024-26689

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=tags/v5.15.149&id=70e329b440762390258a6fe8c0de93c9fdd56c77

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

commit cda4672da1c26835dcbd7aec2bfed954eda9b5ef upstream.

In fs/ceph/caps.c, in encode_cap_msg(), "use after free" error was
caught by KASAN at this line - 'ceph_buffer_get(arg->xattr_buf);'. This
implies before the refcount could be increment here, it was freed.

In same file, in "handle_cap_grant()" refcount is decremented by this
line - 'ceph_buffer_put(ci->i_xattrs.blob);'. It appears that a race
occurred and resource was freed by the latter line before the former
line could increment it.

encode_cap_msg() is called by __send_cap() and __send_cap() is called by
ceph_check_caps() after calling __prep_cap(). __prep_cap() is where
arg->xattr_buf is assigned to ci->i_xattrs.blob. This is the spot where
the refcount must be increased to prevent "use after free" error.

Cc: stable@vger.kernel.org
Link: https://tracker.ceph.com/issues/59259


Signed-off-by: default avatarRishabh Dave <ridave@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatarXiubo Li <xiubli@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Conflicts:
	fs/ceph/caps.c
[__send_cap() has been refacaored]
Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent 52349611
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -1347,7 +1347,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
	if (flushing & CEPH_CAP_XATTR_EXCL) {
		old_blob = __ceph_build_xattrs_blob(ci);
		arg.xattr_version = ci->i_xattrs.version;
		arg.xattr_buf = ci->i_xattrs.blob;
		arg.xattr_buf = ceph_buffer_get(ci->i_xattrs.blob);
	} else {
		arg.xattr_buf = NULL;
	}
@@ -1387,6 +1387,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
		dout("error sending cap msg, must requeue %p\n", inode);
		delayed = 1;
	}
	ceph_buffer_put(arg.xattr_buf);

	if (wake)
		wake_up_all(&ci->i_cap_wq);