1/* 2 * Copyright 2019, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <camkes/error.h> 14 15#define ERR_IF_BUFFER_LENGTH_EXCEEDED(size, curr_offset, desired, method, \ 16 param) \ 17 ERR_IF((desired) > ((size) - (curr_offset)), CAMKES_ERROR_HANDLER, \ 18 ((camkes_error_t){ \ 19 .type = CE_BUFFER_LENGTH_EXCEEDED, \ 20 .instance = CAMKES_INSTANCE_NAME, \ 21 .interface = CAMKES_INTERFACE_NAME, \ 22 .description = \ 23 "buffer exceeded while marshalling " param " in " method, \ 24 .current_length = curr_offset, \ 25 .target_length = curr_offset + desired, \ 26 }), \ 27 ({ return UINT_MAX; })); 28 29#define ERR_IF_MALFORMED_RPC_PAYLOAD(size, curr_offset, desired, method, \ 30 param, cleanup_action) \ 31 ERR_IF((desired) > ((size) - (curr_offset)), CAMKES_ERROR_HANDLER, \ 32 ((camkes_error_t){ \ 33 .type = CE_MALFORMED_RPC_PAYLOAD, \ 34 .instance = CAMKES_INSTANCE_NAME, \ 35 .interface = CAMKES_INTERFACE_NAME, \ 36 .description = \ 37 "truncated message encountered while unmarshalling " param \ 38 " for " method, \ 39 .length = (size), \ 40 .current_index = (curr_offset) + (desired), \ 41 }), \ 42 ({ cleanup_action; })); 43 44#define ERR_IF_MALFORMED_RPC_EXCESS_PAYLOAD(size, received_length, method, \ 45 cleanup_action) \ 46 ERR_IF(ROUND_UP_UNSAFE((received_length), sizeof(seL4_Word)) != (size), \ 47 CAMKES_ERROR_HANDLER, \ 48 ((camkes_error_t){ \ 49 .type = CE_MALFORMED_RPC_PAYLOAD, \ 50 .instance = CAMKES_INSTANCE_NAME, \ 51 .interface = CAMKES_INTERFACE_NAME, \ 52 .description = "excess trailing bytes after unmarshalling " \ 53 "parameters for " method, \ 54 .length = (size), \ 55 .current_index = (received_length), \ 56 }), \ 57 ({ cleanup_action; })); 58 59#define ERR_IF_ALLOCATION_FAILURE(result, size, method, param, cleanup_action) \ 60 ERR_IF((result) == NULL, CAMKES_ERROR_HANDLER, \ 61 ((camkes_error_t){ \ 62 .type = CE_ALLOCATION_FAILURE, \ 63 .instance = CAMKES_INSTANCE_NAME, \ 64 .interface = CAMKES_INTERFACE_NAME, \ 65 .description = \ 66 "out of memory while unmarshalling " param " for " method, \ 67 .alloc_bytes = (size), \ 68 }), \ 69 ({ cleanup_action; })); 70 71#define MARSHAL_ARRAY_PARAM(ptr, ptr_sz, buffer, size, length, method_name, \ 72 param_name) \ 73 ({ \ 74 ERR_IF_BUFFER_LENGTH_EXCEEDED(size, length, sizeof(*ptr_sz), method_name, \ 75 param_name); \ 76 memcpy(buffer + length, ptr_sz, sizeof(*ptr_sz)); \ 77 length += sizeof(*ptr_sz); \ 78 ERR_IF_BUFFER_LENGTH_EXCEEDED(size, length, (sizeof(ptr[0]) * (*ptr_sz)), \ 79 method_name, param_name); \ 80 memcpy(buffer + length, ptr, (sizeof(ptr[0]) * (*ptr_sz))); \ 81 length + (sizeof(ptr[0]) * (*ptr_sz)); \ 82 }) 83 84#define MARSHAL_STRING_ARRAY_PARAM(ptr, ptr_sz, buffer, size, length, \ 85 method_name, param_name) \ 86 ({ \ 87 ERR_IF_BUFFER_LENGTH_EXCEEDED(size, length, sizeof(*ptr_sz), method_name, \ 88 param_name); \ 89 memcpy(buffer + length, ptr_sz, sizeof(*ptr_sz)); \ 90 length += sizeof(*ptr_sz); \ 91 for (int __i = 0; __i < *ptr_sz; __i++) { \ 92 size_t __strlen = strnlen(ptr[__i], size - length); \ 93 ERR_IF_BUFFER_LENGTH_EXCEEDED(size, length, (__strlen + 1), method_name, \ 94 param_name) \ 95 /* If we didn't trigger an error, we now know this strcpy is safe. */ \ 96 (void)strcpy(buffer + length, ptr[__i]); \ 97 length += (__strlen + 1); \ 98 } \ 99 length; \ 100 }) 101 102#define MARSHAL_STRING_PARAM(ptr, buffer, size, length, method_name, \ 103 param_name) \ 104 ({ \ 105 size_t __strlen = strnlen(ptr, size - length); \ 106 ERR_IF_BUFFER_LENGTH_EXCEEDED(size, length, (__strlen + 1), method_name, \ 107 param_name); \ 108 /* If we didn't trigger an error, we now know this strcpy is safe. */ \ 109 (void)strcpy(buffer + length, ptr); \ 110 length + (__strlen + 1); \ 111 }) 112 113#define MARSHAL_PARAM(ptr, buffer, size, length, method_name, param_name) \ 114 ({ \ 115 ERR_IF_BUFFER_LENGTH_EXCEEDED(size, length, sizeof(*ptr), method_name, \ 116 param_name) \ 117 memcpy(buffer + length, ptr, sizeof(*ptr)); \ 118 length + sizeof(*ptr); \ 119 }) 120 121#define UNMARSHAL_ARRAY_PARAM(ptr, ptr_sz, buffer, size, length, method_name, \ 122 param_name, cleanup_action) \ 123 ({ \ 124 ERR_IF_MALFORMED_RPC_PAYLOAD(size, length, sizeof(*ptr_sz), method_name, \ 125 param_name, cleanup_action); \ 126 memcpy(ptr_sz, buffer + length, sizeof(*ptr_sz)); \ 127 length += sizeof(*ptr_sz); \ 128 *ptr = malloc(sizeof((*ptr)[0]) * (*ptr_sz)); \ 129 ERR_IF_ALLOCATION_FAILURE(*ptr, sizeof((*ptr)[0]) * (*ptr_sz), \ 130 method_name, param_name, cleanup_action); \ 131 ERR_IF_MALFORMED_RPC_PAYLOAD(size, length, \ 132 (sizeof((*ptr)[0]) * (*ptr_sz)), method_name, \ 133 param_name, ({ \ 134 free(*ptr); \ 135 cleanup_action; \ 136 })); \ 137 memcpy((*ptr), buffer + length, sizeof((*ptr)[0]) * (*ptr_sz)); \ 138 length + sizeof((*ptr)[0]) * (*ptr_sz); \ 139 }) 140 141#define UNMARSHAL_STRING_ARRAY_PARAM(ptr, ptr_sz, buffer, size, length, \ 142 method_name, param_name, cleanup_action) \ 143 ({ \ 144 ERR_IF_MALFORMED_RPC_PAYLOAD(size, length, sizeof(*ptr_sz), method_name, \ 145 param_name, cleanup_action); \ 146 memcpy(ptr_sz, buffer + length, sizeof(*ptr_sz)); \ 147 length += sizeof(*ptr_sz); \ 148 *ptr = malloc(sizeof(char *) * (*ptr_sz)); \ 149 ERR_IF_ALLOCATION_FAILURE(*ptr, sizeof(char *) * (*ptr_sz), method_name, \ 150 param_name, cleanup_action); \ 151 for (int __i = 0; __i < *ptr_sz; __i++) { \ 152 size_t __strlen = strnlen(buffer + length, size - length); \ 153 ERR_IF_MALFORMED_RPC_PAYLOAD(size, length, (__strlen + 1), method_name, \ 154 param_name, ({ \ 155 for (int __j = 0; __j < __i; __j++) { \ 156 free((*ptr)[__j]); \ 157 } \ 158 free(*ptr); \ 159 cleanup_action; \ 160 })); \ 161 /* If we didn't trigger an error, we now know this strdup is safe. */ \ 162 (*ptr)[__i] = strdup(buffer + length); \ 163 ERR_IF_ALLOCATION_FAILURE((*ptr)[__i], __strlen + 1, method_name, \ 164 param_name, ({ \ 165 for (int __j = 0; __j < __i; __j++) { \ 166 free((*ptr)[__j]); \ 167 } \ 168 free(*ptr); \ 169 cleanup_action; \ 170 })); \ 171 length += __strlen + 1; \ 172 } \ 173 length; \ 174 }) 175 176#define UNMARSHAL_STRING_PARAM(ptr, buffer, size, length, method_name, \ 177 param_name, cleanup_action) \ 178 ({ \ 179 size_t __strlen = strnlen(buffer + length, size - length); \ 180 ERR_IF_MALFORMED_RPC_PAYLOAD(size, length, (__strlen + 1), method_name, \ 181 param_name, cleanup_action); \ 182 *ptr = strdup(buffer + length); \ 183 ERR_IF_ALLOCATION_FAILURE(*ptr, __strlen + 1, method_name, param_name, \ 184 cleanup_action); \ 185 length + __strlen + 1; \ 186 }) 187 188#define UNMARSHAL_PARAM(ptr, buffer, size, length, method_name, param_name, \ 189 cleanup_action) \ 190 ({ \ 191 ERR_IF_MALFORMED_RPC_PAYLOAD(size, length, sizeof(*ptr), method_name, \ 192 param_name, cleanup_action); \ 193 memcpy(ptr, buffer + length, sizeof(*ptr)); \ 194 length + sizeof(*ptr); \ 195 }) 196