Browse Source

[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>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
0acc52519d
3 changed files with 53 additions and 12 deletions
  1. 42
    0
      src/core/iobuf.c
  2. 1
    0
      src/include/ipxe/iobuf.h
  3. 10
    12
      src/net/tls.c

+ 42
- 0
src/core/iobuf.c View File

@@ -158,3 +158,45 @@ int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
158 158
 	return -ENOBUFS;
159 159
 }
160 160
 
161
+/**
162
+ * Concatenate I/O buffers into a single buffer
163
+ *
164
+ * @v list	List of I/O buffers
165
+ * @ret iobuf	Concatenated I/O buffer, or NULL on allocation failure
166
+ *
167
+ * After a successful concatenation, the list will be empty.
168
+ */
169
+struct io_buffer * iob_concatenate ( struct list_head *list ) {
170
+	struct io_buffer *iobuf;
171
+	struct io_buffer *tmp;
172
+	struct io_buffer *concatenated;
173
+	size_t len = 0;
174
+
175
+	/* If the list contains only a single entry, avoid an
176
+	 * unnecessary additional allocation.
177
+	 */
178
+	if ( list_is_singular ( list ) ) {
179
+		iobuf = list_first_entry ( list, struct io_buffer, list );
180
+		INIT_LIST_HEAD ( list );
181
+		return iobuf;
182
+	}
183
+
184
+	/* Calculate total length */
185
+	list_for_each_entry ( iobuf, list, list )
186
+		len += iob_len ( iobuf );
187
+
188
+	/* Allocate new I/O buffer */
189
+	concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
190
+	if ( ! concatenated )
191
+		return NULL;
192
+
193
+	/* Move data to new I/O buffer */
194
+	list_for_each_entry_safe ( iobuf, tmp, list, list ) {
195
+		list_del ( &iobuf->list );
196
+		memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
197
+			 iobuf->data, iob_len ( iobuf ) );
198
+		free_iob ( iobuf );
199
+	}
200
+
201
+	return concatenated;
202
+}

+ 1
- 0
src/include/ipxe/iobuf.h View File

@@ -216,5 +216,6 @@ extern struct io_buffer * __malloc alloc_iob ( size_t len );
216 216
 extern void free_iob ( struct io_buffer *iobuf );
217 217
 extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
218 218
 extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
219
+extern struct io_buffer * iob_concatenate ( struct list_head *list );
219 220
 
220 221
 #endif /* _IPXE_IOBUF_H */

+ 10
- 12
src/net/tls.c View File

@@ -105,10 +105,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
105 105
 #define EINFO_EINVAL_MAC						\
106 106
 	__einfo_uniqify ( EINFO_EINVAL, 0x0d,				\
107 107
 			  "Invalid MAC" )
108
-#define EINVAL_NON_DATA __einfo_error ( EINFO_EINVAL_NON_DATA )
109
-#define EINFO_EINVAL_NON_DATA						\
110
-	__einfo_uniqify ( EINFO_EINVAL, 0x0e,				\
111
-			  "Overlength non-data record" )
112 108
 #define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
113 109
 #define EINFO_EIO_ALERT							\
114 110
 	__einfo_uniqify ( EINFO_EINVAL, 0x01,				\
@@ -137,6 +133,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
137 133
 #define EINFO_ENOMEM_RX_DATA						\
138 134
 	__einfo_uniqify ( EINFO_ENOMEM, 0x07,				\
139 135
 			  "Not enough space for received data" )
136
+#define ENOMEM_RX_CONCAT __einfo_error ( EINFO_ENOMEM_RX_CONCAT )
137
+#define EINFO_ENOMEM_RX_CONCAT						\
138
+	__einfo_uniqify ( EINFO_ENOMEM, 0x08,				\
139
+			  "Not enough space to concatenate received data" )
140 140
 #define ENOTSUP_CIPHER __einfo_error ( EINFO_ENOTSUP_CIPHER )
141 141
 #define EINFO_ENOTSUP_CIPHER						\
142 142
 	__einfo_uniqify ( EINFO_ENOTSUP, 0x01,				\
@@ -1743,14 +1743,12 @@ static int tls_new_record ( struct tls_session *tls, unsigned int type,
1743 1743
 		return 0;
1744 1744
 	}
1745 1745
 
1746
-	/* For all other records, fail unless we have exactly one I/O buffer */
1747
-	iobuf = list_first_entry ( rx_data, struct io_buffer, list );
1748
-	assert ( iobuf != NULL );
1749
-	list_del ( &iobuf->list );
1750
-	if ( ! list_empty ( rx_data ) ) {
1751
-		DBGC ( tls, "TLS %p overlength non-data record\n", tls );
1752
-		free_iob ( iobuf );
1753
-		return -EINVAL_NON_DATA;
1746
+	/* For all other records, merge into a single I/O buffer */
1747
+	iobuf = iob_concatenate ( rx_data );
1748
+	if ( ! iobuf ) {
1749
+		DBGC ( tls, "TLS %p could not concatenate non-data record "
1750
+		       "type %d\n", tls, type );
1751
+		return -ENOMEM_RX_CONCAT;
1754 1752
 	}
1755 1753
 
1756 1754
 	/* Determine handler */

Loading…
Cancel
Save