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 "blob.h" 20 21 static bool 22 blob_buffer_grow(struct blob_buf *buf, int minlen) 23 { 24 struct blob_buf *new; 25 int delta = ((minlen / 256) + 1) * 256; 26 new = realloc(buf->buf, buf->buflen + delta); 27 if (new) { 28 buf->buf = new; 29 memset(buf->buf + buf->buflen, 0, delta); 30 buf->buflen += delta; 31 } 32 return !!new; 33 } 34 35 static void 36 blob_init(struct blob_attr *attr, int id, unsigned int len) 37 { 38 len &= BLOB_ATTR_LEN_MASK; 39 len |= (id << BLOB_ATTR_ID_SHIFT) & BLOB_ATTR_ID_MASK; 40 attr->id_len = cpu_to_be32(len); 41 } 42 43 static inline struct blob_attr * 44 offset_to_attr(struct blob_buf *buf, int offset) 45 { 46 void *ptr = (char *)buf->buf + offset - BLOB_COOKIE; 47 return ptr; 48 } 49 50 static inline int 51 attr_to_offset(struct blob_buf *buf, struct blob_attr *attr) 52 { 53 return (char *)attr - (char *) buf->buf + BLOB_COOKIE; 54 } 55 56 bool 57 blob_buf_grow(struct blob_buf *buf, int required) 58 { 59 int offset_head = attr_to_offset(buf, buf->head); 60 61 if ((buf->buflen + required) > BLOB_ATTR_LEN_MASK) 62 return false; 63 if (!buf->grow || !buf->grow(buf, required)) 64 return false; 65 66 buf->head = offset_to_attr(buf, offset_head); 67 return true; 68 } 69 70 static struct blob_attr * 71 blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload) 72 { 73 int offset = attr_to_offset(buf, pos); 74 int required = (offset - BLOB_COOKIE + sizeof(struct blob_attr) + payload) - buf->buflen; 75 struct blob_attr *attr; 76 77 if (required > 0) { 78 if (!blob_buf_grow(buf, required)) 79 return NULL; 80 attr = offset_to_attr(buf, offset); 81 } else { 82 attr = pos; 83 } 84 85 blob_init(attr, id, payload + sizeof(struct blob_attr)); 86 blob_fill_pad(attr); 87 return attr; 88 } 89 90 int 91 blob_buf_init(struct blob_buf *buf, int id) 92 { 93 if (!buf->grow) 94 buf->grow = blob_buffer_grow; 95 96 buf->head = buf->buf; 97 if (blob_add(buf, buf->buf, id, 0) == NULL) 98 return -ENOMEM; 99 100 return 0; 101 } 102 103 void 104 blob_buf_free(struct blob_buf *buf) 105 { 106 free(buf->buf); 107 buf->buf = NULL; 108 buf->head = NULL; 109 buf->buflen = 0; 110 } 111 112 void 113 blob_fill_pad(struct blob_attr *attr) 114 { 115 char *buf = (char *) attr; 116 int len = blob_pad_len(attr); 117 int delta = len - blob_raw_len(attr); 118 119 if (delta > 0) 120 memset(buf + len - delta, 0, delta); 121 } 122 123 void 124 blob_set_raw_len(struct blob_attr *attr, unsigned int len) 125 { 126 len &= BLOB_ATTR_LEN_MASK; 127 attr->id_len &= ~cpu_to_be32(BLOB_ATTR_LEN_MASK); 128 attr->id_len |= cpu_to_be32(len); 129 } 130 131 struct blob_attr * 132 blob_new(struct blob_buf *buf, int id, int payload) 133 { 134 struct blob_attr *attr; 135 136 attr = blob_add(buf, blob_next(buf->head), id, payload); 137 if (!attr) 138 return NULL; 139 140 blob_set_raw_len(buf->head, blob_pad_len(buf->head) + blob_pad_len(attr)); 141 return attr; 142 } 143 144 struct blob_attr * 145 blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len) 146 { 147 struct blob_attr *attr; 148 149 if (len < sizeof(struct blob_attr) || !ptr) 150 return NULL; 151 152 attr = blob_add(buf, blob_next(buf->head), 0, len - sizeof(struct blob_attr)); 153 if (!attr) 154 return NULL; 155 blob_set_raw_len(buf->head, blob_pad_len(buf->head) + len); 156 memcpy(attr, ptr, len); 157 return attr; 158 } 159 160 struct blob_attr * 161 blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len) 162 { 163 struct blob_attr *attr; 164 165 attr = blob_new(buf, id, len); 166 if (!attr) 167 return NULL; 168 169 if (ptr) 170 memcpy(blob_data(attr), ptr, len); 171 return attr; 172 } 173 174 void * 175 blob_nest_start(struct blob_buf *buf, int id) 176 { 177 unsigned long offset = attr_to_offset(buf, buf->head); 178 buf->head = blob_new(buf, id, 0); 179 if (!buf->head) 180 return NULL; 181 return (void *) offset; 182 } 183 184 void 185 blob_nest_end(struct blob_buf *buf, void *cookie) 186 { 187 struct blob_attr *attr = offset_to_attr(buf, (unsigned long) cookie); 188 blob_set_raw_len(attr, blob_pad_len(attr) + blob_len(buf->head)); 189 buf->head = attr; 190 } 191 192 static const size_t blob_type_minlen[BLOB_ATTR_LAST] = { 193 [BLOB_ATTR_STRING] = 1, 194 [BLOB_ATTR_INT8] = sizeof(uint8_t), 195 [BLOB_ATTR_INT16] = sizeof(uint16_t), 196 [BLOB_ATTR_INT32] = sizeof(uint32_t), 197 [BLOB_ATTR_INT64] = sizeof(uint64_t), 198 [BLOB_ATTR_DOUBLE] = sizeof(double), 199 }; 200 201 bool 202 blob_check_type(const void *ptr, unsigned int len, int type) 203 { 204 const char *data = ptr; 205 206 if (type >= BLOB_ATTR_LAST) 207 return false; 208 209 if (type >= BLOB_ATTR_INT8 && type <= BLOB_ATTR_INT64) { 210 if (len != blob_type_minlen[type]) 211 return false; 212 } else { 213 if (len < blob_type_minlen[type]) 214 return false; 215 } 216 217 if (type == BLOB_ATTR_STRING && data[len - 1] != 0) 218 return false; 219 220 return true; 221 } 222 223 static int 224 blob_parse_attr(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max) 225 { 226 int id; 227 size_t len; 228 int found = 0; 229 size_t data_len; 230 231 if (!attr || attr_len < sizeof(struct blob_attr)) 232 return 0; 233 234 id = blob_id(attr); 235 if (id >= max) 236 return 0; 237 238 len = blob_raw_len(attr); 239 if (len > attr_len || len < sizeof(struct blob_attr)) 240 return 0; 241 242 data_len = blob_len(attr); 243 if (data_len > len) 244 return 0; 245 246 if (info) { 247 int type = info[id].type; 248 249 if (type < BLOB_ATTR_LAST) { 250 if (!blob_check_type(blob_data(attr), data_len, type)) 251 return 0; 252 } 253 254 if (info[id].minlen && len < info[id].minlen) 255 return 0; 256 257 if (info[id].maxlen && len > info[id].maxlen) 258 return 0; 259 260 if (info[id].validate && !info[id].validate(&info[id], attr)) 261 return 0; 262 } 263 264 if (!data[id]) 265 found++; 266 267 data[id] = attr; 268 return found; 269 } 270 271 int 272 blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max) 273 { 274 struct blob_attr *pos; 275 size_t len = 0; 276 int found = 0; 277 size_t rem; 278 279 if (!attr || attr_len < sizeof(struct blob_attr)) 280 return 0; 281 282 len = blob_raw_len(attr); 283 if (attr_len < len) 284 return 0; 285 286 memset(data, 0, sizeof(struct blob_attr *) * max); 287 blob_for_each_attr_len(pos, attr, len, rem) { 288 found += blob_parse_attr(pos, rem, data, info, max); 289 } 290 291 return found; 292 } 293 294 /* use only on trusted input, otherwise consider blob_parse_untrusted */ 295 int 296 blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max) 297 { 298 struct blob_attr *pos; 299 int found = 0; 300 size_t rem; 301 302 memset(data, 0, sizeof(struct blob_attr *) * max); 303 blob_for_each_attr(pos, attr, rem) { 304 found += blob_parse_attr(pos, rem, data, info, max); 305 } 306 307 return found; 308 } 309 310 bool 311 blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2) 312 { 313 if (!a1 && !a2) 314 return true; 315 316 if (!a1 || !a2) 317 return false; 318 319 if (blob_pad_len(a1) != blob_pad_len(a2)) 320 return false; 321 322 return !memcmp(a1, a2, blob_pad_len(a1)); 323 } 324 325 struct blob_attr * 326 blob_memdup(struct blob_attr *attr) 327 { 328 struct blob_attr *ret; 329 int size = blob_pad_len(attr); 330 331 ret = malloc(size); 332 if (!ret) 333 return NULL; 334 335 memcpy(ret, attr, size); 336 return ret; 337 } 338
This page was automatically generated by LXR 0.3.1. • OpenWrt