Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #include "stuffer/s2n_stuffer.h"
17 : :
18 : : #include <sys/param.h>
19 : :
20 : : #include "error/s2n_errno.h"
21 : : #include "utils/s2n_blob.h"
22 : : #include "utils/s2n_mem.h"
23 : : #include "utils/s2n_safety.h"
24 : :
25 : : S2N_RESULT s2n_stuffer_validate(const struct s2n_stuffer *stuffer)
26 : 590728794 : {
27 : : /**
28 : : * Note that we do not assert any properties on the tainted field,
29 : : * as any boolean value in that field is valid.
30 : : */
31 [ + + ][ + - ]: 590728794 : RESULT_ENSURE_REF(stuffer);
32 [ + + ]: 590728784 : RESULT_GUARD(s2n_blob_validate(&stuffer->blob));
33 [ # # ][ - + ]: 590728783 : RESULT_DEBUG_ENSURE(S2N_IMPLIES(stuffer->growable, stuffer->alloced), S2N_ERR_SAFETY);
[ + + ][ + - ]
34 : :
35 : : /* <= is valid because we can have a fully written/read stuffer */
36 [ # # ][ - + ]: 590728783 : RESULT_DEBUG_ENSURE(stuffer->high_water_mark <= stuffer->blob.size, S2N_ERR_SAFETY);
37 [ + - ][ + + ]: 590728783 : RESULT_DEBUG_ENSURE(stuffer->write_cursor <= stuffer->high_water_mark, S2N_ERR_SAFETY);
38 [ + - ][ + + ]: 590728781 : RESULT_DEBUG_ENSURE(stuffer->read_cursor <= stuffer->write_cursor, S2N_ERR_SAFETY);
39 : 590728780 : return S2N_RESULT_OK;
40 : 590728781 : }
41 : :
42 : : S2N_RESULT s2n_stuffer_reservation_validate(const struct s2n_stuffer_reservation *reservation)
43 : 377001 : {
44 : : /**
45 : : * Note that we need two dereferences here to decrease proof complexity
46 : : * for CBMC (see https://github.com/awslabs/s2n/issues/2290). We can roll back
47 : : * this change once CBMC can handle common subexpression elimination.
48 : : */
49 [ - + ][ # # ]: 377001 : RESULT_ENSURE_REF(reservation);
50 : 377001 : const struct s2n_stuffer_reservation reserve_obj = *reservation;
51 [ + + ]: 377001 : RESULT_GUARD(s2n_stuffer_validate(reserve_obj.stuffer));
52 : 377000 : const struct s2n_stuffer stuffer_obj = *(reserve_obj.stuffer);
53 : :
54 : : /* Verify that write_cursor + length can be represented as a uint32_t without overflow */
55 [ - + ][ # # ]: 377000 : RESULT_ENSURE_LTE(reserve_obj.write_cursor, UINT32_MAX - reserve_obj.length);
56 : : /* The entire reservation must fit between the stuffer read and write cursors */
57 [ + + ][ + - ]: 377000 : RESULT_ENSURE_LTE(reserve_obj.write_cursor + reserve_obj.length, stuffer_obj.write_cursor);
58 [ # # ][ - + ]: 376997 : RESULT_ENSURE_GTE(reserve_obj.write_cursor, stuffer_obj.read_cursor);
59 : :
60 : 376997 : return S2N_RESULT_OK;
61 : 376997 : }
62 : :
63 : : /**
64 : : * Initialize a stuffer to reference some data `in`.
65 : : *
66 : : * `stuffer` will not own the data, and the caller is responsible for ensuring that
67 : : * the data pointed to by `in` outlives `stuffer`.
68 : : */
69 : : int s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in)
70 : 20569103 : {
71 [ + - ][ + + ]: 20569103 : POSIX_ENSURE_MUT(stuffer);
72 [ + + ][ + + ]: 20569102 : POSIX_PRECONDITION(s2n_blob_validate(in));
73 : 20569100 : stuffer->blob = *in;
74 : 20569100 : stuffer->read_cursor = 0;
75 : 20569100 : stuffer->write_cursor = 0;
76 : 20569100 : stuffer->high_water_mark = 0;
77 : 20569100 : stuffer->alloced = 0;
78 : 20569100 : stuffer->growable = 0;
79 : 20569100 : stuffer->tainted = 0;
80 [ - + ][ + + ]: 20569100 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
81 : 20569100 : return S2N_SUCCESS;
82 : 20569100 : }
83 : :
84 : : int s2n_stuffer_init_written(struct s2n_stuffer *stuffer, struct s2n_blob *in)
85 : 120395 : {
86 [ - + ][ # # ]: 120395 : POSIX_ENSURE_REF(in);
87 [ - + ]: 120395 : POSIX_GUARD(s2n_stuffer_init(stuffer, in));
88 [ - + ]: 120395 : POSIX_GUARD(s2n_stuffer_skip_write(stuffer, in->size));
89 : 120395 : return S2N_SUCCESS;
90 : 120395 : }
91 : :
92 : : int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size)
93 : 7372688 : {
94 [ - + ][ # # ]: 7372688 : POSIX_ENSURE_REF(stuffer);
95 : 7372688 : *stuffer = (struct s2n_stuffer){ 0 };
96 [ - + ]: 7372688 : POSIX_GUARD(s2n_alloc(&stuffer->blob, size));
97 [ - + ]: 7372688 : POSIX_GUARD(s2n_stuffer_init(stuffer, &stuffer->blob));
98 : :
99 : 7372688 : stuffer->alloced = 1;
100 : :
101 [ - + ][ + - ]: 7372688 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
102 : 7372688 : return S2N_SUCCESS;
103 : 7372688 : }
104 : :
105 : : int s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, const uint32_t size)
106 : 7348374 : {
107 [ - + ]: 7348374 : POSIX_GUARD(s2n_stuffer_alloc(stuffer, size));
108 : :
109 : 7348374 : stuffer->growable = 1;
110 : :
111 [ - + ][ + - ]: 7348374 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
112 : 7348374 : return S2N_SUCCESS;
113 : 7348374 : }
114 : :
115 : : int s2n_stuffer_free(struct s2n_stuffer *stuffer)
116 : 8375100 : {
117 [ - + ][ + - ]: 8375100 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
118 [ + + ]: 8375100 : if (stuffer->alloced) {
119 [ - + ]: 4065209 : POSIX_GUARD(s2n_free(&stuffer->blob));
120 : 4065209 : }
121 : 8375100 : *stuffer = (struct s2n_stuffer){ 0 };
122 : 8375100 : return S2N_SUCCESS;
123 : 8375100 : }
124 : :
125 : : int s2n_stuffer_free_without_wipe(struct s2n_stuffer *stuffer)
126 : 10 : {
127 [ - + ][ + - ]: 10 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
128 [ + - ]: 10 : if (stuffer->alloced) {
129 [ - + ]: 10 : POSIX_GUARD(s2n_free_without_wipe(&stuffer->blob));
130 : 10 : }
131 : 10 : *stuffer = (struct s2n_stuffer){ 0 };
132 : 10 : return S2N_SUCCESS;
133 : 10 : }
134 : :
135 : : int s2n_stuffer_resize(struct s2n_stuffer *stuffer, const uint32_t size)
136 : 13848202 : {
137 [ - + ][ + - ]: 13848202 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
138 [ # # ][ - + ]: 13848202 : POSIX_ENSURE(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER);
139 [ - + ][ # # ]: 13848202 : POSIX_ENSURE(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER);
140 : :
141 [ + + ]: 13848202 : if (size == stuffer->blob.size) {
142 : 6916834 : return S2N_SUCCESS;
143 : 6916834 : }
144 : :
145 [ + + ]: 6931368 : if (size == 0) {
146 : 3310914 : s2n_stuffer_wipe(stuffer);
147 : 3310914 : return s2n_free(&stuffer->blob);
148 : 3310914 : }
149 : :
150 [ + + ]: 3620454 : if (size < stuffer->blob.size) {
151 [ - + ][ # # ]: 75 : POSIX_CHECKED_MEMSET(stuffer->blob.data + size, S2N_WIPE_PATTERN, (stuffer->blob.size - size));
[ + - ]
152 [ - + ]: 75 : if (stuffer->read_cursor > size) {
153 : 0 : stuffer->read_cursor = size;
154 : 0 : }
155 [ - + ]: 75 : if (stuffer->write_cursor > size) {
156 : 0 : stuffer->write_cursor = size;
157 : 0 : }
158 [ - + ]: 75 : if (stuffer->high_water_mark > size) {
159 : 0 : stuffer->high_water_mark = size;
160 : 0 : }
161 : 75 : stuffer->blob.size = size;
162 [ - + ][ + - ]: 75 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
163 : 75 : return S2N_SUCCESS;
164 : 75 : }
165 : :
166 [ - + ]: 3620379 : POSIX_GUARD(s2n_realloc(&stuffer->blob, size));
167 [ - + ][ + - ]: 3620379 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
168 : 3620379 : return S2N_SUCCESS;
169 : 3620379 : }
170 : :
171 : : int s2n_stuffer_resize_if_empty(struct s2n_stuffer *stuffer, const uint32_t size)
172 : 863112 : {
173 [ - + ][ + - ]: 863112 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
174 [ + + ]: 863112 : if (stuffer->blob.data == NULL) {
175 [ - + ][ # # ]: 18182 : POSIX_ENSURE(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER);
176 [ + - ][ + + ]: 18182 : POSIX_ENSURE(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER);
177 [ - + ]: 18181 : POSIX_GUARD(s2n_realloc(&stuffer->blob, size));
178 : 18181 : }
179 [ - + ][ + - ]: 863111 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
180 : 863111 : return S2N_SUCCESS;
181 : 863111 : }
182 : :
183 : : /**
184 : : * Reset read and write progress.
185 : : *
186 : : * This sets the read and write cursors to zero.
187 : : */
188 : : int s2n_stuffer_rewrite(struct s2n_stuffer *stuffer)
189 : 4503785 : {
190 [ - + ][ + - ]: 4503785 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
191 : 4503785 : stuffer->write_cursor = 0;
192 : 4503785 : stuffer->read_cursor = 0;
193 [ - + ][ + - ]: 4503785 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
194 : 4503785 : return S2N_SUCCESS;
195 : 4503785 : }
196 : :
197 : : int s2n_stuffer_rewind_read(struct s2n_stuffer *stuffer, const uint32_t size)
198 : 547082 : {
199 [ - + ][ + - ]: 547082 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
200 [ + + ][ + - ]: 547082 : POSIX_ENSURE(stuffer->read_cursor >= size, S2N_ERR_STUFFER_OUT_OF_DATA);
201 : 547077 : stuffer->read_cursor -= size;
202 [ - + ][ + - ]: 547077 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
203 : 547077 : return S2N_SUCCESS;
204 : 547077 : }
205 : :
206 : : /**
207 : : * Reset read progress.
208 : : *
209 : : * This sets the read cursor to zero.
210 : : */
211 : : int s2n_stuffer_reread(struct s2n_stuffer *stuffer)
212 : 8992511 : {
213 [ - + ][ + - ]: 8992511 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
214 : 8992511 : stuffer->read_cursor = 0;
215 : 8992511 : return S2N_SUCCESS;
216 : 8992511 : }
217 : :
218 : : int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t size)
219 : 517676 : {
220 [ - + ][ + - ]: 517676 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
221 : 517676 : uint32_t wipe_size = MIN(size, stuffer->write_cursor);
222 : :
223 : 517676 : stuffer->write_cursor -= wipe_size;
224 : 517676 : stuffer->read_cursor = MIN(stuffer->read_cursor, stuffer->write_cursor);
225 [ - + ][ # # ]: 517676 : POSIX_CHECKED_MEMSET(stuffer->blob.data + stuffer->write_cursor, S2N_WIPE_PATTERN, wipe_size);
[ + + ]
226 : :
227 [ - + ][ + - ]: 517676 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
228 : 517676 : return S2N_SUCCESS;
229 : 517676 : }
230 : :
231 : : bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer)
232 : 269510 : {
233 [ + - ][ + + ]: 269510 : return stuffer && (stuffer->read_cursor == stuffer->write_cursor) && !stuffer->tainted;
[ + + ]
234 : 269510 : }
235 : :
236 : : int s2n_stuffer_wipe(struct s2n_stuffer *stuffer)
237 : 41507388 : {
238 [ - + ][ + - ]: 41507388 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
239 [ + + ]: 41507388 : if (!s2n_stuffer_is_wiped(stuffer)) {
240 [ # # ][ - + ]: 10759713 : POSIX_CHECKED_MEMSET(stuffer->blob.data, S2N_WIPE_PATTERN, stuffer->high_water_mark);
[ + - ]
241 : 10759713 : }
242 : :
243 : 41507388 : stuffer->tainted = 0;
244 : 41507388 : stuffer->write_cursor = 0;
245 : 41507388 : stuffer->read_cursor = 0;
246 : 41507388 : stuffer->high_water_mark = 0;
247 [ - + ][ + - ]: 41507388 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
248 : 41507388 : return S2N_SUCCESS;
249 : 41507388 : }
250 : :
251 : : int s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n)
252 : 36893564 : {
253 [ - + ][ + - ]: 36893564 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
254 [ + + ][ + - ]: 36893564 : POSIX_ENSURE(s2n_stuffer_data_available(stuffer) >= n, S2N_ERR_STUFFER_OUT_OF_DATA);
255 : :
256 : 36876895 : stuffer->read_cursor += n;
257 : 36876895 : return S2N_SUCCESS;
258 : 36893564 : }
259 : :
260 : : void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len)
261 : 5073041 : {
262 [ + + ]: 5073041 : PTR_GUARD_POSIX(s2n_stuffer_skip_read(stuffer, data_len));
263 : :
264 : 5073038 : stuffer->tainted = 1;
265 : :
266 [ + - ]: 5073038 : return (stuffer->blob.data) ? (stuffer->blob.data + stuffer->read_cursor - data_len) : NULL;
267 : 5073041 : }
268 : :
269 : : int s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out)
270 : 146342 : {
271 [ - + ][ # # ]: 146342 : POSIX_ENSURE_REF(out);
272 : :
273 : 146342 : return s2n_stuffer_read_bytes(stuffer, out->data, out->size);
274 : 146342 : }
275 : :
276 : : int s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out)
277 : 193852 : {
278 [ - + ]: 193852 : POSIX_GUARD(s2n_stuffer_skip_read(stuffer, out->size));
279 : :
280 [ + - ]: 193852 : void *ptr = (stuffer->blob.data) ? (stuffer->blob.data + stuffer->read_cursor - out->size) : NULL;
281 [ # # ][ - + ]: 193852 : POSIX_ENSURE(S2N_MEM_IS_READABLE(ptr, out->size), S2N_ERR_NULL);
[ + - ]
282 : :
283 [ - + ][ # # ]: 193852 : POSIX_CHECKED_MEMCPY(out->data, ptr, out->size);
[ + - ]
284 [ - + ][ # # ]: 193852 : POSIX_CHECKED_MEMSET(ptr, 0, out->size);
[ + - ]
285 : :
286 : 193852 : return S2N_SUCCESS;
287 : 193852 : }
288 : :
289 : : int s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t *data, uint32_t size)
290 : 23504201 : {
291 [ + - ][ + + ]: 23504201 : POSIX_ENSURE_REF(data);
292 [ + + ][ + + ]: 23504199 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
293 [ + + ]: 23504198 : POSIX_GUARD(s2n_stuffer_skip_read(stuffer, size));
294 [ - + ][ # # ]: 23487540 : POSIX_ENSURE_REF(stuffer->blob.data);
295 : 23487540 : void *ptr = stuffer->blob.data + stuffer->read_cursor - size;
296 : :
297 [ - + ][ # # ]: 23487540 : POSIX_CHECKED_MEMCPY(data, ptr, size);
[ + + ]
298 : :
299 : 23487540 : return S2N_SUCCESS;
300 : 23487540 : }
301 : :
302 : : int s2n_stuffer_erase_and_read_bytes(struct s2n_stuffer *stuffer, uint8_t *data, uint32_t size)
303 : 7797 : {
304 [ - + ]: 7797 : POSIX_GUARD(s2n_stuffer_skip_read(stuffer, size));
305 [ - + ][ # # ]: 7797 : POSIX_ENSURE_REF(stuffer->blob.data);
306 : 7797 : void *ptr = stuffer->blob.data + stuffer->read_cursor - size;
307 : :
308 [ - + ][ # # ]: 7797 : POSIX_CHECKED_MEMCPY(data, ptr, size);
[ + - ]
309 [ - + ][ # # ]: 7797 : POSIX_CHECKED_MEMSET(ptr, 0, size);
[ + - ]
310 : :
311 : 7797 : return S2N_SUCCESS;
312 : 7797 : }
313 : :
314 : : int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n)
315 : 69245424 : {
316 [ - + ][ + + ]: 69245424 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
317 [ + + ]: 69245424 : POSIX_GUARD(s2n_stuffer_reserve_space(stuffer, n));
318 : 69227948 : stuffer->write_cursor += n;
319 : 69227948 : stuffer->high_water_mark = MAX(stuffer->write_cursor, stuffer->high_water_mark);
320 [ - + ][ + + ]: 69227948 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
321 : 69227948 : return S2N_SUCCESS;
322 : 69227948 : }
323 : :
324 : : void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, const uint32_t data_len)
325 : 7271993 : {
326 [ + + ]: 7271993 : PTR_GUARD_POSIX(s2n_stuffer_skip_write(stuffer, data_len));
327 : :
328 : 7271992 : stuffer->tainted = 1;
329 : :
330 [ + - ]: 7271992 : return (stuffer->blob.data) ? (stuffer->blob.data + stuffer->write_cursor - data_len) : NULL;
331 : 7271993 : }
332 : :
333 : : int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in)
334 : 559049 : {
335 [ + + ][ + + ]: 559049 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
336 [ - + ][ + - ]: 559047 : POSIX_PRECONDITION(s2n_blob_validate(in));
337 : 559047 : return s2n_stuffer_write_bytes(stuffer, in->data, in->size);
338 : 559047 : }
339 : :
340 : : int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t *data, const uint32_t size)
341 : 37869717 : {
342 [ + + ]: 37869717 : if (size == 0) {
343 : 124397 : return S2N_SUCCESS;
344 : 124397 : }
345 : :
346 [ # # ][ + + ]: 37745320 : POSIX_ENSURE(S2N_MEM_IS_READABLE(data, size), S2N_ERR_SAFETY);
[ + - ]
347 [ - + ][ + + ]: 37745320 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
348 [ + + ]: 37745320 : POSIX_GUARD(s2n_stuffer_skip_write(stuffer, size));
349 : :
350 : 37727850 : void *ptr = stuffer->blob.data + stuffer->write_cursor - size;
351 [ # # ][ + + ]: 37727850 : POSIX_ENSURE(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL);
[ + - ]
352 : :
353 [ + + ]: 37727850 : if (ptr == data) {
354 [ - + ][ + - ]: 8232 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
355 : 8232 : return S2N_SUCCESS;
356 : 8232 : }
357 : :
358 [ - + ][ # # ]: 37719618 : POSIX_CHECKED_MEMCPY(ptr, data, size);
[ + + ]
359 : :
360 [ - + ][ + + ]: 37719618 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
361 : 37719618 : return S2N_SUCCESS;
362 : 37719618 : }
363 : :
364 : : int s2n_stuffer_writev_bytes(struct s2n_stuffer *stuffer, const struct iovec *iov, size_t iov_count, uint32_t offs,
365 : : uint32_t size)
366 : 3605903 : {
367 [ - + ][ + - ]: 3605903 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
368 [ - + ][ # # ]: 3605903 : POSIX_ENSURE_REF(iov);
369 : 3605903 : void *ptr = s2n_stuffer_raw_write(stuffer, size);
370 [ # # ][ + + ]: 3605903 : POSIX_ENSURE(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL);
[ + - ]
371 : :
372 : 3605903 : size_t size_left = size, to_skip = offs;
373 [ + + ]: 3637358 : for (size_t i = 0; i < iov_count; i++) {
374 [ + + ]: 3637265 : if (to_skip >= iov[i].iov_len) {
375 : 31371 : to_skip -= iov[i].iov_len;
376 : 31371 : continue;
377 : 31371 : }
378 : 3605894 : size_t iov_len_op = iov[i].iov_len - to_skip;
379 [ - + ][ # # ]: 3605894 : POSIX_ENSURE_LTE(iov_len_op, UINT32_MAX);
380 : 3605894 : uint32_t iov_len = (uint32_t) iov_len_op;
381 : 3605894 : uint32_t iov_size_to_take = MIN(size_left, iov_len);
382 [ - + ][ # # ]: 3605894 : POSIX_ENSURE_REF(iov[i].iov_base);
383 [ - + ][ # # ]: 3605894 : POSIX_ENSURE_LT(to_skip, iov[i].iov_len);
384 [ - + ][ # # ]: 3605894 : POSIX_CHECKED_MEMCPY(ptr, ((uint8_t *) (iov[i].iov_base)) + to_skip, iov_size_to_take);
[ + - ]
385 : 3605894 : size_left -= iov_size_to_take;
386 [ + + ]: 3605894 : if (size_left == 0) {
387 : 3605810 : break;
388 : 3605810 : }
389 : 84 : ptr = (void *) ((uint8_t *) ptr + iov_size_to_take);
390 : 84 : to_skip = 0;
391 : 84 : }
392 : :
393 : 3605903 : return S2N_SUCCESS;
394 : 3605903 : }
395 : :
396 : : static int s2n_stuffer_copy_impl(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len)
397 : 7345210 : {
398 [ - + ]: 7345210 : POSIX_GUARD(s2n_stuffer_skip_read(from, len));
399 [ - + ]: 7345210 : POSIX_GUARD(s2n_stuffer_skip_write(to, len));
400 : :
401 [ + - ]: 7345210 : uint8_t *from_ptr = (from->blob.data) ? (from->blob.data + from->read_cursor - len) : NULL;
402 [ + - ]: 7345210 : uint8_t *to_ptr = (to->blob.data) ? (to->blob.data + to->write_cursor - len) : NULL;
403 : :
404 [ # # ][ - + ]: 7345210 : POSIX_CHECKED_MEMCPY(to_ptr, from_ptr, len);
[ + + ]
405 : :
406 : 7345210 : return S2N_SUCCESS;
407 : 7345210 : }
408 : :
409 : : int s2n_stuffer_reserve_space(struct s2n_stuffer *stuffer, uint32_t n)
410 : 70198118 : {
411 [ - + ][ + + ]: 70198118 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
412 [ + + ]: 70198118 : if (s2n_stuffer_space_remaining(stuffer) < n) {
413 [ + + ][ + - ]: 3507743 : POSIX_ENSURE(stuffer->growable, S2N_ERR_STUFFER_IS_FULL);
414 : : /* Always grow a stuffer by at least 1k */
415 : 3490266 : const uint32_t growth = MAX(n - s2n_stuffer_space_remaining(stuffer), S2N_MIN_STUFFER_GROWTH_IN_BYTES);
416 : 3490266 : uint32_t new_size = 0;
417 [ - + ]: 3490266 : POSIX_GUARD(s2n_add_overflow(stuffer->blob.size, growth, &new_size));
418 [ - + ]: 3490266 : POSIX_GUARD(s2n_stuffer_resize(stuffer, new_size));
419 : 3490266 : }
420 [ - + ][ + + ]: 70180641 : POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
421 : 70180641 : return S2N_SUCCESS;
422 : 70180641 : }
423 : :
424 : : /* Copies "len" bytes from "from" to "to".
425 : : * If the copy cannot succeed (i.e. there are either not enough bytes available, or there is not enough space to write them
426 : : * restore the old value of the stuffer */
427 : : int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len)
428 : 7345210 : {
429 : 7345210 : const uint32_t orig_read_cursor = from->read_cursor;
430 : 7345210 : const uint32_t orig_write_cursor = to->write_cursor;
431 : :
432 [ - + ]: 7345210 : if (s2n_stuffer_copy_impl(from, to, len) < 0) {
433 : 0 : from->read_cursor = orig_read_cursor;
434 : 0 : to->write_cursor = orig_write_cursor;
435 : 0 : S2N_ERROR_PRESERVE_ERRNO();
436 : 0 : }
437 : :
438 : 7345210 : return S2N_SUCCESS;
439 : 7345210 : }
440 : :
441 : : int s2n_stuffer_extract_blob(struct s2n_stuffer *stuffer, struct s2n_blob *out)
442 : 23 : {
443 [ - + ][ + - ]: 23 : POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
444 [ # # ][ - + ]: 23 : POSIX_ENSURE_REF(out);
445 [ - + ]: 23 : POSIX_GUARD(s2n_realloc(out, s2n_stuffer_data_available(stuffer)));
446 : :
447 [ + - ]: 23 : if (s2n_stuffer_data_available(stuffer) > 0) {
448 [ - + ][ # # ]: 23 : POSIX_CHECKED_MEMCPY(out->data, stuffer->blob.data + stuffer->read_cursor, s2n_stuffer_data_available(stuffer));
[ + - ]
449 : 23 : }
450 : :
451 [ - + ][ + - ]: 23 : POSIX_POSTCONDITION(s2n_blob_validate(out));
452 : 23 : return S2N_SUCCESS;
453 : 23 : }
454 : :
455 : : int s2n_stuffer_shift(struct s2n_stuffer *stuffer)
456 : 508 : {
457 [ + - ][ + + ]: 508 : POSIX_ENSURE_REF(stuffer);
458 : 507 : struct s2n_stuffer copy = *stuffer;
459 [ - + ]: 507 : POSIX_GUARD(s2n_stuffer_rewrite(©));
460 : :
461 : 507 : uint8_t *data = stuffer->blob.data;
462 : : /* Adding 0 to a NULL value is undefined behavior */
463 [ + + ]: 507 : if (stuffer->read_cursor != 0) {
464 : 505 : data += stuffer->read_cursor;
465 : 505 : }
466 : :
467 : 507 : uint32_t data_size = s2n_stuffer_data_available(stuffer);
468 [ - + ]: 507 : POSIX_GUARD(s2n_stuffer_write_bytes(©, data, data_size));
469 : 507 : *stuffer = copy;
470 : 507 : return S2N_SUCCESS;
471 : 507 : }
|