For a MEM_UNINIT ("raw mode") helper argument, check_stack_range_initialized() open-coded a scan that rejected any STACK_DYNPTR slot in the range with "potential write to dynptr". This duplicated, and was stricter than, the handling that runs when the buffer is actually marked initialized. check_helper_call() later replays the write byte by byte via check_mem_access(), which goes through destroy_if_dynptr_stack_slot(), which rejects overwritting a referenced dynptr. Therefore drop the redundant scan and rely on check_mem_access().
Showing the changes to kernel (1 of 2 files). Show all
Unified · Split
| @@ -6733,31 +6733,6 @@ static int check_stack_range_initialized( · 6732 unmodified lines | |||
| 6733 | } | 6733 | } |
| 6734 | 6734 | ||
| 6735 | if (meta && meta->raw_mode) { | 6735 | if (meta && meta->raw_mode) { |
| 6736 | /* Ensure we won't be overwriting dynptrs when simulating byte | ||
| 6737 | * by byte access in check_helper_call using meta.access_size. | ||
| 6738 | * This would be a problem if we have a helper in the future | ||
| 6739 | * which takes: | ||
| 6740 | * | ||
| 6741 | * helper(uninit_mem, len, dynptr) | ||
| 6742 | * | ||
| 6743 | * Now, uninint_mem may overlap with dynptr pointer. Hence, it | ||
| 6744 | * may end up writing to dynptr itself when touching memory from | ||
| 6745 | * arg 1. This can be relaxed on a case by case basis for known | ||
| 6746 | * safe cases, but reject due to the possibilitiy of aliasing by | ||
| 6747 | * default. | ||
| 6748 | */ | ||
| 6749 | for (i = min_off; i < max_off + access_size; i++) { | ||
| 6750 | int stack_off = -i - 1; | ||
| 6751 | |||
| 6752 | spi = bpf_get_spi(i); | ||
| 6753 | /* raw_mode may write past allocated_stack */ | ||
| 6754 | if (state->allocated_stack <= stack_off) | ||
| 6755 | continue; | ||
| 6756 | if (state->stack[spi].slot_type[stack_off % BPF_REG_SIZE] == STACK_DYNPTR) { | ||
| 6757 | verbose(env, "potential write to dynptr at off=%d disallowed\n", i); | ||
| 6758 | return -EACCES; | ||
| 6759 | } | ||
| 6760 | } | ||
| 6761 | meta->access_size = access_size; | 6736 | meta->access_size = access_size; |
| 6762 | meta->regno = reg_from_argno(argno); | 6737 | meta->regno = reg_from_argno(argno); |
| 6763 | return 0; | 6738 | return 0; |