Re: [Security] telnetd slcbuf global buffer overflow in add_slc() — pre-auth, remotely triggerable
Collin Funk <[email protected]> Thu, 11 Jun 2026 19:53:05 -0700
| Newsgroups | gmane.comp.gnu.inetutils.bugs |
|---|---|
| Message-ID | <[email protected]> |
zhangph <[email protected]> writes: > Ran into a buffer overflow in telnetd's SLC handling while fuzzing inetut= ils 2.2. > The add_slc() function in telnetd/slc.c writes triplets into a fixed-size= global > buffer without any bounds check, so a client can overflow it by sending t= oo many > SLC entries in a single LINEMODE suboption. > > > The vulnerable code (slc.c:166-178): > > > static unsigned char slcbuf[NSLC * 6]; /* 108 bytes */ > static unsigned char *slcptr; > > > void add_slc(register char func, register char flag, register cc_t va= l) > { > if ((*slcptr++ =3D (unsigned char) func) =3D=3D 0xff) > *slcptr++; > if ((*slcptr++ =3D (unsigned char) flag) =3D=3D 0xff) > *slcptr++; > if ((*slcptr++ =3D (unsigned char) val) =3D=3D 0xff) > *slcptr++; > } > > > start_slc() sets slcptr =3D slcbuf + 4 (4-byte header). Each triplet adds= 3 bytes. > No length check anywhere. Once do_opt_slc() processes more than 34 triple= ts from > a single suboption, slcptr goes past the end of slcbuf. > > > To trigger, a client sends: > > > FF FB 22 # IAC WILL LINEMODE > FF FA 22 03 (13 03 01 =C3=97 35) FF F0 # IAC SB LINEMODE SLC + 35 tri= plets + SE > > > With ASAN: > > > global-buffer-overflow on address 0x000000dd822c > WRITE of size 1 at 0x000000dd822c > #0 add_slc slc.c:175 > #1 process_slc slc.c:268 > #2 do_opt_slc slc.c:498 > #3 suboption state.c:1263 > 0x000000dd822c is located 0 bytes to the right of 'slcbuf' (size 108) > > > Boundary is sharp: 34 triplets =3D 106 bytes, no crash. 36 triplets =3D 1= 12 bytes, > crash. Max overflow is ~400 bytes (limited by subbuffer[512]). > > > This happens during option negotiation, before any authentication. > > > The adjacent global is def_slcbuf (a pointer), so if the overflow reaches= it, > deferslc() would later use a corrupted pointer in a memmove. Whether that= 's > practically exploitable depends on linker layout =E2=80=94 in my build th= ere's a 52-byte > gap (ASAN redzone), but production builds may place things differently. > > > Suggested fix =E2=80=94 add a bounds check in add_slc(): > > > void add_slc(register char func, register char flag, register cc_t va= l) > { > if (slcptr + 6 > slcbuf + sizeof(slcbuf)) > return; > /* ... existing code ... */ > } > > > And a similar check before the sprintf in end_slc() at line 240. > > > Happy to send over the full PoC, ASAN logs, and analysis if useful. This = code > goes back to 4.4BSD so other telnetd implementations may have the same is= sue. This was already identified [1] and fixed in inetutils-2.8 [2]. Collin [1] https://lists.gnu.org/archive/html/bug-inetutils/2026-03/msg00031.html [2] https://codeberg.org/inetutils/inetutils/commit/6864598a29b652a6b69a958= f5cd1318aa2b258af