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

Sources/libubox/blob.c

  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