Skip to content

Commit 0e74eb4

Browse files
jsitnickiMartin KaFai Lau
authored andcommitted
selftests/bpf: Cover verifier checks for skb_meta dynptr type
dynptr for skb metadata behaves the same way as the dynptr for skb data with one exception - writes to skb_meta dynptr don't invalidate existing skb and skb_meta slices. Duplicate those the skb dynptr tests which we can, since bpf_dynptr_from_skb_meta kfunc can be called only from TC BPF, to cover the skb_meta dynptr verifier checks. Also add a couple of new tests (skb_data_valid_*) to ensure we don't invalidate the slices in the mentioned case, which are specific to skb_meta dynptr. Signed-off-by: Jakub Sitnicki <[email protected]> Signed-off-by: Martin KaFai Lau <[email protected]> Reviewed-by: Jesse Brandeburg <[email protected]> Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-3-8a39e636e0fb@cloudflare.com
1 parent 6877cd3 commit 0e74eb4

File tree

3 files changed

+315
-0
lines changed

3 files changed

+315
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ static struct {
3232
{"test_ringbuf", SETUP_SYSCALL_SLEEP},
3333
{"test_skb_readonly", SETUP_SKB_PROG},
3434
{"test_dynptr_skb_data", SETUP_SKB_PROG},
35+
{"test_dynptr_skb_meta_data", SETUP_SKB_PROG},
36+
{"test_dynptr_skb_meta_flags", SETUP_SKB_PROG},
3537
{"test_adjust", SETUP_SYSCALL_SLEEP},
3638
{"test_adjust_err", SETUP_SYSCALL_SLEEP},
3739
{"test_zero_size_dynptr", SETUP_SYSCALL_SLEEP},

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

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,26 @@ int data_slice_out_of_bounds_skb(struct __sk_buff *skb)
269269
return SK_PASS;
270270
}
271271

272+
/* A metadata slice can't be accessed out of bounds */
273+
SEC("?tc")
274+
__failure __msg("value is outside of the allowed memory range")
275+
int data_slice_out_of_bounds_skb_meta(struct __sk_buff *skb)
276+
{
277+
struct bpf_dynptr meta;
278+
__u8 *md;
279+
280+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
281+
282+
md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md));
283+
if (!md)
284+
return SK_DROP;
285+
286+
/* this should fail */
287+
*(md + 1) = 42;
288+
289+
return SK_PASS;
290+
}
291+
272292
SEC("?raw_tp")
273293
__failure __msg("value is outside of the allowed memory range")
274294
int data_slice_out_of_bounds_map_value(void *ctx)
@@ -1089,6 +1109,26 @@ int skb_invalid_slice_write(struct __sk_buff *skb)
10891109
return SK_PASS;
10901110
}
10911111

1112+
/* bpf_dynptr_slice()s are read-only and cannot be written to */
1113+
SEC("?tc")
1114+
__failure __msg("R{{[0-9]+}} cannot write into rdonly_mem")
1115+
int skb_meta_invalid_slice_write(struct __sk_buff *skb)
1116+
{
1117+
struct bpf_dynptr meta;
1118+
__u8 *md;
1119+
1120+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1121+
1122+
md = bpf_dynptr_slice(&meta, 0, NULL, sizeof(*md));
1123+
if (!md)
1124+
return SK_DROP;
1125+
1126+
/* this should fail */
1127+
*md = 42;
1128+
1129+
return SK_PASS;
1130+
}
1131+
10921132
/* The read-only data slice is invalidated whenever a helper changes packet data */
10931133
SEC("?tc")
10941134
__failure __msg("invalid mem access 'scalar'")
@@ -1192,6 +1232,188 @@ int skb_invalid_data_slice4(struct __sk_buff *skb)
11921232
return SK_PASS;
11931233
}
11941234

