Skip to content

Commit a296d1a

Browse files
jsitnickiKernel Patches Daemon
authored andcommitted
selftests/bpf: Expect unclone to preserve skb metadata
Since pskb_expand_head() no longer clears metadata on unclone, update tests for cloned packets to expect metadata to remain intact. Also simplify the clone_dynptr_kept_on_{data,meta}_slice_write tests. Creating an r/w dynptr slice is sufficient to trigger an unclone in the prologue, so remove the extraneous writes to the data/meta slice. Signed-off-by: Jakub Sitnicki <[email protected]>
1 parent 7287d93 commit a296d1a

File tree

2 files changed

+59
-48
lines changed

2 files changed

+59
-48
lines changed

tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -458,25 +458,25 @@ void test_xdp_context_tuntap(void)
458458
skel->progs.ing_cls_dynptr_offset_oob,
459459
skel->progs.ing_cls,
460460
&skel->bss->test_pass);
461-
if (test__start_subtest("clone_data_meta_empty_on_data_write"))
461+
if (test__start_subtest("clone_data_meta_kept_on_data_write"))
462462
test_tuntap_mirred(skel->progs.ing_xdp,
463-
skel->progs.clone_data_meta_empty_on_data_write,
463+
skel->progs.clone_data_meta_kept_on_data_write,
464464
&skel->bss->test_pass);
465-
if (test__start_subtest("clone_data_meta_empty_on_meta_write"))
465+
if (test__start_subtest("clone_data_meta_kept_on_meta_write"))
466466
test_tuntap_mirred(skel->progs.ing_xdp,
467-
skel->progs.clone_data_meta_empty_on_meta_write,
467+
skel->progs.clone_data_meta_kept_on_meta_write,
468468
&skel->bss->test_pass);
469-
if (test__start_subtest("clone_dynptr_empty_on_data_slice_write"))
469+
if (test__start_subtest("clone_dynptr_kept_on_data_slice_write"))
470470
test_tuntap_mirred(skel->progs.ing_xdp,
471-
skel->progs.clone_dynptr_empty_on_data_slice_write,
471+
skel->progs.clone_dynptr_kept_on_data_slice_write,
472472
&skel->bss->test_pass);
473-
if (test__start_subtest("clone_dynptr_empty_on_meta_slice_write"))
473+
if (test__start_subtest("clone_dynptr_kept_on_meta_slice_write"))
474474
test_tuntap_mirred(skel->progs.ing_xdp,
475-
skel->progs.clone_dynptr_empty_on_meta_slice_write,
475+
skel->progs.clone_dynptr_kept_on_meta_slice_write,
476476
&skel->bss->test_pass);
477-
if (test__start_subtest("clone_dynptr_rdonly_before_data_dynptr_write"))
477+
if (test__start_subtest("clone_dynptr_rdonly_before_data_dynptr_write_then_rw"))
478478
test_tuntap_mirred(skel->progs.ing_xdp,
479-
skel->progs.clone_dynptr_rdonly_before_data_dynptr_write,
479+
skel->progs.clone_dynptr_rdonly_before_data_dynptr_write_then_rw,
480480
&skel->bss->test_pass);
481481
if (test__start_subtest("clone_dynptr_rdonly_before_meta_dynptr_write"))
482482
test_tuntap_mirred(skel->progs.ing_xdp,

tools/testing/selftests/bpf/progs/test_xdp_meta.c

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,13 @@ int ing_xdp(struct xdp_md *ctx)
326326
}
327327

328328
/*
329-
* Check that skb->data_meta..skb->data is empty if prog writes to packet
329+
* Check that skb->data_meta..skb->data is kept in tact if prog writes to packet
330330
* _payload_ using packet pointers. Applies only to cloned skbs.
331331
*/
332332
SEC("tc")
333-
int clone_data_meta_empty_on_data_write(struct __sk_buff *ctx)
333+
int clone_data_meta_kept_on_data_write(struct __sk_buff *ctx)
334334
{
335+
__u8 *meta_have = ctx_ptr(ctx, data_meta);
335336
struct ethhdr *eth = ctx_ptr(ctx, data);
336337

337338
if (eth + 1 > ctx_ptr(ctx, data_end))
@@ -340,8 +341,10 @@ int clone_data_meta_empty_on_data_write(struct __sk_buff *ctx)
340341
if (eth->h_proto != 0)
341342
goto out;
342343

343-
/* Expect no metadata */
344-
if (ctx->data_meta != ctx->data)
344+
if (meta_have + META_SIZE > eth)
345+
goto out;
346+
347+
if (!check_metadata(meta_have))
345348
goto out;
346349

347350
/* Packet write to trigger unclone in prologue */
@@ -353,40 +356,44 @@ int clone_data_meta_empty_on_data_write(struct __sk_buff *ctx)
353356
}
354357

355358
/*
356-
* Check that skb->data_meta..skb->data is empty if prog writes to packet
359+
* Check that skb->data_meta..skb->data is kept in tact if prog writes to packet
357360
* _metadata_ using packet pointers. Applies only to cloned skbs.
358361
*/
359362
SEC("tc")
360-
int clone_data_meta_empty_on_meta_write(struct __sk_buff *ctx)
363+
int clone_data_meta_kept_on_meta_write(struct __sk_buff *ctx)
361364
{
365+
__u8 *meta_have = ctx_ptr(ctx, data_meta);
362366
struct ethhdr *eth = ctx_ptr(ctx, data);
363-
__u8 *md = ctx_ptr(ctx, data_meta);
364367

365368
if (eth + 1 > ctx_ptr(ctx, data_end))
366369
goto out;
367370
/* Ignore non-test packets */
368371
if (eth->h_proto != 0)
369372
goto out;
370373

371-
if (md + 1 > ctx_ptr(ctx, data)) {
372-
/* Expect no metadata */
373-
test_pass = true;
374-
} else {
375-
/* Metadata write to trigger unclone in prologue */
376-
*md = 42;
377-
}
374+
if (meta_have + META_SIZE > eth)
375+
goto out;
376+
377+
if (!check_metadata(meta_have))
378+
goto out;
379+
380+
/* Metadata write to trigger unclone in prologue */
381+
*meta_have = 42;
382+
383+
test_pass = true;
378384
out:
379385
return TC_ACT_SHOT;
380386
}
381387

