Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[tls] Concatenate received non-data records before processing
Allow non-data records to be split across multiple received I/O
buffers, to accommodate large certificate chains.

Reported-by: Nicola Volpini <Nicola.Volpini@kambi.com>
Tested-by: Nicola Volpini <Nicola.Volpini@kambi.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Jan 31, 2013
1 parent 3fcb8cf commit 0acc525
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 12 deletions.
42 changes: 42 additions & 0 deletions src/core/iobuf.c
Expand Up @@ -158,3 +158,45 @@ int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
return -ENOBUFS;
}

/**
* Concatenate I/O buffers into a single buffer
*
* @v list List of I/O buffers
* @ret iobuf Concatenated I/O buffer, or NULL on allocation failure
*
* After a successful concatenation, the list will be empty.
*/
struct io_buffer * iob_concatenate ( struct list_head *list ) {
struct io_buffer *iobuf;
struct io_buffer *tmp;
struct io_buffer *concatenated;
size_t len = 0;

/* If the list contains only a single entry, avoid an
* unnecessary additional allocation.
*/
if ( list_is_singular ( list ) ) {
iobuf = list_first_entry ( list, struct io_buffer, list );
INIT_LIST_HEAD ( list );
return iobuf;
}

/* Calculate total length */
list_for_each_entry ( iobuf, list, list )
len += iob_len ( iobuf );

/* Allocate new I/O buffer */
concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
if ( ! concatenated )
return NULL;

/* Move data to new I/O buffer */
list_for_each_entry_safe ( iobuf, tmp, list, list ) {
list_del ( &iobuf->list );
memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
iobuf->data, iob_len ( iobuf ) );
free_iob ( iobuf );
}

return concatenated;
}
1 change: 1 addition & 0 deletions src/include/ipxe/iobuf.h
Expand Up @@ -216,5 +216,6 @@ extern struct io_buffer * __malloc alloc_iob ( size_t len );
extern void free_iob ( struct io_buffer *iobuf );
extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
extern struct io_buffer * iob_concatenate ( struct list_head *list );

#endif /* _IPXE_IOBUF_H */
22 changes: 10 additions & 12 deletions src/net/tls.c
Expand Up @@ -105,10 +105,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINFO_EINVAL_MAC \
__einfo_uniqify ( EINFO_EINVAL, 0x0d, \
"Invalid MAC" )
#define EINVAL_NON_DATA __einfo_error ( EINFO_EINVAL_NON_DATA )
#define EINFO_EINVAL_NON_DATA \
__einfo_uniqify ( EINFO_EINVAL, 0x0e, \
"Overlength non-data record" )
#define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
#define EINFO_EIO_ALERT \
__einfo_uniqify ( EINFO_EINVAL, 0x01, \
Expand Down Expand Up @@ -137,6 +133,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINFO_ENOMEM_RX_DATA \
__einfo_uniqify ( EINFO_ENOMEM, 0x07, \
"Not enough space for received data" )
#define ENOMEM_RX_CONCAT __einfo_error ( EINFO_ENOMEM_RX_CONCAT )
#define EINFO_ENOMEM_RX_CONCAT \
__einfo_uniqify ( EINFO_ENOMEM, 0x08, \
"Not enough space to concatenate received data" )
#define ENOTSUP_CIPHER __einfo_error ( EINFO_ENOTSUP_CIPHER )
#define EINFO_ENOTSUP_CIPHER \
__einfo_uniqify ( EINFO_ENOTSUP, 0x01, \
Expand Down Expand Up @@ -1743,14 +1743,12 @@ static int tls_new_record ( struct tls_session *tls, unsigned int type,
return 0;
}

/* For all other records, fail unless we have exactly one I/O buffer */
iobuf = list_first_entry ( rx_data, struct io_buffer, list );
assert ( iobuf != NULL );
list_del ( &iobuf->list );
if ( ! list_empty ( rx_data ) ) {
DBGC ( tls, "TLS %p overlength non-data record\n", tls );
free_iob ( iobuf );
return -EINVAL_NON_DATA;
/* For all other records, merge into a single I/O buffer */
iobuf = iob_concatenate ( rx_data );
if ( ! iobuf ) {
DBGC ( tls, "TLS %p could not concatenate non-data record "
"type %d\n", tls, type );
return -ENOMEM_RX_CONCAT;
}

/* Determine handler */
Expand Down

0 comments on commit 0acc525

Please sign in to comment.