-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Description
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\0and removes it if so, then callsnet_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)- callsnet_buf_add_mem(buf, s, strlen(s)): no\0added, fails if not enough room for the string +\0terminator.net_buf_get_str(buf)- adds a trailing\0if 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
Type
Projects
Status