libubox
C utility functions for OpenWrt.
blob.c
Go to the documentation of this file.
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
105 {
106  free(buf->buf);
107  buf->buf = NULL;
108  buf->head = NULL;
109  buf->buflen = 0;
110 }
111 
112 void
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;
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 }
void blob_set_raw_len(struct blob_attr *attr, unsigned int len)
Definition: blob.c:124
static int blob_parse_attr(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
Definition: blob.c:224
struct blob_attr * blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len)
Definition: blob.c:161
static const size_t blob_type_minlen[BLOB_ATTR_LAST]
Definition: blob.c:192
bool blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2)
Definition: blob.c:311
static void blob_init(struct blob_attr *attr, int id, unsigned int len)
Definition: blob.c:36
void blob_buf_free(struct blob_buf *buf)
Definition: blob.c:104
struct blob_attr * blob_new(struct blob_buf *buf, int id, int payload)
Definition: blob.c:132
bool blob_check_type(const void *ptr, unsigned int len, int type)
Definition: blob.c:202
static bool blob_buffer_grow(struct blob_buf *buf, int minlen)
Definition: blob.c:22
static struct blob_attr * blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload)
Definition: blob.c:71
void * blob_nest_start(struct blob_buf *buf, int id)
Definition: blob.c:175
int blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
Definition: blob.c:296
static int attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
Definition: blob.c:51
int blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
Definition: blob.c:272
void blob_nest_end(struct blob_buf *buf, void *cookie)
Definition: blob.c:185
bool blob_buf_grow(struct blob_buf *buf, int required)
Definition: blob.c:57
void blob_fill_pad(struct blob_attr *attr)
Definition: blob.c:113
struct blob_attr * blob_memdup(struct blob_attr *attr)
Definition: blob.c:326
static struct blob_attr * offset_to_attr(struct blob_buf *buf, int offset)
Definition: blob.c:44
struct blob_attr * blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len)
Definition: blob.c:145
int blob_buf_init(struct blob_buf *buf, int id)
Definition: blob.c:91
@ BLOB_ATTR_INT16
Definition: blob.h:39
@ BLOB_ATTR_STRING
Definition: blob.h:37
@ BLOB_ATTR_LAST
Definition: blob.h:43
@ BLOB_ATTR_INT64
Definition: blob.h:41
@ BLOB_ATTR_DOUBLE
Definition: blob.h:42
@ BLOB_ATTR_INT32
Definition: blob.h:40
@ BLOB_ATTR_INT8
Definition: blob.h:38
#define BLOB_COOKIE
Definition: blob.h:31
static size_t blob_raw_len(const struct blob_attr *attr)
Definition: blob.h:109
static size_t blob_pad_len(const struct blob_attr *attr)
Definition: blob.h:118
#define BLOB_ATTR_ID_MASK
Definition: blob.h:46
static struct blob_attr * blob_next(const struct blob_attr *attr)
Definition: blob.h:185
#define blob_for_each_attr_len(pos, attr, attr_len, rem)
Definition: blob.h:258
#define BLOB_ATTR_ID_SHIFT
Definition: blob.h:47
#define blob_for_each_attr(pos, attr, rem)
Definition: blob.h:251
char data[]
Definition: blob.h:1
static size_t blob_len(const struct blob_attr *attr)
Definition: blob.h:100
static void * blob_data(const struct blob_attr *attr)
Definition: blob.h:75
static unsigned int blob_id(const struct blob_attr *attr)
Definition: blob.h:84
#define BLOB_ATTR_LEN_MASK
Definition: blob.h:48
unsigned int type
Definition: blob.h:58
Definition: blob.h:52
uint32_t id_len
Definition: blob.h:53
Definition: blob.h:64
void * buf
Definition: blob.h:68
bool(* grow)(struct blob_buf *buf, int minlen)
Definition: blob.h:66
int buflen
Definition: blob.h:67
struct blob_attr * head
Definition: blob.h:65
uint8_t type
Definition: udebug-proto.h:0
uint32_t id
Definition: udebug-proto.h:2
#define cpu_to_be32(x)
Definition: utils.h:163