1235+
/* Read-only skb data slice is invalidated on write to skb metadata */
1236+
SEC("?tc")
1237+
__failure __msg("invalid mem access 'scalar'")
1238+
int ro_skb_slice_invalid_after_metadata_write(struct __sk_buff *skb)
1239+
{
1240+
struct bpf_dynptr data, meta;
1241+
__u8 *d;
1242+
1243+
bpf_dynptr_from_skb(skb, 0, &data);
1244+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1245+
1246+
d = bpf_dynptr_slice(&data, 0, NULL, sizeof(*d));
1247+
if (!d)
1248+
return SK_DROP;
1249+
1250+
bpf_dynptr_write(&meta, 0, "x", 1, 0);
1251+
1252+
/* this should fail */
1253+
val = *d;
1254+
1255+
return SK_PASS;
1256+
}
1257+
1258+
/* Read-write skb data slice is invalidated on write to skb metadata */
1259+
SEC("?tc")
1260+
__failure __msg("invalid mem access 'scalar'")
1261+
int rw_skb_slice_invalid_after_metadata_write(struct __sk_buff *skb)
1262+
{
1263+
struct bpf_dynptr data, meta;
1264+
__u8 *d;
1265+
1266+
bpf_dynptr_from_skb(skb, 0, &data);
1267+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1268+
1269+
d = bpf_dynptr_slice_rdwr(&data, 0, NULL, sizeof(*d));
1270+
if (!d)
1271+
return SK_DROP;
1272+
1273+
bpf_dynptr_write(&meta, 0, "x", 1, 0);
1274+
1275+
/* this should fail */
1276+
*d = 42;
1277+
1278+
return SK_PASS;
1279+
}
1280+
1281+
/* Read-only skb metadata slice is invalidated on write to skb data */
1282+
SEC("?tc")
1283+
__failure __msg("invalid mem access 'scalar'")
1284+
int ro_skb_meta_slice_invalid_after_payload_write(struct __sk_buff *skb)
1285+
{
1286+
struct bpf_dynptr data, meta;
1287+
__u8 *md;
1288+
1289+
bpf_dynptr_from_skb(skb, 0, &data);
1290+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1291+
1292+
md = bpf_dynptr_slice(&meta, 0, NULL, sizeof(*md));
1293+
if (!md)
1294+
return SK_DROP;
1295+
1296+
bpf_dynptr_write(&data, 0, "x", 1, 0);
1297+
1298+
/* this should fail */
1299+
val = *md;
1300+
1301+
return SK_PASS;
1302+
}
1303+
1304+
/* Read-write skb metadata slice is invalidated on write to skb data slice */
1305+
SEC("?tc")
1306+
__failure __msg("invalid mem access 'scalar'")
1307+
int rw_skb_meta_slice_invalid_after_payload_write(struct __sk_buff *skb)
1308+
{
1309+
struct bpf_dynptr data, meta;
1310+
__u8 *md;
1311+
1312+
bpf_dynptr_from_skb(skb, 0, &data);
1313+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1314+
1315+
md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md));
1316+
if (!md)
1317+
return SK_DROP;
1318+
1319+
bpf_dynptr_write(&data, 0, "x", 1, 0);
1320+
1321+
/* this should fail */
1322+
*md = 42;
1323+
1324+
return SK_PASS;
1325+
}
1326+
1327+
/* Read-only skb metadata slice is invalidated whenever a helper changes packet data */
1328+
SEC("?tc")
1329+
__failure __msg("invalid mem access 'scalar'")
1330+
int ro_skb_meta_slice_invalid_after_payload_helper(struct __sk_buff *skb)
1331+
{
1332+
struct bpf_dynptr meta;
1333+
__u8 *md;
1334+
1335+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1336+
1337+
md = bpf_dynptr_slice(&meta, 0, NULL, sizeof(*md));
1338+
if (!md)
1339+
return SK_DROP;
1340+
1341+
if (bpf_skb_pull_data(skb, skb->len))
1342+
return SK_DROP;
1343+
1344+
/* this should fail */
1345+
val = *md;
1346+
1347+
return SK_PASS;
1348+
}
1349+
1350+
/* Read-write skb metadata slice is invalidated whenever a helper changes packet data */
1351+
SEC("?tc")
1352+
__failure __msg("invalid mem access 'scalar'")
1353+
int rw_skb_meta_slice_invalid_after_payload_helper(struct __sk_buff *skb)
1354+
{
1355+
struct bpf_dynptr meta;
1356+
__u8 *md;
1357+
1358+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1359+
1360+
md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md));
1361+
if (!md)
1362+
return SK_DROP;
1363+
1364+
if (bpf_skb_pull_data(skb, skb->len))
1365+
return SK_DROP;
1366+
1367+
/* this should fail */
1368+
*md = 42;
1369+
1370+
return SK_PASS;
1371+
}
1372+
1373+
/* Read-only skb metadata slice is invalidated on write to skb metadata */
1374+
SEC("?tc")
1375+
__failure __msg("invalid mem access 'scalar'")
1376+
int ro_skb_meta_slice_invalid_after_metadata_write(struct __sk_buff *skb)
1377+
{
1378+
struct bpf_dynptr meta;
1379+
__u8 *md;
1380+
1381+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1382+
1383+
md = bpf_dynptr_slice(&meta, 0, NULL, sizeof(*md));
1384+
if (!md)
1385+
return SK_DROP;
1386+
1387+
bpf_dynptr_write(&meta, 0, "x", 1, 0);
1388+
1389+
/* this should fail */
1390+
val = *md;
1391+
1392+
return SK_PASS;
1393+
}
1394+
1395+
/* Read-write skb metadata slice is invalidated on write to skb metadata */
1396+
SEC("?tc")
1397+
__failure __msg("invalid mem access 'scalar'")
1398+
int rw_skb_meta_slice_invalid_after_metadata_write(struct __sk_buff *skb)
1399+
{
1400+
struct bpf_dynptr meta;
1401+
__u8 *md;
1402+
1403+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1404+
1405+
md = bpf_dynptr_slice_rdwr(&meta, 0, NULL, sizeof(*md));
1406+
if (!md)
1407+
return SK_DROP;
1408+
1409+
bpf_dynptr_write(&meta, 0, "x", 1, 0);
1410+
1411+
/* this should fail */
1412+
*md = 42;
1413+
1414+
return SK_PASS;
1415+
}
1416+
11951417
/* The read-only data slice is invalidated whenever a helper changes packet data */
11961418
SEC("?xdp")
11971419
__failure __msg("invalid mem access 'scalar'")
@@ -1255,6 +1477,19 @@ int skb_invalid_ctx(void *ctx)
12551477
return 0;
12561478
}
12571479

