Bug 19422

Summary: users can overflow argv to make ps segfault
Product: Base System Reporter: Marc Olzheim <marcolz>
Component: binAssignee: Mike Heffner <mikeh>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 3.4-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff
none
ps.argoflow.diff none

Description Marc Olzheim 2000-06-21 21:40:01 UTC
When a user reset his argv[0] within a program to a string, with a size larger
than sysconf(_SC_ARG_MAX), ps does not prevent it from overflowing an internal
buffer with strvis.

How-To-Repeat: 
A program that does argv[0] = blah; , where blah is a string, longer than
sysconf(_SC_ARG_MAX), and keeps waiting. Then just run 'ps wwwaxuU <user>'
and chances are ps segfaults.
Comment 1 Marc Olzheim 2000-06-22 15:58:12 UTC
I must've been sleeping...
A better patch would be:

strvisx(dst, src, arg_max - (dst - buf) - 1, VIS_NL | VIS_CSTYLE);

Btw. This is also the case with FreeBSD 4.0.

Marc
Comment 2 dd freebsd_committer freebsd_triage 2001-06-28 02:39:20 UTC
State Changed
From-To: open->feedback

I can't reproduce this on a recent -current or -stable.  Is this still 
a problem? 


Comment 3 dd freebsd_committer freebsd_triage 2001-06-28 02:39:20 UTC
Responsible Changed
From-To: freebsd-bugs->dd

