• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libubox/blobmsg.c

  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