🐛 [BUG] - `sa_create` Silently Returns Success for an Out-of-Range SPI
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 169
- Forks
- 67
- PR merge metrics
- No merged PRs in 30d
Description
Description
Bug Report: sa_create Silently Returns Success for an Out-of-Range SPI — Rejection Is DEBUG-Print-Only
Summary
| Field | Value |
|---|---|
| Product | NASA CryptoLib (SDLS Protocol Implementation) |
| Version | Observed on 1.5.0; identical code in 1.4.2. |
| Component | src/sa/internal/sa_interface_inmemory.template.c — sa_create |
| Issue | sa_create's else branch, taken when spi >= NUM_SA, contains only a #ifdef DEBUG printf. It never assigns status, so the function returns the CRYPTO_LIB_SUCCESS its initializer set at entry. |
| Bug Type | Conformance (uninitialized-intent fall-through / missing error assignment) |
| Severity | Medium — a rejected SA Create is reported to the ground segment as having succeeded |
| Impact | An SDLS-EP SA Create naming an SPI outside the SA table is answered positively while no SA is created. In a release (non-DEBUG) build the rejection is completely invisible — no message, no error code, no log entry. The ground segment believes the SA exists and will proceed to Rekey/Start it; every subsequent operation on that SPI fails for an apparently unrelated reason. |
Description
sa_create validates the requested SPI against the SA table bound and branches:
static int32_t sa_create(TC_t *tc_frame)
{
// Local variables
int32_t status = CRYPTO_LIB_SUCCESS; // :1428 <-- initialized to success
...
spi = ((uint8_t)sdls_frame.tlv_pdu.data[0] << BYTE_LEN) | (uint8_t)sdls_frame.tlv_pdu.data[1];
control_spi = tc_frame->tc_sec_header.spi;
if (spi == control_spi)
{
...
status = CRYPTO_LIB_ERR_SDLS_EP_WRONG_SPI; // :1446 <-- this path does set a status
return status;
}
// Check if valid SPI
if (spi < NUM_SA) // :1451
{
... parse fields, sa_verify_data(), commit to sa[spi] ... // :1453-1553
}
else
{
#ifdef DEBUG
printf(KRED "ERROR: SPI %d cannot be created.\n" RESET, spi); // :1558
#endif
} // *** status never assigned ***
return status; // :1562 -> CRYPTO_LIB_SUCCESS
}
(src/sa/internal/sa_interface_inmemory.template.c:1425-1563)
The rejection at :1555-1560 is a diagnostic, not a result. status still holds the
CRYPTO_LIB_SUCCESS from :1428 when :1562 returns it. The dispatcher propagates that
verbatim:
case PID_CREATE_SA:
#ifdef PDU_DEBUG
printf(KGRN "SA Create\n" RESET);
#endif
status = sa_if->sa_create(tc_frame);
break;
(src/core/crypto.c:709-714)
Note the inconsistency within the same file: sa_create is the outlier, not the norm.
| Function | Out-of-range SPI handling |
|---|---|
sa_create |
DEBUG printf only → returns CRYPTO_LIB_SUCCESS (:1555-1562) |
sa_delete |
DEBUG printf and status = CRYPTO_LIB_ERR_SPI_INDEX_OOB (:1652-1658) |
sa_get_from_spi |
status = CRYPTO_LIB_ERR_SPI_INDEX_OOB, logs via mc_if->mc_log, early return (:748-756) |
Per CCSDS 355.1-B-1 §5.5.1, an SA Create for an SPI the receiving end cannot host must be
answered negatively. sa_delete and sa_get_from_spi already implement exactly the response
sa_create is missing, with a return code that already exists for this purpose.
Affected Code
src/sa/internal/sa_interface_inmemory.template.c:1555-1562(1.5.0) — theelsebranch and
thereturn statusit falls through tosrc/core/crypto.c:709-714(1.5.0) — dispatcher, propagates the bogus success unchanged
Affected Versions
| Version | Status |
|---|---|
| 1.5.0 | Affected as described — else branch at :1555-1560, printf only, no status assignment |
| 1.4.2 | Affected identically — same else branch, same DEBUG-only printf at :1558, no status assignment |
Reproduction Sequence (from the fuzzing logs)
Eight TC frames on VCID 4 (TC_SDLS_EP_VCID).
| # | Hex | Meaning | Status |
|---|---|---|---|
| 1 | 002c10a6000000001104d0003f4c001001020c0000…ba17 |
SA Create, SPI 63 | 0 |
| 2 | 002c104c000000000102000000…35b9c1422 |
Key OTAR | 0 |
| 3 | 002c100e0000000002001000828a33 |
Key Activate | 0 |
| 4 | 002c101e00000000160090003f00820082000000000000000000000000551f |
SA Rekey | 0 |
| 5 | 002c100e0000000003001000822062 |
Key Deactivate | 0 |
| 6 | 002c1012000000001b0030003f00002c040ac0 |
SA Start | 0 |
| 7 | 002c100e0000000006001000820335 |
Key Destroy | 0 |
| 8 | 002c10b500000000110548cefc0c328401020cfbf13fef8286c9980feff6010200800000…0072df |
SA Create, SPI 52988 | 0 ← should be an error |
Frames 1-7 exercise SPI 63 and the key table; frame 8 does not depend on any of that state —
it is a clear TC frame on control SPI 0 carrying an SA Create for SPI 52988.
Frame 8's TLV: tag 0x11 (type=0, uf=0, sg=1 SA-Management, pid=1 SA-Create), with
data[0..1] = 0xCEFC = 52988. NUM_SA is 64 (include/crypto_config.h:141), so 52988 is far
outside the table.
Debug replay (-DDEBUG=ON), packet 8:
Processing packet 8/8 -> 002c10b500000000110548cefc0c328401020cfbf13fef8286c9980feff6010200800000...
...
TC PDU Calculated Length: 172
Received SDLS command (No Packet Header or PUS): Current CCSDS in memory is:
TLV PDU
type = 0x0
uf = 0x0
sg = 0x1
pid = 0x1 <-- PID_CREATE_SA
pdu_len = 0x0548
data[0] = 0xce
data[1] = 0xfc
data[2] = 0x0c
SA Create
spi = 52988
ERROR: SPI 52988 cannot be created. <-- target correctly identifies the SPI as unhostable
Status code: 0 <-- ...and reports success anyway
The target prints the rejection reason and the success status three lines apart. Both the
control-SPI check (:1441-1448, control SPI is 0, passes) and the range check (:1451, fails)
behaved correctly — only the reporting of the second one is broken.
In a build without -DDEBUG, the ERROR: line does not exist and the only externally visible
result is Status code: 0.
Discovered using the StratoFuzz protocol fuzzing framework.
Branch Name
dev
Reproduction steps
## Reproduction Sequence (from the fuzzing logs)
Eight TC frames on VCID 4 (`TC_SDLS_EP_VCID`).
| # | Hex | Meaning | Status |
|---|-----|---------|--------|
| 1 | `002c10a6000000001104d0003f4c001001020c0000…ba17` | SA Create, SPI 63 | 0 |
| 2 | `002c104c000000000102000000…35b9c1422` | Key OTAR | 0 |
| 3 | `002c100e0000000002001000828a33` | Key Activate | 0 |
| 4 | `002c101e00000000160090003f00820082000000000000000000000000551f` | SA Rekey | 0 |
| 5 | `002c100e0000000003001000822062` | Key Deactivate | 0 |
| 6 | `002c1012000000001b0030003f00002c040ac0` | SA Start | 0 |
| 7 | `002c100e0000000006001000820335` | Key Destroy | 0 |
| 8 | `002c10b500000000110548cefc0c328401020cfbf13fef8286c9980feff6010200800000…0072df` | **SA Create, SPI 52988** | **0** ← should be an error |
Frames 1-7 exercise SPI 63 and the key table; frame 8 does not depend on any of that state —
it is a clear TC frame on control SPI 0 carrying an SA Create for SPI 52988.
**Frame 8's TLV**: tag `0x11` (type=0, uf=0, sg=1 SA-Management, pid=1 SA-Create), with
`data[0..1] = 0xCEFC = 52988`. `NUM_SA` is 64 (`include/crypto_config.h:141`), so 52988 is far
outside the table.
**Debug replay (`-DDEBUG=ON`), packet 8:**
Processing packet 8/8 -> 002c10b500000000110548cefc0c328401020cfbf13fef8286c9980feff6010200800000...
...
TC PDU Calculated Length: 172
Received SDLS command (No Packet Header or PUS): Current CCSDS in memory is:
TLV PDU
type = 0x0
uf = 0x0
sg = 0x1
pid = 0x1 <-- PID_CREATE_SA
pdu_len = 0x0548
data[0] = 0xce
data[1] = 0xfc
data[2] = 0x0c
SA Create
spi = 52988
ERROR: SPI 52988 cannot be created. <-- target correctly identifies the SPI as unhostable
Status code: 0 <-- ...and reports success anyway
The target prints the rejection reason and the success status three lines apart. Both the
control-SPI check (`:1441-1448`, control SPI is 0, passes) and the range check (`:1451`, fails)
behaved correctly — only the reporting of the second one is broken.
In a build without `-DDEBUG`, the `ERROR:` line does not exist and the only externally visible
result is `Status code: 0`.
Screenshots
Logs
OS
Linux
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/sa/internal/sa_interface_inmemory.template.c around sa_create at lines 1425-1563, then read the PID_CREATE_SA dispatch in src/core/crypto.c:709-714 and compare sa_delete’s out-of-range handling. Reproduce with the SPI 52988 frame or the eight-packet sequence; done means an out-of-range SPI returns CRYPTO_LIB_ERR_SPI_INDEX_OOB instead of success, including in a non-DEBUG build.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 86/100