blob.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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. #include "blob.h"
  19. static bool
  20. blob_buffer_grow(struct blob_buf *buf, int minlen)
  21. {
  22. struct blob_buf *new;
  23. int delta = ((minlen / 256) + 1) * 256;
  24. new = realloc(buf->buf, buf->buflen + delta);
  25. if (new) {
  26. buf->buf = new;
  27. memset(buf->buf + buf->buflen, 0, delta);
  28. buf->buflen += delta;
  29. }
  30. return !!new;
  31. }
  32. static void
  33. blob_init(struct blob_attr *attr, int id, unsigned int len)
  34. {
  35. len &= BLOB_ATTR_LEN_MASK;
  36. len |= (id << BLOB_ATTR_ID_SHIFT) & BLOB_ATTR_ID_MASK;
  37. attr->id_len = cpu_to_be32(len);
  38. }
  39. static inline struct blob_attr *
  40. offset_to_attr(struct blob_buf *buf, int offset)
  41. {
  42. void *ptr = (char *)buf->buf + offset - BLOB_COOKIE;
  43. return ptr;
  44. }
  45. static inline int
  46. attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
  47. {
  48. return (char *)attr - (char *) buf->buf + BLOB_COOKIE;
  49. }
  50. bool
  51. blob_buf_grow(struct blob_buf *buf, int required)
  52. {
  53. int offset_head = attr_to_offset(buf, buf->head);
  54. if ((buf->buflen + required) > BLOB_ATTR_LEN_MASK)
  55. return false;
  56. if (!buf->grow || !buf->grow(buf, required))
  57. return false;
  58. buf->head = offset_to_attr(buf, offset_head);
  59. return true;
  60. }
  61. static struct blob_attr *
  62. blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload)
  63. {
  64. int offset = attr_to_offset(buf, pos);
  65. int required = (offset - BLOB_COOKIE + sizeof(struct blob_attr) + payload) - buf->buflen;
  66. struct blob_attr *attr;
  67. if (required > 0) {
  68. if (!blob_buf_grow(buf, required))
  69. return NULL;
  70. attr = offset_to_attr(buf, offset);
  71. } else {
  72. attr = pos;
  73. }
  74. blob_init(attr, id, payload + sizeof(struct blob_attr));
  75. blob_fill_pad(attr);
  76. return attr;
  77. }
  78. int
  79. blob_buf_init(struct blob_buf *buf, int id)
  80. {
  81. if (!buf->grow)
  82. buf->grow = blob_buffer_grow;
  83. buf->head = buf->buf;
  84. if (blob_add(buf, buf->buf, id, 0) == NULL)
  85. return -ENOMEM;
  86. return 0;
  87. }
  88. void
  89. blob_buf_free(struct blob_buf *buf)
  90. {
  91. free(buf->buf);
  92. buf->buf = NULL;
  93. buf->head = NULL;
  94. buf->buflen = 0;
  95. }
  96. void
  97. blob_fill_pad(struct blob_attr *attr)
  98. {
  99. char *buf = (char *) attr;
  100. int len = blob_pad_len(attr);
  101. int delta = len - blob_raw_len(attr);
  102. if (delta > 0)
  103. memset(buf + len - delta, 0, delta);
  104. }
  105. void
  106. blob_set_raw_len(struct blob_attr *attr, unsigned int len)
  107. {
  108. len &= BLOB_ATTR_LEN_MASK;
  109. attr->id_len &= ~cpu_to_be32(BLOB_ATTR_LEN_MASK);
  110. attr->id_len |= cpu_to_be32(len);
  111. }
  112. struct blob_attr *
  113. blob_new(struct blob_buf *buf, int id, int payload)
  114. {
  115. struct blob_attr *attr;
  116. attr = blob_add(buf, blob_next(buf->head), id, payload);
  117. if (!attr)
  118. return NULL;
  119. blob_set_raw_len(buf->head, blob_pad_len(buf->head) + blob_pad_len(attr));
  120. return attr;
  121. }
  122. struct blob_attr *
  123. blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len)
  124. {
  125. struct blob_attr *attr;
  126. if (len < sizeof(struct blob_attr) || !ptr)
  127. return NULL;
  128. attr = blob_add(buf, blob_next(buf->head), 0, len - sizeof(struct blob_attr));
  129. if (!attr)
  130. return NULL;
  131. blob_set_raw_len(buf->head, blob_pad_len(buf->head) + len);
  132. memcpy(attr, ptr, len);
  133. return attr;
  134. }
  135. struct blob_attr *
  136. blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len)
  137. {
  138. struct blob_attr *attr;
  139. attr = blob_new(buf, id, len);
  140. if (!attr)
  141. return NULL;
  142. if (ptr)
  143. memcpy(blob_data(attr), ptr, len);
  144. return attr;
  145. }
  146. void *
  147. blob_nest_start(struct blob_buf *buf, int id)
  148. {
  149. unsigned long offset = attr_to_offset(buf, buf->head);
  150. buf->head = blob_new(buf, id, 0);
  151. if (!buf->head)
  152. return NULL;
  153. return (void *) offset;
  154. }
  155. void
  156. blob_nest_end(struct blob_buf *buf, void *cookie)
  157. {
  158. struct blob_attr *attr = offset_to_attr(buf, (unsigned long) cookie);
  159. blob_set_raw_len(attr, blob_pad_len(attr) + blob_len(buf->head));
  160. buf->head = attr;
  161. }
  162. static const size_t blob_type_minlen[BLOB_ATTR_LAST] = {
  163. [BLOB_ATTR_STRING] = 1,
  164. [BLOB_ATTR_INT8] = sizeof(uint8_t),
  165. [BLOB_ATTR_INT16] = sizeof(uint16_t),
  166. [BLOB_ATTR_INT32] = sizeof(uint32_t),
  167. [BLOB_ATTR_INT64] = sizeof(uint64_t),
  168. [BLOB_ATTR_DOUBLE] = sizeof(double),
  169. };
  170. bool
  171. blob_check_type(const void *ptr, unsigned int len, int type)
  172. {
  173. const char *data = ptr;
  174. if (type >= BLOB_ATTR_LAST)
  175. return false;
  176. if (type >= BLOB_ATTR_INT8 && type <= BLOB_ATTR_INT64) {
  177. if (len != blob_type_minlen[type])
  178. return false;
  179. } else {
  180. if (len < blob_type_minlen[type])
  181. return false;
  182. }
  183. if (type == BLOB_ATTR_STRING && data[len - 1] != 0)
  184. return false;
  185. return true;
  186. }
  187. static int
  188. blob_parse_attr(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
  189. {
  190. int id;
  191. size_t len;
  192. int found = 0;
  193. size_t data_len;
  194. if (!attr || attr_len < sizeof(struct blob_attr))
  195. return 0;
  196. id = blob_id(attr);
  197. if (id >= max)
  198. return 0;
  199. len = blob_raw_len(attr);
  200. if (len > attr_len || len < sizeof(struct blob_attr))
  201. return 0;
  202. data_len = blob_len(attr);
  203. if (data_len > len)
  204. return 0;
  205. if (info) {
  206. int type = info[id].type;
  207. if (type < BLOB_ATTR_LAST) {
  208. if (!blob_check_type(blob_data(attr), data_len, type))
  209. return 0;
  210. }
  211. if (info[id].minlen && len < info[id].minlen)
  212. return 0;
  213. if (info[id].maxlen && len > info[id].maxlen)
  214. return 0;
  215. if (info[id].validate && !info[id].validate(&info[id], attr))
  216. return 0;
  217. }
  218. if (!data[id])
  219. found++;
  220. data[id] = attr;
  221. return found;
  222. }
  223. int
  224. blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
  225. {
  226. struct blob_attr *pos;
  227. size_t len = 0;
  228. int found = 0;
  229. size_t rem;
  230. if (!attr || attr_len < sizeof(struct blob_attr))
  231. return 0;
  232. len = blob_raw_len(attr);
  233. if (attr_len < len)
  234. return 0;
  235. memset(data, 0, sizeof(struct blob_attr *) * max);
  236. blob_for_each_attr_len(pos, attr, len, rem) {
  237. found += blob_parse_attr(pos, rem, data, info, max);
  238. }
  239. return found;
  240. }
  241. /* use only on trusted input, otherwise consider blob_parse_untrusted */
  242. int
  243. blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
  244. {
  245. struct blob_attr *pos;
  246. int found = 0;
  247. size_t rem;
  248. memset(data, 0, sizeof(struct blob_attr *) * max);
  249. blob_for_each_attr(pos, attr, rem) {
  250. found += blob_parse_attr(pos, rem, data, info, max);
  251. }
  252. return found;
  253. }
  254. bool
  255. blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2)
  256. {
  257. if (!a1 && !a2)
  258. return true;
  259. if (!a1 || !a2)
  260. return false;
  261. if (blob_pad_len(a1) != blob_pad_len(a2))
  262. return false;
  263. return !memcmp(a1, a2, blob_pad_len(a1));
  264. }
  265. struct blob_attr *
  266. blob_memdup(struct blob_attr *attr)
  267. {
  268. struct blob_attr *ret;
  269. int size = blob_pad_len(attr);
  270. ret = malloc(size);
  271. if (!ret)
  272. return NULL;
  273. memcpy(ret, attr, size);
  274. return ret;
  275. }