blob.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
  186. {
  187. int id;
  188. size_t len;
  189. int found = 0;
  190. size_t data_len;
  191. if (!attr || attr_len < sizeof(struct blob_attr))
  192. return 0;
  193. id = blob_id(attr);
  194. if (id >= max)
  195. return 0;
  196. len = blob_raw_len(attr);
  197. if (len > attr_len || len < sizeof(struct blob_attr))
  198. return 0;
  199. data_len = blob_len(attr);
  200. if (data_len > len)
  201. return 0;
  202. if (info) {
  203. int type = info[id].type;
  204. if (type < BLOB_ATTR_LAST) {
  205. if (!blob_check_type(blob_data(attr), data_len, type))
  206. return 0;
  207. }
  208. if (info[id].minlen && len < info[id].minlen)
  209. return 0;
  210. if (info[id].maxlen && len > info[id].maxlen)
  211. return 0;
  212. if (info[id].validate && !info[id].validate(&info[id], attr))
  213. return 0;
  214. }
  215. if (!data[id])
  216. found++;
  217. data[id] = attr;
  218. return found;
  219. }
  220. int
  221. blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
  222. {
  223. struct blob_attr *pos;
  224. size_t len = 0;
  225. int found = 0;
  226. size_t rem;
  227. if (!attr || attr_len < sizeof(struct blob_attr))
  228. return 0;
  229. len = blob_raw_len(attr);
  230. if (len != attr_len)
  231. return 0;
  232. memset(data, 0, sizeof(struct blob_attr *) * max);
  233. blob_for_each_attr_len(pos, attr, len, rem) {
  234. found += blob_parse_attr(pos, rem, data, info, max);
  235. }
  236. return found;
  237. }
  238. /* use only on trusted input, otherwise consider blob_parse_untrusted */
  239. int
  240. blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
  241. {
  242. struct blob_attr *pos;
  243. int found = 0;
  244. size_t rem;
  245. memset(data, 0, sizeof(struct blob_attr *) * max);
  246. blob_for_each_attr(pos, attr, rem) {
  247. found += blob_parse_attr(pos, rem, data, info, max);
  248. }
  249. return found;
  250. }
  251. bool
  252. blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2)
  253. {
  254. if (!a1 && !a2)
  255. return true;
  256. if (!a1 || !a2)
  257. return false;
  258. if (blob_pad_len(a1) != blob_pad_len(a2))
  259. return false;
  260. return !memcmp(a1, a2, blob_pad_len(a1));
  261. }
  262. struct blob_attr *
  263. blob_memdup(struct blob_attr *attr)
  264. {
  265. struct blob_attr *ret;
  266. int size = blob_pad_len(attr);
  267. ret = malloc(size);
  268. if (!ret)
  269. return NULL;
  270. memcpy(ret, attr, size);
  271. return ret;
  272. }