| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Container Security Monitor module |
| * |
| * Copyright (c) 2018 Google, Inc |
| */ |
| |
| #include "monitor.h" |
| |
| #include <linux/string.h> |
| #include <net/sock.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)); |
| } |