Skip to content

net: buf: Make a net_buf_add_str() and other string handling #78799

@josuah

Description

@josuah

Introduction

Introduction of a net_buf based safe string handling library that is convenient to use while dealing with string-based network protocols.

[EDIT: This PR shows a possible implementation]

Problem description

String-based network protocols require a fair amount of <string.h> handling, which requires extra care to avoid buffer overflows and other memory corruption. Boundary checks are currently done inline on every protocol handler.

Proposed change

The network library already contains safe wrappers around memory operations on buffers or integers.
The proposal is to add strings concatenation to the collection.

Detailed RFC

What kind of wrapper to build? What would be the underlying net_buf_... calls?

The ideal would be to have something to allow returning an error rather than hitting an assertion failure:

char *type = "KITE";

ret = net_buf_add_str(buf, "type: ");
if (ret < 0) {
        return ret;
}

ret = net_buf_add_str(buf, type);
if (ret < 0) {
        return ret;
}

ret = net_buf_add_str(buf, "\n");
if (ret < 0) {
        return ret;
}

return 0;

This becomes a bit heavyweight, so a string formatting wrapper could also be introduced:

char *type = "KITE";

ret = net_buf_add_fmt(buf, "type: %s\n", type);
if (ret < 0) {
        return ret;
}

return 0;

Then remains the problem of accessing the string: does net_buf_add_str/fmt() always add the trailing \0? This means removing it when concatenating like strncat() does, which could break code that interleaves binary and strings.

Proposed change (Detailed)


char *s = "with nul byte\0";
net_buf_add_mem(buf, s, strlen(s) + 1);
net_buf_add_mem(buf, s, strlen(s) + 1);

This leads to with nul byte\0with nul byte\0 instead of with nul bytewith nul byte\0
Not a viable API.


char *s = "with nul byte\0";
net_buf_add_mem(buf, s, strlen(s));
net_buf_add_mem(buf, s, strlen(s));

This leads to with nul bytewith nul byte instead of with nul bytewith nul byte\0
Not a viable API.


char *s = "with nul byte\0";
net_buf_add_mem(buf, s, strlen(s) + 1);
net_buf_remove_u8(buf); // remove the nul terminator to add another string
net_buf_add_mem(buf, s, strlen(s) + 1);

This works but could be misleading as data is removed from a buffer, so does not mix strings and

  • net_buf_add_str(buf, s) check if there is a trailing \0 and removes it if so, then calls net_buf_add_mem(buf, s, strlen(s) + 1);

char *s = "with nul byte\0";
net_buf_add_mem(buf, s, strlen(s));
net_buf_add_mem(buf, s, strlen(s));
net_buf_add_u8(buf, '\0');

This leads to with nul bytewith nul byte\0 but easy to forget the terminator '\0'

  • net_buff_add_str(buf, s) - calls net_buf_add_mem(buf, s, strlen(s)): no \0 added, fails if not enough room for the string + \0 terminator.
  • net_buf_get_str(buf) - adds a trailing \0 if not already present and returns \s, assertion error upon failure.

It looks like the last option is the least ambiguous, but would require some care to not access buf->data directly as a \0 delmited string.

net_buf_add_fmt() would be:

int len;
len = vsnprintf(net_buf_tailroom(buf) + 1, NULL, ...);
if (len > net_buf_tailroom(buf)) {
       return -ENOMEM;
}
vsnprintf(net_buf_tailroom(buf), net_buf_add(buf, len), fmt, ...);
return 0;

Dependencies

By introducing new APIs on top of the existing ones, no API breakage is expected.

Concerns and Unresolved Questions

Is there something equivalent already in Zephyr?
I would appreciate feedback on the different trade-off and best compromise, and whether this approach is reasonable.

Alternatives

Introduction of extra check_compliance.py verification to try to spot most common pitfalls, and warn about the most misleading string.h functions such as strcat.

Metadata

Metadata

Assignees

Labels

RFCRequest For Comments: want input from the communityarea: Networking Buffersnet_buf/net_buf_simple API & implementation

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions