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.

Reply via email to