blob.c 6.9 KB

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