blobmsg: add _len variants for all attribute checking methods

Introduce _len variants of blobmsg attribute checking functions which
aims to provide safer implementation as those functions should limit all
memory accesses performed on the blob to the range [attr, attr + len]
(upper bound non inclusive) and thus should be suited for checking of
untrusted blob attributes.

While at it add some comments in order to make it clear.

Signed-off-by: Tobias Schramm <tobleminer@gmail.com>
[_safe -> _len, blobmsg_check_array_len fix, commit subject/desc facelift]
Signed-off-by: Petr Štetiar <ynezz@true.cz>
This commit is contained in:
Tobias Schramm 2018-11-15 03:42:48 +01:00 committed by Petr Štetiar
parent cd3059796a
commit b0e21553ae
2 changed files with 72 additions and 4 deletions

View file

@ -100,12 +100,22 @@ bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len)
} }
int blobmsg_check_array(const struct blob_attr *attr, int type) int blobmsg_check_array(const struct blob_attr *attr, int type)
{
return blobmsg_check_array_len(attr, type, blob_raw_len(attr));
}
int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len)
{ {
struct blob_attr *cur; struct blob_attr *cur;
bool name; bool name;
size_t rem;
int size = 0; int size = 0;
if (type > BLOBMSG_TYPE_LAST)
return -1;
if (!blobmsg_check_attr_len(attr, false, len))
return -1;
switch (blobmsg_type(attr)) { switch (blobmsg_type(attr)) {
case BLOBMSG_TYPE_TABLE: case BLOBMSG_TYPE_TABLE:
name = true; name = true;
@ -117,11 +127,11 @@ int blobmsg_check_array(const struct blob_attr *attr, int type)
return -1; return -1;
} }
blobmsg_for_each_attr(cur, attr, rem) { __blobmsg_for_each_attr(cur, attr, len) {
if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type) if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type)
return -1; return -1;
if (!blobmsg_check_attr(cur, name)) if (!blobmsg_check_attr_len(cur, name, len))
return -1; return -1;
size++; size++;
@ -135,6 +145,11 @@ bool blobmsg_check_attr_list(const struct blob_attr *attr, int type)
return blobmsg_check_array(attr, type) >= 0; return blobmsg_check_array(attr, type) >= 0;
} }
bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len)
{
return blobmsg_check_array_len(attr, type, len) >= 0;
}
int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len, int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
struct blob_attr **tb, void *data, unsigned int len) struct blob_attr **tb, void *data, unsigned int len)
{ {

View file

@ -104,19 +104,66 @@ static inline size_t blobmsg_len(const struct blob_attr *attr)
return blobmsg_data_len(attr); return blobmsg_data_len(attr);
} }
/*
* blobmsg_check_attr: validate a list of attributes
*
* This method may be used with trusted data only. Providing
* malformed blobs will cause out of bounds memory access.
*/
bool blobmsg_check_attr(const struct blob_attr *attr, bool name); bool blobmsg_check_attr(const struct blob_attr *attr, bool name);
/*
* blobmsg_check_attr_len: validate a list of attributes
*
* This method should be safer implementation of blobmsg_check_attr.
* It will limit all memory access performed on the blob to the
* range [attr, attr + len] (upper bound non inclusive) and is
* thus suited for checking of untrusted blob attributes.
*/
bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len);
/*
* blobmsg_check_attr_list: validate a list of attributes
*
* This method may be used with trusted data only. Providing
* malformed blobs will cause out of bounds memory access.
*/
bool blobmsg_check_attr_list(const struct blob_attr *attr, int type); bool blobmsg_check_attr_list(const struct blob_attr *attr, int type);
bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len); /*
* blobmsg_check_attr_list_len: validate a list of untrusted attributes
*
* This method should be safer implementation of blobmsg_check_attr_list.
* It will limit all memory access performed on the blob to the
* range [attr, attr + len] (upper bound non inclusive) and is
* thus suited for checking of untrusted blob attributes.
*/
bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len);
/* /*
* blobmsg_check_array: validate array/table and return size * blobmsg_check_array: validate array/table and return size
* *
* Checks if all elements of an array or table are valid and have * Checks if all elements of an array or table are valid and have
* the specified type. Returns the number of elements in the array * the specified type. Returns the number of elements in the array
*
* This method may be used with trusted data only. Providing
* malformed blobs will cause out of bounds memory access.
*/ */
int blobmsg_check_array(const struct blob_attr *attr, int type); int blobmsg_check_array(const struct blob_attr *attr, int type);
/*
* blobmsg_check_array_len: validate untrusted array/table and return size
*
* Checks if all elements of an array or table are valid and have
* the specified type. Returns the number of elements in the array.
*
* This method should be safer implementation of blobmsg_check_array.
* It will limit all memory access performed on the blob to the
* range [attr, attr + len] (upper bound non inclusive) and is
* thus suited for checking of untrusted blob attributes.
*/
int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len);
int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len, int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
struct blob_attr **tb, void *data, unsigned int len); struct blob_attr **tb, void *data, unsigned int len);
int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len, int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
@ -272,4 +319,10 @@ int blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, .
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \ (blob_pad_len(pos) >= sizeof(struct blob_attr)); \
rem -= blob_pad_len(pos), pos = blob_next(pos)) rem -= blob_pad_len(pos), pos = blob_next(pos))
#define __blobmsg_for_each_attr(pos, attr, rem) \
for (pos = (struct blob_attr *) (attr ? blobmsg_data(attr) : NULL); \
rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
rem -= blob_pad_len(pos), pos = blob_next(pos))
#endif #endif