diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c')
-rw-r--r-- | contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c | 822 |
1 files changed, 411 insertions, 411 deletions
diff --git a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c index 04ced5b229..026a909850 100644 --- a/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c +++ b/contrib/restricted/aws/s2n/stuffer/s2n_stuffer.c @@ -1,411 +1,411 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <sys/param.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" -#include "utils/s2n_mem.h" - -S2N_RESULT s2n_stuffer_validate(const struct s2n_stuffer* stuffer) -{ - /** - * Note that we do not assert any properties on the alloced, growable, and tainted fields, - * as all possible combinations of boolean values in those fields are valid. - */ - ENSURE_REF(stuffer); - GUARD_RESULT(s2n_blob_validate(&stuffer->blob)); - - /* <= is valid because we can have a fully written/read stuffer */ - DEBUG_ENSURE(stuffer->high_water_mark <= stuffer->blob.size, S2N_ERR_SAFETY); - DEBUG_ENSURE(stuffer->write_cursor <= stuffer->high_water_mark, S2N_ERR_SAFETY); - DEBUG_ENSURE(stuffer->read_cursor <= stuffer->write_cursor, S2N_ERR_SAFETY); - return S2N_RESULT_OK; -} - -S2N_RESULT s2n_stuffer_reservation_validate(const struct s2n_stuffer_reservation* reservation) -{ - /** - * Note that we need two dereferences here to decrease proof complexity - * for CBMC (see https://github.com/awslabs/s2n/issues/2290). We can roll back - * this change once CBMC can handle common subexpression elimination. - */ - ENSURE_REF(reservation); - const struct s2n_stuffer_reservation reserve_obj = *reservation; - GUARD_RESULT(s2n_stuffer_validate(reserve_obj.stuffer)); - const struct s2n_stuffer stuffer_obj = *(reserve_obj.stuffer); - ENSURE(stuffer_obj.blob.size >= reserve_obj.length, S2N_ERR_SAFETY); - - if (reserve_obj.length > 0) { - ENSURE(reserve_obj.write_cursor < stuffer_obj.write_cursor, S2N_ERR_SAFETY); - ENSURE( - S2N_MEM_IS_WRITABLE(stuffer_obj.blob.data + reserve_obj.write_cursor, reserve_obj.length), - S2N_ERR_SAFETY - ); - } - - return S2N_RESULT_OK; -} - -int s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in) -{ - ENSURE_POSIX_MUT(stuffer); - PRECONDITION_POSIX(s2n_blob_validate(in)); - stuffer->blob = *in; - stuffer->read_cursor = 0; - stuffer->write_cursor = 0; - stuffer->high_water_mark = 0; - stuffer->alloced = 0; - stuffer->growable = 0; - stuffer->tainted = 0; - return S2N_SUCCESS; -} - -int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size) -{ - notnull_check(stuffer); - *stuffer = (struct s2n_stuffer) {0}; - GUARD(s2n_alloc(&stuffer->blob, size)); - GUARD(s2n_stuffer_init(stuffer, &stuffer->blob)); - - stuffer->alloced = 1; - - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, const uint32_t size) -{ - GUARD(s2n_stuffer_alloc(stuffer, size)); - - stuffer->growable = 1; - - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_free(struct s2n_stuffer *stuffer) -{ - if (stuffer != NULL) { - if (stuffer->alloced) { - GUARD(s2n_free(&stuffer->blob)); - } - *stuffer = (struct s2n_stuffer) {0}; - } - return S2N_SUCCESS; -} - -int s2n_stuffer_resize(struct s2n_stuffer *stuffer, const uint32_t size) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - ENSURE_POSIX(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER); - ENSURE_POSIX(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER); - - if (size == stuffer->blob.size) { - return S2N_SUCCESS; - } - - if (size == 0) { - s2n_stuffer_wipe(stuffer); - return s2n_free(&stuffer->blob); - } - - if (size < stuffer->blob.size) { - memset_check(stuffer->blob.data + size, S2N_WIPE_PATTERN, (stuffer->blob.size - size)); - if (stuffer->read_cursor > size) stuffer->read_cursor = size; - if (stuffer->write_cursor > size) stuffer->write_cursor = size; - if (stuffer->high_water_mark > size) stuffer->high_water_mark = size; - stuffer->blob.size = size; - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; - } - - GUARD(s2n_realloc(&stuffer->blob, size)); - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_resize_if_empty(struct s2n_stuffer *stuffer, const uint32_t size) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - if (stuffer->blob.data == NULL) { - ENSURE_POSIX(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER); - ENSURE_POSIX(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER); - GUARD(s2n_realloc(&stuffer->blob, size)); - } - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_rewrite(struct s2n_stuffer *stuffer) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - stuffer->write_cursor = 0; - stuffer->read_cursor = 0; - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_rewind_read(struct s2n_stuffer *stuffer, const uint32_t size) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - ENSURE_POSIX(stuffer->read_cursor >= size, S2N_ERR_STUFFER_OUT_OF_DATA); - stuffer->read_cursor -= size; - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_reread(struct s2n_stuffer *stuffer) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - stuffer->read_cursor = 0; - return S2N_SUCCESS; -} - -int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t size) -{ - if (size >= stuffer->write_cursor) { - return s2n_stuffer_wipe(stuffer); - } - - /* We know that size is now less than write_cursor */ - stuffer->write_cursor -= size; - memset_check(stuffer->blob.data + stuffer->write_cursor, S2N_WIPE_PATTERN, size); - stuffer->read_cursor = MIN(stuffer->read_cursor, stuffer->write_cursor); - - return S2N_SUCCESS; -} - -bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer) { - return stuffer && (stuffer->read_cursor == stuffer->write_cursor); -} - -int s2n_stuffer_wipe(struct s2n_stuffer *stuffer) -{ - if (!s2n_stuffer_is_wiped(stuffer)) { - memset_check(stuffer->blob.data, S2N_WIPE_PATTERN, stuffer->high_water_mark); - } - - stuffer->tainted = 0; - stuffer->write_cursor = 0; - stuffer->read_cursor = 0; - stuffer->high_water_mark = 0; - return S2N_SUCCESS; -} - -int s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - S2N_ERROR_IF(s2n_stuffer_data_available(stuffer) < n, S2N_ERR_STUFFER_OUT_OF_DATA); - - stuffer->read_cursor += n; - return S2N_SUCCESS; -} - -void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len) -{ - GUARD_PTR(s2n_stuffer_skip_read(stuffer, data_len)); - - stuffer->tainted = 1; - - return stuffer->blob.data + stuffer->read_cursor - data_len; -} - -int s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out) -{ - notnull_check(out); - - return s2n_stuffer_read_bytes(stuffer, out->data, out->size); -} - -int s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out) -{ - GUARD(s2n_stuffer_skip_read(stuffer, out->size)); - - void *ptr = stuffer->blob.data + stuffer->read_cursor - out->size; - ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, out->size), S2N_ERR_NULL); - - memcpy_check(out->data, ptr, out->size); - memset_check(ptr, 0, out->size); - - return S2N_SUCCESS; -} - -int s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size) -{ - notnull_check(data); - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - GUARD(s2n_stuffer_skip_read(stuffer, size)); - notnull_check(stuffer->blob.data); - void *ptr = stuffer->blob.data + stuffer->read_cursor - size; - - memcpy_check(data, ptr, size); - - return S2N_SUCCESS; -} - -int s2n_stuffer_erase_and_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size) -{ - GUARD(s2n_stuffer_skip_read(stuffer, size)); - notnull_check(stuffer->blob.data); - void *ptr = stuffer->blob.data + stuffer->read_cursor - size; - - memcpy_check(data, ptr, size); - memset_check(ptr, 0, size); - - return S2N_SUCCESS; -} - -int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - GUARD(s2n_stuffer_reserve_space(stuffer, n)); - stuffer->write_cursor += n; - stuffer->high_water_mark = MAX(stuffer->write_cursor, stuffer->high_water_mark); - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, const uint32_t data_len) -{ - GUARD_PTR(s2n_stuffer_skip_write(stuffer, data_len)); - - stuffer->tainted = 1; - - return stuffer->blob.data + stuffer->write_cursor - data_len; -} - -int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - PRECONDITION_POSIX(s2n_blob_validate(in)); - return s2n_stuffer_write_bytes(stuffer, in->data, in->size); -} - -int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t * data, const uint32_t size) -{ - ENSURE_POSIX(S2N_MEM_IS_READABLE(data, size), S2N_ERR_SAFETY); - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - GUARD(s2n_stuffer_skip_write(stuffer, size)); - - void *ptr = stuffer->blob.data + stuffer->write_cursor - size; - ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL); - - if (ptr == data) { - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; - } - - memcpy_check(ptr, data, size); - - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -int s2n_stuffer_writev_bytes(struct s2n_stuffer *stuffer, const struct iovec* iov, size_t iov_count, uint32_t offs, uint32_t size) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - notnull_check(iov); - void *ptr = s2n_stuffer_raw_write(stuffer, size); - ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL); - - size_t size_left = size, to_skip = offs; - for (int i = 0; i < iov_count; i++) { - if (to_skip >= iov[i].iov_len) { - to_skip -= iov[i].iov_len; - continue; - } - size_t iov_len_op = iov[i].iov_len - to_skip; - ENSURE_POSIX(iov_len_op <= UINT32_MAX, S2N_FAILURE); - uint32_t iov_len = (uint32_t)iov_len_op; - uint32_t iov_size_to_take = MIN(size_left, iov_len); - notnull_check(iov[i].iov_base); - ENSURE_POSIX(to_skip < iov[i].iov_len, S2N_FAILURE); - memcpy_check(ptr, ((uint8_t*)(iov[i].iov_base)) + to_skip, iov_size_to_take); - size_left -= iov_size_to_take; - if (size_left == 0) { - break; - } - ptr = (void*)((uint8_t*)ptr + iov_size_to_take); - to_skip = 0; - } - - return S2N_SUCCESS; -} - -static int s2n_stuffer_copy_impl(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len) -{ - GUARD(s2n_stuffer_skip_read(from, len)); - GUARD(s2n_stuffer_skip_write(to, len)); - - uint8_t *from_ptr = from->blob.data + from->read_cursor - len; - uint8_t *to_ptr = to->blob.data + to->write_cursor - len; - - memcpy_check(to_ptr, from_ptr, len); - - return S2N_SUCCESS; -} - -int s2n_stuffer_reserve_space(struct s2n_stuffer *stuffer, uint32_t n) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - if (s2n_stuffer_space_remaining(stuffer) < n) { - S2N_ERROR_IF(!stuffer->growable, S2N_ERR_STUFFER_IS_FULL); - /* Always grow a stuffer by at least 1k */ - const uint32_t growth = MAX(n - s2n_stuffer_space_remaining(stuffer), S2N_MIN_STUFFER_GROWTH_IN_BYTES); - uint32_t new_size = 0; - GUARD(s2n_add_overflow(stuffer->blob.size, growth, &new_size)); - GUARD(s2n_stuffer_resize(stuffer, new_size)); - } - POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); - return S2N_SUCCESS; -} - -/* Copies "len" bytes from "from" to "to". - * If the copy cannot succeed (i.e. there are either not enough bytes available, or there is not enough space to write them - * restore the old value of the stuffer */ -int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len) -{ - const uint32_t orig_read_cursor = from->read_cursor; - const uint32_t orig_write_cursor = to->write_cursor; - - if (s2n_stuffer_copy_impl(from, to, len) < 0) { - from->read_cursor = orig_read_cursor; - to->write_cursor = orig_write_cursor; - S2N_ERROR_PRESERVE_ERRNO(); - } - - return S2N_SUCCESS; -} - -int s2n_stuffer_extract_blob(struct s2n_stuffer *stuffer, struct s2n_blob *out) -{ - PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); - notnull_check(out); - GUARD(s2n_realloc(out , s2n_stuffer_data_available(stuffer))); - - if (s2n_stuffer_data_available(stuffer) > 0) { - memcpy_check(out->data, - stuffer->blob.data + stuffer->read_cursor, - s2n_stuffer_data_available(stuffer)); - } - - POSTCONDITION_POSIX(s2n_blob_validate(out)); - return S2N_SUCCESS; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <sys/param.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_mem.h" + +S2N_RESULT s2n_stuffer_validate(const struct s2n_stuffer* stuffer) +{ + /** + * Note that we do not assert any properties on the alloced, growable, and tainted fields, + * as all possible combinations of boolean values in those fields are valid. + */ + ENSURE_REF(stuffer); + GUARD_RESULT(s2n_blob_validate(&stuffer->blob)); + + /* <= is valid because we can have a fully written/read stuffer */ + DEBUG_ENSURE(stuffer->high_water_mark <= stuffer->blob.size, S2N_ERR_SAFETY); + DEBUG_ENSURE(stuffer->write_cursor <= stuffer->high_water_mark, S2N_ERR_SAFETY); + DEBUG_ENSURE(stuffer->read_cursor <= stuffer->write_cursor, S2N_ERR_SAFETY); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_stuffer_reservation_validate(const struct s2n_stuffer_reservation* reservation) +{ + /** + * Note that we need two dereferences here to decrease proof complexity + * for CBMC (see https://github.com/awslabs/s2n/issues/2290). We can roll back + * this change once CBMC can handle common subexpression elimination. + */ + ENSURE_REF(reservation); + const struct s2n_stuffer_reservation reserve_obj = *reservation; + GUARD_RESULT(s2n_stuffer_validate(reserve_obj.stuffer)); + const struct s2n_stuffer stuffer_obj = *(reserve_obj.stuffer); + ENSURE(stuffer_obj.blob.size >= reserve_obj.length, S2N_ERR_SAFETY); + + if (reserve_obj.length > 0) { + ENSURE(reserve_obj.write_cursor < stuffer_obj.write_cursor, S2N_ERR_SAFETY); + ENSURE( + S2N_MEM_IS_WRITABLE(stuffer_obj.blob.data + reserve_obj.write_cursor, reserve_obj.length), + S2N_ERR_SAFETY + ); + } + + return S2N_RESULT_OK; +} + +int s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in) +{ + ENSURE_POSIX_MUT(stuffer); + PRECONDITION_POSIX(s2n_blob_validate(in)); + stuffer->blob = *in; + stuffer->read_cursor = 0; + stuffer->write_cursor = 0; + stuffer->high_water_mark = 0; + stuffer->alloced = 0; + stuffer->growable = 0; + stuffer->tainted = 0; + return S2N_SUCCESS; +} + +int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size) +{ + notnull_check(stuffer); + *stuffer = (struct s2n_stuffer) {0}; + GUARD(s2n_alloc(&stuffer->blob, size)); + GUARD(s2n_stuffer_init(stuffer, &stuffer->blob)); + + stuffer->alloced = 1; + + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, const uint32_t size) +{ + GUARD(s2n_stuffer_alloc(stuffer, size)); + + stuffer->growable = 1; + + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_free(struct s2n_stuffer *stuffer) +{ + if (stuffer != NULL) { + if (stuffer->alloced) { + GUARD(s2n_free(&stuffer->blob)); + } + *stuffer = (struct s2n_stuffer) {0}; + } + return S2N_SUCCESS; +} + +int s2n_stuffer_resize(struct s2n_stuffer *stuffer, const uint32_t size) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + ENSURE_POSIX(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER); + ENSURE_POSIX(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER); + + if (size == stuffer->blob.size) { + return S2N_SUCCESS; + } + + if (size == 0) { + s2n_stuffer_wipe(stuffer); + return s2n_free(&stuffer->blob); + } + + if (size < stuffer->blob.size) { + memset_check(stuffer->blob.data + size, S2N_WIPE_PATTERN, (stuffer->blob.size - size)); + if (stuffer->read_cursor > size) stuffer->read_cursor = size; + if (stuffer->write_cursor > size) stuffer->write_cursor = size; + if (stuffer->high_water_mark > size) stuffer->high_water_mark = size; + stuffer->blob.size = size; + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; + } + + GUARD(s2n_realloc(&stuffer->blob, size)); + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_resize_if_empty(struct s2n_stuffer *stuffer, const uint32_t size) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + if (stuffer->blob.data == NULL) { + ENSURE_POSIX(!stuffer->tainted, S2N_ERR_RESIZE_TAINTED_STUFFER); + ENSURE_POSIX(stuffer->growable, S2N_ERR_RESIZE_STATIC_STUFFER); + GUARD(s2n_realloc(&stuffer->blob, size)); + } + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_rewrite(struct s2n_stuffer *stuffer) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + stuffer->write_cursor = 0; + stuffer->read_cursor = 0; + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_rewind_read(struct s2n_stuffer *stuffer, const uint32_t size) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + ENSURE_POSIX(stuffer->read_cursor >= size, S2N_ERR_STUFFER_OUT_OF_DATA); + stuffer->read_cursor -= size; + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_reread(struct s2n_stuffer *stuffer) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + stuffer->read_cursor = 0; + return S2N_SUCCESS; +} + +int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t size) +{ + if (size >= stuffer->write_cursor) { + return s2n_stuffer_wipe(stuffer); + } + + /* We know that size is now less than write_cursor */ + stuffer->write_cursor -= size; + memset_check(stuffer->blob.data + stuffer->write_cursor, S2N_WIPE_PATTERN, size); + stuffer->read_cursor = MIN(stuffer->read_cursor, stuffer->write_cursor); + + return S2N_SUCCESS; +} + +bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer) { + return stuffer && (stuffer->read_cursor == stuffer->write_cursor); +} + +int s2n_stuffer_wipe(struct s2n_stuffer *stuffer) +{ + if (!s2n_stuffer_is_wiped(stuffer)) { + memset_check(stuffer->blob.data, S2N_WIPE_PATTERN, stuffer->high_water_mark); + } + + stuffer->tainted = 0; + stuffer->write_cursor = 0; + stuffer->read_cursor = 0; + stuffer->high_water_mark = 0; + return S2N_SUCCESS; +} + +int s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + S2N_ERROR_IF(s2n_stuffer_data_available(stuffer) < n, S2N_ERR_STUFFER_OUT_OF_DATA); + + stuffer->read_cursor += n; + return S2N_SUCCESS; +} + +void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len) +{ + GUARD_PTR(s2n_stuffer_skip_read(stuffer, data_len)); + + stuffer->tainted = 1; + + return stuffer->blob.data + stuffer->read_cursor - data_len; +} + +int s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out) +{ + notnull_check(out); + + return s2n_stuffer_read_bytes(stuffer, out->data, out->size); +} + +int s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out) +{ + GUARD(s2n_stuffer_skip_read(stuffer, out->size)); + + void *ptr = stuffer->blob.data + stuffer->read_cursor - out->size; + ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, out->size), S2N_ERR_NULL); + + memcpy_check(out->data, ptr, out->size); + memset_check(ptr, 0, out->size); + + return S2N_SUCCESS; +} + +int s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size) +{ + notnull_check(data); + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + GUARD(s2n_stuffer_skip_read(stuffer, size)); + notnull_check(stuffer->blob.data); + void *ptr = stuffer->blob.data + stuffer->read_cursor - size; + + memcpy_check(data, ptr, size); + + return S2N_SUCCESS; +} + +int s2n_stuffer_erase_and_read_bytes(struct s2n_stuffer *stuffer, uint8_t * data, uint32_t size) +{ + GUARD(s2n_stuffer_skip_read(stuffer, size)); + notnull_check(stuffer->blob.data); + void *ptr = stuffer->blob.data + stuffer->read_cursor - size; + + memcpy_check(data, ptr, size); + memset_check(ptr, 0, size); + + return S2N_SUCCESS; +} + +int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + GUARD(s2n_stuffer_reserve_space(stuffer, n)); + stuffer->write_cursor += n; + stuffer->high_water_mark = MAX(stuffer->write_cursor, stuffer->high_water_mark); + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, const uint32_t data_len) +{ + GUARD_PTR(s2n_stuffer_skip_write(stuffer, data_len)); + + stuffer->tainted = 1; + + return stuffer->blob.data + stuffer->write_cursor - data_len; +} + +int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + PRECONDITION_POSIX(s2n_blob_validate(in)); + return s2n_stuffer_write_bytes(stuffer, in->data, in->size); +} + +int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t * data, const uint32_t size) +{ + ENSURE_POSIX(S2N_MEM_IS_READABLE(data, size), S2N_ERR_SAFETY); + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + GUARD(s2n_stuffer_skip_write(stuffer, size)); + + void *ptr = stuffer->blob.data + stuffer->write_cursor - size; + ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL); + + if (ptr == data) { + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; + } + + memcpy_check(ptr, data, size); + + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +int s2n_stuffer_writev_bytes(struct s2n_stuffer *stuffer, const struct iovec* iov, size_t iov_count, uint32_t offs, uint32_t size) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + notnull_check(iov); + void *ptr = s2n_stuffer_raw_write(stuffer, size); + ENSURE_POSIX(S2N_MEM_IS_READABLE(ptr, size), S2N_ERR_NULL); + + size_t size_left = size, to_skip = offs; + for (int i = 0; i < iov_count; i++) { + if (to_skip >= iov[i].iov_len) { + to_skip -= iov[i].iov_len; + continue; + } + size_t iov_len_op = iov[i].iov_len - to_skip; + ENSURE_POSIX(iov_len_op <= UINT32_MAX, S2N_FAILURE); + uint32_t iov_len = (uint32_t)iov_len_op; + uint32_t iov_size_to_take = MIN(size_left, iov_len); + notnull_check(iov[i].iov_base); + ENSURE_POSIX(to_skip < iov[i].iov_len, S2N_FAILURE); + memcpy_check(ptr, ((uint8_t*)(iov[i].iov_base)) + to_skip, iov_size_to_take); + size_left -= iov_size_to_take; + if (size_left == 0) { + break; + } + ptr = (void*)((uint8_t*)ptr + iov_size_to_take); + to_skip = 0; + } + + return S2N_SUCCESS; +} + +static int s2n_stuffer_copy_impl(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len) +{ + GUARD(s2n_stuffer_skip_read(from, len)); + GUARD(s2n_stuffer_skip_write(to, len)); + + uint8_t *from_ptr = from->blob.data + from->read_cursor - len; + uint8_t *to_ptr = to->blob.data + to->write_cursor - len; + + memcpy_check(to_ptr, from_ptr, len); + + return S2N_SUCCESS; +} + +int s2n_stuffer_reserve_space(struct s2n_stuffer *stuffer, uint32_t n) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + if (s2n_stuffer_space_remaining(stuffer) < n) { + S2N_ERROR_IF(!stuffer->growable, S2N_ERR_STUFFER_IS_FULL); + /* Always grow a stuffer by at least 1k */ + const uint32_t growth = MAX(n - s2n_stuffer_space_remaining(stuffer), S2N_MIN_STUFFER_GROWTH_IN_BYTES); + uint32_t new_size = 0; + GUARD(s2n_add_overflow(stuffer->blob.size, growth, &new_size)); + GUARD(s2n_stuffer_resize(stuffer, new_size)); + } + POSTCONDITION_POSIX(s2n_stuffer_validate(stuffer)); + return S2N_SUCCESS; +} + +/* Copies "len" bytes from "from" to "to". + * If the copy cannot succeed (i.e. there are either not enough bytes available, or there is not enough space to write them + * restore the old value of the stuffer */ +int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, const uint32_t len) +{ + const uint32_t orig_read_cursor = from->read_cursor; + const uint32_t orig_write_cursor = to->write_cursor; + + if (s2n_stuffer_copy_impl(from, to, len) < 0) { + from->read_cursor = orig_read_cursor; + to->write_cursor = orig_write_cursor; + S2N_ERROR_PRESERVE_ERRNO(); + } + + return S2N_SUCCESS; +} + +int s2n_stuffer_extract_blob(struct s2n_stuffer *stuffer, struct s2n_blob *out) +{ + PRECONDITION_POSIX(s2n_stuffer_validate(stuffer)); + notnull_check(out); + GUARD(s2n_realloc(out , s2n_stuffer_data_available(stuffer))); + + if (s2n_stuffer_data_available(stuffer) > 0) { + memcpy_check(out->data, + stuffer->blob.data + stuffer->read_cursor, + s2n_stuffer_data_available(stuffer)); + } + + POSTCONDITION_POSIX(s2n_blob_validate(out)); + return S2N_SUCCESS; +} |