https://bugs.dpdk.org/show_bug.cgi?id=1997

            Bug ID: 1997
           Summary: CN20K inline IPsec 3DES 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 am reporting what looks like a real current-head intra-object overflow in the
`cn20k` inline-IPsec Ethernet security path. I rechecked current `main`
(`8dc80afda7a52a1bd28088fe34102e7c1ba17282`) on 2026-03-10 before writing this
mail.


As on `cn10k`, the DPDK security core forwards the caller-provided
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 the `cn20k` inline path, current head then calls the `OW` SA fill helpers
directly:


```c
rc = cnxk_ow_ipsec_outb_sa_fill(outb_sa_dptr, ipsec, crypto, 0);
...
rc = cnxk_ow_ipsec_outb_sa_fill(outb_sa_dptr, ipsec, crypto, 0);
```


and again does not first call `cnxk_ipsec_xform_verify()`.


In the shared `OW` helper, `3DES` is accepted by setting `enc_type`, but there
is no exact `== 24` check before the key 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 same `cn20k` driver publishes exact `24` for `3DES` in its capability
table:


```c
.key_size = {
    .min = 24,
    .max = 24,
    .increment = 0
},
```


But the runtime inline path still copies the full user-provided `length` into a
fixed object field.


The destination object is:


```c
struct roc_ow_ipsec_outb_sa {
    ...
    uint8_t cipher_key[ROC_CTX_MAX_CKEY_LEN];
    union roc_ow_ipsec_outb_iv iv;
    ...
};
```


with `ROC_CTX_MAX_CKEY_LEN == 32`.


So any `3DES` key longer than `32` bytes writes into the adjacent live `iv`.


The cleanest concrete 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 returns `0`
- `cn20k_eth_sec_session_create()` proceeds with SA installation


Why I think this should be accepted as a real bug:


- the path is current-head and reachable from the public session-create API
- capability metadata is not a runtime guard in this path
- the runtime code bypasses the verifier that would have enforced exact-length
constraints
- the sink writes through a fixed in-object array into the next live member
- the corrupted SA is still treated as successfully created


The local proof results for the narrow `40`-byte case 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` key length before `cnxk_ow_ipsec_*_sa_fill()` is called
on the inline path.
2. Add a direct upper-bound guard before `memcpy(cipher_key, key, length)`.
3. Reuse the same xform-length verification logic across inline and non-inline
`cnxk` IPsec paths.

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to