Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crush: pass weight vector size to map function

Pass the size of the weight vector into crush_do_rule() to ensure that we
don't access values past the end. This can happen if the caller misbehaves
and passes a weight vector that is smaller than max_devices.

Currently the monitor tries to prevent that from happening, but this will
gracefully tolerate previous bad osdmaps that got into this state. It's
also a bit more defensive.

Reflects ceph.git commit 5922e2c2b8335b5e46c9504349c3a55b7434c01a.

Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
Reviewed-by: Sage Weil <sage@inktank.com>

+14 -7
+1 -1
include/linux/crush/mapper.h
··· 14 14 extern int crush_do_rule(const struct crush_map *map, 15 15 int ruleno, 16 16 int x, int *result, int result_max, 17 - const __u32 *weights); 17 + const __u32 *weights, int weight_max); 18 18 19 19 #endif
+12 -5
net/ceph/crush/mapper.c
··· 264 264 * true if device is marked "out" (failed, fully offloaded) 265 265 * of the cluster 266 266 */ 267 - static int is_out(const struct crush_map *map, const __u32 *weight, int item, int x) 267 + static int is_out(const struct crush_map *map, 268 + const __u32 *weight, int weight_max, 269 + int item, int x) 268 270 { 271 + if (item >= weight_max) 272 + return 1; 269 273 if (weight[item] >= 0x10000) 270 274 return 0; 271 275 if (weight[item] == 0) ··· 296 292 */ 297 293 static int crush_choose(const struct crush_map *map, 298 294 struct crush_bucket *bucket, 299 - const __u32 *weight, 295 + const __u32 *weight, int weight_max, 300 296 int x, int numrep, int type, 301 297 int *out, int outpos, 302 298 int firstn, int recurse_to_leaf, ··· 400 396 if (item < 0) { 401 397 if (crush_choose(map, 402 398 map->buckets[-1-item], 403 - weight, 399 + weight, weight_max, 404 400 x, outpos+1, 0, 405 401 out2, outpos, 406 402 firstn, 0, ··· 418 414 /* out? */ 419 415 if (itemtype == 0) 420 416 reject = is_out(map, weight, 417 + weight_max, 421 418 item, x); 422 419 else 423 420 reject = 0; ··· 475 470 * @x: hash input 476 471 * @result: pointer to result vector 477 472 * @result_max: maximum result size 473 + * @weight: weight vector (for map leaves) 474 + * @weight_max: size of weight vector 478 475 */ 479 476 int crush_do_rule(const struct crush_map *map, 480 477 int ruleno, int x, int *result, int result_max, 481 - const __u32 *weight) 478 + const __u32 *weight, int weight_max) 482 479 { 483 480 int result_len; 484 481 int a[CRUSH_MAX_SET]; ··· 552 545 j = 0; 553 546 osize += crush_choose(map, 554 547 map->buckets[-1-w[i]], 555 - weight, 548 + weight, weight_max, 556 549 x, numrep, 557 550 curstep->arg2, 558 551 o+osize, j,
+1 -1
net/ceph/osdmap.c
··· 1165 1165 } 1166 1166 r = crush_do_rule(osdmap->crush, ruleno, pps, osds, 1167 1167 min_t(int, pool->size, *num), 1168 - osdmap->osd_weight); 1168 + osdmap->osd_weight, osdmap->max_osd); 1169 1169 if (r < 0) { 1170 1170 pr_err("error %d from crush rule: pool %lld ruleset %d type %d" 1171 1171 " size %d\n", r, pgid.pool, pool->crush_ruleset,