| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * Container Security Monitor module | |
| * | |
| * Copyright (c) 2018 Google, Inc | |
| */ | |
| #include "monitor.h" | |
| #include <linux/string.h> | |
| #include <net/tcp.h> | |
| #include <net/ipv6.h> | |
| bool pb_encode_string_field(pb_ostream_t *stream, const pb_field_t *field, | |
| void * const *arg) | |
| { | |
| const uint8_t *str = (const uint8_t *)*arg; | |
| /* If the string is not set, skip this string. */ | |
| if (!str) | |
| return true; | |
| if (!pb_encode_tag_for_field(stream, field)) | |
| return false; | |
| return pb_encode_string(stream, str, strlen(str)); | |
| } | |
| bool pb_decode_string_field(pb_istream_t *stream, const pb_field_t *field, | |
| void **arg) | |
| { | |
| size_t size; | |
| void *data; | |
| *arg = NULL; | |
| size = stream->bytes_left; | |
| /* Ensure a null-byte at the end */ | |
| if (size + 1 < size) | |
| return false; | |
| data = kzalloc(size + 1, GFP_KERNEL); | |
| if (!data) | |
| return false; | |
| if (!pb_read(stream, data, size)) { | |
| kfree(data); | |
| return false; | |
| } | |
| *arg = data; | |
| return true; | |
| } | |
| bool pb_encode_string_array(pb_ostream_t *stream, const pb_field_t *field, | |
| void * const *arg) | |
| { | |
| char *strs = (char *)*arg; | |
| /* If the string array is not set, skip this string array. */ | |
| if (!strs) | |
| return true; | |
| do { | |
| if (!pb_encode_string_field(stream, field, | |
| (void * const *) &strs)) | |
| return false; | |
| strs += strlen(strs) + 1; | |
| } while (*strs != 0); | |
| return true; | |
| } | |
| /* Limit the encoded string size and return how many characters were added. */ | |
| ssize_t pb_encode_string_field_limit(pb_ostream_t *stream, | |
| const pb_field_t *field, | |
| void * const *arg, size_t limit) | |
| { | |
| char *str = (char *)*arg; | |
| size_t length; | |
| /* If the string is not set, skip this string. */ | |
| if (!str) | |
| return 0; | |
| if (!pb_encode_tag_for_field(stream, field)) | |
| return -EINVAL; | |
| length = strlen(str); | |
| if (length > limit) | |
| length = limit; | |
| if (!pb_encode_string(stream, (uint8_t *)str, length)) | |
| return -EINVAL; | |
| return length; | |
| } | |
| bool pb_decode_string_array(pb_istream_t *stream, const pb_field_t *field, | |
| void **arg) | |
| { | |
| size_t needed, used = 0; | |
| char *data, *strs; | |
| /* String length, and two null-bytes for the end of the list. */ | |
| needed = stream->bytes_left + 2; | |
| if (needed < stream->bytes_left) | |
| return false; | |
| if (*arg) { | |
| /* Calculate used space from the current list. */ | |
| strs = (char *)*arg; | |
| do { | |
| used += strlen(strs + used) + 1; | |
| } while (strs[used] != 0); | |
| if (used + needed < needed) | |
| return false; | |
| } | |
| data = krealloc(*arg, used + needed, GFP_KERNEL); | |
| if (!data) | |
| return false; | |
| /* Will always be freed by the caller */ | |
| *arg = data; | |
| /* Reset the new part of the buffer. */ | |
| memset(data + used, 0, needed); | |
| /* Read what's in the stream buffer only. */ | |
| if (!pb_read(stream, data + used, stream->bytes_left)) | |
| return false; | |
| return true; | |
| } | |
| bool pb_encode_fixed_string(pb_ostream_t *stream, const pb_field_t *field, | |
| const uint8_t *data, size_t length) | |
| { | |
| /* If the data is not set, skip this string. */ | |
| if (!data) | |
| return true; | |
| if (!pb_encode_tag_for_field(stream, field)) | |
| return false; | |
| return pb_encode_string(stream, data, length); | |
| } | |
| bool pb_encode_uuid_field(pb_ostream_t *stream, const pb_field_t *field, | |
| void * const *arg) | |
| { | |
| return pb_encode_fixed_string(stream, field, (const uint8_t *)*arg, | |
| PROCESS_UUID_SIZE); | |
| } | |
| bool pb_encode_ip4(pb_ostream_t *stream, const pb_field_t *field, | |
| void * const *arg) | |
| { | |
| return pb_encode_fixed_string(stream, field, (const uint8_t *)*arg, | |
| sizeof(struct in_addr)); | |
| } | |
| bool pb_encode_ip6(pb_ostream_t *stream, const pb_field_t *field, | |
| void * const *arg) | |
| { | |
| return pb_encode_fixed_string(stream, field, (const uint8_t *)*arg, | |
| sizeof(struct in6_addr)); | |
| } |