Merge tag 'ceph-for-6.18-rc8' of https://github.com/ceph/ceph-client

Pull ceph fixes from Ilya Dryomov:
 "A patch to make sparse read handling work in msgr2 secure mode from
  Slava and a couple of fixes from Ziming and myself to avoid operating
  on potentially invalid memory, all marked for stable"

* tag 'ceph-for-6.18-rc8' of https://github.com/ceph/ceph-client:
  libceph: prevent potential out-of-bounds writes in handle_auth_session_key()
  libceph: replace BUG_ON with bounds check for map->max_osd
  ceph: fix crash in process_v2_sparse_read() for encrypted directories
  libceph: drop started parameter of __ceph_open_session()
  libceph: fix potential use-after-free in have_mon_and_osd_map()
This commit is contained in:
Linus Torvalds
2025-11-27 11:11:03 -08:00
7 changed files with 67 additions and 43 deletions

View File

@@ -1149,7 +1149,7 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
const char *path = fsc->mount_options->server_path ? const char *path = fsc->mount_options->server_path ?
fsc->mount_options->server_path + 1 : ""; fsc->mount_options->server_path + 1 : "";
err = __ceph_open_session(fsc->client, started); err = __ceph_open_session(fsc->client);
if (err < 0) if (err < 0)
goto out; goto out;

View File

@@ -306,8 +306,7 @@ struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client);
u64 ceph_client_gid(struct ceph_client *client); u64 ceph_client_gid(struct ceph_client *client);
extern void ceph_destroy_client(struct ceph_client *client); extern void ceph_destroy_client(struct ceph_client *client);
extern void ceph_reset_client_addr(struct ceph_client *client); extern void ceph_reset_client_addr(struct ceph_client *client);
extern int __ceph_open_session(struct ceph_client *client, extern int __ceph_open_session(struct ceph_client *client);
unsigned long started);
extern int ceph_open_session(struct ceph_client *client); extern int ceph_open_session(struct ceph_client *client);
int ceph_wait_for_latest_osdmap(struct ceph_client *client, int ceph_wait_for_latest_osdmap(struct ceph_client *client,
unsigned long timeout); unsigned long timeout);

View File

