mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 02:01:18 -04:00
Merge tag 'ceph-for-7.1-rc4' of https://github.com/ceph/ceph-client
Pull ceph fixes from Ilya Dryomov: "An important patch from Hristo that squashes a folio reference leak that could lead to OOM kills in CephFS and a number of miscellaneous fixes from Raphael and Slava. All but two are marked for stable" * tag 'ceph-for-7.1-rc4' of https://github.com/ceph/ceph-client: libceph: Fix potential null-ptr-deref in decode_choose_args() libceph: handle rbtree insertion error in decode_choose_args() libceph: Fix potential out-of-bounds access in osdmap_decode() ceph: put folios not suitable for writeback ceph: add ceph_has_realms_with_quotas() check to ceph_quota_update_statfs() libceph: Fix potential out-of-bounds access in __ceph_x_decrypt() ceph: fix BUG_ON in __ceph_build_xattrs_blob() due to stale blob size ceph: fix a buffer leak in __ceph_setxattr() libceph: Fix unnecessarily high ceph_decode_need() for uniform bucket libceph: Fix potential out-of-bounds access in crush_decode()
This commit is contained in:
@@ -1336,6 +1336,7 @@ void ceph_process_folio_batch(struct address_space *mapping,
|
||||
ceph_wbc, folio);
|
||||
if (rc == -ENODATA) {
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
ceph_wbc->fbatch.folios[i] = NULL;
|
||||
continue;
|
||||
} else if (rc == -E2BIG) {
|
||||
@@ -1346,6 +1347,7 @@ void ceph_process_folio_batch(struct address_space *mapping,
|
||||
if (!folio_clear_dirty_for_io(folio)) {
|
||||
doutc(cl, "%p !folio_clear_dirty_for_io\n", folio);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
ceph_wbc->fbatch.folios[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -228,12 +228,19 @@ static int get_quota_realm(struct ceph_mds_client *mdsc, struct inode *inode,
|
||||
|
||||
restart:
|
||||
realm = ceph_inode(inode)->i_snap_realm;
|
||||
if (realm)
|
||||
if (realm) {
|
||||
ceph_get_snap_realm(mdsc, realm);
|
||||
else
|
||||
pr_err_ratelimited_client(cl,
|
||||
"%p %llx.%llx null i_snap_realm\n",
|
||||
inode, ceph_vinop(inode));
|
||||
} else {
|
||||
/*
|
||||
* i_snap_realm is NULL when all caps have been released, e.g.
|
||||
* after an MDS session rejection. This is a transient state;
|
||||
* the realm will be restored once caps are re-granted.
|
||||
* Treat it as "no quota realm found".
|
||||
*/
|
||||
doutc(cl, "%p %llx.%llx null i_snap_realm\n",
|
||||
inode, ceph_vinop(inode));
|
||||
}
|
||||
|
||||
while (realm) {
|
||||
bool has_inode;
|
||||
|
||||
@@ -340,12 +347,19 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
|
||||
down_read(&mdsc->snap_rwsem);
|
||||
restart:
|
||||
realm = ceph_inode(inode)->i_snap_realm;
|
||||
if (realm)
|
||||
if (realm) {
|
||||
ceph_get_snap_realm(mdsc, realm);
|
||||
else
|
||||
pr_err_ratelimited_client(cl,
|
||||
"%p %llx.%llx null i_snap_realm\n",
|
||||
inode, ceph_vinop(inode));
|
||||
} else {
|
||||
/*
|
||||
* i_snap_realm is NULL when all caps have been released, e.g.
|
||||
* after an MDS session rejection. This is a transient state;
|
||||
* the realm will be restored once caps are re-granted.
|
||||
* Treat it as "quota not exceeded".
|
||||
*/
|
||||
doutc(cl, "%p %llx.%llx null i_snap_realm\n",
|
||||
inode, ceph_vinop(inode));
|
||||
}
|
||||
|
||||
while (realm) {
|
||||
bool has_inode;
|
||||
|
||||
@@ -496,6 +510,9 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
|
||||
u64 total = 0, used, free;
|
||||
bool is_updated = false;
|
||||
|
||||
if (!ceph_has_realms_with_quotas(d_inode(fsc->sb->s_root)))
|
||||
return false;
|
||||
|
||||
down_read(&mdsc->snap_rwsem);
|
||||
get_quota_realm(mdsc, d_inode(fsc->sb->s_root), QUOTA_GET_MAX_BYTES,
|
||||
&realm, true);
|
||||
|
||||
@@ -1254,6 +1254,22 @@ int __ceph_setxattr(struct inode *inode, const char *name,
|
||||
ceph_vinop(inode), name, ceph_cap_string(issued));
|
||||
__build_xattrs(inode);
|
||||
|
||||
/*
|
||||
* __build_xattrs() may have released and reacquired i_ceph_lock,
|
||||
* during which handle_cap_grant() could have replaced i_xattrs.blob
|
||||
* with a newer MDS-provided blob and bumped i_xattrs.version. If that
|
||||
* caused __build_xattrs() to rebuild the rb-tree from the new blob,
|
||||
* count/names_size/vals_size may now be larger than when
|
||||
* required_blob_size was computed above. Recompute it here so the
|
||||
* prealloc_blob size check below reflects the current tree state.
|
||||
*/
|
||||
required_blob_size = __get_required_blob_size(ci, name_len, val_len);
|
||||
if (required_blob_size > mdsc->mdsmap->m_max_xattr_size) {
|
||||
doutc(cl, "sync (size too large): %d > %llu\n",
|
||||
required_blob_size, mdsc->mdsmap->m_max_xattr_size);
|
||||
goto do_sync;
|
||||
}
|
||||
|
||||
if (!ci->i_xattrs.prealloc_blob ||
|
||||
required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
|
||||
struct ceph_buffer *blob;
|
||||
@@ -1294,6 +1310,7 @@ int __ceph_setxattr(struct inode *inode, const char *name,
|
||||
|
||||
do_sync:
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
ceph_buffer_put(old_blob);
|
||||
do_sync_unlocked:
|
||||
if (lock_snap_rwsem)
|
||||
up_read(&mdsc->snap_rwsem);
|
||||
|
||||
@@ -115,6 +115,11 @@ static int __ceph_x_decrypt(const struct ceph_crypto_key *key, int usage_slot,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (plaintext_len < sizeof(*hdr)) {
|
||||
pr_err("%s plaintext too small %d\n", __func__, plaintext_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdr = p + ceph_crypt_data_offset(key);
|
||||
if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) {
|
||||
pr_err("%s bad magic\n", __func__);
|
||||
|
||||
@@ -47,7 +47,6 @@ int crush_get_bucket_item_weight(const struct crush_bucket *b, int p)
|
||||
void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
|
||||
{
|
||||
kfree(b->h.items);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket_list(struct crush_bucket_list *b)
|
||||
@@ -55,14 +54,12 @@ void crush_destroy_bucket_list(struct crush_bucket_list *b)
|
||||
kfree(b->item_weights);
|
||||
kfree(b->sum_weights);
|
||||
kfree(b->h.items);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
|
||||
{
|
||||
kfree(b->h.items);
|
||||
kfree(b->node_weights);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
|
||||
@@ -70,14 +67,12 @@ void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
|
||||
kfree(b->straws);
|
||||
kfree(b->item_weights);
|
||||
kfree(b->h.items);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket_straw2(struct crush_bucket_straw2 *b)
|
||||
{
|
||||
kfree(b->item_weights);
|
||||
kfree(b->h.items);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket(struct crush_bucket *b)
|
||||
@@ -99,6 +94,7 @@ void crush_destroy_bucket(struct crush_bucket *b)
|
||||
crush_destroy_bucket_straw2((struct crush_bucket_straw2 *)b);
|
||||
break;
|
||||
}
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,8 +72,7 @@ static int crush_decode_uniform_bucket(void **p, void *end,
|
||||
struct crush_bucket_uniform *b)
|
||||
{
|
||||
dout("crush_decode_uniform_bucket %p to %p\n", *p, end);
|
||||
ceph_decode_need(p, end, (1+b->h.size) * sizeof(u32), bad);
|
||||
b->item_weight = ceph_decode_32(p);
|
||||
ceph_decode_32_safe(p, end, b->item_weight, bad);
|
||||
return 0;
|
||||
bad:
|
||||
return -EINVAL;
|
||||
@@ -389,11 +388,15 @@ static int decode_choose_args(void **p, void *end, struct crush_map *c)
|
||||
goto fail;
|
||||
|
||||
if (arg->ids_size &&
|
||||
arg->ids_size != c->buckets[bucket_index]->size)
|
||||
(!c->buckets[bucket_index] ||
|
||||
arg->ids_size != c->buckets[bucket_index]->size))
|
||||
goto e_inval;
|
||||
}
|
||||
|
||||
insert_choose_arg_map(&c->choose_args, arg_map);
|
||||
if (!__insert_choose_arg_map(&c->choose_args, arg_map)) {
|
||||
ret = -EEXIST;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -516,6 +519,10 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
|
||||
b->id = ceph_decode_32(p);
|
||||
b->type = ceph_decode_16(p);
|
||||
b->alg = ceph_decode_8(p);
|
||||
if (b->alg != alg) {
|
||||
b->alg = 0;
|
||||
goto bad;
|
||||
}
|
||||
b->hash = ceph_decode_8(p);
|
||||
b->weight = ceph_decode_32(p);
|
||||
b->size = ceph_decode_32(p);
|
||||
@@ -1702,7 +1709,7 @@ static int osdmap_decode(void **p, void *end, bool msgr2,
|
||||
ceph_decode_need(p, end, 3*sizeof(u32) +
|
||||
map->max_osd*(struct_v >= 5 ? sizeof(u32) :
|
||||
sizeof(u8)) +
|
||||
sizeof(*map->osd_weight), e_inval);
|
||||
map->max_osd*sizeof(*map->osd_weight), e_inval);
|
||||
if (ceph_decode_32(p) != map->max_osd)
|
||||
goto e_inval;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user