Skip to content

Commit

Permalink
Add aws_byte_buf_append_dynamic_secure (#649)
Browse files Browse the repository at this point in the history
* Add aws_byte_buf_append_dynamic_secure
* Added byte appends
  • Loading branch information
bretambrose authored Jun 29, 2020
1 parent 84409df commit 78dbfab
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 8 deletions.
33 changes: 33 additions & 0 deletions include/aws/common/byte_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,39 @@ int aws_byte_buf_append_with_lookup(
AWS_COMMON_API
int aws_byte_buf_append_dynamic(struct aws_byte_buf *to, const struct aws_byte_cursor *from);

/**
* Copies `from` to `to`. If `to` is too small, the buffer will be grown appropriately and
* the old contents copied over, before the new contents are appended.
*
* If the grow fails (overflow or OOM), then an error will be returned.
*
* If the buffer is grown, the old buffer will be securely cleared before getting freed.
*
* `from` and `to` may be the same buffer, permitting copying a buffer into itself.
*/
AWS_COMMON_API
int aws_byte_buf_append_dynamic_secure(struct aws_byte_buf *to, const struct aws_byte_cursor *from);

/**
* Copies a single byte into `to`. If `to` is too small, the buffer will be grown appropriately and
* the old contents copied over, before the byte is appended.
*
* If the grow fails (overflow or OOM), then an error will be returned.
*/
AWS_COMMON_API
int aws_byte_buf_append_byte_dynamic(struct aws_byte_buf *buffer, uint8_t value);

/**
* Copies a single byte into `to`. If `to` is too small, the buffer will be grown appropriately and
* the old contents copied over, before the byte is appended.
*
* If the grow fails (overflow or OOM), then an error will be returned.
*
* If the buffer is grown, the old buffer will be securely cleared before getting freed.
*/
AWS_COMMON_API
int aws_byte_buf_append_byte_dynamic_secure(struct aws_byte_buf *buffer, uint8_t value);

/**
* Copy contents of cursor to buffer, then update cursor to reference the memory stored in the buffer.
* If buffer is too small, AWS_ERROR_DEST_COPY_TOO_SMALL will be returned.
Expand Down
42 changes: 41 additions & 1 deletion source/byte_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,10 @@ int aws_byte_buf_append_with_lookup(
return AWS_OP_SUCCESS;
}

int aws_byte_buf_append_dynamic(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
static int s_aws_byte_buf_append_dynamic(
struct aws_byte_buf *to,
const struct aws_byte_cursor *from,
bool clear_released_memory) {
AWS_PRECONDITION(aws_byte_buf_is_valid(to));
AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
AWS_ERROR_PRECONDITION(to->allocator);
Expand Down Expand Up @@ -629,6 +632,11 @@ int aws_byte_buf_append_dynamic(struct aws_byte_buf *to, const struct aws_byte_c
if (from->len > 0) {
memcpy(new_buffer + to->len, from->ptr, from->len);
}

if (clear_released_memory) {
aws_secure_zero(to->buffer, to->capacity);
}

/*
* Get rid of the old buffer
*/
Expand All @@ -655,6 +663,38 @@ int aws_byte_buf_append_dynamic(struct aws_byte_buf *to, const struct aws_byte_c
return AWS_OP_SUCCESS;
}

int aws_byte_buf_append_dynamic(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
return s_aws_byte_buf_append_dynamic(to, from, false);
}

int aws_byte_buf_append_dynamic_secure(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
return s_aws_byte_buf_append_dynamic(to, from, true);
}

static int s_aws_byte_buf_append_byte_dynamic(struct aws_byte_buf *buffer, uint8_t value, bool clear_released_memory) {
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4221)
#endif /* _MSC_VER */

/* msvc isn't a fan of this pointer-to-local assignment */
struct aws_byte_cursor eq_cursor = {.len = 1, .ptr = &value};

#if defined(_MSC_VER)
# pragma warning(pop)
#endif /* _MSC_VER */

return s_aws_byte_buf_append_dynamic(buffer, &eq_cursor, clear_released_memory);
}

int aws_byte_buf_append_byte_dynamic(struct aws_byte_buf *buffer, uint8_t value) {
return s_aws_byte_buf_append_byte_dynamic(buffer, value, false);
}

int aws_byte_buf_append_byte_dynamic_secure(struct aws_byte_buf *buffer, uint8_t value) {
return s_aws_byte_buf_append_byte_dynamic(buffer, value, true);
}

int aws_byte_buf_reserve(struct aws_byte_buf *buffer, size_t requested_capacity) {
AWS_ERROR_PRECONDITION(buffer->allocator);
AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(buffer));
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ add_test_case(test_array_eq_c_str)
add_test_case(test_array_eq_c_str_ignore_case)
add_test_case(test_array_hash_ignore_case)
add_test_case(test_byte_buf_append_dynamic)
add_test_case(test_byte_buf_append_byte)
add_test_case(test_byte_buf_append_lookup_success)
add_test_case(test_byte_buf_append_lookup_failure)
add_test_case(test_byte_buf_reserve)
Expand Down
47 changes: 40 additions & 7 deletions tests/byte_buf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ static int s_do_append_dynamic_test(
struct aws_allocator *allocator,
size_t starting_size,
size_t append_size,
size_t iterations) {
size_t iterations,
int (*append_dynamic)(struct aws_byte_buf *, const struct aws_byte_cursor *)) {
struct aws_byte_buf accum_buf;
aws_byte_buf_init(&accum_buf, allocator, starting_size);
memset(accum_buf.buffer, 0, starting_size);
Expand All @@ -514,7 +515,7 @@ static int s_do_append_dynamic_test(
memset(accum_buf.buffer, 0, accum_buf.capacity);

size_t before_size = accum_buf.len;
ASSERT_TRUE(aws_byte_buf_append_dynamic(&accum_buf, &append_cursor) == AWS_OP_SUCCESS);
ASSERT_TRUE(append_dynamic(&accum_buf, &append_cursor) == AWS_OP_SUCCESS);
size_t after_size = accum_buf.len;

size_t expected_len = starting_size + (i + 1) * append_size;
Expand Down Expand Up @@ -546,17 +547,49 @@ static int s_test_byte_buf_append_dynamic(struct aws_allocator *allocator, void
(void)ctx;

/*
* Throw a small sample of different growth request profiles at the function
* Throw a small sample of different growth request profiles at the functions
*/
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 1, 10000, 1) == AWS_OP_SUCCESS);
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 1, 1, 1000) == AWS_OP_SUCCESS);
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 10000, 1, 2) == AWS_OP_SUCCESS);
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 100, 10, 100) == AWS_OP_SUCCESS);

