srsRAN_4G
srsRAN_4G copied to clipboard
Bug in ASN.1 APER Unpacking
Issue Description
The unpack_constrained_whole_number method in src/asn1/asn1_utils.cc:509 contains a bug in the way it decodes integers from packet data. In particular, when packets use Aligned PER rules, the function does not check that the upper bound is satisfied:
SRSASN_CODE unpack_constrained_whole_number(IntType& n, cbit_ref& bref, IntType lb, IntType ub, bool aligned)
{
if (ub < lb) {
log_error("The condition lb <= ub (%ld <= %ld) was not met\n", (long)lb, (long)ub);
return SRSASN_ERROR_DECODE_FAIL;
}
uint64_t ra = (uint64_t)(ub - lb) + 1; // NOTE: Can overflow if IntType is kept.
if (ra == 1) {
n = lb;
return SRSASN_SUCCESS;
}
uint32_t n_bits = (uint32_t)ceilf(log2f((float)ra));
if (not aligned) {
// UNALIGNED variant
HANDLE_CODE(bref.unpack(n, n_bits));
n += lb;
if (n > ub) {
log_error("The condition lb <= n <= ub (%ld <= %ld <= %ld) was not met\n", (long)lb, (long)n, (long)ub);
return SRSASN_ERROR_DECODE_FAIL;
}
} else {
// ALIGNED variant
if (ra < 256) {
HANDLE_CODE(bref.unpack(n, n_bits)); // BUG: `ra` is not considered here. If the decoded value is outside of the range, the `ub` constraint will be broken
} else if (ra <= ASN_64K) {
uint32_t n_octets = ceil_frac(n_bits, 8u);
HANDLE_CODE(bref.align_bytes());
HANDLE_CODE(bref.unpack(n, n_octets * 8));
HANDLE_CODE(bref.align_bytes());
} else {
// TODO: Check if this is correct
uint32_t n_bits_len = (uint32_t)ceilf(log2f(ceil_frac(n_bits, 8u)));
uint32_t n_octets;
HANDLE_CODE(bref.unpack(n_octets, n_bits_len));
n_octets += 1;
HANDLE_CODE(bref.align_bytes());
HANDLE_CODE(bref.unpack(n, n_octets * 8));
}
n += lb;
}
// RECOMMENDED FIX: move upper bounds check here:
// if (n > ub) {
// log_error("The condition lb <= n <= ub (%ld <= %ld <= %ld) was not met\n", (long)lb, (long)n, (long)ub);
// return SRSASN_ERROR_DECODE_FAIL;
// }
return SRSASN_SUCCESS;
}
This bug is possible when the decoded number is constrained by a range that is not a power of two.
Note that the unpack_integer and unpack_length functions both use this function to obtain their values. In turn, the unpack_dyn_seq_of function uses unpack_length to determine how many elements to parse into a fixed-size buffer. As a result of this, the internal size field of the dynamic sequence struct can be overwritten during unpacking, which can lead to arbitrary-length out of bound reads and writes elsewhere in code.
This issue only affects the S1AP and NGAP protocols. It does not affect the RRC protocol, which uses Unaligned PER ASN.1 rules instead of Aligned.
A similar issue has been filed for srsRAN_Project as it uses the same ASN.1 decoding routines.