1 /* 2 * Copyright 2014 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 #include <string.h> 25 26 #include "main/macros.h" 27 #include "util/ralloc.h" 28 #include "blob.h" 29 30 #define BLOB_INITIAL_SIZE 4096 31 32 /* Ensure that \blob will be able to fit an additional object of size 33 * \additional. The growing (if any) will occur by doubling the existing 34 * allocation. 35 */ 36 static bool 37 grow_to_fit(struct blob *blob, size_t additional) 38 { 39 size_t to_allocate; 40 uint8_t *new_data; 41 42 if (blob->size + additional <= blob->allocated) 43 return true; 44 45 if (blob->allocated == 0) 46 to_allocate = BLOB_INITIAL_SIZE; 47 else 48 to_allocate = blob->allocated * 2; 49 50 to_allocate = MAX2(to_allocate, blob->allocated + additional); 51 52 new_data = reralloc_size(blob, blob->data, to_allocate); 53 if (new_data == NULL) 54 return false; 55 56 blob->data = new_data; 57 blob->allocated = to_allocate; 58 59 return true; 60 } 61 62 /* Align the blob->size so that reading or writing a value at (blob->data + 63 * blob->size) will result in an access aligned to a granularity of \alignment 64 * bytes. 65 * 66 * \return True unless allocation fails 67 */ 68 static bool 69 align_blob(struct blob *blob, size_t alignment) 70 { 71 const size_t new_size = ALIGN(blob->size, alignment); 72 73 if (! grow_to_fit (blob, new_size - blob->size)) 74 return false; 75 76 blob->size = new_size; 77 78 return true; 79 } 80 81 static void 82 align_blob_reader(struct blob_reader *blob, size_t alignment) 83 { 84 blob->current = blob->data + ALIGN(blob->current - blob->data, alignment); 85 } 86 87 struct blob * 88 blob_create(void *mem_ctx) 89 { 90 struct blob *blob; 91 92 blob = ralloc(mem_ctx, struct blob); 93 if (blob == NULL) 94 return NULL; 95 96 blob->data = NULL; 97 blob->allocated = 0; 98 blob->size = 0; 99 100 return blob; 101 } 102 103 bool 104 blob_overwrite_bytes(struct blob *blob, 105 size_t offset, 106 const void *bytes, 107 size_t to_write) 108 { 109 /* Detect an attempt to overwrite data out of bounds. */ 110 if (offset < 0 || blob->size - offset < to_write) 111 return false; 112 113 memcpy(blob->data + offset, bytes, to_write); 114 115 return true; 116 } 117 118 bool 119 blob_write_bytes(struct blob *blob, const void *bytes, size_t to_write) 120 { 121 if (! grow_to_fit(blob, to_write)) 122 return false; 123 124 memcpy(blob->data + blob->size, bytes, to_write); 125 blob->size += to_write; 126 127 return true; 128 } 129 130 uint8_t * 131 blob_reserve_bytes(struct blob *blob, size_t to_write) 132 { 133 uint8_t *ret; 134 135 if (! grow_to_fit (blob, to_write)) 136 return NULL; 137 138 ret = blob->data + blob->size; 139 blob->size += to_write; 140 141 return ret; 142 } 143 144 bool 145 blob_write_uint32(struct blob *blob, uint32_t value) 146 { 147 align_blob(blob, sizeof(value)); 148 149 return blob_write_bytes(blob, &value, sizeof(value)); 150 } 151 152 bool 153 blob_overwrite_uint32 (struct blob *blob, 154 size_t offset, 155 uint32_t value) 156 { 157 return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); 158 } 159 160 bool 161 blob_write_uint64(struct blob *blob, uint64_t value) 162 { 163 align_blob(blob, sizeof(value)); 164 165 return blob_write_bytes(blob, &value, sizeof(value)); 166 } 167 168 bool 169 blob_write_intptr(struct blob *blob, intptr_t value) 170 { 171 align_blob(blob, sizeof(value)); 172 173 return blob_write_bytes(blob, &value, sizeof(value)); 174 } 175 176 bool 177 blob_write_string(struct blob *blob, const char *str) 178 { 179 return blob_write_bytes(blob, str, strlen(str) + 1); 180 } 181 182 void 183 blob_reader_init(struct blob_reader *blob, uint8_t *data, size_t size) 184 { 185 blob->data = data; 186 blob->end = data + size; 187 blob->current = data; 188 blob->overrun = false; 189 } 190 191 /* Check that an object of size \size can be read from this blob. 192 * 193 * If not, set blob->overrun to indicate that we attempted to read too far. 194 */ 195 static bool 196 ensure_can_read(struct blob_reader *blob, size_t size) 197 { 198 if (blob->current < blob->end && blob->end - blob->current >= size) 199 return true; 200 201 blob->overrun = true; 202 203 return false; 204 } 205 206 void * 207 blob_read_bytes(struct blob_reader *blob, size_t size) 208 { 209 void *ret; 210 211 if (! ensure_can_read (blob, size)) 212 return NULL; 213 214 ret = blob->current; 215 216 blob->current += size; 217 218 return ret; 219 } 220 221 void 222 blob_copy_bytes(struct blob_reader *blob, uint8_t *dest, size_t size) 223 { 224 uint8_t *bytes; 225 226 bytes = blob_read_bytes(blob, size); 227 if (bytes == NULL) 228 return; 229 230 memcpy(dest, bytes, size); 231 } 232 233 /* These next three read functions have identical form. If we add any beyond 234 * these first three we should probably switch to generating these with a 235 * preprocessor macro. 236 */ 237 uint32_t 238 blob_read_uint32(struct blob_reader *blob) 239 { 240 uint32_t ret; 241 int size = sizeof(ret); 242 243 align_blob_reader(blob, size); 244 245 if (! ensure_can_read(blob, size)) 246 return 0; 247 248 ret = *((uint32_t*) blob->current); 249 250 blob->current += size; 251 252 return ret; 253 } 254 255 uint64_t 256 blob_read_uint64(struct blob_reader *blob) 257 { 258 uint64_t ret; 259 int size = sizeof(ret); 260 261 align_blob_reader(blob, size); 262 263 if (! ensure_can_read(blob, size)) 264 return 0; 265 266 ret = *((uint64_t*) blob->current); 267 268 blob->current += size; 269 270 return ret; 271 } 272 273 intptr_t 274 blob_read_intptr(struct blob_reader *blob) 275 { 276 intptr_t ret; 277 int size = sizeof(ret); 278 279 align_blob_reader(blob, size); 280 281 if (! ensure_can_read(blob, size)) 282 return 0; 283 284 ret = *((intptr_t *) blob->current); 285 286 blob->current += size; 287 288 return ret; 289 } 290 291 char * 292 blob_read_string(struct blob_reader *blob) 293 { 294 int size; 295 char *ret; 296 uint8_t *nul; 297 298 /* If we're already at the end, then this is an overrun. */ 299 if (blob->current >= blob->end) { 300 blob->overrun = true; 301 return NULL; 302 } 303 304 /* Similarly, if there is no zero byte in the data remaining in this blob, 305 * we also consider that an overrun. 306 */ 307 nul = memchr(blob->current, 0, blob->end - blob->current); 308 309 if (nul == NULL) { 310 blob->overrun = true; 311 return NULL; 312 } 313 314 size = nul - blob->current + 1; 315 316 assert(ensure_can_read(blob, size)); 317 318 ret = (char *) blob->current; 319 320 blob->current += size; 321 322 return ret; 323 } 324