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

            Bug ID: 1999
           Summary: cnxk ON common SA 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 would like to report what appears to be a real current-head intra-object
overflow in the `cnxk` ON-family IPsec security-SA creation path. I rechecked
current `main` on 2026-03-10 before writing this report.


The relevant issue is in `drivers/common/cnxk/cnxk_security.c`.


The front-door logic accepts `DES` / `3DES` by setting `enc_type`, but it only
performs an AES-family key-length switch:


```c
if (cipher_xform != NULL) {
    switch (cipher_xform->cipher.algo) {
    case RTE_CRYPTO_CIPHER_DES_CBC:
        ctl->enc_type = ROC_IE_SA_ENC_DES_CBC;
        break;
    case RTE_CRYPTO_CIPHER_3DES_CBC:
        ctl->enc_type = ROC_IE_SA_ENC_3DES_CBC;
        break;
    case RTE_CRYPTO_CIPHER_AES_CBC:
    case RTE_CRYPTO_CIPHER_AES_CTR:
        aes_key_len = cipher_xform->cipher.key.length;
        break;
    }
}


if (ctl->enc_type == ROC_IE_SA_ENC_AES_CBC ||
    ctl->enc_type == ROC_IE_SA_ENC_AES_CTR ||
    ctl->enc_type == ROC_IE_SA_ENC_AES_GCM ||
    ctl->enc_type == ROC_IE_SA_ENC_AES_CCM ||
    ctl->auth_type == ROC_IE_SA_AUTH_AES_GMAC) {
    switch (aes_key_len) {
    case 16:
    case 24:
    case 32:
        ...
    default:
        return -EINVAL;
    }
}
```


Later in the same helper, the full runtime key length is copied into a fixed
in-object array with no upper bound:


```c
cipher_key = cipher_xform->cipher.key.data;
cipher_key_len = cipher_xform->cipher.key.length;
...
if (cipher_key_len != 0)
    memcpy(common_sa->cipher_key, cipher_key, cipher_key_len);
```


The affected object layout is:


```c
struct roc_ie_on_common_sa {
    struct roc_ie_on_sa_ctl ctl;
    uint8_t cipher_key[32];
    union roc_ie_on_bit_perfect_iv iv;
    ...
};
```


So any `DES` / `3DES` key longer than `32` bytes writes past `cipher_key[32]`
and into the adjacent live `iv` member.


Why I think this is a real bug and not just a capability-metadata concern:


- the DPDK security core does not enforce cipher key sizes before calling the
driver:


```c
if (instance->ops->session_create(instance->device, conf, sess)) {
    rte_mempool_put(mp, (void *)sess);
    return NULL;
}
```


- the driver contract in `rte_security_driver.h` says invalid or unsupported
transforms should be rejected, not accepted after memory corruption
- the copy sink is on the real current-head caller chain:
  - `rte_security_session_create()`
  - `cn9k_eth_sec_session_create()`
  - `cnxk_on_ipsec_outb_sa_create()`
  - `on_fill_ipsec_common_sa()`
- the path still returns success after the adjacent overwrite


The cleanest concrete case is `RTE_CRYPTO_CIPHER_3DES_CBC` with a `40`-byte
key:


- first `32` bytes fill `cipher_key`
- next `8` bytes overwrite the beginning of adjacent `iv`
- the helper returns `0`


I also prepared a minimal local proof that mirrors the current-head layout and
write order. The key outputs are:


- `distance_cipher_key_to_iv=32`
- `accepted_des3_key_without_upper_bound=1`
- `provided_key_len=40`
- `returned=0`
- `overflow_bytes_into_iv=8`
- `iv_prefix_hex=4242424242424242`
- `guard_unchanged=1`


That shows the first eight bytes beyond `cipher_key[32]` already corrupt the
live adjacent `iv` member, while the modeled current-head path still returns
success.


Suggested fix:
1. Reject `DES` / `3DES` key lengths that do not match the supported runtime
contract before the copy.
2. Add a defensive check near the sink, e.g. `if (cipher_key_len >
sizeof(common_sa->cipher_key)) return -EINVAL;`.

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

Reply via email to