1480+
/* Only supported prog type can create skb_meta-type dynptrs */
1481+
SEC("?raw_tp")
1482+
__failure __msg("calling kernel function bpf_dynptr_from_skb_meta is not allowed")
1483+
int skb_meta_invalid_ctx(void *ctx)
1484+
{
1485+
struct bpf_dynptr meta;
1486+
1487+
/* this should fail */
1488+
bpf_dynptr_from_skb_meta(ctx, 0, &meta);
1489+
1490+
return 0;
1491+
}
1492+
12581493
SEC("fentry/skb_tx_error")
12591494
__failure __msg("must be referenced or trusted")
12601495
int BPF_PROG(skb_invalid_ctx_fentry, void *skb)
@@ -1665,6 +1900,29 @@ int clone_skb_packet_data(struct __sk_buff *skb)
16651900
return 0;
16661901
}
16671902

1903+
/* A skb clone's metadata slice becomes invalid anytime packet data changes */
1904+
SEC("?tc")
1905+
__failure __msg("invalid mem access 'scalar'")
1906+
int clone_skb_packet_meta(struct __sk_buff *skb)
1907+
{
1908+
struct bpf_dynptr clone, meta;
1909+
__u8 *md;
1910+
1911+
bpf_dynptr_from_skb_meta(skb, 0, &meta);
1912+
bpf_dynptr_clone(&meta, &clone);
1913+
md = bpf_dynptr_slice_rdwr(&clone, 0, NULL, sizeof(*md));
1914+
if (!md)
1915+
return SK_DROP;
1916+
1917+
if (bpf_skb_pull_data(skb, skb->len))
1918+
return SK_DROP;
1919+
1920+
/* this should fail */
1921+
*md = 42;
1922+
1923+
return 0;
1924+
}
1925+
16681926
/* A xdp clone's data slices should be invalid anytime packet data changes */
16691927
SEC("?xdp")
16701928
__failure __msg("invalid mem access 'scalar'")

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,61 @@ int test_dynptr_skb_data(struct __sk_buff *skb)
211211
return 1;
212212
}
213213

214+
SEC("?tc")
215+
int test_dynptr_skb_meta_data(struct __sk_buff *skb)
216+
{
217+
struct bpf_dynptr meta;
218+
__u8 *md;
219+
int ret;
220+
221+
err = 1;
222+
ret = bpf_dynptr_from_skb_meta(skb, 0, &meta);
223+
if (ret)
224+
return 1;
225+
226+
/* This should return NULL. Must use bpf_dynptr_slice API */
227+
err = 2;
228+
md = bpf_dynptr_data(&meta, 0, sizeof(*md));
229+
if (md)
230+
return 1;
231+
232+
err = 0;
233+
return 1;
234+
}
235+
236+
/* Check that skb metadata dynptr ops don't accept any flags. */
237+
SEC("?tc")
238+
int test_dynptr_skb_meta_flags(struct __sk_buff *skb)
239+
{
240+
const __u64 INVALID_FLAGS = ~0ULL;
241+
struct bpf_dynptr meta;
242+
__u8 buf;
243+
int ret;
244+
245+
err = 1;
246+
ret = bpf_dynptr_from_skb_meta(skb, INVALID_FLAGS, &meta);
247+
if (ret != -EINVAL)
248+
return 1;
249+
250+
err = 2;
251+
ret = bpf_dynptr_from_skb_meta(skb, 0, &meta);
252+
if (ret)
253+
return 1;
254+
255+
err = 3;
256+
ret = bpf_dynptr_read(&buf, 0, &meta, 0, INVALID_FLAGS);
257+
if (ret != -EINVAL)
258+
return 1;
259+
260+
err = 4;
261+
ret = bpf_dynptr_write(&meta, 0, &buf, 0, INVALID_FLAGS);
262+
if (ret != -EINVAL)
263+
return 1;
264+
265+
err = 0;
266+
return 1;
267+
}
268+
214269
SEC("tp/syscalls/sys_enter_nanosleep")
215270
int test_adjust(void *ctx)
216271
{

0 commit comments

Comments
 (0)