bufferoverflow upon receive at mtu 256
Amateur Radio AX.25 chat and PBBS program using Linux's AX.25 stack
Brought to you by:
dranch
linpac crashes with a bufferoverflow upon receiving the first out of a lot of full-mtu 256 byte packets containing "AAAAAAAAAAAAA" (no \r). the sequence is terminated as it should in the last of many packets containing just 'AAAAA' with MSG_EOR and an "\r" there but it doesn't even get that far. it just dies horribly upon receiving the first packet...(and then has to remove that lockfile again... pretty sure that lockfile issue can be solved with a failing bind() to something instead of a lockfile too ;)
note that both SP and GP in dosbox have no issues with the same packet sequence.
Diff:
note that the bufferoverflow actually seems to be caused by axlisten. which works fine when run on its own outside of linpac (ubuntu 16 lts)... as linpac also bufferoverflows on line 181 of /usr/bin/linpac when its not even receiving the 'long' (for 1960s standards, maybe) packets not terminated by \r itself. it just hears another station doing so (or rather, axlisten does so ;)
the whole thing works fine until that first long packet out of a lot... it connects it talks it does everything... but then poof ;) even worse after it dies the termios settings are still set to \r so you have to type 'reset' to the terminal blindly AND remove that silly good-for-nothing lockfile ;) (but guess that just comes with a core dump ;)
also happens on ubuntu 18 LTS desktop with it's axlisten... looks like linpac takes the output of axlisten and 'does stuff to it' (ansi color?) causing it somehow. pretty sure the axlisten of ubuntu is fairly old. linpac itself was packaged at 0.24 or so (yes it is 0.28 now ;).., still. should not happen. ;)
Thank you for the report.
Few ideas here. 1) Have you tried VE7FET's ax25 repo ( https://github.com/ve7fet/linuxax25 ) or possibly a newer version of listen from the official ax25 sources maintained at DL5RB ( https://www.linux-ax25.org/wiki/Main_Page ) . Both repos have lots of fixes compared to the old versions pre-packaged by various distros. If the issue is really in listen itself, the fix needs to be reported to say DL5RB and/or VE7FET so a fix can be mainlined. As a work around, maybe try lowering your MTU in /etc/ax25/axports to something smaller.. maybe 250 bytes?
One last question, did you happen to determine the maximum number of bytes that can be sent that Linpac won't crash on? Understanding this delta will help determine how much overhead Linpac's coloring might be adding and thus help clear up the issue in the code.
so far for the attempt to just install that by running the ./ax25upd thing in his repository ;)
(ubuntu 16 lts with all 'dev' stuff installed ;) - nope ldconfig didn't fix axlisten either ;)
anyway. don't quite see the point in using that old ax25lib stuff -at all-... getifaddrs() will happily return all ax_25 interfaces AND their mtu's (which seriously should be 256 anyway, most definately not 255 such as in the default axports file ;)... SOCK_PACKET will happily give you a monitor (it needs to run as root or at least have the capability - but so does opening axlisten in a popen or pty - as that too won't run as a mortal user ;) (the one thing it won't do is display packets your own computer sent out... as that setsockopt seems not to work)
will take a closer look at linpac source anyway as i need to figure out how it binds to callsigns that are NOT on an interface and they work fine for both connect() and listen() somehow for our own software.
the lockfile thing whenever linpac dies or otherwise gets terminated 'unexpectedly' is just 'annoying'... for all i care just create a PF_LOCAL socket or if you want to rely on it also running an ip stack, bind to some udp port (it can only do that once system wide ;)... no lockfiles getting stuck. ;)
(last time i saw lockfiles in use was with getty on serial ports and they didn't even work well there ;)
can just test it yourself... kiss-tcp server at 208.109.9.123:8001 ... connect to 'MUTINY'.. it'll give a few short lines and then move on to transferring a huge blob of text 20 times in a row. it crashes on the first packet of that. source code for both the mutiny node as a kissattach for tcp here: https://github.com/cb3rob/CB3ROB-AX25-TOOLS-LINUX
Have you tried lowering your Linux /etc/ax25/axports MTU to a level that Linpac doesn't have an issue with? Yes.. Linpac should deal with with it but knowing the limit would be useful
i'll just code an increment counter on it just sending packets until it crashes... should be able to see the last one it passed before the coredump ;)
it occurs at exactly 256 bytes. and yes in that silly old axports file it is also set to 256 (not 255). it doesn't -have- to be one of linpac's own connections. just 'seeing 2 other hosts do it on the network' in the monitor suffices. (so it's not related to linpac's own mtu). think it's purely in the parsing of the output of axlisten and displaying it. axlisten itself by itself works fine.
(and yes it is quite common for the linux ax.25 stack to receive and clearly also acknowledge a shitload of packets by itself before passing them onto recv() ;) thats why nothing is shown above. ;P funny part is. if your server closes() immediately afterwards they'll never get processed at all ;) you never notice that at 1200 baud ;) you do at 1000mbit/s or more ;) but then again gp isn't exactly 'real time multitasking' either ;) connect, server sends a shitload of packets, then it suddenly goes plop plop plop or plopprrroploprrrrploplop if you do it in 2 windows at the same time ;) but neither graphic packet nor sp crash on 256 byte packets. think that latest version of the ax.25 protocol which nobody implemented also allows for more than 256. but let's just stick with 256. it's fine. and on 8 bit systems you need a double byte counter anyway as the entire packet can still be 340-ish long anyway. and 0 byte packets are not done so a 1 byte counter for the payload suffices. ;)
Last edit: Sven Olaf Kamphuis 2021-11-24
with axlisten broken on the box i tried to update that axlibrary stuff on at least it no longer crashes ;) no monitor tho. not that a monitor is needed per-se on a multi user multi tasking os... if they want axlisten they can just run one in another terminal.
Last edit: Sven Olaf Kamphuis 2021-11-24
there appears to be no check on the length of mon_line ;P (no that's not what the '1' in strncat does - that function has no total length limitation ;)
so either mon_line itself is overflowed. or printf overflows at not seeing a terminating '0' to the overflowed string ;)
windows.h: char mon_line[256];
/Downloads/linpac-0.28/src# less windows.cc
if (ev.type == EV_NONE)
{
if (listpid >= 0)
{
char buf[512];
int rc = read(list, buf, 512);
if (rc > 0)
{
int i;
for (i=0; i < rc; i++)
{
if (buf[i] == '\r' || buf[i] == '\n')
{
next_mon_line();
strcpy(mon_line, "");
}
else strncat(mon_line, &buf[i], 1);
}
draw();
}
}
}
works fine after changing mon_line to 512 in src/windows.h ... could be a bit overkill... the way it is done highly depends on pre-existing termios settings etc anyway. (as in if it even is one line of text at a time that gets read() in the first place ) think that whole part could well do with a rewrite... for one thing... instead of pipe dup2 exec ( axlisten )
Last edit: Sven Olaf Kamphuis 2021-11-24
axlisten seems to write() it actually line by line. (not just one write() with a lot of \n's in it ;) but how many bytes you get from a read() on a redirected terminal depends on the termios settings of that terminal. and is not per-se one line at a time... (especially not since it is also in non blocking mode ;) anyway the problem is in that strncat(bla,mon_line,1) bit which doesn't check the length of mon_line at all. just that it appends one byte at a time to it. ;) also the newlines, carriage returns, etc overhead.
Last edit: Sven Olaf Kamphuis 2021-11-24
according to the manpage on pipe() pipe's buffer size can simply be set to PIPE_BUF (mon_line=PIPE_BUF;) (#include<limits.h> as there appear to be 2 diffent ones one for posix (512) and one for gnu (4096) and then, at least with with O_DIRECT it'll never fail on that bit ;)</limits.h>
Writes of greater than PIPE_BUF bytes (see pipe(7)) will be split into multiple packets. The constant PIPE_BUF is defined in <limits.h>.</limits.h>