VT switching (Was: SECURITY: Kill process when on console)

Peter Benie (pjb1008@cam.ac.uk)
Mon, 30 Mar 1998 13:00:32 +0100


Pavel Machek writes ("SECURITY: Kill process when on console"):
> It seems to me like we got a small security hole: when sitting on
> console, you can send signal to newly created process (owned by
> anyone). How?
>
> Let's see:
>
> case VT_SETMODE:
>
> [etc]

Much of the VT console switching code needs cleaning up; there are
several race conditions that can, and do, cause problems.
In particular, starting multiple X-servers simultaneously as
children of xdm is very likely to trigger races when xdm is started.

If you have XFree86 sources to hand, you may useful to study the
VT handling code for Linux in <linux-kernel>/drivers/chars/vt.c
and <Xsrc>/xc/programs/Xserver/hw/xfree86/os-support/linux/lnx_init.c.
I have omitted much of the error handling in quoted code for clarity.

The X-server begins by choosing which VT to use:

fd = open("/dev/tty0", O_WRONLY, 0);
ioctl(fd, VT_OPENQRY, &xf86Info.vtno);
close(fd);
sprintf(vtname, "/dev/tty%d", xf86Info.vtno);
xf86Info.consoleFd = open(vtname, O_RDWR|O_NDELAY, 0);

Since two Xservers are doing this, it is possible for both servers to
call VT_OPENQRY, get the same VT no., and then start two X-servers on
the same VT.

I can think of two solutions to this:
1) Combine choosing a free VT with open so that the process is atomic.
This is similar to /dev/ptmx. A process opening this would need a
way to find out which VT is had got so that the VT ioctls could be used.
2) Provide a method of determining if you are the first processes to
open a VT, so you can detect when another process got the tty just
before you did.

Once the X-server has the opened the VT, it switches to that VT. This
is so it can call VT_SETMODE, and so that it can probe the video
hardware without interfering with other processes' displays.

ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno);
ioctl(xf86Info.consoleFd, VT_WAITACTIVE, xf86Info.vtno);

If two X-servers request a VT change at the same time, one of them
will succeed, and the other will fail.

If you are particularly unluckly, it is possible to get a momentary
change of VT, followed by another change: both both ioctls will
succeed in both X-servers so both servers!

If you aren't so unlucky, VT_WAITACTIVE will return with EINTR in one
of the servers. Putting VT_WAITACTIVE in a loop testing for EINTR
doesn't help - the second VT_ACTIVATE request overwrote the first
request so the kernel doesn't know it's supposed to change VT.

What the X-server needs is a 'change VT and stay there' ioctl.
VT_SETMODE tries to give you that, but VT_SETMODE works on the
current VT, so you need to change to that VT first.
VT_GETMODE and VT_SETMODE should be made safe by giving them the VT
no. as an argument. (Some of the other VT ioctls already have this.)

With a safe version of VT_SETMODE, you tell when you managed to change
VT sucessfully, but it would be nice to have an reliable (possibly
blocking) version of VT_ACTIVATE. Without a reliable VT_ACTIVATE, you
need to keep calling the VT_ACTIVATE every second or so because you
don't know if your request to change VTs got lost or if the machine is
just slow.

-- 
Peter Benie, Unix Support, University of Cambridge Computing Service,
New Museums Site, Pembroke Street, Cambridge CB2 3QG  +44 1223 34728

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu