mirror of
https://github.com/versity/scoutfs.git
synced 2026-08-15 19:56:36 +00:00
Guard log_merge, srch_root, and mounted_client item printers
Scoutfs print segfaults walking a log_merge btree that has more than one level. print_btree_block() prints parent (level > 0) items via print_block_ref(), which invokes the item callback with a NULL value to print the key portion before printing the child ref: func(key, 0, 0, NULL, 0, arg); print_log_merge_item immediately casts val and reads a field, dereferencing NULL. A log_merge of a single leaf block (height 1) never hits the parent path; one with height > 1 crashes on the first parent item: scoutfs[22043]: segfault at 8 ip 0000000000408ef0 sp 00007fffc5edd8b0 error 4 #0 0x0000000000408ef0 in print_log_merge_item () #1 0x000000000040958d in print_btree_block.constprop.0.isra () #2 0x000000000040a471 in print_cmd () #3 0x0000000000404264 in cmd_execute () #4 0x00000000004025c9 in main () print_mounted_client_entry has the same bug: it casts val and reads mcv->addr / mcv->flags with no NULL guard, so a mounted_clients btree of height > 1 segfaults the same way. print_srch_root_item guards NULL but casts to scoutfs_srch_compact or scoutfs_srch_file without bounds checking, so a short or malformed item reads past its end. Fix all three: return early when val is NULL (printing just the key for the parent ref where applicable), and bounds-check val_len before each cast so a short item is reported instead of read past its end. Signed-off-by: Auke Kok <auke.kok@versity.com>
This commit is contained in:
+49
-1
@@ -375,6 +375,11 @@ static int print_srch_root_item(struct scoutfs_key *key, u64 seq, u8 flags, void
|
||||
if (val) {
|
||||
if (key->sk_type == SCOUTFS_SRCH_PENDING_TYPE ||
|
||||
key->sk_type == SCOUTFS_SRCH_BUSY_TYPE) {
|
||||
if (val_len < sizeof(*sc)) {
|
||||
printf(" (short srch compact value: val_len %u)\n",
|
||||
val_len);
|
||||
return 0;
|
||||
}
|
||||
sc = val;
|
||||
printf(" compact %s: nr %u flags 0x%x\n",
|
||||
key->sk_type == SCOUTFS_SRCH_PENDING_TYPE ?
|
||||
@@ -387,6 +392,11 @@ static int print_srch_root_item(struct scoutfs_key *key, u64 seq, u8 flags, void
|
||||
SRF_A(&sc->in[i].sfl));
|
||||
}
|
||||
} else {
|
||||
if (val_len < sizeof(*sfl)) {
|
||||
printf(" (short srch file value: val_len %u)\n",
|
||||
val_len);
|
||||
return 0;
|
||||
}
|
||||
sfl = val;
|
||||
printf(" "SRF_FMT"\n", SRF_A(sfl));
|
||||
}
|
||||
@@ -398,9 +408,25 @@ static int print_srch_root_item(struct scoutfs_key *key, u64 seq, u8 flags, void
|
||||
static int print_mounted_client_entry(struct scoutfs_key *key, u64 seq, u8 flags, void *val,
|
||||
unsigned val_len, void *arg)
|
||||
{
|
||||
struct scoutfs_mounted_client_btree_val *mcv = val;
|
||||
struct scoutfs_mounted_client_btree_val *mcv;
|
||||
struct in_addr in;
|
||||
|
||||
/*
|
||||
* Parent block items reference child blocks and have no value;
|
||||
* print_block_ref() calls us with a NULL val just to print the key.
|
||||
*/
|
||||
if (!val) {
|
||||
printf(" rid %016llx\n", le64_to_cpu(key->skmc_rid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val_len < sizeof(*mcv)) {
|
||||
printf(" rid %016llx (short mounted client value: val_len %u)\n",
|
||||
le64_to_cpu(key->skmc_rid), val_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mcv = val;
|
||||
memset(&in, 0, sizeof(in));
|
||||
in.s_addr = htonl(le32_to_cpu(mcv->addr.v4.addr));
|
||||
|
||||
@@ -419,8 +445,17 @@ static int print_log_merge_item(struct scoutfs_key *key, u64 seq, u8 flags, void
|
||||
struct scoutfs_log_merge_complete *comp;
|
||||
struct scoutfs_log_merge_freeing *fr;
|
||||
|
||||
/*
|
||||
* Parent block items reference child blocks and have no value;
|
||||
* print_block_ref() calls us with a NULL val just to print the key.
|
||||
*/
|
||||
if (!val)
|
||||
return 0;
|
||||
|
||||
switch (key->sk_zone) {
|
||||
case SCOUTFS_LOG_MERGE_STATUS_ZONE:
|
||||
if (val_len < sizeof(*stat))
|
||||
goto bad_len;
|
||||
stat = val;
|
||||
printf(" status: next_range_key "SK_FMT" nr_req %llu nr_comp %llu seq %llu\n",
|
||||
SK_ARG(&stat->next_range_key),
|
||||
@@ -429,12 +464,16 @@ static int print_log_merge_item(struct scoutfs_key *key, u64 seq, u8 flags, void
|
||||
le64_to_cpu(stat->seq));
|
||||
break;
|
||||
case SCOUTFS_LOG_MERGE_RANGE_ZONE:
|
||||
if (val_len < sizeof(*rng))
|
||||
goto bad_len;
|
||||
rng = val;
|
||||
printf(" range: start "SK_FMT" end "SK_FMT"\n",
|
||||
SK_ARG(&rng->start),
|
||||
SK_ARG(&rng->end));
|
||||
break;
|
||||
case SCOUTFS_LOG_MERGE_REQUEST_ZONE:
|
||||
if (val_len < sizeof(*req))
|
||||
goto bad_len;
|
||||
req = val;
|
||||
printf(" request: logs_root "BTROOT_F" logs_root "BTROOT_F" start "SK_FMT
|
||||
" end "SK_FMT" input_seq %llu rid %016llx seq %llu flags 0x%llx\n",
|
||||
@@ -448,6 +487,8 @@ static int print_log_merge_item(struct scoutfs_key *key, u64 seq, u8 flags, void
|
||||
le64_to_cpu(req->flags));
|
||||
break;
|
||||
case SCOUTFS_LOG_MERGE_COMPLETE_ZONE:
|
||||
if (val_len < sizeof(*comp))
|
||||
goto bad_len;
|
||||
comp = val;
|
||||
printf(" complete: root "BTROOT_F" start "SK_FMT" end "SK_FMT
|
||||
" remain "SK_FMT" rid %016llx seq %llu flags %llx\n",
|
||||
@@ -460,6 +501,8 @@ static int print_log_merge_item(struct scoutfs_key *key, u64 seq, u8 flags, void
|
||||
le64_to_cpu(comp->flags));
|
||||
break;
|
||||
case SCOUTFS_LOG_MERGE_FREEING_ZONE:
|
||||
if (val_len < sizeof(*fr))
|
||||
goto bad_len;
|
||||
fr = val;
|
||||
printf(" freeing: root "BTROOT_F" key "SK_FMT" seq %llu\n",
|
||||
BTROOT_A(&fr->root),
|
||||
@@ -472,6 +515,11 @@ static int print_log_merge_item(struct scoutfs_key *key, u64 seq, u8 flags, void
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bad_len:
|
||||
printf(" (short log merge value: zone %u val_len %u)\n",
|
||||
key->sk_zone, val_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_alloc_item(struct scoutfs_key *key, u64 seq, u8 flags, void *val,
|
||||
|
||||
Reference in New Issue
Block a user