1 /* 2 * blob - library for generating/parsing tagged binary data 3 * 4 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <limits.h> 20 21 #include "blob.h" 22 23 static bool 24 blob_buffer_grow(struct blob_buf *buf, int minlen) 25 { 26 void *new; 27 int delta; 28 29 if (minlen < 0 || minlen > INT_MAX - 256) 30 return false; 31 32 delta = ((minlen / 256) + 1) * 256; 33 if (buf->buflen < 0 || delta > INT_MAX - buf->buflen) 34 return false; 35 36 new = realloc(buf->buf, buf->buflen + delta); 37 if (new) { 38 buf->buf = new; 39 memset(buf->buf + buf->buflen, 0, delta); 40 buf->buflen += delta; 41 } 42 return !!new; 43 } 44 45 static void 46 blob_init(struct blob_attr *attr, int id, unsigned int len) 47 { 48 len &= BLOB_ATTR_LEN_MASK; 49 len |= (id << BLOB_ATTR_ID_SHIFT) & BLOB_ATTR_ID_MASK; 50 attr->id_len = cpu_to_be32(len); 51 } 52 53 static inline struct blob_attr * 54 offset_to_attr(struct blob_buf *buf, int offset) 55 { 56 void *ptr = (char *)buf->buf + offset - BLOB_COOKIE; 57 return ptr; 58 } 59 60 static inline int 61 attr_to_offset(struct blob_buf *buf, struct blob_attr *attr) 62 { 63 return (char *)attr - (char *) buf->buf + BLOB_COOKIE; 64 } 65 66 bool 67 blob_buf_grow(struct blob_buf *buf, int required) 68 { 69 int offset_head = attr_to_offset(buf, buf->head); 70 71 if (required < 0 || buf->buflen < 0) 72 return false; 73 if (required > BLOB_ATTR_LEN_MASK - buf->buflen) 74 return false; 75 if (!buf->grow || !buf->grow(buf, required)) 76 return false; 77 78 buf->head = offset_to_attr(buf, offset_head); 79 return true; 80 } 81 82 static struct blob_attr * 83 blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload) 84 { 85 int offset = attr_to_offset(buf, pos); 86 int required = (offset - BLOB_COOKIE + sizeof(struct blob_attr) + payload) - buf->buflen; 87 struct blob_attr *attr; 88 89 if (required > 0) { 90 if (!blob_buf_grow(buf, required)) 91 return NULL; 92 attr = offset_to_attr(buf, offset); 93 } else { 94 attr = pos; 95 } 96 97 blob_init(attr, id, payload + sizeof(struct blob_attr)); 98 blob_fill_pad(attr); 99 return attr; 100 } 101 102 int 103 blob_buf_init(struct blob_buf *buf, int id) 104 { 105 if (!buf->grow) 106 buf->grow = blob_buffer_grow; 107 108 buf->head = buf->buf; 109 if (blob_add(buf, buf->buf, id, 0) == NULL) 110 return -ENOMEM; 111 112 return 0; 113 } 114 115 void 116 blob_buf_free(struct blob_buf *buf) 117 { 118 free(buf->buf); 119 buf->buf = NULL; 120 buf->head = NULL; 121 buf->buflen = 0; 122 } 123 124 void 125 blob_fill_pad(struct blob_attr *attr) 126 { 127 char *buf = (char *) attr; 128 size_t len = blob_pad_len(attr); 129 size_t delta = len - blob_raw_len(attr); 130 131 if (delta > 0) 132 memset(buf + len - delta, 0, delta); 133 } 134 135 void 136 blob_set_raw_len(struct blob_attr *attr, unsigned int len) 137 { 138 len &= BLOB_ATTR_LEN_MASK; 139 attr->id_len &= ~cpu_to_be32(BLOB_ATTR_LEN_MASK); 140 attr->id_len |= cpu_to_be32(len); 141 } 142 143 struct blob_attr * 144 blob_new(struct blob_buf *buf, int id, int payload) 145 { 146 struct blob_attr *attr; 147 148 attr = blob_add(buf, blob_next(buf->head), id, payload); 149 if (!attr) 150 return NULL; 151 152 blob_set_raw_len(buf->head, blob_pad_len(buf->head) + blob_pad_len(attr)); 153 return attr; 154 } 155 156 struct blob_attr * 157 blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len) 158 { 159 struct blob_attr *attr; 160 161 if (len < sizeof(struct blob_attr) || !ptr) 162 return NULL; 163 164 attr = blob_add(buf, blob_next(buf->head), 0, len - sizeof(struct blob_attr)); 165 if (!attr) 166 return NULL; 167 blob_set_raw_len(buf->head, blob_pad_len(buf->head) + len); 168 memcpy(attr, ptr, len); 169 return attr; 170 } 171 172 struct blob_attr * 173 blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len) 174 { 175 struct blob_attr *attr; 176 177 attr = blob_new(buf, id, len); 178 if (!attr) 179 return NULL; 180 181 if (ptr) 182 memcpy(blob_data(attr), ptr, len); 183 return attr; 184 } 185 186 void * 187 blob_nest_start(struct blob_buf *buf, int id) 188 { 189 unsigned long offset = attr_to_offset(buf, buf->head); 190 buf->head = blob_new(buf, id, 0); 191 if (!buf->head) 192 return NULL; 193 return (void *) offset; 194 } 195 196 void 197 blob_nest_end(struct blob_buf *buf, void *cookie) 198 { 199 struct blob_attr *attr = offset_to_attr(buf, (unsigned long) cookie); 200 blob_set_raw_len(attr, blob_pad_len(attr) + blob_len(buf->head)); 201 buf->head = attr; 202 } 203 204 static const size_t blob_type_minlen[BLOB_ATTR_LAST] = { 205 [BLOB_ATTR_STRING] = 1, 206 [BLOB_ATTR_INT8] = sizeof(uint8_t), 207 [BLOB_ATTR_INT16] = sizeof(uint16_t), 208 [BLOB_ATTR_INT32] = sizeof(uint32_t), 209 [BLOB_ATTR_INT64] = sizeof(uint64_t), 210 [BLOB_ATTR_DOUBLE] = sizeof(double), 211 }; 212 213 bool 214 blob_check_type(const void *ptr, unsigned int len, int type) 215 { 216 const char *data = ptr; 217 218 if (type >= BLOB_ATTR_LAST) 219 return false; 220 221 if (type >= BLOB_ATTR_INT8 && type <= BLOB_ATTR_INT64) { 222 if (len != blob_type_minlen[type]) 223 return false; 224 } else { 225 if (len < blob_type_minlen[type]) 226 return false; 227 } 228 229 if (type == BLOB_ATTR_STRING && data[len - 1] != 0) 230 return false; 231 232 return true; 233 } 234 235 static int 236 blob_parse_attr(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max) 237 { 238 int id; 239 size_t len; 240 int found = 0; 241 size_t data_len; 242 243 if (!attr || attr_len < sizeof(struct blob_attr)) 244 return 0; 245 246 id = blob_id(attr); 247 if (id >= max) 248 return 0; 249 250 len = blob_raw_len(attr); 251 if (len > attr_len || len < sizeof(struct blob_attr)) 252 return 0; 253 254 data_len = blob_len(attr); 255 if (data_len > len) 256 return 0; 257 258 if (info) { 259 int type = info[id].type; 260 261 if (type < BLOB_ATTR_LAST) { 262 if (!blob_check_type(blob_data(attr), data_len, type)) 263 return 0; 264 } 265 266 if (info[id].minlen && len < info[id].minlen) 267 return 0; 268 269 if (info[id].maxlen && len > info[id].maxlen) 270 return 0; 271 272 if (info[id].validate && !info[id].validate(&info[id], attr)) 273 return 0; 274 } 275 276 if (!data[id]) 277 found++; 278 279 data[id] = attr; 280 return found; 281 } 282 283 int 284 blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max) 285 { 286 struct blob_attr *pos; 287 size_t len = 0; 288 int found = 0; 289 size_t rem; 290 291 if (!attr || attr_len < sizeof(struct blob_attr)) 292 return 0; 293 294 len = blob_raw_len(attr); 295 if (attr_len < len) 296 return 0; 297 298 memset(data, 0, sizeof(struct blob_attr *) * max); 299 blob_for_each_attr_len(pos, attr, len, rem) { 300 found += blob_parse_attr(pos, rem, data, info, max); 301 } 302 303 return found; 304 } 305 306 /* use only on trusted input, otherwise consider blob_parse_untrusted */ 307 int 308 blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max) 309 { 310 struct blob_attr *pos; 311 int found = 0; 312 size_t rem; 313 314 memset(data, 0, sizeof(struct blob_attr *) * max); 315 blob_for_each_attr(pos, attr, rem) { 316 found += blob_parse_attr(pos, rem, data, info, max); 317 } 318 319 return found; 320 } 321 322 bool 323 blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2) 324 { 325 if (!a1 && !a2) 326 return true; 327 328 if (!a1 || !a2) 329 return false; 330 331 if (blob_pad_len(a1) != blob_pad_len(a2)) 332 return false; 333 334 return !memcmp(a1, a2, blob_pad_len(a1)); 335 } 336 337 struct blob_attr * 338 blob_memdup(const struct blob_attr *attr) 339 { 340 struct blob_attr *ret; 341 size_t size = blob_pad_len(attr); 342 343 ret = malloc(size); 344 if (!ret) 345 return NULL; 346 347 memcpy(ret, attr, size); 348 return ret; 349 } 350
This page was automatically generated by LXR 0.3.1. • OpenWrt