revoke(2) redux...

2002-12-24 Thread Poul-Henning Kamp

I've been studying revoke(2), and somehow fail to see it fulfill
its promise from the man-page.

Consider this piece of code from init(8):

/*
 * Start a session and allocate a controlling terminal.
 * Only called by children of init after forking.
 */
void
setctty(char *name)
{
int fd;
 
(void) revoke(name);
if ((fd = open(name, O_RDWR)) == -1) {
stall(can't open %s: %m, name);
_exit(1);
}

Isn't there a pretty obvious race between the revoke() and the open() ?

Wouldn't it in fact make much more sense if revoke(2) was defined as

int revoke(int fd); /* kick everybody else off */

and the code above would look like:

if ((fd = open(name, O_RDWR)) == -1) {
stall(can't open %s: %m, name);
_exit(1);
}
(void) revoke(fd);


-- 
Poul-Henning Kamp   | UNIX since Zilog Zeus 3.20
[EMAIL PROTECTED] | TCP/IP since RFC 956
FreeBSD committer   | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread David Malone
On Tue, Dec 24, 2002 at 12:40:25PM +0100, Poul-Henning Kamp wrote:
 Wouldn't it in fact make much more sense if revoke(2) was defined as
 
   int revoke(int fd); /* kick everybody else off */
 
 and the code above would look like:

An O_REVOKE flag to open might be neater?

David.

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread Paul A. Scott

-- 

 From: Poul-Henning Kamp [EMAIL PROTECTED]
void setctty(char *name) {
(void) revoke(name);
if ((fd = open(name, O_RDWR)) == -1) {
 Isn't there a pretty obvious race between the revoke() and the open() ?
 Wouldn't it in fact make much more sense if revoke(2) was defined as
 int revoke(int fd);/* kick everybody else off */
 and the code above would look like:
if ((fd = open(name, O_RDWR)) == -1) {
}
(void) revoke(fd);

But, revoke() invalidates all descriptors for the named path, so any
subsequent operations on the open file descriptor would fail, which defeats
the purpose of open(). I think what's needed is some form of serialization
around revoke() and open(). I'm not a master of the init code, but it may be
that the code is inherently non-reentrant, so the original code would then
be okay. 

Paul

Paul A. Scott
mailto:[EMAIL PROTECTED]
http://skycoast.us/pscott/


To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread Robert Watson

On Tue, 24 Dec 2002, Poul-Henning Kamp wrote:

 Isn't there a pretty obvious race between the revoke() and the open() ? 
 
 Wouldn't it in fact make much more sense if revoke(2) was defined as
 
   int revoke(int fd); /* kick everybody else off */
 
 and the code above would look like: 

There are many races here, but one race is closed by this.  The way the
login process works is that it chowns the device, then revokes the device.
If the problem being addressed is that fd's remain open even after the
chown, then revoke works fine, since once you've chowned/chmodded the
file, the original process with a normal user uid can't re-open.  That
said, revoke() has terrible properties from a VFS perspective.  I'd be
interested in learning about the approaches taken in Linux, etc, to
address the same problem.

Robert N M Watson FreeBSD Core Team, TrustedBSD Projects
[EMAIL PROTECTED]  Network Associates Laboratories



To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread phk
In message [EMAIL PROTECTED], Paul A. Scott writes:

-- 

 From: Poul-Henning Kamp [EMAIL PROTECTED]
void setctty(char *name) {
(void) revoke(name);
if ((fd = open(name, O_RDWR)) == -1) {
 Isn't there a pretty obvious race between the revoke() and the open() ?
 Wouldn't it in fact make much more sense if revoke(2) was defined as
 int revoke(int fd);/* kick everybody else off */
 and the code above would look like:
if ((fd = open(name, O_RDWR)) == -1) {
}
(void) revoke(fd);

But, revoke() invalidates all descriptors for the named path, so any
subsequent operations on the open file descriptor would fail, which defeats
the purpose of open().

I think you missed the fine point in the kick everybody *else*
off comment.

I think what's needed is some form of serialization
around revoke() and open(). I'm not a master of the init code, but it may be
that the code is inherently non-reentrant, so the original code would then
be okay. 

There is more code like this in places.  The point is you cannot serialize
against other processes.

-- 
Poul-Henning Kamp   | UNIX since Zilog Zeus 3.20
[EMAIL PROTECTED] | TCP/IP since RFC 956
FreeBSD committer   | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread Paul A. Scott

 From: Paul A. Scott [EMAIL PROTECTED]
 I think what's needed is some form of serialization
 around revoke() and open(). I'm not a master of the init code, but it may be
 that the code is inherently non-reentrant, so the original code would then
 be okay. 

Or, it may use spltty()? Or some other lock-out mechanism?

Paul

-- 
Paul A. Scott
mailto:[EMAIL PROTECTED]
http://skycoast.us/pscott/


To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread Paul A. Scott
 I think you missed the fine point in the kick everybody *else*
 off comment.

Ahhh. I guess you mean that revoke() would change to do that. You're right,
I did miss your point.

 The point is you cannot serialize against other processes.

But that's the point of serialization. Anyway, if init is the only process
opening a tty, serialization would be inherent. But, like I said earlier,
I'm no master of init code. I've just never heard of any problems springing
from this, so I offer a possible explanation of why it seems (to me) to
work.

-- 
Paul A. Scott
mailto:[EMAIL PROTECTED]
http://skycoast.us/pscott/


To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



revoke(2) redux...

2002-12-24 Thread Garrett Wollman
On Tue, 24 Dec 2002 12:40:25 +0100, Poul-Henning Kamp [EMAIL PROTECTED] said:

 Isn't there a pretty obvious race between the revoke() and the open() ?

To the extent that the race matters, it is obviated by making sure
that only the current user has permission to open the device.  If the
user somehow manages to open a device that he owns anyway, it's his
problem if doing so screws it up.

revoke() was a POSIX invention; it replaces the older vhangup().  The
problem with vhangup() was that it merely signalled the previous
openers -- if they had a SIGHUP handler installed, they did not
actually lose access to the device.

AIX has an extension such as you suggest (they call it frevoke()).
AIX also implements it for all vnodes, not just device-specials, so it
is somewhat more general-purpose.  The POSIX function was introduced
for only one reason: to provide a secure replacement for vhangup() in
the POSIX tty model.  Thus, it is not fully general.

-GAWollman


To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread phk
In message [EMAIL PROTECTED], Paul A. Scott writes:
 I think you missed the fine point in the kick everybody *else*
 off comment.

Ahhh. I guess you mean that revoke() would change to do that. You're right,
I did miss your point.

 The point is you cannot serialize against other processes.

But that's the point of serialization. Anyway, if init is the only process
opening a tty,

revoke is used in most login daemons, telnetd, getty and elsewhere.

There is no way you can close the race between:

revoke(/dev/ttyfoo);
and
open(/dev/ttyfoo);

Not even in init(8).  There is always the risk that another process
opens the device between the two.

-- 
Poul-Henning Kamp   | UNIX since Zilog Zeus 3.20
[EMAIL PROTECTED] | TCP/IP since RFC 956
FreeBSD committer   | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread Garrett Wollman
On Tue, 24 Dec 2002 15:43:56 +0100, [EMAIL PROTECTED] said:

 There is no way you can close the race between:

   revoke(/dev/ttyfoo);
 and
   open(/dev/ttyfoo);

 Not even in init(8).  There is always the risk that another process
 opens the device between the two.

If that process belongs to root then it doesn't matter.

If that process belongs to the user who's logging in, then it doesn't
matter (the user can hose himself, but that's his own fault).

If that process belongs to someone else, then the permissions on the
device are set wrong, and that's a security problem that revoke()
isn't trying to fix.

-GAWollman


To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread phk
In message [EMAIL PROTECTED], Garrett Wollman
 writes:
On Tue, 24 Dec 2002 12:40:25 +0100, Poul-Henning Kamp [EMAIL PROTECTED] said:

 Isn't there a pretty obvious race between the revoke() and the open() ?

To the extent that the race matters, it is obviated by making sure
that only the current user has permission to open the device.  If the
user somehow manages to open a device that he owns anyway, it's his
problem if doing so screws it up.

revoke() was a POSIX invention; it replaces the older vhangup().

But I can't find mention of it in SUS ?

AIX has an extension such as you suggest (they call it frevoke()).

I think we should implement that in the kernel instead of revoke(2)
because it is actually a lot simpler to implement correctly.

We can then provide revoke(2) as a wrapper:

revoke(const char *name)
{
int fd, e;

fd = open(name, O_RDONLY);
if (fd  0)
return (fd);
e = frevoke(fd);
close(fd);
return (e);
}

-- 
Poul-Henning Kamp   | UNIX since Zilog Zeus 3.20
[EMAIL PROTECTED] | TCP/IP since RFC 956
FreeBSD committer   | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread Juli Mallett
* De: [EMAIL PROTECTED] [ Data: 2002-12-24 ]
[ Subjecte: Re: revoke(2) redux... ]
 revoke is used in most login daemons, telnetd, getty and elsewhere.
 
 There is no way you can close the race between:
 
   revoke(/dev/ttyfoo);
 and
   open(/dev/ttyfoo);
 
 Not even in init(8).  There is always the risk that another process
 opens the device between the two.

Don't the chmod hacks performed on TTYs to essentially go from this is
free to this is mine close that race more or less?  I understand from
watching xpty discussion that if a tty matches certain mode/... requirements
then one should try to chown it and chmod it appropriately to themselves,
and if that fails, go back to looking for one (aquiring a lock on the tty
essentially) then do a revoke on it, because it's now really ours, and then
go on to open it...  Kicking people off only once the open works is an
interesting idea (wrt frevoke), but by then we've already trashed the perms...
I'm not sure whether there's a meaningful race in that (though of course
there are lots of races in that, especially if not appropriately coded)
and how much of a bad window exists wrt revoke/frevoke, and whether it is
really solved by fvrevoke.

juli.
-- 
Juli Mallett [EMAIL PROTECTED]
OpenDarwin, Mono, FreeBSD Developer.
ircd-hybrid Developer, EFnet addict.
FreeBSD on MIPS-Anything on FreeBSD.

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message



Re: revoke(2) redux...

2002-12-24 Thread David Malone
On Tue, Dec 24, 2002 at 03:52:05PM +0100, [EMAIL PROTECTED] wrote:
 We can then provide revoke(2) as a wrapper:
 
   revoke(const char *name)
   {
   int fd, e;
 
   fd = open(name, O_RDONLY);

Assuming you can open the thing name points to. I guess it might
be a (NFS) directory or socket. I think revoke used to work on
directories for a bit, until someone found it didn't work on named
pipes and sockets, and then it was restricted to devices again.

David.

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-current in the body of the message