Skip to content

Commit 2c361c9

Browse files
committed
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
2 parents 399af66 + b282c43 commit 2c361c9

10 files changed

Lines changed: 52 additions & 24 deletions

File tree

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21937,7 +21937,7 @@ F: drivers/media/radio/radio-tea5777.c
2193721937

2193821938
RADOS BLOCK DEVICE (RBD)
2193921939
M: Ilya Dryomov <idryomov@gmail.com>
21940-
R: Dongsheng Yang <dongsheng.yang@easystack.cn>
21940+
R: Dongsheng Yang <dongsheng.yang@linux.dev>
2194121941
L: ceph-devel@vger.kernel.org
2194221942
S: Supported
2194321943
W: http://ceph.com/

fs/ceph/addr.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,6 @@ void ceph_process_folio_batch(struct address_space *mapping,
13261326
continue;
13271327
} else if (rc == -E2BIG) {
13281328
folio_unlock(folio);
1329-
ceph_wbc->fbatch.folios[i] = NULL;
13301329
break;
13311330
}
13321331

fs/ceph/debugfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ static int mdsc_show(struct seq_file *s, void *p)
7979
if (req->r_inode) {
8080
seq_printf(s, " #%llx", ceph_ino(req->r_inode));
8181
} else if (req->r_dentry) {
82-
struct ceph_path_info path_info;
82+
struct ceph_path_info path_info = {0};
8383
path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0);
8484
if (IS_ERR(path))
8585
path = NULL;
@@ -98,7 +98,7 @@ static int mdsc_show(struct seq_file *s, void *p)
9898
}
9999

100100
if (req->r_old_dentry) {
101-
struct ceph_path_info path_info;
101+
struct ceph_path_info path_info = {0};
102102
path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &path_info, 0);
103103
if (IS_ERR(path))
104104
path = NULL;