/*
* regular append
*/
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 1, 10000, 1, aws_byte_buf_append_dynamic) == AWS_OP_SUCCESS);
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 1, 1, 1000, aws_byte_buf_append_dynamic) == AWS_OP_SUCCESS);
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 10000, 1, 2, aws_byte_buf_append_dynamic) == AWS_OP_SUCCESS);
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 100, 10, 100, aws_byte_buf_append_dynamic) == AWS_OP_SUCCESS);

/*
* secure append - note we don't attempt to check if the memory was actually zeroed
*/
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 1, 10000, 1, aws_byte_buf_append_dynamic_secure) == AWS_OP_SUCCESS);
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 1, 1, 1000, aws_byte_buf_append_dynamic_secure) == AWS_OP_SUCCESS);
ASSERT_TRUE(s_do_append_dynamic_test(allocator, 10000, 1, 2, aws_byte_buf_append_dynamic_secure) == AWS_OP_SUCCESS);
ASSERT_TRUE(
s_do_append_dynamic_test(allocator, 100, 10, 100, aws_byte_buf_append_dynamic_secure) == AWS_OP_SUCCESS);

return 0;
}
AWS_TEST_CASE(test_byte_buf_append_dynamic, s_test_byte_buf_append_dynamic)

static uint8_t s_append_byte_array[] = {0xFF, 0xFE, 0xAB, 0x00, 0x55, 0x62};

static int s_test_byte_buf_append_byte(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

struct aws_byte_buf buffer;
aws_byte_buf_init(&buffer, allocator, 1);

for (size_t i = 0; i < AWS_ARRAY_SIZE(s_append_byte_array); ++i) {
ASSERT_SUCCESS(aws_byte_buf_append_byte_dynamic(&buffer, s_append_byte_array[i]));
ASSERT_BIN_ARRAYS_EQUALS(s_append_byte_array, i + 1, buffer.buffer, buffer.len);
}

aws_byte_buf_clean_up(&buffer);

return 0;
}
AWS_TEST_CASE(test_byte_buf_append_byte, s_test_byte_buf_append_byte)

AWS_STATIC_STRING_FROM_LITERAL(s_to_lower_test, "UPPerANdLowercASE");

static int s_test_byte_buf_append_lookup_success(struct aws_allocator *allocator, void *ctx) {
Expand Down

0 comments on commit 78dbfab

Please sign in to comment.