From cc1e66f92bf52abfcb55bbb8d6f48fa7a922b7ce Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Sat, 3 Jun 2017 09:35:05 +0200 Subject: vt: use copy_from/to_user instead of __get/put_user for scrnmap ioctls Linus wants to get rid of these functions, and these uses are especially egregious: they copy a big linear array element by element. Signed-off-by: Adam Borowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) (limited to 'drivers/tty/vt') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 1f6e17f..1361f2a 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -322,15 +322,13 @@ int con_set_trans_old(unsigned char __user * arg) { int i; unsigned short inbuf[E_TABSZ]; + unsigned char ubuf[E_TABSZ]; - if (!access_ok(VERIFY_READ, arg, E_TABSZ)) + if (copy_from_user(ubuf, arg, E_TABSZ)) return -EFAULT; - for (i = 0; i < E_TABSZ ; i++) { - unsigned char uc; - __get_user(uc, arg+i); - inbuf[i] = UNI_DIRECT_BASE | uc; - } + for (i = 0; i < E_TABSZ ; i++) + inbuf[i] = UNI_DIRECT_BASE | ubuf[i]; console_lock(); memcpy(translations[USER_MAP], inbuf, sizeof(inbuf)); @@ -345,9 +343,6 @@ int con_get_trans_old(unsigned char __user * arg) unsigned short *p = translations[USER_MAP]; unsigned char outbuf[E_TABSZ]; - if (!access_ok(VERIFY_WRITE, arg, E_TABSZ)) - return -EFAULT; - console_lock(); for (i = 0; i < E_TABSZ ; i++) { @@ -356,22 +351,16 @@ int con_get_trans_old(unsigned char __user * arg) } console_unlock(); - for (i = 0; i < E_TABSZ ; i++) - __put_user(outbuf[i], arg+i); - return 0; + return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0; } int con_set_trans_new(ushort __user * arg) { - int i; unsigned short inbuf[E_TABSZ]; - if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short))) + if (copy_from_user(inbuf, arg, sizeof(inbuf))) return -EFAULT; - for (i = 0; i < E_TABSZ ; i++) - __get_user(inbuf[i], arg+i); - console_lock(); memcpy(translations[USER_MAP], inbuf, sizeof(inbuf)); update_user_maps(); @@ -381,19 +370,13 @@ int con_set_trans_new(ushort __user * arg) int con_get_trans_new(ushort __user * arg) { - int i; unsigned short outbuf[E_TABSZ]; - if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short))) - return -EFAULT; - console_lock(); memcpy(outbuf, translations[USER_MAP], sizeof(outbuf)); console_unlock(); - for (i = 0; i < E_TABSZ ; i++) - __put_user(outbuf[i], arg+i); - return 0; + return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0; } /* -- cgit v1.1 From 6987dc8a70976561d22450b5858fc9767788cc1c Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Sat, 3 Jun 2017 09:35:06 +0200 Subject: vt: fix unchecked __put_user() in tioclinux ioctls Only read access is checked before this call. Actually, at the moment this is not an issue, as every in-tree arch does the same manual checks for VERIFY_READ vs VERIFY_WRITE, relying on the MMU to tell them apart, but this wasn't the case in the past and may happen again on some odd arch in the future. If anyone cares about 3.7 and earlier, this is a security hole (untested) on real 80386 CPUs. Signed-off-by: Adam Borowski CC: stable@vger.kernel.org # v3.7- Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty/vt') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 9c99452..bacc48b 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2709,13 +2709,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) * related to the kernel should not use this. */ data = vt_get_shift_state(); - ret = __put_user(data, p); + ret = put_user(data, p); break; case TIOCL_GETMOUSEREPORTING: console_lock(); /* May be overkill */ data = mouse_reporting(); console_unlock(); - ret = __put_user(data, p); + ret = put_user(data, p); break; case TIOCL_SETVESABLANK: console_lock(); @@ -2724,7 +2724,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) break; case TIOCL_GETKMSGREDIRECT: data = vt_get_kmsg_redirect(); - ret = __put_user(data, p); + ret = put_user(data, p); break; case TIOCL_SETKMSGREDIRECT: if (!capable(CAP_SYS_ADMIN)) { -- cgit v1.1 From 915f0a8d2884d05538ae5c06e09f40d364fa2c3f Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Sat, 3 Jun 2017 09:35:07 +0200 Subject: vt: use copy_to_user instead of __put_user in GIO_UNIMAP ioctl A nice big linear transfer, no need to flip stac/PAN/etc every half-entry. Also, yay __put_user() after checking only read. Signed-off-by: Adam Borowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/tty/vt') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 1361f2a..c6a692f 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -740,11 +740,11 @@ EXPORT_SYMBOL(con_copy_unimap); */ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) { - int i, j, k; + int i, j, k, ret = 0; ushort ect; u16 **p1, *p2; struct uni_pagedir *p; - struct unipair *unilist, *plist; + struct unipair *unilist; unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL); if (!unilist) @@ -775,13 +775,11 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni } } console_unlock(); - for (i = min(ect, ct), plist = unilist; i; i--, list++, plist++) { - __put_user(plist->unicode, &list->unicode); - __put_user(plist->fontpos, &list->fontpos); - } - __put_user(ect, uct); + if (copy_to_user(list, unilist, min(ect, ct) * sizeof(struct unipair))) + ret = -EFAULT; + put_user(ect, uct); kfree(unilist); - return ((ect <= ct) ? 0 : -ENOMEM); + return ret ? ret : (ect <= ct) ? 0 : -ENOMEM; } /* -- cgit v1.1 From 4f1be1b5d9aaef9c887140de5f2b9c2a989577d8 Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Sat, 3 Jun 2017 09:35:08 +0200 Subject: vt: use memdup_user in PIO_UNIMAP ioctl Again, a nice linear transfer that simplifies the code. Signed-off-by: Adam Borowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/tty/vt') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index c6a692f..a5f88cf 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -540,14 +540,9 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) if (!ct) return 0; - unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL); - if (!unilist) - return -ENOMEM; - - for (i = ct, plist = unilist; i; i--, plist++, list++) { - __get_user(plist->unicode, &list->unicode); - __get_user(plist->fontpos, &list->fontpos); - } + unilist = memdup_user(list, ct * sizeof(struct unipair)); + if (IS_ERR(unilist)) + return PTR_ERR(unilist); console_lock(); -- cgit v1.1 From f8564c93e0907651e21d586920e629227bb0d024 Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Sat, 3 Jun 2017 09:35:09 +0200 Subject: vt: drop access_ok() calls in unimap ioctls Done by copy_{from,to}_user(). Signed-off-by: Adam Borowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt_ioctl.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/tty/vt') diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 0cbfe1f..96d389c 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -266,10 +266,6 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_ if (copy_from_user(&tmp, user_ud, sizeof tmp)) return -EFAULT; - 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) @@ -1170,10 +1166,6 @@ compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud, 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) -- cgit v1.1