https://bugs.dpdk.org/show_bug.cgi?id=1998
Bug ID: 1998
Summary: CN9K inline inbound AES-XCBC auth key overflow
Product: DPDK
Version: unspecified
Hardware: All
OS: All
Status: UNCONFIRMED
Severity: normal
Priority: Normal
Component: cryptodev
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: ---
Group: security
Report date: 2026-03-11
Reported by: 侯朋朋 <[email protected]>
Hello DPDK maintainers,
I would like to report what appears to be a real current-head intra-object
overflow in the `cn9k` inline IPsec inbound path for `AES_XCBC_MAC`. I
rechecked current `main` (`8dc80afda7a52a1bd28088fe34102e7c1ba17282`) on
2026-03-10 before writing this report.
The relevant inline caller path is:
```c
cn9k_eth_sec_session_create(...)
{
...
rc = cnxk_on_ipsec_inb_sa_create(ipsec, crypto, inb_sa);
...
}
```
This inline path does not call `cnxk_ipsec_xform_verify()`.
That matters because the exact-length check for XCBC exists in the reusable
verifier:
```c
if (crypto_xform->auth.algo == RTE_CRYPTO_AUTH_AES_XCBC_MAC &&
keylen == ROC_CPT_AES_XCBC_KEY_LENGTH)
return 0;
```
But the inline inbound path bypasses that verifier and reaches this sink
instead:
```c
case RTE_CRYPTO_AUTH_AES_XCBC_MAC:
memcpy(in_sa->aes_xcbc.key, auth_key, auth_key_len);
ctx_len = offsetof(struct roc_ie_on_inb_sa, aes_xcbc.selector);
break;
```
The relevant object layout is:
```c
struct {
uint8_t key[16];
uint8_t unused[32];
struct roc_ie_on_traffic_selector selector;
} aes_xcbc;
```
So the first live adjacent member starts `48` bytes after the beginning of
`aes_xcbc.key`.
The key point here is narrow and specific:
- if the claim is only “copy into `key[16]` without a bound”, then any
`auth.key.length > 16` is already a real overwrite into adjacent in-object
storage
- if the claim is specifically “corrupts the live `selector` member”, then the
clean threshold is `auth.key.length > 48`
This report is about that second, narrower claim.
The same driver advertises `AES_XCBC_MAC` as exact-size only:
```c
.key_size = {
.min = 16,
.max = 16,
.increment = 0
},
```
But the runtime inline inbound path still copies the full user-provided length
into `key[16]`.
The clean concrete case is a `64`-byte `AES_XCBC_MAC` key:
- bytes `0..15` fill `key[16]`
- bytes `16..47` fill `unused[32]`
- bytes `48..63` overwrite the first `16` bytes of live `selector`
The later `roc_aes_xcbc_key_derive()` call does not repair that selector
overwrite, because it only writes derived material into the first `48` bytes of
the union region.
The local proof results for this narrow case are:
- `distance_key_to_selector=48`
- `advertised_aes_xcbc_key_max=16`
- `provided_key_len=64`
- `returned_ctx_len=120`
- `overflow_bytes_into_selector=16`
- `selector_prefix_hex=4242424242424242`
- `guard_unchanged=1`
Why I think this is a real bug:
- the sink is current-head shared security code
- the caller is a production inline session-create path
- the verifier that would have enforced exact XCBC length exists but is
bypassed here
- the destination is a fixed in-object field, not a flexible array
- the overwritten bytes belong to a live adjacent member, `selector`
Suggested fix:
1. Reject `AES_XCBC_MAC` keys whose length is not exactly `16` before
`cnxk_on_ipsec_inb_sa_create()` is reached on this inline path.
2. Add a local check such as `if (auth_key_len != sizeof(in_sa->aes_xcbc.key))
return -EINVAL;` before the `memcpy()`.
3. Reuse the same xform verification logic for inline callers that already
exists for the lookaside path.
--
You are receiving this mail because:
You are the assignee for the bug.