diff options
| author | Denys Fedoryshchenko <denys.f@collabora.com> | 2026-08-10 08:55:22 +0300 |
|---|---|---|
| committer | Denys Fedoryshchenko <denys.f@collabora.com> | 2026-08-10 08:55:22 +0300 |
| commit | 3aa2a84122a48e28aef252b8777d5e57f28fafe5 (patch) | |
| tree | 57c3b2192020a0c7f59803caeccbe9887024f53e | |
| parent | 4600e779e801b51405ed51d421ecfe8e33e5059d (diff) | |
| download | accel-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.
| -rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 8 |
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) { |
