Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Aug 2003 00:11:13 -0500 (CDT)
From:      Joe Greco <jgreco@ns.sol.net>
To:        bde@zeta.org.au (Bruce Evans)
Cc:        freebsd-current@freebsd.org
Subject:   Re: Someone help me understand this...?
Message-ID:  <200308280511.h7S5BDvF009880@aurora.sol.net>
In-Reply-To: <20030828140312.N2706@gamplex.bde.org> from "Bruce Evans" at Aug 28, 2003 02:33:20 PM

next in thread | previous in thread | raw e-mail | index | archive | help
> On Wed, 27 Aug 2003, Joe Greco wrote:
> > I've got a weirdness with kill(2).
> >
> > This code is out of Diablo, the news package, and has been working fine for
> > some years.  It apparently works fine on other OS's.
> >
> > In the Diablo model, the parent process may choose to tell its children to
> > update status via a signal.  The loop basically consists of going through
> > and issuing a SIGALRM.
> >
> > This stopped working a while ago, don't know precisely when.  I was in the
> > process of debugging it today and ran into this.
> >
> > The specific OS below is 5.1-RELEASE but apparently this happens on 4.8 as
> > well.
> 
> Perhaps the children are setuid, the parent doesn't have appropriate
> privelege and you are mistaken about this happening under 4.8 as well.

Well, the parent process does the code I listed below early on in the
initialization process - it pretty much does a little initialization,
opens its socket (119), sheds privilege, and begins accepting conns.

It then forks off processes for each connection.

The program itself is not a suid executable, but rather relies on being
launched by a root user.

I'm not sure what "appropriate privilege" would be.  If both the uid/euid
of the parent match both the uid/euid of the child, I would expect to be
able to kill the process...

Client complains about the resulting problems also happening under 4.8 
servers.  Dunno.  Could possibly be a separate issue.

> In 5.x since at least rev.1.80 of kern_prot.c, only certain signals
> not including SIGALRM can be sent from unprivileged processes to setuid
> processes.
> 
> This is very UN-unixlike although it is permitted as an-implementation-
> defined restriction in at least POSIX.1-2001.  It breaks^Wexposes bugs
> in some old POSIX test programs and I don't have many security concerns
> so I just disable it locally:
> 
> %%%
> Index: kern_prot.c
> ===================================================================
> RCS file: /home/ncvs/src/sys/kern/kern_prot.c,v
> retrieving revision 1.175
> diff -u -2 -r1.175 kern_prot.c
> --- kern_prot.c	13 Jul 2003 01:22:20 -0000	1.175
> +++ kern_prot.c	17 Aug 2003 04:26:00 -0000
> @@ -1395,4 +1387,5 @@
>  		return (error);
> 
> +#if 0
>  	/*
>  	 * UNIX signal semantics depend on the status of the P_SUGID
> @@ -1425,4 +1418,5 @@
>  		}
>  	}
> +#endif
> 
>  	/*
> %%%
> 
> > Wot?  Why can't I send it a signal?
> >
> > I've read kill(2) rather carefully and cannot find the reason.  It says,
> >
> >      For a process to have permission to send a signal to a process designated
> >      by pid, the real or effective user ID of the receiving process must match
> >      that of the sending process or the user must have appropriate privileges
> >      (such as given by a set-user-ID program or the user is the super-user).
> 
> The implementation-defined restrictions are not documented, of course ;-).
> 
> > Well, the sending and receiving processes both clearly have equal uid/euid.
> >
> > We're not running in a jail, so I don't expect any issues there.
> >
> > The parent process did actually start as root and then shed privilege with
> >
> >         struct passwd *pw = getpwnam("news");
> >         struct group *gr = getgrnam("news");
> >         gid_t gid;
> >
> >         if (pw == NULL) {
> >             perror("getpwnam('news')");
> >             exit(1);
> >         }
> >         if (gr == NULL) {
> >             perror("getgrnam('news')");
> >             exit(1);
> >         }
> >         gid = gr->gr_gid;
> >         setgroups(1, &gid);
> >         setgid(gr->gr_gid);
> >         setuid(pw->pw_uid);
> >
> > so that looks all well and fine...  so why can't it kill its own children,
> > and why can't I kill one of its children from a shell with equivalent
> > uid/euid?
> 
> Changing the ids is one way to make the process setuid (setuid-on-exec is
> another but that doesn't seem to be the problem here).  The relevant setuid
> bit (P_SUGID) is normally cleared on exec, but perhaps it isn't here,
> either because the children don't exec or the effective ids don't match
> the real ids at the time of the exec.

The children aren't spawned via exec, but clearly they have equal 
uid/euid's.

So what you're saying, I guess, is it's not supposed to work.

I guess I'm a bit confused by the logic of this.  I've seen numerous
forking daemons over the years that do this sort of thing (not to mention
I've written a number).  I've always viewed shedding root privs as being a
good thing...  Was it really intended to break things in this manner?

> > I know there's been some paranoia about signal delivery and all that, but
> > my searching hasn't turned up anything that would explain this.  Certainly
> > the manual page ought to be updated if this is a new expected behaviour or
> > something...  at least some clue as to why it might fail would be helpful.
> 
> Certainly.  It is incomplete even not counting complications for jails
> or other implementation-defined restrictions related to "appropriate
> privilege".

Sigh.

Thanks for the note,

... JG
-- 
Joe Greco - sol.net Network Services - Milwaukee, WI - http://www.sol.net
"We call it the 'one bite at the apple' rule. Give me one chance [and] then I
won't contact you again." - Direct Marketing Ass'n position on e-mail spam(CNN)
With 24 million small businesses in the US alone, that's way too many apples.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200308280511.h7S5BDvF009880>