1 /* 2 * Copyright (C) 2010-2012 Felix Fietkau <nbd@openwrt.org> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 #include <limits.h> 17 18 #include "blobmsg.h" 19 20 static const int blob_type[__BLOBMSG_TYPE_LAST] = { 21 [BLOBMSG_TYPE_INT8] = BLOB_ATTR_INT8, 22 [BLOBMSG_TYPE_INT16] = BLOB_ATTR_INT16, 23 [BLOBMSG_TYPE_INT32] = BLOB_ATTR_INT32, 24 [BLOBMSG_TYPE_INT64] = BLOB_ATTR_INT64, 25 [BLOBMSG_TYPE_DOUBLE] = BLOB_ATTR_DOUBLE, 26 [BLOBMSG_TYPE_STRING] = BLOB_ATTR_STRING, 27 [BLOBMSG_TYPE_UNSPEC] = BLOB_ATTR_BINARY, 28 }; 29 30 bool blobmsg_check_attr(const struct blob_attr *attr, bool name) 31 { 32 return blobmsg_check_attr_len(attr, name, blob_raw_len(attr)); 33 } 34 35 static bool blobmsg_check_name(const struct blob_attr *attr, bool name) 36 { 37 const struct blobmsg_hdr *hdr; 38 uint16_t namelen; 39 40 if (!blob_is_extended(attr)) 41 return !name; 42 43 if (blob_len(attr) < sizeof(struct blobmsg_hdr)) 44 return false; 45 46 hdr = (const struct blobmsg_hdr *)blob_data(attr); 47 if (name && !hdr->namelen) 48 return false; 49 50 namelen = blobmsg_namelen(hdr); 51 if (blob_len(attr) < (size_t)blobmsg_hdrlen(namelen)) 52 return false; 53 54 if (hdr->name[namelen] != 0) 55 return false; 56 57 return true; 58 } 59 60 bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len) 61 { 62 const char *data; 63 size_t data_len; 64 int id; 65 66 if (len < sizeof(struct blob_attr)) 67 return false; 68 69 data_len = blob_raw_len(attr); 70 if (data_len < sizeof(struct blob_attr) || data_len > len) 71 return false; 72 73 if (!blobmsg_check_name(attr, name)) 74 return false; 75 76 id = blob_id(attr); 77 if (id > BLOBMSG_TYPE_LAST) 78 return false; 79 80 if (!blob_type[id]) 81 return true; 82 83 data = blobmsg_data(attr); 84 data_len = blobmsg_data_len(attr); 85 86 return blob_check_type(data, data_len, blob_type[id]); 87 } 88 89 int blobmsg_check_array(const struct blob_attr *attr, int type) 90 { 91 return blobmsg_check_array_len(attr, type, blob_raw_len(attr)); 92 } 93 94 int blobmsg_check_array_len(const struct blob_attr *attr, int type, 95 size_t blob_len) 96 { 97 struct blob_attr *cur; 98 size_t rem; 99 bool name; 100 int size = 0; 101 102 if (type > BLOBMSG_TYPE_LAST) 103 return -1; 104 105 if (!blobmsg_check_attr_len(attr, false, blob_len)) 106 return -1; 107 108 switch (blobmsg_type(attr)) { 109 case BLOBMSG_TYPE_TABLE: 110 name = true; 111 break; 112 case BLOBMSG_TYPE_ARRAY: 113 name = false; 114 break; 115 default: 116 return -1; 117 } 118 119 blobmsg_for_each_attr(cur, attr, rem) { 120 if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type) 121 return -1; 122 123 if (!blobmsg_check_attr_len(cur, name, rem)) 124 return -1; 125 126 size++; 127 } 128 129 return size; 130 } 131 132 bool blobmsg_check_attr_list(const struct blob_attr *attr, int type) 133 { 134 return blobmsg_check_array(attr, type) >= 0; 135 } 136 137 bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len) 138 { 139 return blobmsg_check_array_len(attr, type, len) >= 0; 140 } 141 142 int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len, 143 struct blob_attr **tb, void *data, unsigned int len) 144 { 145 struct blob_attr *attr; 146 int i = 0; 147 148 memset(tb, 0, policy_len * sizeof(*tb)); 149 __blob_for_each_attr(attr, data, len) { 150 if (policy[i].type != BLOBMSG_TYPE_UNSPEC && 151 blob_id(attr) != policy[i].type) 152 continue; 153 154 if (!blobmsg_check_attr_len(attr, false, len)) 155 return -1; 156 157 if (tb[i]) 158 continue; 159 160 tb[i++] = attr; 161 if (i == policy_len) 162 break; 163 } 164 165 return 0; 166 } 167 168 /* 169 * Upper bound on the number of policy entries blobmsg_parse() will 170 * accept. The pslen scratch array is allocated on the stack via 171 * alloca(); 4096 entries cap the per-call stack use at 172 * 4096 * sizeof(uint16_t) = 8 KiB, which comfortably fits the typical 173 * 8 KiB thread default while being far above any realistic policy 174 * size used in practice (a few dozen entries). 175 */ 176 #define BLOBMSG_PARSE_MAX_POLICY 4096 177 178 int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len, 179 struct blob_attr **tb, void *data, unsigned int len) 180 { 181 const struct blobmsg_hdr *hdr; 182 struct blob_attr *attr; 183 uint16_t *pslen; 184 int i; 185 186 memset(tb, 0, policy_len * sizeof(*tb)); 187 if (!data || !len) 188 return -EINVAL; 189 if (policy_len < 0 || policy_len > BLOBMSG_PARSE_MAX_POLICY) 190 return -ENOMEM; 191 pslen = alloca(policy_len * sizeof(*pslen)); 192 for (i = 0; i < policy_len; i++) { 193 if (!policy[i].name) 194 continue; 195 196 pslen[i] = strlen(policy[i].name); 197 } 198 199 __blob_for_each_attr(attr, data, len) { 200 if (!blobmsg_check_attr_len(attr, false, len)) 201 return -1; 202 203 if (!blob_is_extended(attr)) 204 continue; 205 206 hdr = blob_data(attr); 207 for (i = 0; i < policy_len; i++) { 208 if (!policy[i].name) 209 continue; 210 211 if (policy[i].type != BLOBMSG_TYPE_UNSPEC && 212 policy[i].type != BLOBMSG_CAST_INT64 && 213 blob_id(attr) != policy[i].type) 214 continue; 215 216 if (policy[i].type == BLOBMSG_CAST_INT64 && 217 (blob_id(attr) != BLOBMSG_TYPE_INT64 && 218 blob_id(attr) != BLOBMSG_TYPE_INT32 && 219 blob_id(attr) != BLOBMSG_TYPE_INT16 && 220 blob_id(attr) != BLOBMSG_TYPE_INT8)) 221 continue; 222 223 if (blobmsg_namelen(hdr) != pslen[i]) 224 continue; 225 226 if (tb[i]) 227 continue; 228 229 if (strcmp(policy[i].name, (char *) hdr->name) != 0) 230 continue; 231 232 tb[i] = attr; 233 } 234 } 235 236 return 0; 237 } 238 239 240 static struct blob_attr * 241 blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data) 242 { 243 struct blob_attr *attr; 244 struct blobmsg_hdr *hdr; 245 int attrlen, namelen; 246 char *pad_start, *pad_end; 247 248 if (!name) 249 name = ""; 250 251 namelen = strlen(name); 252 attrlen = blobmsg_hdrlen(namelen) + payload_len; 253 attr = blob_new(buf, type, attrlen); 254 if (!attr) 255 return NULL; 256 257 attr->id_len |= cpu_to_be32(BLOB_ATTR_EXTENDED); 258 hdr = blob_data(attr); 259 hdr->namelen = cpu_to_be16(namelen); 260 261 memcpy(hdr->name, name, namelen); 262 hdr->name[namelen] = '\0'; 263 264 pad_end = *data = blobmsg_data(attr); 265 pad_start = (char *) &hdr->name[namelen]; 266 if (pad_start < pad_end) 267 memset(pad_start, 0, pad_end - pad_start); 268 269 return attr; 270 } 271 272 static inline int 273 attr_to_offset(struct blob_buf *buf, struct blob_attr *attr) 274 { 275 return (char *)attr - (char *) buf->buf + BLOB_COOKIE; 276 } 277 278 279 void * 280 blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array) 281 { 282 struct blob_attr *head; 283 int type = array ? BLOBMSG_TYPE_ARRAY : BLOBMSG_TYPE_TABLE; 284 unsigned long offset = attr_to_offset(buf, buf->head); 285 void *data; 286 287 if (!name) 288 name = ""; 289 290 head = blobmsg_new(buf, type, name, 0, &data); 291 if (!head) 292 return NULL; 293 blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blobmsg_hdrlen(strlen(name))); 294 buf->head = head; 295 return (void *)offset; 296 } 297 298 __attribute__((format(printf, 3, 0))) 299 int blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg) 300 { 301 va_list arg2; 302 char cbuf; 303 char *sbuf; 304 int len, ret; 305 306 va_copy(arg2, arg); 307 len = vsnprintf(&cbuf, sizeof(cbuf), format, arg2); 308 va_end(arg2); 309 310 if (len < 0) 311 return -1; 312 313 sbuf = blobmsg_alloc_string_buffer(buf, name, len); 314 if (!sbuf) 315 return -1; 316 317 ret = vsnprintf(sbuf, len + 1, format, arg); 318 if (ret < 0) 319 return -1; 320 321 blobmsg_add_string_buffer(buf); 322 323 return ret; 324 } 325 326 __attribute__((format(printf, 3, 4))) 327 int blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...) 328 { 329 va_list ap; 330 int ret; 331 332 va_start(ap, format); 333 ret = blobmsg_vprintf(buf, name, format, ap); 334 va_end(ap); 335 336 return ret; 337 } 338 339 void * 340 blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen) 341 { 342 struct blob_attr *attr; 343 void *data_dest; 344 345 if (maxlen == (unsigned int)-1) 346 return NULL; 347 maxlen++; 348 attr = blobmsg_new(buf, BLOBMSG_TYPE_STRING, name, maxlen, &data_dest); 349 if (!attr) 350 return NULL; 351 352 blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blob_pad_len(attr)); 353 blob_set_raw_len(attr, blob_raw_len(attr) - maxlen); 354 355 return data_dest; 356 } 357 358 void * 359 blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen) 360 { 361 struct blob_attr *attr = blob_next(buf->head); 362 int offset = attr_to_offset(buf, blob_next(buf->head)) + blob_pad_len(attr) - BLOB_COOKIE; 363 int required; 364 365 if (maxlen >= INT_MAX) 366 return NULL; 367 368 if (buf->buflen < 0 || offset < 0 || offset > buf->buflen) 369 return NULL; 370 371 if ((int)maxlen + 1 <= buf->buflen - offset) 372 goto out; 373 374 required = (int)maxlen + 1 - (buf->buflen - offset); 375 376 if (!blob_buf_grow(buf, required)) 377 return NULL; 378 attr = blob_next(buf->head); 379 380 out: 381 return blobmsg_data(attr); 382 } 383 384 void 385 blobmsg_add_string_buffer(struct blob_buf *buf) 386 { 387 struct blob_attr *attr; 388 int len, attrlen; 389 390 attr = blob_next(buf->head); 391 len = strlen(blobmsg_data(attr)) + 1; 392 393 attrlen = blob_raw_len(attr) + len; 394 blob_set_raw_len(attr, attrlen); 395 blob_fill_pad(attr); 396 397 blob_set_raw_len(buf->head, blob_raw_len(buf->head) + blob_pad_len(attr)); 398 } 399 400 int 401 blobmsg_add_field(struct blob_buf *buf, int type, const char *name, 402 const void *data, unsigned int len) 403 { 404 struct blob_attr *attr; 405 void *data_dest; 406 407 attr = blobmsg_new(buf, type, name, len, &data_dest); 408 if (!attr) 409 return -1; 410 411 if (len > 0) 412 memcpy(data_dest, data, len); 413 414 return 0; 415 } 416
This page was automatically generated by LXR 0.3.1. • OpenWrt