[PATCH] Infrastructure to un-/lock vts in vt_ioctl.c

From: Simone Weiss
Date: Thu Mar 26 2015 - 11:23:22 EST


Makes it possible to lock and unlock specific VTs.
When someone tries to switch to a locked vt, he gets redirected to VT 12.

We added the three cases VT_LOCK, VT_UNLOCK and VT_IS_LOCKED to vt_ioctl().
To indicate if a VT is locked we also added a flag to the struct vc_data.

VT_LOCK: allows the owner of a sppecified VT to set the lock flag.
VT_UNLOCK: allows caller with root permissions to reset the lock flag
VT_ISLOCKED: returns the value of the lock flag

If anyone tries to switch to a locked VT he gets redirected to VT 12
in complete_change_console.

Signed-off-by: Simone Weiss <simone.weiss@xxxxxx>
Signed-off-by: Helene Gsaenger <helene.gsaenger@xxxxxxxxxxxxxx>
---
The implementation of the lock functionality in the kernel provides advantages
which are hard to realize in userspace programms.
Situation right now:
Screensavers that are implemented as userspace programs can die (for example
by segfault) and give unauthorized users access.
Our implementation makes it possiple to lock single VTs witchout having to
change existing userspace programms.
It makes it possiple to add a Secure acess Key later on.

Regards
Simone Weiss and Helene Gsaenger

drivers/tty/vt/vt_ioctl.c | 101 ++++++++++++++++++++++++++++++++++++++++-
include/linux/console_struct.h | 1 +
include/uapi/linux/vt.h | 3 ++
3 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 3e3b092..e1f6b5c 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -1039,6 +1039,101 @@ int vt_ioctl(struct tty_struct *tty,
case VT_WAITEVENT:
ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
break;
+ case VT_LOCK:
+ {
+ struct tty_struct *target;
+
+ if (arg > MAX_NR_CONSOLES)
+ return -ENXIO;
+
+ /* Locking vt12 is fobidden*/
+ if (arg == 12)
+ return -EPERM;
+
+ /* redirect to vt12 after locking current vt */
+ if ((vc_cons[fg_console].d->vc_num == arg-1) || arg == 0) {
+ console_lock();
+ vc->vc_locked = 1;
+ console_unlock();
+ ret = vt_ioctl(tty, VT_ACTIVATE, 12);
+ break;
+ }
+
+ arg--;
+
+ /* check if target is allocated */
+ if (!vc_cons_allocated(arg)) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ /* check if caller = owner or root */
+ if (!uid_eq(current_uid(), GLOBAL_ROOT_UID)) {
+ target = vc_cons[arg].d->port.tty;
+ spin_lock(&tty_files_lock);
+ if (!list_empty(&target->tty_files)) {
+ struct tty_file_private *file_priv;
+ struct file *file;
+
+ file_priv = list_first_entry(&target->tty_files,
+ struct tty_file_private,
+ list);
+ file = file_priv->file;
+ if (!uid_eq(current_uid(),
+ file->f_inode->i_uid)) {
+ spin_unlock(&tty_files_lock);
+ return -EPERM;
+ }
+ }
+ spin_unlock(&tty_files_lock);
+ }
+
+ /* lock target */
+ console_lock();
+ if (vc_cons[arg].d->vc_locked == 1) {
+ console_unlock();
+ return -EACCES;
+ }
+ vc_cons[arg].d->vc_locked = 1;
+ console_unlock();
+ break;
+ }
+
+ case VT_UNLOCK:
+ if (arg > MAX_NR_CONSOLES || arg == 0)
+ return -ENXIO;
+
+ /* only root can unlock vts */
+ if (!uid_eq(current_uid(), GLOBAL_ROOT_UID))
+ return -EPERM;
+
+ arg--;
+
+ /* check if target is allocated */
+ if (!vc_cons_allocated(arg)) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ /* unlock target */
+ console_lock();
+ vc_cons[arg].d->vc_locked = 0;
+ console_unlock();
+ break;
+ case VT_IS_LOCKED:
+ if (arg > MAX_NR_CONSOLES || arg == 0)
+ return -ENXIO;
+
+ arg--;
+
+ /* check if target is allocated */
+ if (!vc_cons_allocated(arg)) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ ret = vc_cons[arg].d->vc_locked;
+ break;
default:
ret = -ENOIOCTLCMD;
}
@@ -1288,9 +1383,13 @@ static void complete_change_console(struct vc_data *vc)
{
unsigned char old_vc_mode;
int old = fg_console;
+ int backup_vtnum = vc->vc_num;

last_console = fg_console;

+ if (vc->vc_locked)
+ vc = vc_cons[11].d;
+
/*
* If we're switching, we could be going from KD_GRAPHICS to
* KD_TEXT mode or vice versa, which means we need to blank or
@@ -1351,7 +1450,7 @@ static void complete_change_console(struct vc_data *vc)
/*
* Wake anyone waiting for their VT to activate
*/
- vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
+ vt_event_post(VT_EVENT_SWITCH, old, backup_vtnum);
return;
}

diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index e859c98..902a36c 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -59,6 +59,7 @@ struct vc_data {
/* VT terminal data */
unsigned int vc_state; /* Escape sequence parser state */
unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */
+ unsigned int vc_locked; /* Set if console is locked */
/* data for manual vt switching */
struct vt_mode vt_mode;
struct pid *vt_pid;
diff --git a/include/uapi/linux/vt.h b/include/uapi/linux/vt.h
index 978578b..58832a7 100644
--- a/include/uapi/linux/vt.h
+++ b/include/uapi/linux/vt.h
@@ -42,6 +42,9 @@ struct vt_stat {
#define VT_ACTIVATE 0x5606 /* make vt active */
#define VT_WAITACTIVE 0x5607 /* wait for vt active */
#define VT_DISALLOCATE 0x5608 /* free memory associated to vt */
+#define VT_LOCK 0x5610 /* lock vt */
+#define VT_UNLOCK 0x5611 /* unlock vt */
+#define VT_IS_LOCKED 0x5612 /* show if vt is locked */

struct vt_sizes {
unsigned short v_rows; /* number of rows */
--
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/