7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Yuanfu Xie [ Upstream commit ec8d583469ed64b4973192a21b5a41c33219721f ] ceph_mdsc_wait_request() returns the reply head result code of the MDS request to its callers as a plain int errno. The value is a server-controlled u32 and nothing checks that it actually is an errno; several callers pass it straight to ERR_PTR(), e.g. ceph_finish_lookup() on the atomic open path: err = ceph_mdsc_wait_request(...) /* e.g. +0x50fc00 */ ... if (err) dentry = ERR_PTR(err); IS_ERR() only recognizes the [-MAX_ERRNO, -1] window, so an out-of-range value is not caught anywhere and survives as a "struct dentry *". On the open path the positive error travels ceph_finish_lookup() -> ceph_atomic_open() -> ERR_PTR() in fs/namei.c's atomic_open() wrapper -> step_into(), which dereferences it as a dentry and oopses (mainline 7.3-rc3-135-g4982d3552a3b, the value in R12 is the server-supplied result): BUG: KASAN: probably user-memory-access in range [0x000000000050fc00-0x000000000050fc07] RIP: 0010:step_into_slowpath+0x3e3/0xe60 R12: 000000000050fc00 Call Trace: ? __pfx_ceph_atomic_open+0x10/0x10 path_openat+0xf41/0x2440 do_file_open+0x228/0x480 do_sys_openat2+0x103/0x1d0 __x64_sys_openat+0x141/0x200 do_syscall_64+0xe8/0x4f0 entry_SYSCALL_64_after_hwframe+0x77/0x79 (0xdffffc00000a1f80 in the full report is the KASAN shadow of 0x50fc00; without KASAN the raw value is read.) Values with the top bit set fare no better: 0xd8000000 sign-extends through the int conversion into the kernel address range and takes a page fault instead. Clamp the result at the single read and return -EIO for anything outside the errno range, which is what a malformed reply means there. net/9p does the same to server errno values with safe_errno(). This is the path the reported crash takes; the other readers of head->result, including the ceph_async_create_cb() and ceph_async_unlink_cb() callbacks, are not covered by this patch. Each of the six crashing opens was run on a build of 7.3-rc3-135-g4982d3552a3bf with only this change applied: it crashes the unpatched kernel on the first openat() (verified on the same tree without the patch), and with the patch the open fails cleanly without an oops. A few hundred normal file operations on the patched kernel also completed without a crash; valid errno values pass through unchanged. Cc: stable@vger.kernel.org Fixes: 2f2dc053404febedc9c273452d9d518fb31fde72 ("ceph: MDS client") Signed-off-by: Yuanfu Xie Reviewed-by: Alex Markuze Signed-off-by: Ilya Dryomov Signed-off-by: Sasha Levin --- fs/ceph/mds_client.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d370c43cf02f5..b354c3296de36 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3987,6 +3987,14 @@ int ceph_mdsc_wait_request(struct ceph_mds_client *mdsc, /* only abort if we didn't race with a real reply */ if (test_bit(CEPH_MDS_R_GOT_RESULT, &req->r_req_flags)) { err = le32_to_cpu(req->r_reply_info.head->result); + if (err > 0 || err < -MAX_ERRNO) { + /* + * The result is server-controlled. Values outside + * the errno range are turned into bogus pointers by + * the ERR_PTR() users among the callers. + */ + err = -EIO; + } } else if (err < 0) { doutc(cl, "aborted request %lld with %d\n", req->r_tid, err); -- 2.53.0