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

bpf, test_run: Subtract size of xdp_frame from allowed metadata size

The xdp_frame structure takes up part of the XDP frame headroom,
limiting the size of the metadata. However, in bpf_test_run, we don't
take this into account, which makes it possible for userspace to supply
a metadata size that is too large (taking up the entire headroom).

If userspace supplies such a large metadata size in live packet mode,
the xdp_update_frame_from_buff() call in xdp_test_run_init_page() call
will fail, after which packet transmission proceeds with an
uninitialised frame structure, leading to the usual Bad Stuff.

The commit in the Fixes tag fixed a related bug where the second check
in xdp_update_frame_from_buff() could fail, but did not add any
additional constraints on the metadata size. Complete the fix by adding
an additional check on the metadata size. Reorder the checks slightly to
make the logic clearer and add a comment.

Link: https://lore.kernel.org/r/fa2be179-bad7-4ee3-8668-4903d1853461@hust.edu.cn
Fixes: b6f1f780b393 ("bpf, test_run: Fix packet size check for live packet mode")
Reported-by: Yinhao Hu <dddddd@hust.edu.cn>
Reported-by: Kaiyan Mei <M202472210@hust.edu.cn>
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
Link: https://lore.kernel.org/r/20260105114747.1358750-1-toke@redhat.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Toke Høiland-Jørgensen and committed by
Alexei Starovoitov
e558cca2 8f3e00af

+13 -5
+13 -5
net/bpf/test_run.c
··· 1294 1294 batch_size = NAPI_POLL_WEIGHT; 1295 1295 else if (batch_size > TEST_XDP_MAX_BATCH) 1296 1296 return -E2BIG; 1297 - 1298 - headroom += sizeof(struct xdp_page_head); 1299 1297 } else if (batch_size) { 1300 1298 return -EINVAL; 1301 1299 } ··· 1306 1308 /* There can't be user provided data before the meta data */ 1307 1309 if (ctx->data_meta || ctx->data_end > kattr->test.data_size_in || 1308 1310 ctx->data > ctx->data_end || 1309 - unlikely(xdp_metalen_invalid(ctx->data)) || 1310 1311 (do_live && (kattr->test.data_out || kattr->test.ctx_out))) 1311 1312 goto free_ctx; 1312 - /* Meta data is allocated from the headroom */ 1313 - headroom -= ctx->data; 1314 1313 1315 1314 meta_sz = ctx->data; 1315 + if (xdp_metalen_invalid(meta_sz) || meta_sz > headroom - sizeof(struct xdp_frame)) 1316 + goto free_ctx; 1317 + 1318 + /* Meta data is allocated from the headroom */ 1319 + headroom -= meta_sz; 1316 1320 linear_sz = ctx->data_end; 1317 1321 } 1322 + 1323 + /* The xdp_page_head structure takes up space in each page, limiting the 1324 + * size of the packet data; add the extra size to headroom here to make 1325 + * sure it's accounted in the length checks below, but not in the 1326 + * metadata size check above. 1327 + */ 1328 + if (do_live) 1329 + headroom += sizeof(struct xdp_page_head); 1318 1330 1319 1331 max_linear_sz = PAGE_SIZE - headroom - tailroom; 1320 1332 linear_sz = min_t(u32, linear_sz, max_linear_sz);