mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
A small pile of CephFS and messenger bug fixes, all marked for stable.
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEydHwtzie9C7TfviiSn/eOAIR84sFAmm0YQoTHGlkcnlvbW92 QGdtYWlsLmNvbQAKCRBKf944AhHzi1J3B/wMbep9iQcnasEmsj1FIcTCx777ytsk 9QifY6OeWnJ1rmNlFqshkQOYZO/fNced0zS1uRvVusS+bSwjWAGHV44p/PuhHlXN A7mHf9oN0vh+ET1qgRaPvBdPuIZFLcqffmlzpCLW4fNvCXNqJH+kR237RdPLS557 +g8mMgv2dCa3xBRjIz2QCZaY1ZetMgwpbBSfJHmQ6gLHctc6MQhz42Yr9xb3NCo7 mUDPbuEvyMBgfxzS3HsYDNQ0NIg3RvesTTSzrgYY45ZTl69FCuYf8lGADRap3kvR wDQqwa9J2UefErw4crR4zHmpZIswrt4jyGbYbQp+GWWNX1IAHZLjVE70 =URMd -----END PGP SIGNATURE----- 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:
commit
2c361c9b7f
|
|
@ -21937,7 +21937,7 @@ F: drivers/media/radio/radio-tea5777.c
|
||||||
|
|
||||||
RADOS BLOCK DEVICE (RBD)
|
RADOS BLOCK DEVICE (RBD)
|
||||||
M: Ilya Dryomov <idryomov@gmail.com>
|
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
|
L: ceph-devel@vger.kernel.org
|
||||||
S: Supported
|
S: Supported
|
||||||
W: http://ceph.com/
|
W: http://ceph.com/
|
||||||
|
|
|
||||||
|
|
@ -1326,7 +1326,6 @@ void ceph_process_folio_batch(struct address_space *mapping,
|
||||||
continue;
|
continue;
|
||||||
} else if (rc == -E2BIG) {
|
} else if (rc == -E2BIG) {
|
||||||
folio_unlock(folio);
|
folio_unlock(folio);
|
||||||
ceph_wbc->fbatch.folios[i] = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ static int mdsc_show(struct seq_file *s, void *p)
|
||||||
if (req->r_inode) {
|
if (req->r_inode) {
|
||||||
seq_printf(s, " #%llx", ceph_ino(req->r_inode));
|
seq_printf(s, " #%llx", ceph_ino(req->r_inode));
|
||||||
} else if (req->r_dentry) {
|
} 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);
|
path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0);
|
||||||
if (IS_ERR(path))
|
if (IS_ERR(path))
|
||||||
path = NULL;
|
path = NULL;
|
||||||
|
|
@ -98,7 +98,7 @@ static int mdsc_show(struct seq_file *s, void *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->r_old_dentry) {
|
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);
|
path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &path_info, 0);
|
||||||
if (IS_ERR(path))
|
if (IS_ERR(path))
|
||||||
path = NULL;
|
path = NULL;
|
||||||
|
|
|
||||||
|
|
@ -1339,6 +1339,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
struct ceph_client *cl = fsc->client;
|
struct ceph_client *cl = fsc->client;
|
||||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||||
struct inode *inode = d_inode(dentry);
|
struct inode *inode = d_inode(dentry);
|
||||||
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||||
struct ceph_mds_request *req;
|
struct ceph_mds_request *req;
|
||||||
bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
|
bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
|
||||||
struct dentry *dn;
|
struct dentry *dn;
|
||||||
|
|
@ -1363,7 +1364,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
if (!dn) {
|
if (!dn) {
|
||||||
try_async = false;
|
try_async = false;
|
||||||
} else {
|
} else {
|
||||||
struct ceph_path_info path_info;
|
struct ceph_path_info path_info = {0};
|
||||||
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
|
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
|
||||||
if (IS_ERR(path)) {
|
if (IS_ERR(path)) {
|
||||||
try_async = false;
|
try_async = false;
|
||||||
|
|
@ -1424,7 +1425,19 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
* We have enough caps, so we assume that the unlink
|
* We have enough caps, so we assume that the unlink
|
||||||
* will succeed. Fix up the target inode and dcache.
|
* 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);
|
d_delete(dentry);
|
||||||
} else {
|
} else {
|
||||||
spin_lock(&fsc->async_unlink_conflict_lock);
|
spin_lock(&fsc->async_unlink_conflict_lock);
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,7 @@ int ceph_open(struct inode *inode, struct file *file)
|
||||||
if (!dentry) {
|
if (!dentry) {
|
||||||
do_sync = true;
|
do_sync = true;
|
||||||
} else {
|
} else {
|
||||||
struct ceph_path_info path_info;
|
struct ceph_path_info path_info = {0};
|
||||||
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
|
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
|
||||||
if (IS_ERR(path)) {
|
if (IS_ERR(path)) {
|
||||||
do_sync = true;
|
do_sync = true;
|
||||||
|
|
@ -807,7 +807,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
|
||||||
if (!dn) {
|
if (!dn) {
|
||||||
try_async = false;
|
try_async = false;
|
||||||
} else {
|
} else {
|
||||||
struct ceph_path_info path_info;
|
struct ceph_path_info path_info = {0};
|
||||||
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
|
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
|
||||||
if (IS_ERR(path)) {
|
if (IS_ERR(path)) {
|
||||||
try_async = false;
|
try_async = false;
|
||||||
|
|
|
||||||
|
|
@ -2551,7 +2551,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
|
||||||
if (!dentry) {
|
if (!dentry) {
|
||||||
do_sync = true;
|
do_sync = true;
|
||||||
} else {
|
} else {
|
||||||
struct ceph_path_info path_info;
|
struct ceph_path_info path_info = {0};
|
||||||
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
|
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
|
||||||
if (IS_ERR(path)) {
|
if (IS_ERR(path)) {
|
||||||
do_sync = true;
|
do_sync = true;
|
||||||
|
|
|
||||||
|
|
@ -2768,6 +2768,7 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dput(parent);
|
dput(parent);
|
||||||
dput(cur);
|
dput(cur);
|
||||||
|
__putname(path);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2777,6 +2778,7 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
dput(parent);
|
dput(parent);
|
||||||
dput(cur);
|
dput(cur);
|
||||||
|
__putname(path);
|
||||||
return ERR_PTR(len);
|
return ERR_PTR(len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2813,6 +2815,7 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
|
||||||
* cannot ever succeed. Creating paths that long is
|
* cannot ever succeed. Creating paths that long is
|
||||||
* possible with Ceph, but Linux cannot use them.
|
* possible with Ceph, but Linux cannot use them.
|
||||||
*/
|
*/
|
||||||
|
__putname(path);
|
||||||
return ERR_PTR(-ENAMETOOLONG);
|
return ERR_PTR(-ENAMETOOLONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -205,9 +205,9 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
|
||||||
s32 result;
|
s32 result;
|
||||||
u64 global_id;
|
u64 global_id;
|
||||||
void *payload, *payload_end;
|
void *payload, *payload_end;
|
||||||
int payload_len;
|
u32 payload_len;
|
||||||
char *result_msg;
|
char *result_msg;
|
||||||
int result_msg_len;
|
u32 result_msg_len;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&ac->mutex);
|
mutex_lock(&ac->mutex);
|
||||||
|
|
@ -217,10 +217,12 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
|
||||||
result = ceph_decode_32(&p);
|
result = ceph_decode_32(&p);
|
||||||
global_id = ceph_decode_64(&p);
|
global_id = ceph_decode_64(&p);
|
||||||
payload_len = ceph_decode_32(&p);
|
payload_len = ceph_decode_32(&p);
|
||||||
|
ceph_decode_need(&p, end, payload_len, bad);
|
||||||
payload = p;
|
payload = p;
|
||||||
p += payload_len;
|
p += payload_len;
|
||||||
ceph_decode_need(&p, end, sizeof(u32), bad);
|
ceph_decode_need(&p, end, sizeof(u32), bad);
|
||||||
result_msg_len = ceph_decode_32(&p);
|
result_msg_len = ceph_decode_32(&p);
|
||||||
|
ceph_decode_need(&p, end, result_msg_len, bad);
|
||||||
result_msg = p;
|
result_msg = p;
|
||||||
p += result_msg_len;
|
p += result_msg_len;
|
||||||
if (p != end)
|
if (p != end)
|
||||||
|
|
|
||||||
|
|
@ -392,7 +392,7 @@ static int head_onwire_len(int ctrl_len, bool secure)
|
||||||
int head_len;
|
int head_len;
|
||||||
int rem_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) {
|
if (secure) {
|
||||||
head_len = CEPH_PREAMBLE_SECURE_LEN;
|
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;
|
head_len += padded_len(rem_len) + CEPH_GCM_TAG_LEN;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
head_len = CEPH_PREAMBLE_PLAIN_LEN;
|
head_len = CEPH_PREAMBLE_PLAIN_LEN + ctrl_len + CEPH_CRC_LEN;
|
||||||
if (ctrl_len)
|
|
||||||
head_len += ctrl_len + CEPH_CRC_LEN;
|
|
||||||
}
|
}
|
||||||
return head_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);
|
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) {
|
desc->fd_lens[0] > CEPH_MSG_MAX_CONTROL_LEN) {
|
||||||
pr_err("bad control segment length %d\n", desc->fd_lens[0]);
|
pr_err("bad control segment length %d\n", desc->fd_lens[0]);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc->fd_lens[1] < 0 ||
|
if (desc->fd_lens[1] < 0 ||
|
||||||
desc->fd_lens[1] > CEPH_MSG_MAX_FRONT_LEN) {
|
desc->fd_lens[1] > CEPH_MSG_MAX_FRONT_LEN) {
|
||||||
pr_err("bad front segment length %d\n", desc->fd_lens[1]);
|
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;
|
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]) {
|
if (!desc->fd_lens[desc->fd_seg_cnt - 1]) {
|
||||||
pr_err("last segment empty, segment count %d\n",
|
pr_err("last segment empty, segment count %d\n",
|
||||||
desc->fd_seg_cnt);
|
desc->fd_seg_cnt);
|
||||||
|
|
@ -2833,12 +2832,15 @@ static int process_message_header(struct ceph_connection *con,
|
||||||
void *p, void *end)
|
void *p, void *end)
|
||||||
{
|
{
|
||||||
struct ceph_frame_desc *desc = &con->v2.in_desc;
|
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;
|
struct ceph_msg_header hdr;
|
||||||
int skip;
|
int skip;
|
||||||
int ret;
|
int ret;
|
||||||
u64 seq;
|
u64 seq;
|
||||||
|
|
||||||
|
ceph_decode_need(&p, end, sizeof(*hdr2), bad);
|
||||||
|
hdr2 = p;
|
||||||
|
|
||||||
/* verify seq# */
|
/* verify seq# */
|
||||||
seq = le64_to_cpu(hdr2->seq);
|
seq = le64_to_cpu(hdr2->seq);
|
||||||
if ((s64)seq - (s64)con->in_seq < 1) {
|
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);
|
||||||
WARN_ON(con->in_msg->con != con);
|
WARN_ON(con->in_msg->con != con);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
pr_err("failed to decode message header\n");
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_message(struct ceph_connection *con)
|
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)
|
if (con->v2.in_desc.fd_tag != FRAME_TAG_MESSAGE)
|
||||||
return process_control(con, p, end);
|
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);
|
ret = process_message_header(con, p, end);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
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_monmap *monmap = NULL;
|
||||||
struct ceph_fsid fsid;
|
struct ceph_fsid fsid;
|
||||||
u32 struct_len;
|
u32 struct_len;
|
||||||
int blob_len;
|
u32 blob_len;
|
||||||
int num_mon;
|
u32 num_mon;
|
||||||
u8 struct_v;
|
u8 struct_v;
|
||||||
u32 epoch;
|
u32 epoch;
|
||||||
int ret;
|
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);
|
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);
|
num_mon);
|
||||||
if (num_mon > CEPH_MAX_MON)
|
if (num_mon > CEPH_MAX_MON)
|
||||||
goto e_inval;
|
goto e_inval;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user