fs/ceph/dir.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
13391339
struct ceph_client *cl = fsc->client;
13401340
struct ceph_mds_client *mdsc = fsc->mdsc;
13411341
struct inode *inode = d_inode(dentry);
1342+
struct ceph_inode_info *ci = ceph_inode(inode);
13421343
struct ceph_mds_request *req;
13431344
bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
13441345
struct dentry *dn;
@@ -1363,7 +1364,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
13631364
if (!dn) {
13641365
try_async = false;
13651366
} else {
1366-
struct ceph_path_info path_info;
1367+
struct ceph_path_info path_info = {0};
13671368
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
13681369
if (IS_ERR(path)) {
13691370
try_async = false;
@@ -1424,7 +1425,19 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
14241425
* We have enough caps, so we assume that the unlink
14251426
* will succeed. Fix up the target inode and dcache.
14261427
*/
1427-
drop_nlink(inode);
1428+
1429+
/*
1430+
* Protect the i_nlink update with i_ceph_lock
1431+
* to precent racing against ceph_fill_inode()
1432+
* handling our completion on a worker thread
1433+
* and don't decrement if i_nlink has already
1434+
* been updated to zero by this completion.
1435+
*/
1436+
spin_lock(&ci->i_ceph_lock);
1437+
if (inode->i_nlink > 0)
1438+
drop_nlink(inode);
1439+
spin_unlock(&ci->i_ceph_lock);
1440+
14281441
d_delete(dentry);
14291442
} else {
14301443
spin_lock(&fsc->async_unlink_conflict_lock);

fs/ceph/file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ int ceph_open(struct inode *inode, struct file *file)
397397
if (!dentry) {
398398
do_sync = true;
399399
} else {
400-
struct ceph_path_info path_info;
400+
struct ceph_path_info path_info = {0};
401401
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
402402
if (IS_ERR(path)) {
403403
do_sync = true;
@@ -807,7 +807,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
807807
if (!dn) {
808808
try_async = false;
809809
} else {
810-
struct ceph_path_info path_info;
810+
struct ceph_path_info path_info = {0};
811811
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
812812
if (IS_ERR(path)) {
813813
try_async = false;

fs/ceph/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2551,7 +2551,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
25512551
if (!dentry) {
25522552
do_sync = true;
25532553
} else {
2554-
struct ceph_path_info path_info;
2554+
struct ceph_path_info path_info = {0};
25552555
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
25562556
if (IS_ERR(path)) {
25572557
do_sync = true;

fs/ceph/mds_client.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2768,6 +2768,7 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
27682768
if (ret < 0) {
27692769
dput(parent);
27702770
dput(cur);
2771+
__putname(path);
27712772
return ERR_PTR(ret);
27722773
}
27732774

@@ -2777,6 +2778,7 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
27772778
if (len < 0) {
27782779
dput(parent);
27792780
dput(cur);
2781+
__putname(path);
27802782
return ERR_PTR(len);
27812783
}
27822784
}
@@ -2813,6 +2815,7 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
28132815
* cannot ever succeed. Creating paths that long is
28142816
* possible with Ceph, but Linux cannot use them.
28152817
*/
2818+
__putname(path);
28162819
return ERR_PTR(-ENAMETOOLONG);
28172820
}
28182821

net/ceph/auth.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
205205
s32 result;
206206
u64 global_id;
207207
void *payload, *payload_end;
208-
int payload_len;
208+
u32 payload_len;
209209
char *result_msg;
210-
int result_msg_len;
210+
u32 result_msg_len;
211211
int ret = -EINVAL;
212212

213213
mutex_lock(&ac->mutex);
@@ -217,10 +217,12 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
217217
result = ceph_decode_32(&p);
218218
global_id = ceph_decode_64(&p);
219219
payload_len = ceph_decode_32(&p);
220+
ceph_decode_need(&p, end, payload_len, bad);
220221
payload = p;
221222
p += payload_len;
222223
ceph_decode_need(&p, end, sizeof(u32), bad);
223224
result_msg_len = ceph_decode_32(&p);
225+
ceph_decode_need(&p, end, result_msg_len, bad);
224226
result_msg = p;
225227
p += result_msg_len;
226228
if (p != end)

net/ceph/messenger_v2.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ static int head_onwire_len(int ctrl_len, bool secure)
392392
int head_len;
393393
int rem_len;
394394

395-
BUG_ON(ctrl_len < 0 || ctrl_len > CEPH_MSG_MAX_CONTROL_LEN);
395+
BUG_ON(ctrl_len < 1 || ctrl_len > CEPH_MSG_MAX_CONTROL_LEN);
396396

397397
if (secure) {
398398
head_len = CEPH_PREAMBLE_SECURE_LEN;
@@ -401,9 +401,7 @@ static int head_onwire_len(int ctrl_len, bool secure)
401401
head_len += padded_len(rem_len) + CEPH_GCM_TAG_LEN;
402402
}
403403
} else {
404-
head_len = CEPH_PREAMBLE_PLAIN_LEN;
405-
if (ctrl_len)
406-
head_len += ctrl_len + CEPH_CRC_LEN;
404+
head_len = CEPH_PREAMBLE_PLAIN_LEN + ctrl_len + CEPH_CRC_LEN;
407405
}
408406
return head_len;
409407
}
@@ -528,11 +526,16 @@ static int decode_preamble(void *p, struct ceph_frame_desc *desc)
528526
desc->fd_aligns[i] = ceph_decode_16(&p);
529527
}
530528

531-
if (desc->fd_lens[0] < 0 ||
529+
/*
530+
* This would fire for FRAME_TAG_WAIT (it has one empty
531+
* segment), but we should never get it as client.
532+
*/
533+
if (desc->fd_lens[0] < 1 ||
532534
desc->fd_lens[0] > CEPH_MSG_MAX_CONTROL_LEN) {
533535
pr_err("bad control segment length %d\n", desc->fd_lens[0]);
534536
return -EINVAL;
535537
}
538+
536539
if (desc->fd_lens[1] < 0 ||
537540
desc->fd_lens[1] > CEPH_MSG_MAX_FRONT_LEN) {
538541
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)
549552
return -EINVAL;
550553
}
551554

552-
/*
553-
* This would fire for FRAME_TAG_WAIT (it has one empty
554-
* segment), but we should never get it as client.
555-
*/
556555
if (!desc->fd_lens[desc->fd_seg_cnt - 1]) {
557556
pr_err("last segment empty, segment count %d\n",
558557
desc->fd_seg_cnt);
@@ -2833,12 +2832,15 @@ static int process_message_header(struct ceph_connection *con,
28332832
void *p, void *end)
28342833
{
28352834
struct ceph_frame_desc *desc = &con->v2.in_desc;
2836-
struct ceph_msg_header2 *hdr2 = p;
2835+
struct ceph_msg_header2 *hdr2;
28372836
struct ceph_msg_header hdr;
28382837
int skip;
28392838
int ret;
28402839
u64 seq;
28412840

2841+
ceph_decode_need(&p, end, sizeof(*hdr2), bad);
2842+
hdr2 = p;
2843+
28422844
/* verify seq# */
28432845
seq = le64_to_cpu(hdr2->seq);
28442846
if ((s64)seq - (s64)con->in_seq < 1) {
@@ -2869,6 +2871,10 @@ static int process_message_header(struct ceph_connection *con,
28692871
WARN_ON(!con->in_msg);
28702872
WARN_ON(con->in_msg->con != con);
28712873
return 1;
2874+
2875+
bad:
2876+
pr_err("failed to decode message header\n");
2877+
return -EINVAL;
28722878
}
28732879

28742880
static int process_message(struct ceph_connection *con)
@@ -2898,6 +2904,11 @@ static int __handle_control(struct ceph_connection *con, void *p)
28982904
if (con->v2.in_desc.fd_tag != FRAME_TAG_MESSAGE)
28992905
return process_control(con, p, end);
29002906

2907+
if (con->state != CEPH_CON_S_OPEN) {
2908+
con->error_msg = "protocol error, unexpected message";
2909+
return -EINVAL;
2910+
}
2911+
29012912
ret = process_message_header(con, p, end);
29022913
if (ret < 0)
29032914
return ret;

net/ceph/mon_client.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ static struct ceph_monmap *ceph_monmap_decode(void **p, void *end, bool msgr2)
7272
struct ceph_monmap *monmap = NULL;
7373
struct ceph_fsid fsid;
7474
u32 struct_len;
75-
int blob_len;
76-
int num_mon;
75+
u32 blob_len;
76+
u32 num_mon;
7777
u8 struct_v;
7878
u32 epoch;
7979
int ret;
@@ -112,7 +112,7 @@ static struct ceph_monmap *ceph_monmap_decode(void **p, void *end, bool msgr2)
112112
}
113113
ceph_decode_32_safe(p, end, num_mon, e_inval);
114114

115-
dout("%s fsid %pU epoch %u num_mon %d\n", __func__, &fsid, epoch,
115+
dout("%s fsid %pU epoch %u num_mon %u\n", __func__, &fsid, epoch,
116116
num_mon);
117117
if (num_mon > CEPH_MAX_MON)
118118
goto e_inval;

0 commit comments

Comments
 (0)