https://bugs.dpdk.org/show_bug.cgi?id=1995
Bug ID: 1995
Summary: CN10K inline IPsec 3DES keys 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 am reporting what looks like a real current-head intra-object overflow in the
`cn10k` inline-IPsec Ethernet security path. I rechecked current `main`
(`8dc80afda7a52a1bd28088fe34102e7c1ba17282`) on 2026-03-10 before writing this
mail.
The important point is that the public DPDK security API forwards the
configuration directly into the driver callback:
```c
if (instance->ops->session_create(instance->device, conf, sess)) {
rte_mempool_put(mp, (void *)sess);
return NULL;
}
```
For `cn10k`, the inline Ethernet path then goes straight into the SA fill
helpers:
```c
rc = cnxk_ot_ipsec_outb_sa_fill(outb_sa_dptr, ipsec, crypto, 0);
...
rc = cnxk_ot_ipsec_outb_sa_fill(outb_sa_dptr, ipsec, crypto, 0);
```
and does not first call `cnxk_ipsec_xform_verify()`.
In the shared helper, `3DES` is accepted by setting `enc_type`, but there is no
exact `== 24` runtime check before the copy:
```c
case RTE_CRYPTO_CIPHER_3DES_CBC:
w2->s.enc_type = ROC_IE_SA_ENC_3DES_CBC;
break;
...
key = cipher_xfrm->cipher.key.data;
length = cipher_xfrm->cipher.key.length;
...
if (key != NULL && length != 0) {
memcpy(cipher_key, key, length);
...
}
```
The capability table for this same path advertises `3DES` as exact-size only:
```c
.key_size = {
.min = 24,
.max = 24,
.increment = 0
},
```
But the runtime inline path above does not enforce that before the copy.
The destination object is:
```c
struct roc_ot_ipsec_outb_sa {
...
uint8_t cipher_key[ROC_CTX_MAX_CKEY_LEN];
union roc_ot_ipsec_outb_iv iv;
...
};
```
with `ROC_CTX_MAX_CKEY_LEN == 32`.
So any `3DES` key longer than `32` bytes writes through `cipher_key[32]` and
into the adjacent live `iv`.
The cleanest current-head case is a `40`-byte `RTE_CRYPTO_CIPHER_3DES_CBC` key:
- first `32` bytes fill `cipher_key`
- next `8` bytes overwrite the beginning of `iv`
- the helper still returns `0`
- the session-create path proceeds with SA installation
This is why I think this is a strong bug:
- the caller chain is current-head and production, not test code
- the exact-size constraint is published by the driver itself
- the runtime path bypasses the verifier that would have enforced it
- the sink writes attacker-controlled data into a fixed in-object array
- the overwrite reaches a live adjacent member and the path still succeeds
I also prepared a local proof mirroring the current-head layout and write
order. The key outputs are:
- `distance_cipher_key_to_iv=32`
- `advertised_3des_key_max=24`
- `provided_key_len=40`
- `returned=0`
- `overflow_bytes_into_iv=8`
- `iv_prefix_hex=4242424242424242`
- `guard_unchanged=1`
Suggested fix:
1. Enforce exact `3DES` length before `cnxk_ot_ipsec_*_sa_fill()` is reached on
the inline path.
2. Add a local `length <= sizeof(cipher_key)` guard inside the helper before
`memcpy()`.
3. Reuse the same xform verification logic on this inline path that already
exists elsewhere in the `cnxk` IPsec stack.
--
You are receiving this mail because:
You are the assignee for the bug.