xundump: Refuse to undump strings too long for terminating null

We're dealing with three kinds of string storage: char * pointing to a
null-terminated string, char[] holding a null-terminated string, and
char holding a string of length 0 or 1.

Unfortunately, xdump meta data doesn't distinguish the latter two:
both are NSC_STRINGY.  Because of that, xundump happily fills char[]
to the limit, producing strings that aren't null-terminated, resulting
in read beyond buffer and possibly worse.

Affects struct shpstr members shp_path, shp_name, shp_rpath, struct
lndstr member lnd_rpath, and struct natstr members nat_cnam, nat_pnam,
nat_hostaddr, nat_hostname, nat_userid.  Since these are all in game
state, only the empdump utility program is affected, not the
configuration table reader.

We clearly need to require null-termination for char[] values.  Since
using char[1] for null-terminated strings makes no sense, we can still
make NSC_STRINGY with length 1 serve char values as before, by
permitting non-null-terminated strings only when length is 1.  Ugly
wart, but it fixes the bug without a possibly awkward change xdump
meta-data.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This commit is contained in:
Markus Armbruster 2014-01-27 17:52:32 +01:00
parent 47ccc40e38
commit 002a3a3f1e
2 changed files with 14 additions and 9 deletions

View file

@ -28,7 +28,7 @@
*
* Known contributors to this file:
* Ron Koenderink, 2005
* Markus Armbruster, 2005-2011
* Markus Armbruster, 2005-2014
*/
/*
@ -775,7 +775,7 @@ setstr(int fldno, char *str)
{
struct castr *ca;
int must_match, idx;
size_t len;
size_t sz, len;
char *memb_ptr, *old;
ca = getfld(fldno, &idx);
@ -803,13 +803,15 @@ setstr(int fldno, char *str)
return -1;
if (!str)
return gripe("Field %d doesn't take nil", fldno + 1);
len = ca->ca_len;
/* Wart: if ca_len <= 1, the terminating null may be omitted */
sz = ca->ca_len;
len = sz > 1 ? sz - 1 : sz;
if (strlen(str) > len)
return gripe("Field %d takes at most %d characters",
fldno + 1, (int)len);
old = memb_ptr;
if (!must_match)
strncpy(memb_ptr, str, len);
strncpy(memb_ptr, str, sz);
break;
default:
return gripe("Field %d doesn't take strings", fldno + 1);