382388
/*
383-
* Check that skb_meta dynptr is writable but empty if prog writes to packet
384-
* _payload_ using a dynptr slice. Applies only to cloned skbs.
389+
* Check that skb_meta dynptr is writable and was kept in tact if prog creates a
390+
* r/w slice to packet _payload_. Applies only to cloned skbs.
385391
*/
386392
SEC("tc")
387-
int clone_dynptr_empty_on_data_slice_write(struct __sk_buff *ctx)
393+
int clone_dynptr_kept_on_data_slice_write(struct __sk_buff *ctx)
388394
{
389395
struct bpf_dynptr data, meta;
396+
__u8 meta_have[META_SIZE];
390397
struct ethhdr *eth;
391398

392399
bpf_dynptr_from_skb(ctx, 0, &data);
@@ -397,29 +404,26 @@ int clone_dynptr_empty_on_data_slice_write(struct __sk_buff *ctx)
397404
if (eth->h_proto != 0)
398405
goto out;
399406

400-
/* Expect no metadata */
401407
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
402-
if (bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) > 0)
408+
bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0);
409+
if (!check_metadata(meta_have))
403410
goto out;
404411

405-
/* Packet write to trigger unclone in prologue */
406-
eth->h_proto = 42;
407-
408412
test_pass = true;
409413
out:
410414
return TC_ACT_SHOT;
411415
}
412416

413417
/*
414-
* Check that skb_meta dynptr is writable but empty if prog writes to packet
415-
* _metadata_ using a dynptr slice. Applies only to cloned skbs.
418+
* Check that skb_meta dynptr is writable and was kept in tact if prog creates
419+
* an r/w slice to packet _metadata_. Applies only to cloned skbs.
416420
*/
417421
SEC("tc")
418-
int clone_dynptr_empty_on_meta_slice_write(struct __sk_buff *ctx)
422+
int clone_dynptr_kept_on_meta_slice_write(struct __sk_buff *ctx)
419423
{
420424
struct bpf_dynptr data, meta;
421425
const struct ethhdr *eth;
422-
__u8 *md;
426+
__u8 *meta_have;
423427

424428
bpf_dynptr_from_skb(ctx, 0, &data);
425429
eth = bpf_dynptr_slice(&data, 0, NULL, sizeof(*eth));
@@ -429,16 +433,13 @@ int clone_dynptr_empty_on_meta_slice_write(struct __sk_buff *ctx)
429433
if (eth->h_proto != 0)
430434
goto out;
431435

432-
/* Expect no metadata */
433436
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
434-
if (bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) > 0)
437+
meta_have = bpf_dynptr_slice_rdwr(&meta, 0, NULL, META_SIZE);
438+
if (!meta_have)
435439
goto out;
436440

437-
/* Metadata write to trigger unclone in prologue */
438-
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
439-
md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md));
440-
if (md)
441-
*md = 42;
441+
if (!check_metadata(meta_have))
442+
goto out;
442443

443444
test_pass = true;
444445
out:
@@ -447,12 +448,14 @@ int clone_dynptr_empty_on_meta_slice_write(struct __sk_buff *ctx)
447448

448449
/*
449450
* Check that skb_meta dynptr is read-only before prog writes to packet payload
450-
* using dynptr_write helper. Applies only to cloned skbs.
451+
* using dynptr_write helper, and becomes read-write afterwards. Applies only to
452+
* cloned skbs.
451453
*/
452454
SEC("tc")
453-
int clone_dynptr_rdonly_before_data_dynptr_write(struct __sk_buff *ctx)
455+
int clone_dynptr_rdonly_before_data_dynptr_write_then_rw(struct __sk_buff *ctx)
454456
{
455457
struct bpf_dynptr data, meta;
458+
__u8 meta_have[META_SIZE];
456459
const struct ethhdr *eth;
457460

458461
bpf_dynptr_from_skb(ctx, 0, &data);
@@ -465,15 +468,23 @@ int clone_dynptr_rdonly_before_data_dynptr_write(struct __sk_buff *ctx)
465468

466469
/* Expect read-only metadata before unclone */
467470
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
468-
if (!bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) != META_SIZE)
471+
if (!bpf_dynptr_is_rdonly(&meta))
472+
goto out;
473+
474+
bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0);
475+
if (!check_metadata(meta_have))
469476
goto out;
470477

471478
/* Helper write to payload will unclone the packet */
472479
bpf_dynptr_write(&data, offsetof(struct ethhdr, h_proto), "x", 1, 0);
473480

474-
/* Expect no metadata after unclone */
481+
/* Expect r/w metadata after unclone */
475482
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
476-
if (bpf_dynptr_is_rdonly(&meta) || bpf_dynptr_size(&meta) != 0)
483+
if (bpf_dynptr_is_rdonly(&meta))
484+
goto out;
485+
486+
bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0);
487+
if (!check_metadata(meta_have))
477488
goto out;
478489

479490
test_pass = true;

0 commit comments

Comments
 (0)