Skip to content

Commit

Permalink
tty: handle VT specific compat ioctls in vt driver
Browse files Browse the repository at this point in the history
The VT specific compat_ioctl handlers are the only ones
in common code that require the BKL. Moving them into
the vt driver lets us remove the BKL from the other handlers
and cleans up the code.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
arndb authored and Live-CD User committed Sep 19, 2009
1 parent 62b2635 commit e921665
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 0 deletions.
3 changes: 3 additions & 0 deletions drivers/char/vt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2910,6 +2910,9 @@ static const struct tty_operations con_ops = {
.flush_chars = con_flush_chars,
.chars_in_buffer = con_chars_in_buffer,
.ioctl = vt_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = vt_compat_ioctl,
#endif
.stop = con_stop,
.start = con_start,
.throttle = con_throttle,
Expand Down
203 changes: 203 additions & 0 deletions drivers/char/vt_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/tty.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/compat.h>
#include <linux/module.h>
#include <linux/kd.h>
#include <linux/vt.h>
Expand Down Expand Up @@ -1376,6 +1377,208 @@ void vc_SAK(struct work_struct *work)
release_console_sem();
}

#ifdef CONFIG_COMPAT

struct compat_consolefontdesc {
unsigned short charcount; /* characters in font (256 or 512) */
unsigned short charheight; /* scan lines per character (1-32) */
compat_caddr_t chardata; /* font data in expanded form */
};

static inline int
compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
int perm, struct console_font_op *op)
{
struct compat_consolefontdesc cfdarg;
int i;

if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
return -EFAULT;

switch (cmd) {
case PIO_FONTX:
if (!perm)
return -EPERM;
op->op = KD_FONT_OP_SET;
op->flags = KD_FONT_FLAG_OLD;
op->width = 8;
op->height = cfdarg.charheight;
op->charcount = cfdarg.charcount;
op->data = compat_ptr(cfdarg.chardata);
return con_font_op(vc_cons[fg_console].d, op);
case GIO_FONTX:
op->op = KD_FONT_OP_GET;
op->flags = KD_FONT_FLAG_OLD;
op->width = 8;
op->height = cfdarg.charheight;
op->charcount = cfdarg.charcount;
op->data = compat_ptr(cfdarg.chardata);
i = con_font_op(vc_cons[fg_console].d, op);
if (i)
return i;
cfdarg.charheight = op->height;
cfdarg.charcount = op->charcount;
if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
return -EFAULT;
return 0;
}
return -EINVAL;
}

struct compat_console_font_op {
compat_uint_t op; /* operation code KD_FONT_OP_* */
compat_uint_t flags; /* KD_FONT_FLAG_* */
compat_uint_t width, height; /* font size */
compat_uint_t charcount;
compat_caddr_t data; /* font data with height fixed to 32 */
};

static inline int
compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
int perm, struct console_font_op *op, struct vc_data *vc)
{
int i;

if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
return -EFAULT;
if (!perm && op->op != KD_FONT_OP_GET)
return -EPERM;
op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
op->flags |= KD_FONT_FLAG_OLD;
i = con_font_op(vc, op);
if (i)
return i;
((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
return -EFAULT;
return 0;
}

struct compat_unimapdesc {
unsigned short entry_ct;
compat_caddr_t entries;
};

static inline int
compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
int perm, struct vc_data *vc)
{
struct compat_unimapdesc tmp;
struct unipair __user *tmp_entries;

if (copy_from_user(&tmp, user_ud, sizeof tmp))
return -EFAULT;
tmp_entries = compat_ptr(tmp.entries);
if (tmp_entries)
if (!access_ok(VERIFY_WRITE, tmp_entries,
tmp.entry_ct*sizeof(struct unipair)))
return -EFAULT;
switch (cmd) {
case PIO_UNIMAP:
if (!perm)
return -EPERM;
return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
case GIO_UNIMAP:
if (!perm && fg_console != vc->vc_num)
return -EPERM;
return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
}
return 0;
}

long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct vc_data *vc = tty->driver_data;
struct console_font_op op; /* used in multiple places here */
struct kbd_struct *kbd;
unsigned int console;
void __user *up = (void __user *)arg;
int perm;
int ret = 0;

console = vc->vc_num;

lock_kernel();

if (!vc_cons_allocated(console)) { /* impossible? */
ret = -ENOIOCTLCMD;
goto out;
}

/*
* To have permissions to do most of the vt ioctls, we either have
* to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
*/
perm = 0;
if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
perm = 1;

kbd = kbd_table + console;
switch (cmd) {
/*
* these need special handlers for incompatible data structures
*/
case PIO_FONTX:
case GIO_FONTX:
ret = compat_fontx_ioctl(cmd, up, perm, &op);
break;

case KDFONTOP:
ret = compat_kdfontop_ioctl(up, perm, &op, vc);
break;

case PIO_UNIMAP:
case GIO_UNIMAP:
ret = do_unimap_ioctl(cmd, up, perm, vc);
break;

/*
* all these treat 'arg' as an integer
*/
case KIOCSOUND:
case KDMKTONE:
#ifdef CONFIG_X86
case KDADDIO:
case KDDELIO:
#endif
case KDSETMODE:
case KDMAPDISP:
case KDUNMAPDISP:
case KDSKBMODE:
case KDSKBMETA:
case KDSKBLED:
case KDSETLED:
case KDSIGACCEPT:
case VT_ACTIVATE:
case VT_WAITACTIVE:
case VT_RELDISP:
case VT_DISALLOCATE:
case VT_RESIZE:
case VT_RESIZEX:
goto fallback;

/*
* the rest has a compatible data structure behind arg,
* but we have to convert it to a proper 64 bit pointer.
*/
default:
arg = (unsigned long)compat_ptr(arg);
goto fallback;
}
out:
unlock_kernel();
return ret;

fallback:
unlock_kernel();
return vt_ioctl(tty, file, cmd, arg);
}


#endif /* CONFIG_COMPAT */


/*
* Performs the back end of a vt switch. Called under the console
* semaphore.
Expand Down
3 changes: 3 additions & 0 deletions include/linux/tty.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,5 +536,8 @@ extern int pcxe_open(struct tty_struct *tty, struct file *filp);
extern int vt_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);

extern long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);

#endif /* __KERNEL__ */
#endif

0 comments on commit e921665

Please sign in to comment.