3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-25 17:59:25 +01:00

wscutil: Allow 0-length attributes in wsc_attr_builder

wsc_attr_builder_start_attr and wsc_attr_builder_free look at
builder->curlen to see whether the TLV's length needs to be updated to
include the previous attribute.  If builder->curlen is 0
wsc_attr_builder_start_attr assumes there's no previous attribute and
starts writing at current builder->offset.  If the previous attribute
length was 0 curlen would stay at 0 and that attribute would get
overwritten with the new one.  To solve this add the 4 bytes of the T
and L to curlen as soon as a new attribute is started, and subtract
them when writing the L value.  The alternative would be to set a flag
to say whether an attribute was started.

The spec explicitly allows 0-length attributes in section 12:
"The variable length string attributes, e.g., Device Name, are encoded
without null-termination, i.e., no 0x00 octets added to the end of the
value. If the string is empty, the attribute length is set to zero."
This commit is contained in:
Andrew Zaborowski 2020-08-25 00:34:22 +02:00 committed by Denis Kenzior
parent 8840d4623d
commit 8173ded0eb

View File

@ -1634,11 +1634,12 @@ static bool wsc_attr_builder_start_attr(struct wsc_attr_builder *builder,
/* Record previous attribute's length */ /* Record previous attribute's length */
if (builder->curlen > 0) { if (builder->curlen > 0) {
bytes = builder->buf + builder->offset; bytes = builder->buf + builder->offset;
l_put_be16(builder->curlen, bytes + 2); l_put_be16(builder->curlen - 4, bytes + 2);
builder->offset += 4 + builder->curlen; builder->offset += builder->curlen;
builder->curlen = 0;
} }
builder->curlen = 4;
if (builder->offset + 4 >= builder->capacity) if (builder->offset + 4 >= builder->capacity)
wsc_attr_builder_grow(builder); wsc_attr_builder_grow(builder);
@ -1650,10 +1651,10 @@ static bool wsc_attr_builder_start_attr(struct wsc_attr_builder *builder,
static bool wsc_attr_builder_put_u8(struct wsc_attr_builder *builder, uint8_t v) static bool wsc_attr_builder_put_u8(struct wsc_attr_builder *builder, uint8_t v)
{ {
if (builder->offset + 4 + builder->curlen + 1 >= builder->capacity) if (builder->offset + builder->curlen + 1 >= builder->capacity)
wsc_attr_builder_grow(builder); wsc_attr_builder_grow(builder);
builder->buf[builder->offset + 4 + builder->curlen] = v; builder->buf[builder->offset + builder->curlen] = v;
builder->curlen += 1; builder->curlen += 1;
return true; return true;
@ -1662,10 +1663,10 @@ static bool wsc_attr_builder_put_u8(struct wsc_attr_builder *builder, uint8_t v)
static bool wsc_attr_builder_put_u16(struct wsc_attr_builder *builder, static bool wsc_attr_builder_put_u16(struct wsc_attr_builder *builder,
uint16_t v) uint16_t v)
{ {
if (builder->offset + 4 + builder->curlen + 2 >= builder->capacity) if (builder->offset + builder->curlen + 2 >= builder->capacity)
wsc_attr_builder_grow(builder); wsc_attr_builder_grow(builder);
l_put_be16(v, builder->buf + builder->offset + 4 + builder->curlen); l_put_be16(v, builder->buf + builder->offset + builder->curlen);
builder->curlen += 2; builder->curlen += 2;
return true; return true;
@ -1674,10 +1675,10 @@ static bool wsc_attr_builder_put_u16(struct wsc_attr_builder *builder,
static bool wsc_attr_builder_put_u32(struct wsc_attr_builder *builder, static bool wsc_attr_builder_put_u32(struct wsc_attr_builder *builder,
uint32_t v) uint32_t v)
{ {
if (builder->offset + 4 + builder->curlen + 4 >= builder->capacity) if (builder->offset + builder->curlen + 4 >= builder->capacity)
wsc_attr_builder_grow(builder); wsc_attr_builder_grow(builder);
l_put_be32(v, builder->buf + builder->offset + 4 + builder->curlen); l_put_be32(v, builder->buf + builder->offset + builder->curlen);
builder->curlen += 4; builder->curlen += 4;
return true; return true;
@ -1686,12 +1687,10 @@ static bool wsc_attr_builder_put_u32(struct wsc_attr_builder *builder,
static bool wsc_attr_builder_put_bytes(struct wsc_attr_builder *builder, static bool wsc_attr_builder_put_bytes(struct wsc_attr_builder *builder,
const void *bytes, size_t size) const void *bytes, size_t size)
{ {
while (builder->offset + 4 + builder->curlen + size >= while (builder->offset + builder->curlen + size >= builder->capacity)
builder->capacity)
wsc_attr_builder_grow(builder); wsc_attr_builder_grow(builder);
memcpy(builder->buf + builder->offset + 4 + builder->curlen, memcpy(builder->buf + builder->offset + builder->curlen, bytes, size);
bytes, size);
builder->curlen += size; builder->curlen += size;
return true; return true;
@ -1700,10 +1699,10 @@ static bool wsc_attr_builder_put_bytes(struct wsc_attr_builder *builder,
static bool wsc_attr_builder_put_oui(struct wsc_attr_builder *builder, static bool wsc_attr_builder_put_oui(struct wsc_attr_builder *builder,
const uint8_t *oui) const uint8_t *oui)
{ {
if (builder->offset + 4 + builder->curlen + 3 >= builder->capacity) if (builder->offset + builder->curlen + 3 >= builder->capacity)
wsc_attr_builder_grow(builder); wsc_attr_builder_grow(builder);
memcpy(builder->buf + builder->offset + 4 + builder->curlen, oui, 3); memcpy(builder->buf + builder->offset + builder->curlen, oui, 3);
builder->curlen += 3; builder->curlen += 3;
return true; return true;
@ -1721,11 +1720,10 @@ static bool wsc_attr_builder_put_string(struct wsc_attr_builder *builder,
len = 1; len = 1;
} }
if (builder->offset + 4 + builder->curlen + len >= builder->capacity) if (builder->offset + builder->curlen + len >= builder->capacity)
wsc_attr_builder_grow(builder); wsc_attr_builder_grow(builder);
memcpy(builder->buf + builder->offset + 4 + builder->curlen, memcpy(builder->buf + builder->offset + builder->curlen, string, len);
string, len);
builder->curlen += len; builder->curlen += len;
return true; return true;
@ -1753,8 +1751,8 @@ static uint8_t *wsc_attr_builder_free(struct wsc_attr_builder *builder,
if (builder->curlen > 0) { if (builder->curlen > 0) {
uint8_t *bytes = builder->buf + builder->offset; uint8_t *bytes = builder->buf + builder->offset;
l_put_be16(builder->curlen, bytes + 2); l_put_be16(builder->curlen - 4, bytes + 2);
builder->offset += 4 + builder->curlen; builder->offset += builder->curlen;
builder->curlen = 0; builder->curlen = 0;
} }