[PATCH v2 1/4] net: lwip: tftp: fix find_option()
Heinrich Schuchardt
heinrich.schuchardt at canonical.com
Sat Feb 1 07:22:11 CET 2025
Find_option() is used to retrieve the block size value in an option
acknowledgment in response to a request containing a block size option
according to RFC2348.
The format of an OACK response is described in RFC2347 as
+-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
| opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 |
+-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
The current implementation of find_option() only works if
* blksize is the first option
* lwip_strnstr() ignores the length parameter,
i.e. is implemented via strstr()
The OACK messages starts with 0x00 0x06. If 'blksize' is the first option,
strstr() reports a match when the first parameter points to 0x06. Adding
the string length of 'blksize' plus 2 to the location of the 0x06 byte
points to the value.
Find_option() would report a match for option 'blksize' if the response
contained an option called 'foo_blksize_bar'. In this case find_option()
would return 'bar' as the value string.
If 'blksize' were the second option, find_option() would return a pointer
to the second character of the value string.
Furthermore find_option() does not detect if the value string is NUL
terminated. This may lead to a buffer overrun.
Provide an implementation that correctly steps from option to option.
Fixes: 27d7ccda94fa ("net: lwip: tftp: add support of blksize option to client")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt at canonical.com>
---
v2:
new patch
---
lib/lwip/lwip/src/apps/tftp/tftp.c | 54 +++++++++++++++++++++++++-----
1 file changed, 45 insertions(+), 9 deletions(-)
diff --git a/lib/lwip/lwip/src/apps/tftp/tftp.c b/lib/lwip/lwip/src/apps/tftp/tftp.c
index 56aeabc4d73..e85e3623066 100644
--- a/lib/lwip/lwip/src/apps/tftp/tftp.c
+++ b/lib/lwip/lwip/src/apps/tftp/tftp.c
@@ -264,19 +264,55 @@ static u16_t payload_size(void)
return TFTP_DEFAULT_BLOCK_SIZE;
}
+/**
+ * find_option() - check if OACK message contains option
+ *
+ * @p: message buffer
+ * @option: option key
+ * Return: option value
+ */
static const char *
find_option(struct pbuf *p, const char *option)
{
- int i;
- u16_t optlen = strlen(option);
- const char *b = p->payload;
-
- for (i = 0; i + optlen + 1 < p->len; i++) {
- if (lwip_strnstr(b + i, option, optlen))
- return b + i + optlen + 2;
- }
+ const char *pos = p->payload;
+ int rem = p->len;
+
+ /*
+ * According to RFC 2347 the OACK packet has the following format:
+ *
+ * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
+ * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 |
+ * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
+ */
+
+ /* Skip opc */
+ pos += 2;
+ rem -= 2;
+ if (rem <= 0)
+ return NULL;
+
+ for (;;) {
+ int len;
+ int match;
+
+ len = strnlen(pos, rem) + 1;
+ if (rem < len)
+ break;
+ match = strcmp(pos, option);
+ /* Skip option */
+ pos += len;
+ rem -= len;
+ len = strnlen(pos, rem) + 1;
+ if (rem < len)
+ break;
+ if (!match)
+ return pos;
+ /* Skip value */
+ pos += len;
+ rem -= len;
+ }
- return NULL;
+ return NULL;
}
static void
--
2.47.1
More information about the U-Boot
mailing list