Hopefully fix Coverity CID 1008328 (Out-of-bounds write) in /bin/sh.

Replace the magic constant 127 in the loop interation count with
"PROMPTLEN - 1".

gethostname() is not guaranteed to NUL terminate the destination
string if it is too short. Decrease the length passed to gethostname()
by one, and add a NUL at the end of the buffer to make sure the
following loop to find the end of the name properly terminates.

The default: case is the likely cause of Coverity CID 1008328.  If
i is 126 at the top of the loop interation where the default case
is triggered, i will be incremented to 127 by the default case,
then incremented to 128 at the top of the loop before being compared
to 127 (PROMPTLENT - 1) and terminating the loop. Then the NUL
termination code after the loop will write to ps[128].  Fix by
checking for overflow before incrementing the index and storing the
second character in the buffer.

These fixes are not guaranteed to satisfy Coverity. The code that
increments i in the 'h'/'H' and 'w'/'W' cases may be beyond its
capability to analyze, but the code appears to be safe.

Reported by:	Coverity
CID:		1008328
Reviewed by:	jilles, cem
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D6482
This commit is contained in:
Don Lewis 2016-05-23 01:01:23 +00:00
parent 4c36e917b2
commit 63a4675d89
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=300442

View File

@ -1998,7 +1998,7 @@ getprompt(void *unused __unused)
/*
* Format prompt string.
*/
for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++)
for (i = 0; (i < PROMPTLEN - 1) && (*fmt != '\0'); i++, fmt++)
if (*fmt == '\\')
switch (*++fmt) {
@ -2011,7 +2011,8 @@ getprompt(void *unused __unused)
case 'h':
case 'H':
ps[i] = '\0';
gethostname(&ps[i], PROMPTLEN - i);
gethostname(&ps[i], PROMPTLEN - i - 1);
ps[PROMPTLEN - 1] = '\0';
/* Skip to end of hostname. */
trim = (*fmt == 'h') ? '.' : '\0';
while ((ps[i] != '\0') && (ps[i] != trim))
@ -2061,8 +2062,9 @@ getprompt(void *unused __unused)
* Emit unrecognized formats verbatim.
*/
default:
ps[i++] = '\\';
ps[i] = *fmt;
ps[i] = '\\';
if (i < PROMPTLEN - 1)
ps[++i] = *fmt;
break;
}
else