At this point we have the tty_lock guarding a couple of oddities, plus the
translation and unimap still.
We also extend the console_lock in a couple of spots where coverage is wrong
and switch vcs_open to use the right lock !
[Fixed the locking issue Jiri reported]
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
unsigned int currcons = iminor(inode) & 127;
int ret = 0;
unsigned int currcons = iminor(inode) & 127;
int ret = 0;
if(currcons && !vc_cons_allocated(currcons-1))
ret = -ENXIO;
if(currcons && !vc_cons_allocated(currcons-1))
ret = -ENXIO;
if (!vc_cons_allocated(console)) { /* impossible? */
ret = -ENOIOCTLCMD;
if (!vc_cons_allocated(console)) { /* impossible? */
ret = -ENOIOCTLCMD;
switch (cmd) {
case TIOCLINUX:
switch (cmd) {
case TIOCLINUX:
ret = tioclinux(tty, arg);
ret = tioclinux(tty, arg);
break;
case KIOCSOUND:
if (!perm)
break;
case KIOCSOUND:
if (!perm)
/*
* The use of PIT_TICK_RATE is historic, it used to be
* the platform-dependent CLOCK_TICK_RATE between 2.6.12
* and 2.6.36, which was a minor but unfortunate ABI
/*
* The use of PIT_TICK_RATE is historic, it used to be
* the platform-dependent CLOCK_TICK_RATE between 2.6.12
* and 2.6.36, which was a minor but unfortunate ABI
+ * change. kd_mksound is locked by the input layer.
*/
if (arg)
arg = PIT_TICK_RATE / arg;
*/
if (arg)
arg = PIT_TICK_RATE / arg;
case KDMKTONE:
if (!perm)
case KDMKTONE:
if (!perm)
{
unsigned int ticks, count;
{
unsigned int ticks, count;
*/
ucval = KB_101;
ret = put_user(ucval, (char __user *)arg);
*/
ucval = KB_101;
ret = put_user(ucval, (char __user *)arg);
/*
* KDADDIO and KDDELIO may be able to add ports beyond what
* we reject here, but to be safe...
/*
* KDADDIO and KDDELIO may be able to add ports beyond what
* we reject here, but to be safe...
+ *
+ * These are locked internally via sys_ioperm
*/
if (arg < GPFIRST || arg > GPLAST) {
ret = -EINVAL;
*/
if (arg < GPFIRST || arg > GPLAST) {
ret = -EINVAL;
struct kbd_repeat kbrep;
if (!capable(CAP_SYS_TTY_CONFIG))
struct kbd_repeat kbrep;
if (!capable(CAP_SYS_TTY_CONFIG))
if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
ret = -EFAULT;
if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
ret = -EFAULT;
* need to restore their engine state. --BenH
*/
if (!perm)
* need to restore their engine state. --BenH
*/
if (!perm)
switch (arg) {
case KD_GRAPHICS:
break;
switch (arg) {
case KD_GRAPHICS:
break;
ret = -EINVAL;
goto out;
}
ret = -EINVAL;
goto out;
}
+ /* FIXME: this needs the console lock extending */
if (vc->vc_mode == (unsigned char) arg)
break;
vc->vc_mode = (unsigned char) arg;
if (vc->vc_mode == (unsigned char) arg)
break;
vc->vc_mode = (unsigned char) arg;
case KDSKBMODE:
if (!perm)
case KDSKBMODE:
if (!perm)
ret = vt_do_kdskbmode(console, arg);
if (ret == 0)
tty_ldisc_flush(tty);
ret = vt_do_kdskbmode(console, arg);
if (ret == 0)
tty_ldisc_flush(tty);
case KDSIGACCEPT:
{
if (!perm || !capable(CAP_KILL))
case KDSIGACCEPT:
{
if (!perm || !capable(CAP_KILL))
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
ret = -EINVAL;
else {
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
ret = -EINVAL;
else {
struct vt_mode tmp;
if (!perm)
struct vt_mode tmp;
if (!perm)
if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
ret = -EFAULT;
goto out;
if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
ret = -EFAULT;
goto out;
struct vt_stat __user *vtstat = up;
unsigned short state, mask;
struct vt_stat __user *vtstat = up;
unsigned short state, mask;
+ /* Review: FIXME: Console lock ? */
if (put_user(fg_console + 1, &vtstat->v_active))
ret = -EFAULT;
else {
if (put_user(fg_console + 1, &vtstat->v_active))
ret = -EFAULT;
else {
* Returns the first available (non-opened) console.
*/
case VT_OPENQRY:
* Returns the first available (non-opened) console.
*/
case VT_OPENQRY:
+ /* FIXME: locking ? - but then this is a stupid API */
for (i = 0; i < MAX_NR_CONSOLES; ++i)
if (! VT_IS_IN_USE(i))
break;
for (i = 0; i < MAX_NR_CONSOLES; ++i)
if (! VT_IS_IN_USE(i))
break;
*/
case VT_ACTIVATE:
if (!perm)
*/
case VT_ACTIVATE:
if (!perm)
if (arg == 0 || arg > MAX_NR_CONSOLES)
ret = -ENXIO;
else {
if (arg == 0 || arg > MAX_NR_CONSOLES)
ret = -ENXIO;
else {
struct vt_setactivate vsa;
if (!perm)
struct vt_setactivate vsa;
if (!perm)
if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
sizeof(struct vt_setactivate))) {
if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
sizeof(struct vt_setactivate))) {
if (ret)
break;
/* Commence switch and lock */
if (ret)
break;
/* Commence switch and lock */
+ /* Review set_console locks */
set_console(vsa.console);
}
break;
set_console(vsa.console);
}
break;
*/
case VT_WAITACTIVE:
if (!perm)
*/
case VT_WAITACTIVE:
if (!perm)
if (arg == 0 || arg > MAX_NR_CONSOLES)
ret = -ENXIO;
if (arg == 0 || arg > MAX_NR_CONSOLES)
ret = -ENXIO;
ret = vt_waitactive(arg);
ret = vt_waitactive(arg);
*/
case VT_RELDISP:
if (!perm)
*/
case VT_RELDISP:
if (!perm)
if (vc->vt_mode.mode != VT_PROCESS) {
if (vc->vt_mode.mode != VT_PROCESS) {
ret = -EINVAL;
break;
}
/*
* Switching-from response
*/
ret = -EINVAL;
break;
}
/*
* Switching-from response
*/
if (vc->vt_newvt >= 0) {
if (arg == 0)
/*
if (vc->vt_newvt >= 0) {
if (arg == 0)
/*
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
ret = -EFAULT;
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
ret = -EFAULT;
if (vc) {
vc->vc_resize_user = 1;
if (vc) {
vc->vc_resize_user = 1;
+ /* FIXME: review v tty lock */
vc_resize(vc_cons[i].d, cc, ll);
}
}
vc_resize(vc_cons[i].d, cc, ll);
}
}
struct vt_consize __user *vtconsize = up;
ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm)
struct vt_consize __user *vtconsize = up;
ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm)
if (!access_ok(VERIFY_READ, vtconsize,
sizeof(struct vt_consize))) {
ret = -EFAULT;
if (!access_ok(VERIFY_READ, vtconsize,
sizeof(struct vt_consize))) {
ret = -EFAULT;
case PIO_FONT: {
if (!perm)
case PIO_FONT: {
if (!perm)
op.op = KD_FONT_OP_SET;
op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
op.width = 8;
op.op = KD_FONT_OP_SET;
op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
op.width = 8;
case PIO_FONTRESET:
{
if (!perm)
case PIO_FONTRESET:
{
if (!perm)
#ifdef BROKEN_GRAPHICS_PROGRAMS
/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
#ifdef BROKEN_GRAPHICS_PROGRAMS
/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
break;
}
if (!perm && op.op != KD_FONT_OP_GET)
break;
}
if (!perm && op.op != KD_FONT_OP_GET)
ret = con_font_op(vc, &op);
if (ret)
break;
ret = con_font_op(vc, &op);
if (ret)
break;
case PIO_SCRNMAP:
if (!perm)
ret = -EPERM;
case PIO_SCRNMAP:
if (!perm)
ret = -EPERM;
ret = con_set_trans_old(up);
ret = con_set_trans_old(up);
ret = con_get_trans_old(up);
ret = con_get_trans_old(up);
break;
case PIO_UNISCRNMAP:
if (!perm)
ret = -EPERM;
break;
case PIO_UNISCRNMAP:
if (!perm)
ret = -EPERM;
ret = con_set_trans_new(up);
ret = con_set_trans_new(up);
break;
case GIO_UNISCRNMAP:
break;
case GIO_UNISCRNMAP:
ret = con_get_trans_new(up);
ret = con_get_trans_new(up);
break;
case PIO_UNIMAPCLR:
{ struct unimapinit ui;
if (!perm)
break;
case PIO_UNIMAPCLR:
{ struct unimapinit ui;
if (!perm)
ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
if (ret)
ret = -EFAULT;
ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
if (ret)
ret = -EFAULT;
con_clear_unimap(vc, &ui);
con_clear_unimap(vc, &ui);
break;
}
case PIO_UNIMAP:
case GIO_UNIMAP:
break;
}
case PIO_UNIMAP:
case GIO_UNIMAP:
ret = do_unimap_ioctl(cmd, up, perm, vc);
ret = do_unimap_ioctl(cmd, up, perm, vc);
break;
case VT_LOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
break;
case VT_LOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
vt_dont_switch = 1;
break;
case VT_UNLOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
vt_dont_switch = 1;
break;
case VT_UNLOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
vt_dont_switch = 0;
break;
case VT_GETHIFONTMASK:
vt_dont_switch = 0;
break;
case VT_GETHIFONTMASK:
ret = -ENOIOCTLCMD;
}
out:
ret = -ENOIOCTLCMD;
}
out:
-eperm:
- ret = -EPERM;
- goto out;
}
void reset_vc(struct vc_data *vc)
}
void reset_vc(struct vc_data *vc)
if (!vc_cons_allocated(console)) { /* impossible? */
ret = -ENOIOCTLCMD;
goto out;
if (!vc_cons_allocated(console)) { /* impossible? */
ret = -ENOIOCTLCMD;
goto out;
case PIO_UNIMAP:
case GIO_UNIMAP:
case PIO_UNIMAP:
case GIO_UNIMAP:
ret = compat_unimap_ioctl(cmd, up, perm, vc);
ret = compat_unimap_ioctl(cmd, up, perm, vc);
return vt_ioctl(tty, cmd, arg);
}
return vt_ioctl(tty, cmd, arg);
}
return -EIO;
}
console_unlock();
return -EIO;
}
console_unlock();
+ /* Review: I don't see why we need tty_lock here FIXME */
tty_lock();
if (vt_waitactive(vt + 1)) {
pr_debug("Suspend: Can't switch VCs.");
tty_lock();
if (vt_waitactive(vt + 1)) {
pr_debug("Suspend: Can't switch VCs.");