• 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 <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