| From 71630f053c8da3b7d8e52c99ff2592f44dd28979 Mon Sep 17 00:00:00 2001 |
| From: Sage Weil <sage@inktank.com> |
| Date: Mon, 29 Oct 2012 11:01:42 -0700 |
| Subject: libceph: fix osdmap decode error paths |
| |
| |
| From: Sage Weil <sage@inktank.com> |
| |
| (cherry picked from commit 0ed7285e0001b960c888e5455ae982025210ed3d) |
| |
| Ensure that we set the err value correctly so that we do not pass a 0 |
| value to ERR_PTR and confuse the calling code. (In particular, |
| osd_client.c handle_map() will BUG(!newmap)). |
| |
| Signed-off-by: Sage Weil <sage@inktank.com> |
| Reviewed-by: Alex Elder <elder@inktank.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ceph/osdmap.c | 31 ++++++++++++++++++++----------- |
| 1 file changed, 20 insertions(+), 11 deletions(-) |
| |
| --- a/net/ceph/osdmap.c |
| +++ b/net/ceph/osdmap.c |
| @@ -645,10 +645,12 @@ struct ceph_osdmap *osdmap_decode(void * |
| ceph_decode_32_safe(p, end, max, bad); |
| while (max--) { |
| ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad); |
| + err = -ENOMEM; |
| pi = kzalloc(sizeof(*pi), GFP_NOFS); |
| if (!pi) |
| goto bad; |
| pi->id = ceph_decode_32(p); |
| + err = -EINVAL; |
| ev = ceph_decode_8(p); /* encoding version */ |
| if (ev > CEPH_PG_POOL_VERSION) { |
| pr_warning("got unknown v %d > %d of ceph_pg_pool\n", |
| @@ -664,8 +666,13 @@ struct ceph_osdmap *osdmap_decode(void * |
| __insert_pg_pool(&map->pg_pools, pi); |
| } |
| |
| - if (version >= 5 && __decode_pool_names(p, end, map) < 0) |
| - goto bad; |
| + if (version >= 5) { |
| + err = __decode_pool_names(p, end, map); |
| + if (err < 0) { |
| + dout("fail to decode pool names"); |
| + goto bad; |
| + } |
| + } |
| |
| ceph_decode_32_safe(p, end, map->pool_max, bad); |
| |
| @@ -745,7 +752,7 @@ struct ceph_osdmap *osdmap_decode(void * |
| return map; |
| |
| bad: |
| - dout("osdmap_decode fail\n"); |
| + dout("osdmap_decode fail err %d\n", err); |
| ceph_osdmap_destroy(map); |
| return ERR_PTR(err); |
| } |
| @@ -839,6 +846,7 @@ struct ceph_osdmap *osdmap_apply_increme |
| if (ev > CEPH_PG_POOL_VERSION) { |
| pr_warning("got unknown v %d > %d of ceph_pg_pool\n", |
| ev, CEPH_PG_POOL_VERSION); |
| + err = -EINVAL; |
| goto bad; |
| } |
| pi = __lookup_pg_pool(&map->pg_pools, pool); |
| @@ -855,8 +863,11 @@ struct ceph_osdmap *osdmap_apply_increme |
| if (err < 0) |
| goto bad; |
| } |
| - if (version >= 5 && __decode_pool_names(p, end, map) < 0) |
| - goto bad; |
| + if (version >= 5) { |
| + err = __decode_pool_names(p, end, map); |
| + if (err < 0) |
| + goto bad; |
| + } |
| |
| /* old_pool */ |
| ceph_decode_32_safe(p, end, len, bad); |
| @@ -932,15 +943,13 @@ struct ceph_osdmap *osdmap_apply_increme |
| (void) __remove_pg_mapping(&map->pg_temp, pgid); |
| |
| /* insert */ |
| - if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) { |
| - err = -EINVAL; |
| + err = -EINVAL; |
| + if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) |
| goto bad; |
| - } |
| + err = -ENOMEM; |
| pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS); |
| - if (!pg) { |
| - err = -ENOMEM; |
| + if (!pg) |
| goto bad; |
| - } |
| pg->pgid = pgid; |
| pg->len = pglen; |
| for (j = 0; j < pglen; j++) |