From: PatR Date: Mon, 19 Feb 2018 19:59:14 +0000 (-0800) Subject: fix #H6867 - mail buffer overrun X-Git-Tag: NetHack-3.6.1_RC01~177^2~2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=859ef823d6ae78401ae12c5628e6811a675a47b0;p=nethack fix #H6867 - mail buffer overrun Web contact report of a github pull request. A previous fix from same user dealt with potential crash caused by freeing mailbox data when the mailbox came from getenv("MAIL"). getenv() doesn't return a value obtained by malloc so freeing it was bad. The fix was to allocate memory to hold a copy of getenv("MAIL") so that free() was valid. Unfortunately it didn't allocate enough space to hold the terminating '\0' so potentially corrupted malloc/free bookkeeping data. And the alloc+copy was being performed every time the mailbox was checked, resulting in leaked memory from the previous check (if MAIL came from player's environment). Fortunately the recheck only takes place after new mail is actually detected and reported to the player so the leak was probably small for most folks. This compiles for the set of conditionals that apply to me (after taking out -DNOMAIL that the hints put in my Makefile) but I can't test that it actually works since mail is never delivered to this machine. --- diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 9b8633956..0ce719fe4 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -577,6 +577,11 @@ the fix for secret doors on special levels always having vertical orientation the fix intended for "a shop object stolen from outside the shop (via grappling hook) would be left marked as 'unpaid'" broke normal pickup, preventing any picked up item from merging with compatible stack +unix: freeing mailbox data at game end crashed if MAIL came from environment +unix: fix for freeing MAIL introduced a one-byte buffer overrun which could + interfere with malloc/free operation +unix: fix for freeing MAIL also introduced a memory leak whenever new mail + is detected and MAIL comes from the environment Platform- and/or Interface-Specific Fixes diff --git a/src/mail.c b/src/mail.c index 9d8986db9..af5773af1 100644 --- a/src/mail.c +++ b/src/mail.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mail.c $NHDT-Date: 1464222344 2016/05/26 00:25:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.6 mail.c $NHDT-Date: 1519070343 2018/02/19 19:59:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.31 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -90,38 +90,44 @@ free_maildata() void getmailstatus() { - char *emailbox; - if ((emailbox = nh_getenv("MAIL")) != 0) { - mailbox = (char *) alloc((unsigned) strlen(emailbox)); - Strcpy(mailbox, emailbox); - } - if (!mailbox) { + if (mailbox) { + ; /* no need to repeat the setup */ + } else if ((mailbox = nh_getenv("MAIL")) != 0) { + mailbox = dupstr(mailbox); #ifdef MAILPATH + } else { #ifdef AMS struct passwd ppasswd; - (void) memcpy(&ppasswd, getpwuid(getuid()), sizeof(struct passwd)); + (void) memcpy(&ppasswd, getpwuid(getuid()), sizeof (struct passwd)); if (ppasswd.pw_dir) { - mailbox = (char *) alloc((unsigned) strlen(ppasswd.pw_dir) - + sizeof(AMS_MAILBOX)); + /* note: 'sizeof "LITERAL"' includes +1 for terminating '\0' */ + mailbox = (char *) alloc((unsigned) (strlen(ppasswd.pw_dir) + + sizeof AMS_MAILBOX)); Strcpy(mailbox, ppasswd.pw_dir); Strcat(mailbox, AMS_MAILBOX); - } else - return; + } #else const char *pw_name = getpwuid(getuid())->pw_name; - mailbox = (char *) alloc(sizeof(MAILPATH) + strlen(pw_name)); + + /* note: 'sizeof "LITERAL"' includes +1 for terminating '\0' */ + mailbox = (char *) alloc((unsigned) (strlen(pw_name) + + sizeof MAILPATH)); Strcpy(mailbox, MAILPATH); Strcat(mailbox, pw_name); #endif /* AMS */ -#else - return; -#endif +#endif /* MAILPATH */ } - if (stat(mailbox, &omstat)) { + + debugpline3("mailbox=%c%s%c", + mailbox ? '\"' : '<', + mailbox ? mailbox : "null", + mailbox ? '\"' : '>'); + + if (mailbox && stat(mailbox, &omstat)) { #ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=\"%s\".", mailbox); - mailbox = 0; + free_maildata(); /* set 'mailbox' to Null */ #else omstat.st_mtime = 0; #endif @@ -495,7 +501,7 @@ ckmailstatus() if (stat(mailbox, &nmstat)) { #ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=\"%s\" anymore.", mailbox); - mailbox = 0; + free_maildata(); #else nmstat.st_mtime = 0; #endif