summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl/ipoe
diff options
context:
space:
mode:
authorDenys Fedoryshchenko <denys.f@collabora.com>2026-08-10 08:55:22 +0300
committerDenys Fedoryshchenko <denys.f@collabora.com>2026-08-10 08:55:22 +0300
commit3aa2a84122a48e28aef252b8777d5e57f28fafe5 (patch)
tree57c3b2192020a0c7f59803caeccbe9887024f53e /accel-pppd/ctrl/ipoe
parent4600e779e801b51405ed51d421ecfe8e33e5059d (diff)
downloadaccel-ppp-3aa2a84122a48e28aef252b8777d5e57f28fafe5.tar.gz
accel-ppp-3aa2a84122a48e28aef252b8777d5e57f28fafe5.zip
ipoe: harden local-net prefix length parsing
The netmask was built by shifting ~0, which is a signed int holding -1, and left shifting a negative value is undefined in C. Every compiler we build with produces the expected mask, so this is not a behaviour fix, but it trips -fsanitize=shift and relies on latitude the standard does not grant. Shift an unsigned operand instead. The prefix length itself was not validated properly either. strtoul() accepts a leading minus and negates, so 'local-net=10.0.0.0/-1' yields ULONG_MAX, which truncates to -1 in the int and passes the 'mask > 32' test. The shift count then becomes 33, which is out of range whether the operand is signed or unsigned. endptr was set but never looked at, so trailing garbage was silently ignored and '/abc' quietly became a /0. Keep the parsed value unsigned, reject anything that is not a complete number in 0..32, and only then narrow it.
Diffstat (limited to 'accel-pppd/ctrl/ipoe')
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 18e9228d..1e3f7054 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -3814,6 +3814,7 @@ static void parse_local_net(const char *opt)
char str[17];
in_addr_t addr;
int mask;
+ unsigned long val;
char *endptr;
struct local_net *n;
@@ -3824,9 +3825,10 @@ static void parse_local_net(const char *opt)
addr = inet_addr(str);
if (addr == INADDR_NONE)
goto out_err;
- mask = strtoul(ptr + 1, &endptr, 10);
- if (mask > 32)
+ val = strtoul(ptr + 1, &endptr, 10);
+ if (*endptr || val > 32)
goto out_err;
+ mask = val;
} else {
addr = inet_addr(opt);
if (addr == INADDR_NONE)
@@ -3834,7 +3836,7 @@ static void parse_local_net(const char *opt)
mask = 24;
}
- mask = htonl(mask ? ~0 << (32 - mask) : 0);
+ mask = htonl(mask ? UINT32_MAX << (32 - mask) : 0);
addr = addr & mask;
list_for_each_entry(n, &local_nets, entry) {