@@ -631,6 +631,7 @@ static int handle_auth_session_key(struct ceph_auth_client *ac, u64 global_id,
/* connection secret */ /* connection secret */
ceph_decode_32_safe(p, end, len, e_inval); ceph_decode_32_safe(p, end, len, e_inval);
ceph_decode_need(p, end, len, e_inval);
dout("%s connection secret blob len %d\n", __func__, len); dout("%s connection secret blob len %d\n", __func__, len);
if (len > 0) { if (len > 0) {
dp = *p + ceph_x_encrypt_offset(); dp = *p + ceph_x_encrypt_offset();
@@ -648,6 +649,7 @@ static int handle_auth_session_key(struct ceph_auth_client *ac, u64 global_id,
/* service tickets */ /* service tickets */
ceph_decode_32_safe(p, end, len, e_inval); ceph_decode_32_safe(p, end, len, e_inval);
ceph_decode_need(p, end, len, e_inval);
dout("%s service tickets blob len %d\n", __func__, len); dout("%s service tickets blob len %d\n", __func__, len);
if (len > 0) { if (len > 0) {
ret = ceph_x_proc_ticket_reply(ac, &th->session_key, ret = ceph_x_proc_ticket_reply(ac, &th->session_key,

View File

@@ -785,42 +785,53 @@ void ceph_reset_client_addr(struct ceph_client *client)
} }
EXPORT_SYMBOL(ceph_reset_client_addr); EXPORT_SYMBOL(ceph_reset_client_addr);
/*
* true if we have the mon map (and have thus joined the cluster)
*/
static bool have_mon_and_osd_map(struct ceph_client *client)
{
return client->monc.monmap && client->monc.monmap->epoch &&
client->osdc.osdmap && client->osdc.osdmap->epoch;
}
/* /*
* mount: join the ceph cluster, and open root directory. * mount: join the ceph cluster, and open root directory.
*/ */
int __ceph_open_session(struct ceph_client *client, unsigned long started) int __ceph_open_session(struct ceph_client *client)
{ {
unsigned long timeout = client->options->mount_timeout; DEFINE_WAIT_FUNC(wait, woken_wake_function);
long err; long timeout = ceph_timeout_jiffies(client->options->mount_timeout);
bool have_monmap, have_osdmap;
int err;
/* open session, and wait for mon and osd maps */ /* open session, and wait for mon and osd maps */
err = ceph_monc_open_session(&client->monc); err = ceph_monc_open_session(&client->monc);
if (err < 0) if (err < 0)
return err; return err;
while (!have_mon_and_osd_map(client)) { add_wait_queue(&client->auth_wq, &wait);
if (timeout && time_after_eq(jiffies, started + timeout)) for (;;) {
return -ETIMEDOUT; mutex_lock(&client->monc.mutex);
err = client->auth_err;
have_monmap = client->monc.monmap && client->monc.monmap->epoch;
mutex_unlock(&client->monc.mutex);
down_read(&client->osdc.lock);
have_osdmap = client->osdc.osdmap && client->osdc.osdmap->epoch;
up_read(&client->osdc.lock);
if (err || (have_monmap && have_osdmap))
break;
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
if (!timeout) {
err = -ETIMEDOUT;
break;
}
/* wait */ /* wait */
dout("mount waiting for mon_map\n"); dout("mount waiting for mon_map\n");
err = wait_event_interruptible_timeout(client->auth_wq, timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, timeout);
have_mon_and_osd_map(client) || (client->auth_err < 0),
ceph_timeout_jiffies(timeout));
if (err < 0)
return err;
if (client->auth_err < 0)
return client->auth_err;
} }
remove_wait_queue(&client->auth_wq, &wait);
if (err)
return err;
pr_info("client%llu fsid %pU\n", ceph_client_gid(client), pr_info("client%llu fsid %pU\n", ceph_client_gid(client),
&client->fsid); &client->fsid);
@@ -833,12 +844,11 @@ EXPORT_SYMBOL(__ceph_open_session);
int ceph_open_session(struct ceph_client *client) int ceph_open_session(struct ceph_client *client)
{ {
int ret; int ret;
unsigned long started = jiffies; /* note the start time */
dout("open_session start\n"); dout("open_session start\n");
mutex_lock(&client->mount_mutex); mutex_lock(&client->mount_mutex);
ret = __ceph_open_session(client, started); ret = __ceph_open_session(client);
mutex_unlock(&client->mount_mutex); mutex_unlock(&client->mount_mutex);
return ret; return ret;

View File

@@ -36,8 +36,9 @@ static int monmap_show(struct seq_file *s, void *p)
int i; int i;
struct ceph_client *client = s->private; struct ceph_client *client = s->private;
mutex_lock(&client->monc.mutex);
if (client->monc.monmap == NULL) if (client->monc.monmap == NULL)
return 0; goto out_unlock;
seq_printf(s, "epoch %d\n", client->monc.monmap->epoch); seq_printf(s, "epoch %d\n", client->monc.monmap->epoch);
for (i = 0; i < client->monc.monmap->num_mon; i++) { for (i = 0; i < client->monc.monmap->num_mon; i++) {
@@ -48,6 +49,9 @@ static int monmap_show(struct seq_file *s, void *p)
ENTITY_NAME(inst->name), ENTITY_NAME(inst->name),
ceph_pr_addr(&inst->addr)); ceph_pr_addr(&inst->addr));
} }
out_unlock:
mutex_unlock(&client->monc.mutex);
return 0; return 0;
} }
@@ -56,13 +60,14 @@ static int osdmap_show(struct seq_file *s, void *p)
int i; int i;
struct ceph_client *client = s->private; struct ceph_client *client = s->private;
struct ceph_osd_client *osdc = &client->osdc; struct ceph_osd_client *osdc = &client->osdc;
struct ceph_osdmap *map = osdc->osdmap; struct ceph_osdmap *map;
struct rb_node *n; struct rb_node *n;
if (map == NULL)
return 0;
down_read(&osdc->lock); down_read(&osdc->lock);
map = osdc->osdmap;
if (map == NULL)
goto out_unlock;
seq_printf(s, "epoch %u barrier %u flags 0x%x\n", map->epoch, seq_printf(s, "epoch %u barrier %u flags 0x%x\n", map->epoch,
osdc->epoch_barrier, map->flags); osdc->epoch_barrier, map->flags);
@@ -131,6 +136,7 @@ static int osdmap_show(struct seq_file *s, void *p)
seq_printf(s, "]\n"); seq_printf(s, "]\n");
} }
out_unlock:
up_read(&osdc->lock); up_read(&osdc->lock);
return 0; return 0;
} }

View File

@@ -1061,13 +1061,16 @@ static int decrypt_control_remainder(struct ceph_connection *con)
static int process_v2_sparse_read(struct ceph_connection *con, static int process_v2_sparse_read(struct ceph_connection *con,
struct page **pages, int spos) struct page **pages, int spos)
{ {
struct ceph_msg_data_cursor *cursor = &con->v2.in_cursor; struct ceph_msg_data_cursor cursor;
int ret; int ret;
ceph_msg_data_cursor_init(&cursor, con->in_msg,
con->in_msg->sparse_read_total);
for (;;) { for (;;) {
char *buf = NULL; char *buf = NULL;
ret = con->ops->sparse_read(con, cursor, &buf); ret = con->ops->sparse_read(con, &cursor, &buf);
if (ret <= 0) if (ret <= 0)
return ret; return ret;
@@ -1085,11 +1088,11 @@ static int process_v2_sparse_read(struct ceph_connection *con,
} else { } else {
struct bio_vec bv; struct bio_vec bv;
get_bvec_at(cursor, &bv); get_bvec_at(&cursor, &bv);
len = min_t(int, len, bv.bv_len); len = min_t(int, len, bv.bv_len);
memcpy_page(bv.bv_page, bv.bv_offset, memcpy_page(bv.bv_page, bv.bv_offset,
spage, soff, len); spage, soff, len);
ceph_msg_data_advance(cursor, len); ceph_msg_data_advance(&cursor, len);
} }
spos += len; spos += len;
ret -= len; ret -= len;

View File

@@ -1504,8 +1504,6 @@ static int decode_new_primary_temp(void **p, void *end,
u32 ceph_get_primary_affinity(struct ceph_osdmap *map, int osd) u32 ceph_get_primary_affinity(struct ceph_osdmap *map, int osd)
{ {
BUG_ON(osd >= map->max_osd);
if (!map->osd_primary_affinity) if (!map->osd_primary_affinity)
return CEPH_OSD_DEFAULT_PRIMARY_AFFINITY; return CEPH_OSD_DEFAULT_PRIMARY_AFFINITY;
@@ -1514,8 +1512,6 @@ u32 ceph_get_primary_affinity(struct ceph_osdmap *map, int osd)
static int set_primary_affinity(struct ceph_osdmap *map, int osd, u32 aff) static int set_primary_affinity(struct ceph_osdmap *map, int osd, u32 aff)
{ {
BUG_ON(osd >= map->max_osd);
if (!map->osd_primary_affinity) { if (!map->osd_primary_affinity) {
int i; int i;
@@ -1577,6 +1573,8 @@ static int decode_new_primary_affinity(void **p, void *end,
ceph_decode_32_safe(p, end, osd, e_inval); ceph_decode_32_safe(p, end, osd, e_inval);
ceph_decode_32_safe(p, end, aff, e_inval); ceph_decode_32_safe(p, end, aff, e_inval);
if (osd >= map->max_osd)
goto e_inval;
ret = set_primary_affinity(map, osd, aff); ret = set_primary_affinity(map, osd, aff);
if (ret) if (ret)
@@ -1879,7 +1877,9 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
ceph_decode_need(p, end, 2*sizeof(u32), e_inval); ceph_decode_need(p, end, 2*sizeof(u32), e_inval);
osd = ceph_decode_32(p); osd = ceph_decode_32(p);
w = ceph_decode_32(p); w = ceph_decode_32(p);
BUG_ON(osd >= map->max_osd); if (osd >= map->max_osd)
goto e_inval;
osdmap_info(map, "osd%d weight 0x%x %s\n", osd, w, osdmap_info(map, "osd%d weight 0x%x %s\n", osd, w,
w == CEPH_OSD_IN ? "(in)" : w == CEPH_OSD_IN ? "(in)" :
(w == CEPH_OSD_OUT ? "(out)" : "")); (w == CEPH_OSD_OUT ? "(out)" : ""));
@@ -1905,13 +1905,15 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
u32 xorstate; u32 xorstate;
osd = ceph_decode_32(p); osd = ceph_decode_32(p);
if (osd >= map->max_osd)
goto e_inval;
if (struct_v >= 5) if (struct_v >= 5)
xorstate = ceph_decode_32(p); xorstate = ceph_decode_32(p);
else else
xorstate = ceph_decode_8(p); xorstate = ceph_decode_8(p);
if (xorstate == 0) if (xorstate == 0)
xorstate = CEPH_OSD_UP; xorstate = CEPH_OSD_UP;
BUG_ON(osd >= map->max_osd);
if ((map->osd_state[osd] & CEPH_OSD_UP) && if ((map->osd_state[osd] & CEPH_OSD_UP) &&
(xorstate & CEPH_OSD_UP)) (xorstate & CEPH_OSD_UP))
osdmap_info(map, "osd%d down\n", osd); osdmap_info(map, "osd%d down\n", osd);
@@ -1937,7 +1939,9 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
struct ceph_entity_addr addr; struct ceph_entity_addr addr;
osd = ceph_decode_32(p); osd = ceph_decode_32(p);
BUG_ON(osd >= map->max_osd); if (osd >= map->max_osd)
goto e_inval;
if (struct_v >= 7) if (struct_v >= 7)
ret = ceph_decode_entity_addrvec(p, end, msgr2, &addr); ret = ceph_decode_entity_addrvec(p, end, msgr2, &addr);
else else