mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
Merge tag 'ceph-for-7.0-rc4' of https://github.com/ceph/ceph-client
Pull ceph fixes from Ilya Dryomov: "A small pile of CephFS and messenger bug fixes, all marked for stable" * tag 'ceph-for-7.0-rc4' of https://github.com/ceph/ceph-client: libceph: Fix potential out-of-bounds access in ceph_handle_auth_reply() libceph: Use u32 for non-negative values in ceph_monmap_decode() MAINTAINERS: update email address of Dongsheng Yang libceph: reject preamble if control segment is empty libceph: admit message frames only in CEPH_CON_S_OPEN state libceph: prevent potential out-of-bounds reads in process_message_header() ceph: do not skip the first folio of the next object in writeback ceph: fix memory leaks in ceph_mdsc_build_path() ceph: add a bunch of missing ceph_path_info initializers ceph: fix i_nlink underrun during async unlink
This commit is contained in:
@@ -21937,7 +21937,7 @@ F: drivers/media/radio/radio-tea5777.c
|
||||
|
||||
RADOS BLOCK DEVICE (RBD)
|
||||
M: Ilya Dryomov <idryomov@gmail.com>
|
||||
R: Dongsheng Yang <dongsheng.yang@easystack.cn>
|
||||
R: Dongsheng Yang <dongsheng.yang@linux.dev>
|
||||
L: ceph-devel@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://ceph.com/
|
||||
|
||||
@@ -1326,7 +1326,6 @@ void ceph_process_folio_batch(struct address_space *mapping,
|
||||
continue;
|
||||
} else if (rc == -E2BIG) {
|
||||
folio_unlock(folio);
|
||||
ceph_wbc->fbatch.folios[i] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ static int mdsc_show(struct seq_file *s, void *p)
|
||||
if (req->r_inode) {
|
||||
seq_printf(s, " #%llx", ceph_ino(req->r_inode));
|
||||
} else if (req->r_dentry) {
|
||||
struct ceph_path_info path_info;
|
||||
struct ceph_path_info path_info = {0};
|
||||
path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0);
|
||||
if (IS_ERR(path))
|
||||
path = NULL;
|
||||
@@ -98,7 +98,7 @@ static int mdsc_show(struct seq_file *s, void *p)
|
||||
}
|
||||
|
||||
if (req->r_old_dentry) {
|
||||
struct ceph_path_info path_info;
|
||||
struct ceph_path_info path_info = {0};
|
||||
path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &path_info, 0);
|
||||
if (IS_ERR(path))
|
||||
path = NULL;
|
||||
|
||||
@@ -1339,6 +1339,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
|
||||
struct ceph_client *cl = fsc->client;
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_mds_request *req;
|
||||
bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
|
||||
struct dentry *dn;
|
||||
@@ -1363,7 +1364,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
|
||||
if (!dn) {
|
||||
try_async = false;
|
||||
} else {
|
||||
struct ceph_path_info path_info;
|
||||
struct ceph_path_info path_info = {0};
|
||||
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
|
||||
if (IS_ERR(path)) {
|
||||
try_async = false;
|
||||
@@ -1424,7 +1425,19 @@ retry:
|
||||
* We have enough caps, so we assume that the unlink
|
||||
* will succeed. Fix up the target inode and dcache.
|
||||
*/
|
||||
drop_nlink(inode);
|
||||
|
||||
/*
|
||||
* Protect the i_nlink update with i_ceph_lock
|
||||
* to precent racing against ceph_fill_inode()
|
||||
* handling our completion on a worker thread
|
||||
* and don't decrement if i_nlink has already
|
||||
* been updated to zero by this completion.
|
||||
*/
|
||||
spin_lock(&ci->i_ceph_lock);
|
||||
if (inode->i_nlink > 0)
|
||||
drop_nlink(inode);
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
|
||||
d_delete(dentry);
|
||||
} else {
|
||||
spin_lock(&fsc->async_unlink_conflict_lock);
|
||||
|
||||
@@ -397,7 +397,7 @@ int ceph_open(struct inode *inode, struct file *file)
|
||||
if (!dentry) {
|
||||
do_sync = true;
|
||||
} else {
|
||||
struct ceph_path_info path_info;
|
||||
struct ceph_path_info path_info = {0};
|
||||
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
|
||||
if (IS_ERR(path)) {
|
||||
do_sync = true;
|
||||
@@ -807,7 +807,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
|
||||
if (!dn) {
|
||||
try_async = false;
|
||||
} else {
|
||||
struct ceph_path_info path_info;
|
||||
struct ceph_path_info path_info = {0};
|
||||
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
|
||||
if (IS_ERR(path)) {
|
||||
try_async = false;
|
||||
|
||||
@@ -2551,7 +2551,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
|
||||
if (!dentry) {
|
||||
do_sync = true;
|
||||
} else {
|
||||
struct ceph_path_info path_info;
|
||||
struct ceph_path_info path_info = {0};
|
||||
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
|
||||
if (IS_ERR(path)) {
|
||||
do_sync = true;
|
||||
|
||||
@@ -2768,6 +2768,7 @@ retry:
|
||||
if (ret < 0) {
|
||||
dput(parent);
|
||||
dput(cur);
|
||||
__putname(path);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@@ -2777,6 +2778,7 @@ retry:
|
||||
if (len < 0) {
|
||||
dput(parent);
|
||||
dput(cur);
|
||||
__putname(path);
|
||||
return ERR_PTR(len);
|
||||
}
|
||||
}
|
||||
@@ -2813,6 +2815,7 @@ retry:
|
||||
* cannot ever succeed. Creating paths that long is
|
||||
* possible with Ceph, but Linux cannot use them.
|
||||
*/
|
||||
__putname(path);
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
}
|
||||
|
||||
|
||||
@@ -205,9 +205,9 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
|
||||
s32 result;
|
||||
u64 global_id;
|
||||
void *payload, *payload_end;
|
||||
int payload_len;
|
||||
u32 payload_len;
|
||||
char *result_msg;
|
||||
int result_msg_len;
|
||||
u32 result_msg_len;
|
||||
int ret = -EINVAL;
|
||||
|
||||
mutex_lock(&ac->mutex);
|
||||
@@ -217,10 +217,12 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
|
||||
result = ceph_decode_32(&p);
|
||||
global_id = ceph_decode_64(&p);
|
||||
payload_len = ceph_decode_32(&p);
|
||||
ceph_decode_need(&p, end, payload_len, bad);
|
||||
payload = p;
|
||||
p += payload_len;
|
||||
ceph_decode_need(&p, end, sizeof(u32), bad);
|
||||
result_msg_len = ceph_decode_32(&p);
|
||||
ceph_decode_need(&p, end, result_msg_len, bad);
|
||||
result_msg = p;
|
||||
p += result_msg_len;
|
||||
if (p != end)
|
||||
|
||||
@@ -392,7 +392,7 @@ static int head_onwire_len(int ctrl_len, bool secure)
|
||||
int head_len;
|
||||
int rem_len;
|
||||
|
||||
BUG_ON(ctrl_len < 0 || ctrl_len > CEPH_MSG_MAX_CONTROL_LEN);
|
||||
BUG_ON(ctrl_len < 1 || ctrl_len > CEPH_MSG_MAX_CONTROL_LEN);
|
||||
|
||||
if (secure) {
|
||||
head_len = CEPH_PREAMBLE_SECURE_LEN;
|
||||
@@ -401,9 +401,7 @@ static int head_onwire_len(int ctrl_len, bool secure)
|
||||
head_len += padded_len(rem_len) + CEPH_GCM_TAG_LEN;
|
||||
}
|
||||
} else {
|
||||
head_len = CEPH_PREAMBLE_PLAIN_LEN;
|
||||
if (ctrl_len)
|
||||
head_len += ctrl_len + CEPH_CRC_LEN;
|
||||
head_len = CEPH_PREAMBLE_PLAIN_LEN + ctrl_len + CEPH_CRC_LEN;
|
||||
}
|
||||
return head_len;
|
||||
}
|
||||
@@ -528,11 +526,16 @@ static int decode_preamble(void *p, struct ceph_frame_desc *desc)
|
||||
desc->fd_aligns[i] = ceph_decode_16(&p);
|
||||
}
|
||||
|
||||
if (desc->fd_lens[0] < 0 ||
|
||||
/*
|
||||
* This would fire for FRAME_TAG_WAIT (it has one empty
|
||||
* segment), but we should never get it as client.
|
||||
*/
|
||||
if (desc->fd_lens[0] < 1 ||
|
||||
desc->fd_lens[0] > CEPH_MSG_MAX_CONTROL_LEN) {
|
||||
pr_err("bad control segment length %d\n", desc->fd_lens[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (desc->fd_lens[1] < 0 ||
|
||||
desc->fd_lens[1] > CEPH_MSG_MAX_FRONT_LEN) {
|
||||
pr_err("bad front segment length %d\n", desc->fd_lens[1]);
|
||||
@@ -549,10 +552,6 @@ static int decode_preamble(void *p, struct ceph_frame_desc *desc)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This would fire for FRAME_TAG_WAIT (it has one empty
|
||||
* segment), but we should never get it as client.
|
||||
*/
|
||||
if (!desc->fd_lens[desc->fd_seg_cnt - 1]) {
|
||||
pr_err("last segment empty, segment count %d\n",
|
||||
desc->fd_seg_cnt);
|
||||
@@ -2833,12 +2832,15 @@ static int process_message_header(struct ceph_connection *con,
|
||||
void *p, void *end)
|
||||
{
|
||||
struct ceph_frame_desc *desc = &con->v2.in_desc;
|
||||
struct ceph_msg_header2 *hdr2 = p;
|
||||
struct ceph_msg_header2 *hdr2;
|
||||
struct ceph_msg_header hdr;
|
||||
int skip;
|
||||
int ret;
|
||||
u64 seq;
|
||||
|
||||
ceph_decode_need(&p, end, sizeof(*hdr2), bad);
|
||||
hdr2 = p;
|
||||
|
||||
/* verify seq# */
|
||||
seq = le64_to_cpu(hdr2->seq);
|
||||
if ((s64)seq - (s64)con->in_seq < 1) {
|
||||
@@ -2869,6 +2871,10 @@ static int process_message_header(struct ceph_connection *con,
|
||||
WARN_ON(!con->in_msg);
|
||||
WARN_ON(con->in_msg->con != con);
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
pr_err("failed to decode message header\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int process_message(struct ceph_connection *con)
|
||||
@@ -2898,6 +2904,11 @@ static int __handle_control(struct ceph_connection *con, void *p)
|
||||
if (con->v2.in_desc.fd_tag != FRAME_TAG_MESSAGE)
|
||||
return process_control(con, p, end);
|
||||
|
||||
if (con->state != CEPH_CON_S_OPEN) {
|
||||
con->error_msg = "protocol error, unexpected message";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = process_message_header(con, p, end);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -72,8 +72,8 @@ static struct ceph_monmap *ceph_monmap_decode(void **p, void *end, bool msgr2)
|
||||
struct ceph_monmap *monmap = NULL;
|
||||
struct ceph_fsid fsid;
|
||||
u32 struct_len;
|
||||
int blob_len;
|
||||
int num_mon;
|
||||
u32 blob_len;
|
||||
u32 num_mon;
|
||||
u8 struct_v;
|
||||
u32 epoch;
|
||||
int ret;
|
||||
@@ -112,7 +112,7 @@ static struct ceph_monmap *ceph_monmap_decode(void **p, void *end, bool msgr2)
|
||||
}
|
||||
ceph_decode_32_safe(p, end, num_mon, e_inval);
|
||||
|
||||
dout("%s fsid %pU epoch %u num_mon %d\n", __func__, &fsid, epoch,
|
||||
dout("%s fsid %pU epoch %u num_mon %u\n", __func__, &fsid, epoch,
|
||||
num_mon);
|
||||
if (num_mon > CEPH_MAX_MON)
|
||||
goto e_inval;
|
||||
|
||||
Reference in New Issue
Block a user