В ядре Linux устранена следующая уязвимость:
SUNRPC: усиление защиты gss_krb5_unwrap_v2 от коротких токенов
gss_krb5_unwrap_v2() считывает поля заголовков EC и RRC по адресу ptr+4 и
ptr+6 перед проверкой того, что токен имеет значение не ниже GSS_KRB5_TOK_HDR_LEN.
(16) байт, и его помощник Rotate_left() передает buf->len - base
в xdr_buf_subsegment() без проверки того, что base <= buf->len. Когда
вызывающий абонент передает токен размером менее 16 байт или токен, объявленный len
покидает базу за пределами буфера, следуют три отдельных сбоя:
gss_krb5_unwrap_v2 (смещение, длина, буф)
ptr = buf->head[0].iov_base + смещение
ec = *(ptr + 4) /* OOB читается по короткой головке */
rrc = *(ptr + 6) /* OOB читается по короткой головке */
Rotate_left (смещение + 16, buf, rrc)
xdr_buf_subsegment(buf, &subbuf,
base, buf->len - base) /* u32 перенос, когда base > len */
_rotate_left(&subbuf, сдвиг)
сдвиг %= buf->len /* деление на ноль, когда база == len */
После расшифровки арифметика очистки имеет тот же вид:
movelen = min_t(unsigned int, buf->head[0].iov_len, len);
movelen -= смещение + GSS_KRB5_TOK_HDR_LEN + хедскип;
BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen >
buf->head[0].iov_len);
BUG_ON повторно добавляет только что вычтенное значение, поэтому оно уменьшается до
min(A, B) > A и постоянно ложно; он не может поймать беззнаковый
опустошение метода movelen, который затем вызывает вызов memmove() размером ~UINT_MAX.
Добавьте четыре элемента глубокоэшелонированной защиты внутри ядра развертки, чтобы оно было в безопасности.
независимо от того, что проверяют вызывающие стороны:
- отклонять токены с помощью len - смещение < GSS_KRB5_TOK_HDR_LEN раньше
касание ptr+4/ptr+6;
- освобождение от Rotate_left(), когда buf->len <= base, охватывающее как
случаи нижнего переполнения и нулевой длины;
- возврат досрочно из _rotate_left(), когда buf->len равен нулю, поэтому
сдвиг %= buf->len по модулю не может привести к ошибке;
- заменить мертвый BUG_ON живой проверкой, которая возвращает
GSS_S_DEFECTIVE_TOKEN перед вычитанием перемещения.
Показать оригинальное описание (EN)
In the Linux kernel, the following vulnerability has been resolved: SUNRPC: harden gss_krb5_unwrap_v2 against short tokens gss_krb5_unwrap_v2() reads the EC and RRC header fields at ptr+4 and ptr+6 before validating that the token is at least GSS_KRB5_TOK_HDR_LEN (16) bytes long, and its rotate_left() helper passes buf->len - base to xdr_buf_subsegment() without verifying that base <= buf->len. When a caller hands in a sub-16-byte token, or a token whose declared len leaves base past the end of the buffer, three distinct failures follow: gss_krb5_unwrap_v2(offset, len, buf) ptr = buf->head[0].iov_base + offset ec = *(ptr + 4) /* OOB read on short head */ rrc = *(ptr + 6) /* OOB read on short head */ rotate_left(offset + 16, buf, rrc) xdr_buf_subsegment(buf, &subbuf, base, buf->len - base) /* u32 wrap when base > len */ _rotate_left(&subbuf, shift) shift %= buf->len /* divide-by-zero when base == len */ After decryption, the cleanup arithmetic has the same shape: movelen = min_t(unsigned int, buf->head[0].iov_len, len); movelen -= offset + GSS_KRB5_TOK_HDR_LEN + headskip; BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen > buf->head[0].iov_len); The BUG_ON re-adds the value just subtracted, so it reduces to min(A, B) > A and is permanently false; it cannot catch the unsigned underflow of movelen, which then drives a ~UINT_MAX-byte memmove(). Add four defense-in-depth guards inside the unwrap core so it is safe regardless of what its callers validate: - reject tokens with len - offset < GSS_KRB5_TOK_HDR_LEN before touching ptr+4/ptr+6; - bail from rotate_left() when buf->len <= base, covering both the underflow and zero-length cases; - return early from _rotate_left() when buf->len is zero, so the shift %= buf->len modulo cannot fault; - replace the dead BUG_ON with a live check that returns GSS_S_DEFECTIVE_TOKEN before the movelen subtraction.
Характеристики атаки
Последствия
Строка CVSS v3.1