The field `cur_out_ctr` in the SSL context keeps track of the
record sequence number for the next outgoing record.
For TLS, this sequence number is implicit and not transmitted
on the wire, while for DTLS, it's part of of the record header.
For DTLS, the position of the record sequence number of the next
outgoing record in that record's header is tracked in the pointer
`out_ctr`. This pointer moves forward along with other pointers
such as `out_hdr` or `out_msg` within the outgoing data buffer
`out_buf` as multiple records are written in the same datagram.
For TLS, the `out_ctr` pointer is logically superfluous, but
for some reason, we're still maintaining it by having it point
to the 8 Bytes prior to the header of the next outgoing record,
and always copying `cur_out_ctr` to this position prior to
encrypting an outgoing record.
After a record has been prepared for writing in `ssl_write_record()`,
the `out_xxx` pointers (except for `out_buf`, which is static),
are shifted forward so that they point to the header and content
of the next outgoing record. This is used only in DTLS in order
to stack multiple records into a single datagram, but the shifting
is happening for TLS as well. However, it has little effect in TLS
because we're always flushing immediately after writing, and afterwards
reset the `out_xxx` pointers.
While the present code works as-is, it is wrong to shift `out_ctr`
in the case of TLS, because it makes `out_ctr` point to the last 8
Bytes of the ciphertext of the last outgoing record. Should we ever
aim to prepare more than one protected record in `out_buf` before
dispatching it to the underlying transport, the superfluous copying
of `cur_out_ctr` to `out_buf` will corrupt the last 8 bytes of the
last record.
This commit aims to fix this problem in the minimal possible way,
by simply not shifting `out_ctr` after a record has been written.
It does deliberately not attempt to remove `out_ctr` for TLS altogether,
because any change in the messaging layer is hard to review, and
we're going to replace it soon anyhow.
The shifting happens in the helper routine mbedtls_ssl_update_out_pointers,
which assumed correctness of `out_hdr` for the beginning of the record header
of the next outgoing record, and derives the other `out_xxx` variables.
We remove the update of `out_ctr` from this function in the case of TLS,
and instead move the proper initialization of `out_ctr` to
`out_buf == initial_out_hdr - 8` to the function
mbedtls_ssl_reset_in_out_pointers().
Signed-off-by: Hanno Becker <hanno.becker@arm.com>
Fix sloppy wording around stricly less-than vs less or equal in
comments. Also fix an off-by-one error in a comparison which led to
calling setrlimit if the limit was exactly the minimum required for
the test, which was unnecessary but harmless.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
Fix a stack buffer overflow with mbedtls_net_poll() and
mbedtls_net_recv_timeout() when given a file descriptor that is beyond
FD_SETSIZE. The bug was due to not checking that the file descriptor
is within the range of an fd_set object.
Fix#4169
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
mbedtls_net_poll() and mbedtls_net_recv_timeout() rely on select(),
which represents sets of file descriptors through the fd_set type.
This type cannot hold file descriptors larger than FD_SETSIZE. Make
sure that these functions identify this failure code.
Without a proper range check of the file descriptor in the
mbedtls_net_xxx function, this test fails when running with UBSan:
```
net_poll beyond FD_SETSIZE ........................................ source/library/net_sockets.c:482:9: runtime error: index 16 out of bounds for type '__fd_mask [16]'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior source/library/net_sockets.c:482:9 in
```
This is a non-regression test for
https://github.com/ARMmbed/mbedtls/issues/4169 .
The implementation of this test is specific to Unix-like platforms.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>