My reminder to deal with this.
Comment 4 mheffner 2001-06-28 05:22:11 UTC
When I looked at this it appears that rev. 1.10 of fmt.c was meant to fix this.
However it looks like the change just increased the buffer size, but didn't
put any restrictions on the strvis() -- which just means a bigger string is
needed to overflow `buf'. But I haven't looked at the code in detail, so
there might be caps on the size of argv[0] some where else that would block any
overflow.


On 28-Jun-2001 dd@FreeBSD.org wrote:
| Synopsis: users can overflow argv to make ps segfault
| 
| State-Changed-From-To: open->feedback
| State-Changed-By: dd
| State-Changed-When: Wed Jun 27 18:39:20 PDT 2001
| State-Changed-Why: 
| I can't reproduce this on a recent -current or -stable.  Is this still
| a problem?


Mike

-- 
  Mike Heffner         <mheffner@[acm.]vt.edu>
  Fredericksburg, VA       <mikeh@FreeBSD.org>
Comment 5 marcolz 2001-06-28 12:58:28 UTC
It's still possible:

#include	<stdio.h>
#include	<sys/exec.h>
#include	<sys/param.h>
#include	<sys/sysctl.h>
#include	<sys/types.h>
#include	<unistd.h>

int
main(int argc, char *argv[])
{
	int	oid[4];
	char	buf[65537];

	if (argc >= 2)
		argv[0] = argv[1];
	else
	{
		memset(buf, 'A', 65537);
		argv[0] = buf;
	}

	// setproctitle("%s", argv[0]);

	oid[0] = CTL_KERN;
	oid[1] = KERN_PROC;
	oid[2] = KERN_PROC_ARGS;
	oid[3] = getpid();
	sysctl(oid, 4, 0, 0, buf, 65537);

	sleep(600);

	return(0);
}

Run it and do a ps uxwww
ps either segfaults or shows you some strvis-d data.

Marc
Comment 6 Marc Olzheim 2001-06-28 13:03:27 UTC
And if you put a
#if __FreeBSD__ == 4
and a #endif around the setproctitle stuff, it will run on both
FreeBSD 3 and 4

Marc
Comment 7 marcolz 2001-09-01 16:03:20 UTC
FreeBSD 5.0 still has the same problem...

Marc
Comment 8 dd freebsd_committer freebsd_triage 2001-11-24 16:30:51 UTC
Responsible Changed
From-To: dd->freebsd-bugs

I still can't reproduce this with the originator's code, and don't have time 
to persure this further.
Comment 9 Mike Heffner freebsd_committer freebsd_triage 2001-11-27 04:37:01 UTC
Responsible Changed
From-To: freebsd-bugs->mikeh

I'll look at this  in the next couple weeks.
Comment 10 mheffner 2001-12-12 04:18:54 UTC
Well, I've looked at this a little more. I was able to reproduce it (it
took a few times though). Unfortunately, the patch isn't as simple as the
one in the PR. Could you please try the attached patch? There is still a
problem though, and that is that the strlen()s can seg. fault if the
argv[] strings aren't NULL terminated - I don't know how to fix this
problem though :(

Mike

-- 
  Mike Heffner     <mheffner@[acm.]vt.edu>
  Blacksburg, VA       <mikeh@FreeBSD.org>
Comment 11 Peter Pentchev 2001-12-12 09:50:39 UTC
On Tue, Dec 11, 2001 at 11:18:54PM -0500, Mike Heffner wrote:
> 
> Well, I've looked at this a little more. I was able to reproduce it (it
> took a few times though). Unfortunately, the patch isn't as simple as the
> one in the PR. Could you please try the attached patch? There is still a
> problem though, and that is that the strlen()s can seg. fault if the
> argv[] strings aren't NULL terminated - I don't know how to fix this
> problem though :(

If argv[] is the program arguments' array, as passed to main(), then
you should not worry about it - its elements are supposed to be proper
C strings, i.e. terminated by a '\0' character, and I still have to see
a platform where they are not :)

G'luck,
Peter

-- 
This sentence would be seven words long if it were six words shorter.
Comment 12 mheffner 2001-12-12 15:36:03 UTC
On 12-Dec-2001 Peter Pentchev wrote:
| On Tue, Dec 11, 2001 at 11:18:54PM -0500, Mike Heffner wrote:
|> 
|> Well, I've looked at this a little more. I was able to reproduce it (it
|> took a few times though). Unfortunately, the patch isn't as simple as
|> the
|> one in the PR. Could you please try the attached patch? There is still
|> a
|> problem though, and that is that the strlen()s can seg. fault if the
|> argv[] strings aren't NULL terminated - I don't know how to fix this
|> problem though :(
| 
| If argv[] is the program arguments' array, as passed to main(), then
| you should not worry about it - its elements are supposed to be proper
| C strings, i.e. terminated by a '\0' character, and I still have to see
| a platform where they are not :)


But when a user modifies those arguments by explicilty setting argv[0], or
whatever, is where the problem is:

test5.c:

#include       <stdio.h>
#include       <sys/exec.h>
#include       <sys/param.h>
#include       <sys/sysctl.h>
#include       <sys/types.h>
#include       <unistd.h>

int
main(int argc, char *argv[])
{
        int     oid[4];
        char    before[] = "BBBBBBB";
        char    after[5];

        memset(after, 'A', sizeof(after));
        argv[0] = after;
      
        oid[0] = CTL_KERN;
        oid[1] = KERN_PROC;
        oid[2] = KERN_PROC_ARGS;
        oid[3] = getpid();
        sysctl(oid, 4, 0, 0, after, 65537);
      
        sleep(600);
      
        return(0);
}


$ ./test5


on another terminal:

$ ps auxwww

...
spock   290  0.0  0.3   980  109  p0  S+   10:30AM   0:00.01 \
AAAAA\M-{\M-?\M-?BBBBBBB (test5)
     ^^^^^^^^^^^^^^^^^^^



Mike

-- 
  Mike Heffner     <mheffner@[acm.]vt.edu>
  Blacksburg, VA       <mikeh@FreeBSD.org>
Comment 13 Mike Heffner freebsd_committer freebsd_triage 2002-01-21 19:40:29 UTC
State Changed
From-To: feedback->analyzed

Fix committed to current, awaiting MFC.
Comment 14 Mike Heffner freebsd_committer freebsd_triage 2002-03-18 19:34:13 UTC
State Changed
From-To: analyzed->closed

Fix MFC'd.