ustream: prevent recursive calls to the read callback
[project/libubox.git] / 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 }