All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] vt: keyboard, reorder user buffer handling in vt_do_kdgkb_ioctl
@ 2020-10-16 12:24 Jiri Slaby
  2020-10-16 12:24 ` [PATCH 2/3] vt: keyboard, simplify vt_kdgkbsent Jiri Slaby
  2020-10-16 12:24 ` [PATCH 3/3] vt: keyboard, extend func_buf_lock to readers Jiri Slaby
  0 siblings, 2 replies; 6+ messages in thread
From: Jiri Slaby @ 2020-10-16 12:24 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, linux-kernel, Minh Yuan, Jiri Slaby

KDGKBSENT (the getter) needs only user_kdgkb->kb_func from the
userspace, i.e. the index. So do the complete copy only in KDSKBSENT
(the setter). That means, we obtain the index before the switch-case
and use it in both paths and copy the string only in the setter case.
And we do it by strndup_user helper now which was not available when
this function was written.

Given we copy the two members of struct kbsentry separately, we no
longer need a local definition. Hence we need to change all the sizeofs
here too.

And also the getter now returns in all fail paths, not freeing the
setter's string.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 drivers/tty/vt/keyboard.c | 51 ++++++++++++++++-----------------------
 1 file changed, 21 insertions(+), 30 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 0db53b5b3acf..d8e2452da1bd 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1994,7 +1994,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
 /* FIXME: This one needs untangling and locking */
 int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 {
-	struct kbsentry *kbs;
+	char *kbs;
 	char *p;
 	u_char *q;
 	u_char __user *up;
@@ -2008,43 +2008,34 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 	if (!capable(CAP_SYS_TTY_CONFIG))
 		perm = 0;
 
-	kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
-	if (!kbs) {
-		ret = -ENOMEM;
-		goto reterr;
-	}
+	if (get_user(i, &user_kdgkb->kb_func))
+		return -EFAULT;
 
-	/* we mostly copy too much here (512bytes), but who cares ;) */
-	if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
-		ret = -EFAULT;
-		goto reterr;
-	}
-	kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
-	i = array_index_nospec(kbs->kb_func, MAX_NR_FUNC);
+	i = array_index_nospec(i, MAX_NR_FUNC);
 
 	switch (cmd) {
 	case KDGKBSENT:
-		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-						  a struct member */
+		/* sz should have been a struct member */
+		sz = sizeof_field(struct kbsentry, kb_string) - 1;
 		up = user_kdgkb->kb_string;
 		p = func_table[i];
 		if(p)
 			for ( ; *p && sz; p++, sz--)
-				if (put_user(*p, up++)) {
-					ret = -EFAULT;
-					goto reterr;
-				}
-		if (put_user('\0', up)) {
-			ret = -EFAULT;
-			goto reterr;
-		}
-		kfree(kbs);
+				if (put_user(*p, up++))
+					return -EFAULT;
+
+		if (put_user('\0', up))
+			return -EFAULT;
+
 		return ((p && *p) ? -EOVERFLOW : 0);
 	case KDSKBSENT:
-		if (!perm) {
-			ret = -EPERM;
-			goto reterr;
-		}
+		if (!perm)
+			return -EPERM;
+
+		kbs = strndup_user(user_kdgkb->kb_string,
+				sizeof(user_kdgkb->kb_string));
+		if (IS_ERR(kbs))
+			return PTR_ERR(kbs);
 
 		fnw = NULL;
 		fnw_sz = 0;
@@ -2062,7 +2053,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 		else
 			fj = first_free;
 		/* buffer usage increase by new entry */
-		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
+		delta = (q ? -strlen(q) : 1) + strlen(kbs);
 
 		if (delta <= funcbufleft) { 	/* it fits in current buf */
 		    if (j < MAX_NR_FUNC) {
@@ -2114,7 +2105,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 		    funcbufsize = sz;
 		}
 		/* finally insert item itself */
-		strcpy(func_table[i], kbs->kb_string);
+		strcpy(func_table[i], kbs);
 		spin_unlock_irqrestore(&func_buf_lock, flags);
 		break;
 	}
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] vt: keyboard, simplify vt_kdgkbsent
  2020-10-16 12:24 [PATCH 1/3] vt: keyboard, reorder user buffer handling in vt_do_kdgkb_ioctl Jiri Slaby
@ 2020-10-16 12:24 ` Jiri Slaby
  2020-10-16 12:24 ` [PATCH 3/3] vt: keyboard, extend func_buf_lock to readers Jiri Slaby
  1 sibling, 0 replies; 6+ messages in thread
From: Jiri Slaby @ 2020-10-16 12:24 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, linux-kernel, Minh Yuan, Jiri Slaby

Use 'strlen' of the string, add one for NUL and simply do 'copy_to_user'
instead of the explicit 'for' loop. This makes the KDGKBSENT case more
compact.

The only thing we need to take care about is NULL 'from'.

The original check for overflow could never trigger as the func_buf
(called 'from' here) strings are always shorter or equal to struct
kbsentry's.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 drivers/tty/vt/keyboard.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index d8e2452da1bd..68f9f6a62d02 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1995,9 +1995,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
 int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 {
 	char *kbs;
-	char *p;
 	u_char *q;
-	u_char __user *up;
 	int sz, fnw_sz;
 	int delta;
 	char *first_free, *fj, *fnw;
@@ -2014,20 +2012,15 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 	i = array_index_nospec(i, MAX_NR_FUNC);
 
 	switch (cmd) {
-	case KDGKBSENT:
-		/* sz should have been a struct member */
-		sz = sizeof_field(struct kbsentry, kb_string) - 1;
-		up = user_kdgkb->kb_string;
-		p = func_table[i];
-		if(p)
-			for ( ; *p && sz; p++, sz--)
-				if (put_user(*p, up++))
-					return -EFAULT;
-
-		if (put_user('\0', up))
+	case KDGKBSENT: {
+		/* size should have been a struct member */
+		unsigned char *from = func_table[i] ? : "";
+
+		if (copy_to_user(user_kdgkb->kb_string, from, strlen(from) + 1))
 			return -EFAULT;
 
-		return ((p && *p) ? -EOVERFLOW : 0);
+		return 0;
+	}
 	case KDSKBSENT:
 		if (!perm)
 			return -EPERM;
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] vt: keyboard, extend func_buf_lock to readers
  2020-10-16 12:24 [PATCH 1/3] vt: keyboard, reorder user buffer handling in vt_do_kdgkb_ioctl Jiri Slaby
  2020-10-16 12:24 ` [PATCH 2/3] vt: keyboard, simplify vt_kdgkbsent Jiri Slaby
@ 2020-10-16 12:24 ` Jiri Slaby
  2020-10-16 13:20   ` Greg KH
  1 sibling, 1 reply; 6+ messages in thread
From: Jiri Slaby @ 2020-10-16 12:24 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, linux-kernel, Minh Yuan, Jiri Slaby

Both read-side users of func_table/func_buf need locking. Without that,
one can easily confuse the code by repeatedly setting altering strings
like:
while (1)
	for (a = 0; a < 2; a++) {
		struct kbsentry kbs = {};
		strcpy((char *)kbs.kb_string, a ? ".\n" : "88888\n");
		ioctl(fd, KDSKBSENT, &kbs);
	}

When that program runs, one can get unexpected output by holding F1
(note the unxpected period on the last line):
.
88888
.8888

So protect all accesses to 'func_table' (and func_buf) by preexisting
'func_buf_lock'.

It is easy in 'k_fn' handler as 'puts_queue' is expected not to sleep.
On the other hand, KDGKBSENT needs a local (atomic) copy of the string
because copy_to_user can sleep.

Likely fixes CVE-2020-25656.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Reported-by: Minh Yuan <yuanmingbuaa@gmail.com>
---
 drivers/tty/vt/keyboard.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 68f9f6a62d02..68b1acc0074c 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -743,8 +743,13 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
 		return;
 
 	if ((unsigned)value < ARRAY_SIZE(func_table)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&func_buf_lock, flags);
 		if (func_table[value])
 			puts_queue(vc, func_table[value]);
+		spin_unlock_irqrestore(&func_buf_lock, flags);
+
 	} else
 		pr_err("k_fn called with value=%d\n", value);
 }
@@ -1991,7 +1996,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
 #undef s
 #undef v
 
-/* FIXME: This one needs untangling and locking */
+/* FIXME: This one needs untangling */
 int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 {
 	char *kbs;
@@ -2014,12 +2019,23 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 	switch (cmd) {
 	case KDGKBSENT: {
 		/* size should have been a struct member */
-		unsigned char *from = func_table[i] ? : "";
+		char *func_copy;
+		ssize_t len = sizeof(user_kdgkb->kb_string);
 
-		if (copy_to_user(user_kdgkb->kb_string, from, strlen(from) + 1))
-			return -EFAULT;
+		func_copy = kmalloc(len, GFP_KERNEL);
+		if (!func_copy)
+			return -ENOMEM;
 
-		return 0;
+		spin_lock_irqsave(&func_buf_lock, flags);
+		len = strlcpy(func_copy, func_table[i] ? : "", len);
+		spin_unlock_irqrestore(&func_buf_lock, flags);
+
+		ret = copy_to_user(user_kdgkb->kb_string, func_copy, len + 1) ?
+			-EFAULT : 0;
+
+		kfree(func_copy);
+
+		return ret;
 	}
 	case KDSKBSENT:
 		if (!perm)
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] vt: keyboard, extend func_buf_lock to readers
  2020-10-16 12:24 ` [PATCH 3/3] vt: keyboard, extend func_buf_lock to readers Jiri Slaby
@ 2020-10-16 13:20   ` Greg KH
  2020-10-19  8:00     ` Jiri Slaby
  0 siblings, 1 reply; 6+ messages in thread
From: Greg KH @ 2020-10-16 13:20 UTC (permalink / raw)
  To: Jiri Slaby; +Cc: linux-serial, linux-kernel, Minh Yuan

On Fri, Oct 16, 2020 at 02:24:12PM +0200, Jiri Slaby wrote:
> Both read-side users of func_table/func_buf need locking. Without that,
> one can easily confuse the code by repeatedly setting altering strings
> like:
> while (1)
> 	for (a = 0; a < 2; a++) {
> 		struct kbsentry kbs = {};
> 		strcpy((char *)kbs.kb_string, a ? ".\n" : "88888\n");
> 		ioctl(fd, KDSKBSENT, &kbs);
> 	}
> 
> When that program runs, one can get unexpected output by holding F1
> (note the unxpected period on the last line):
> .
> 88888
> .8888
> 
> So protect all accesses to 'func_table' (and func_buf) by preexisting
> 'func_buf_lock'.
> 
> It is easy in 'k_fn' handler as 'puts_queue' is expected not to sleep.
> On the other hand, KDGKBSENT needs a local (atomic) copy of the string
> because copy_to_user can sleep.
> 
> Likely fixes CVE-2020-25656.
> 
> Signed-off-by: Jiri Slaby <jslaby@suse.cz>
> Reported-by: Minh Yuan <yuanmingbuaa@gmail.com>
> ---
>  drivers/tty/vt/keyboard.c | 26 +++++++++++++++++++++-----
>  1 file changed, 21 insertions(+), 5 deletions(-)

So all 3 of these should go to 5.10-final?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] vt: keyboard, extend func_buf_lock to readers
  2020-10-16 13:20   ` Greg KH
@ 2020-10-19  8:00     ` Jiri Slaby
  0 siblings, 0 replies; 6+ messages in thread
From: Jiri Slaby @ 2020-10-19  8:00 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-serial, linux-kernel, Minh Yuan

On 16. 10. 20, 15:20, Greg KH wrote:
> On Fri, Oct 16, 2020 at 02:24:12PM +0200, Jiri Slaby wrote:
>> Both read-side users of func_table/func_buf need locking. Without that,
>> one can easily confuse the code by repeatedly setting altering strings
>> like:
>> while (1)
>> 	for (a = 0; a < 2; a++) {
>> 		struct kbsentry kbs = {};
>> 		strcpy((char *)kbs.kb_string, a ? ".\n" : "88888\n");
>> 		ioctl(fd, KDSKBSENT, &kbs);
>> 	}
>>
>> When that program runs, one can get unexpected output by holding F1
>> (note the unxpected period on the last line):
>> .
>> 88888
>> .8888
>>
>> So protect all accesses to 'func_table' (and func_buf) by preexisting
>> 'func_buf_lock'.
>>
>> It is easy in 'k_fn' handler as 'puts_queue' is expected not to sleep.
>> On the other hand, KDGKBSENT needs a local (atomic) copy of the string
>> because copy_to_user can sleep.
>>
>> Likely fixes CVE-2020-25656.
>>
>> Signed-off-by: Jiri Slaby <jslaby@suse.cz>
>> Reported-by: Minh Yuan <yuanmingbuaa@gmail.com>
>> ---
>>   drivers/tty/vt/keyboard.c | 26 +++++++++++++++++++++-----
>>   1 file changed, 21 insertions(+), 5 deletions(-)
> 
> So all 3 of these should go to 5.10-final?

Let me try to eliminate also patch 1/3 which I now think is possible.

-- 
js
suse labs

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] vt: keyboard, extend func_buf_lock to readers
@ 2020-10-16 14:43 kernel test robot
  0 siblings, 0 replies; 6+ messages in thread
From: kernel test robot @ 2020-10-16 14:43 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 12213 bytes --]

CC: kbuild-all(a)lists.01.org
In-Reply-To: <20201016122412.31767-3-jslaby@suse.cz>
References: <20201016122412.31767-3-jslaby@suse.cz>
TO: Jiri Slaby <jslaby@suse.cz>

Hi Jiri,

I love your patch! Perhaps something to improve:

[auto build test WARNING on tty/tty-testing]
[also build test WARNING on v5.9 next-20201016]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jiri-Slaby/vt-keyboard-reorder-user-buffer-handling-in-vt_do_kdgkb_ioctl/20201016-202459
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
:::::: branch date: 2 hours ago
:::::: commit date: 2 hours ago
config: i386-randconfig-m021-20201016 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

New smatch warnings:
drivers/tty/vt/keyboard.c:2033 vt_do_kdgkb_ioctl() warn: possible info leak 'func_copy'

Old smatch warnings:
drivers/tty/vt/keyboard.c:1914 vt_do_kdsk_ioctl() warn: potential spectre issue 'key_map' [r]
drivers/tty/vt/keyboard.c:2061 vt_do_kdgkb_ioctl() warn: potential spectre issue 'func_table' [r] (local cap)
drivers/tty/vt/keyboard.c:2070 vt_do_kdgkb_ioctl() warn: possible spectre second half.  'fj'
drivers/tty/vt/keyboard.c:2076 vt_do_kdgkb_ioctl() warn: possible spectre second half.  'fj'
drivers/tty/vt/keyboard.c:2095 vt_do_kdgkb_ioctl() warn: possible spectre second half.  'fj'
drivers/tty/vt/keyboard.c:2097 vt_do_kdgkb_ioctl() warn: possible spectre second half.  'fj'
drivers/tty/vt/keyboard.c:2123 vt_do_kdgkb_ioctl() error: uninitialized symbol 'kbs'.

vim +/func_copy +2033 drivers/tty/vt/keyboard.c

079c9534a96da9a Alan Cox           2012-02-28  1998  
4d5d6cd424ed623 Jiri Slaby         2020-10-16  1999  /* FIXME: This one needs untangling */
079c9534a96da9a Alan Cox           2012-02-28  2000  int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
079c9534a96da9a Alan Cox           2012-02-28  2001  {
987bbe4f15e721c Jiri Slaby         2020-10-16  2002  	char *kbs;
079c9534a96da9a Alan Cox           2012-02-28  2003  	u_char *q;
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2004  	int sz, fnw_sz;
079c9534a96da9a Alan Cox           2012-02-28  2005  	int delta;
079c9534a96da9a Alan Cox           2012-02-28  2006  	char *first_free, *fj, *fnw;
079c9534a96da9a Alan Cox           2012-02-28  2007  	int i, j, k;
079c9534a96da9a Alan Cox           2012-02-28  2008  	int ret;
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2009  	unsigned long flags;
079c9534a96da9a Alan Cox           2012-02-28  2010  
079c9534a96da9a Alan Cox           2012-02-28  2011  	if (!capable(CAP_SYS_TTY_CONFIG))
079c9534a96da9a Alan Cox           2012-02-28  2012  		perm = 0;
079c9534a96da9a Alan Cox           2012-02-28  2013  
987bbe4f15e721c Jiri Slaby         2020-10-16  2014  	if (get_user(i, &user_kdgkb->kb_func))
987bbe4f15e721c Jiri Slaby         2020-10-16  2015  		return -EFAULT;
079c9534a96da9a Alan Cox           2012-02-28  2016  
987bbe4f15e721c Jiri Slaby         2020-10-16  2017  	i = array_index_nospec(i, MAX_NR_FUNC);
079c9534a96da9a Alan Cox           2012-02-28  2018  
079c9534a96da9a Alan Cox           2012-02-28  2019  	switch (cmd) {
ab8a5f48e9d7cc2 Jiri Slaby         2020-10-16  2020  	case KDGKBSENT: {
ab8a5f48e9d7cc2 Jiri Slaby         2020-10-16  2021  		/* size should have been a struct member */
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2022  		char *func_copy;
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2023  		ssize_t len = sizeof(user_kdgkb->kb_string);
987bbe4f15e721c Jiri Slaby         2020-10-16  2024  
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2025  		func_copy = kmalloc(len, GFP_KERNEL);
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2026  		if (!func_copy)
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2027  			return -ENOMEM;
987bbe4f15e721c Jiri Slaby         2020-10-16  2028  
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2029  		spin_lock_irqsave(&func_buf_lock, flags);
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2030  		len = strlcpy(func_copy, func_table[i] ? : "", len);
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2031  		spin_unlock_irqrestore(&func_buf_lock, flags);
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2032  
4d5d6cd424ed623 Jiri Slaby         2020-10-16 @2033  		ret = copy_to_user(user_kdgkb->kb_string, func_copy, len + 1) ?
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2034  			-EFAULT : 0;
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2035  
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2036  		kfree(func_copy);
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2037  
4d5d6cd424ed623 Jiri Slaby         2020-10-16  2038  		return ret;
ab8a5f48e9d7cc2 Jiri Slaby         2020-10-16  2039  	}
079c9534a96da9a Alan Cox           2012-02-28  2040  	case KDSKBSENT:
987bbe4f15e721c Jiri Slaby         2020-10-16  2041  		if (!perm)
987bbe4f15e721c Jiri Slaby         2020-10-16  2042  			return -EPERM;
987bbe4f15e721c Jiri Slaby         2020-10-16  2043  
987bbe4f15e721c Jiri Slaby         2020-10-16  2044  		kbs = strndup_user(user_kdgkb->kb_string,
987bbe4f15e721c Jiri Slaby         2020-10-16  2045  				sizeof(user_kdgkb->kb_string));
987bbe4f15e721c Jiri Slaby         2020-10-16  2046  		if (IS_ERR(kbs))
987bbe4f15e721c Jiri Slaby         2020-10-16  2047  			return PTR_ERR(kbs);
079c9534a96da9a Alan Cox           2012-02-28  2048  
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2049  		fnw = NULL;
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2050  		fnw_sz = 0;
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2051  		/* race aginst other writers */
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2052  		again:
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2053  		spin_lock_irqsave(&func_buf_lock, flags);
079c9534a96da9a Alan Cox           2012-02-28  2054  		q = func_table[i];
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2055  
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2056  		/* fj pointer to next entry after 'q' */
079c9534a96da9a Alan Cox           2012-02-28  2057  		first_free = funcbufptr + (funcbufsize - funcbufleft);
079c9534a96da9a Alan Cox           2012-02-28  2058  		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
079c9534a96da9a Alan Cox           2012-02-28  2059  			;
079c9534a96da9a Alan Cox           2012-02-28  2060  		if (j < MAX_NR_FUNC)
079c9534a96da9a Alan Cox           2012-02-28  2061  			fj = func_table[j];
079c9534a96da9a Alan Cox           2012-02-28  2062  		else
079c9534a96da9a Alan Cox           2012-02-28  2063  			fj = first_free;
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2064  		/* buffer usage increase by new entry */
987bbe4f15e721c Jiri Slaby         2020-10-16  2065  		delta = (q ? -strlen(q) : 1) + strlen(kbs);
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2066  
079c9534a96da9a Alan Cox           2012-02-28  2067  		if (delta <= funcbufleft) { 	/* it fits in current buf */
079c9534a96da9a Alan Cox           2012-02-28  2068  		    if (j < MAX_NR_FUNC) {
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2069  			/* make enough space for new entry@'fj' */
079c9534a96da9a Alan Cox           2012-02-28  2070  			memmove(fj + delta, fj, first_free - fj);
079c9534a96da9a Alan Cox           2012-02-28  2071  			for (k = j; k < MAX_NR_FUNC; k++)
079c9534a96da9a Alan Cox           2012-02-28  2072  			    if (func_table[k])
079c9534a96da9a Alan Cox           2012-02-28  2073  				func_table[k] += delta;
079c9534a96da9a Alan Cox           2012-02-28  2074  		    }
079c9534a96da9a Alan Cox           2012-02-28  2075  		    if (!q)
079c9534a96da9a Alan Cox           2012-02-28  2076  		      func_table[i] = fj;
079c9534a96da9a Alan Cox           2012-02-28  2077  		    funcbufleft -= delta;
079c9534a96da9a Alan Cox           2012-02-28  2078  		} else {			/* allocate a larger buffer */
079c9534a96da9a Alan Cox           2012-02-28  2079  		    sz = 256;
079c9534a96da9a Alan Cox           2012-02-28  2080  		    while (sz < funcbufsize - funcbufleft + delta)
079c9534a96da9a Alan Cox           2012-02-28  2081  		      sz <<= 1;
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2082  		    if (fnw_sz != sz) {
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2083  		      spin_unlock_irqrestore(&func_buf_lock, flags);
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2084  		      kfree(fnw);
079c9534a96da9a Alan Cox           2012-02-28  2085  		      fnw = kmalloc(sz, GFP_KERNEL);
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2086  		      fnw_sz = sz;
079c9534a96da9a Alan Cox           2012-02-28  2087  		      if (!fnw) {
079c9534a96da9a Alan Cox           2012-02-28  2088  			ret = -ENOMEM;
079c9534a96da9a Alan Cox           2012-02-28  2089  			goto reterr;
079c9534a96da9a Alan Cox           2012-02-28  2090  		      }
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2091  		      goto again;
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2092  		    }
079c9534a96da9a Alan Cox           2012-02-28  2093  
079c9534a96da9a Alan Cox           2012-02-28  2094  		    if (!q)
079c9534a96da9a Alan Cox           2012-02-28  2095  		      func_table[i] = fj;
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2096  		    /* copy data before insertion point to new location */
079c9534a96da9a Alan Cox           2012-02-28  2097  		    if (fj > funcbufptr)
079c9534a96da9a Alan Cox           2012-02-28  2098  			memmove(fnw, funcbufptr, fj - funcbufptr);
079c9534a96da9a Alan Cox           2012-02-28  2099  		    for (k = 0; k < j; k++)
079c9534a96da9a Alan Cox           2012-02-28  2100  		      if (func_table[k])
079c9534a96da9a Alan Cox           2012-02-28  2101  			func_table[k] = fnw + (func_table[k] - funcbufptr);
079c9534a96da9a Alan Cox           2012-02-28  2102  
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2103  		    /* copy data after insertion point to new location */
079c9534a96da9a Alan Cox           2012-02-28  2104  		    if (first_free > fj) {
079c9534a96da9a Alan Cox           2012-02-28  2105  			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
079c9534a96da9a Alan Cox           2012-02-28  2106  			for (k = j; k < MAX_NR_FUNC; k++)
079c9534a96da9a Alan Cox           2012-02-28  2107  			  if (func_table[k])
079c9534a96da9a Alan Cox           2012-02-28  2108  			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
079c9534a96da9a Alan Cox           2012-02-28  2109  		    }
079c9534a96da9a Alan Cox           2012-02-28  2110  		    if (funcbufptr != func_buf)
079c9534a96da9a Alan Cox           2012-02-28  2111  		      kfree(funcbufptr);
079c9534a96da9a Alan Cox           2012-02-28  2112  		    funcbufptr = fnw;
079c9534a96da9a Alan Cox           2012-02-28  2113  		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
079c9534a96da9a Alan Cox           2012-02-28  2114  		    funcbufsize = sz;
079c9534a96da9a Alan Cox           2012-02-28  2115  		}
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2116  		/* finally insert item itself */
987bbe4f15e721c Jiri Slaby         2020-10-16  2117  		strcpy(func_table[i], kbs);
46ca3f735f345c9 Sergei Trofimovich 2019-03-10  2118  		spin_unlock_irqrestore(&func_buf_lock, flags);
079c9534a96da9a Alan Cox           2012-02-28  2119  		break;
079c9534a96da9a Alan Cox           2012-02-28  2120  	}
079c9534a96da9a Alan Cox           2012-02-28  2121  	ret = 0;
079c9534a96da9a Alan Cox           2012-02-28  2122  reterr:
079c9534a96da9a Alan Cox           2012-02-28  2123  	kfree(kbs);
079c9534a96da9a Alan Cox           2012-02-28  2124  	return ret;
079c9534a96da9a Alan Cox           2012-02-28  2125  }
079c9534a96da9a Alan Cox           2012-02-28  2126  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 31955 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-10-19  8:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-16 12:24 [PATCH 1/3] vt: keyboard, reorder user buffer handling in vt_do_kdgkb_ioctl Jiri Slaby
2020-10-16 12:24 ` [PATCH 2/3] vt: keyboard, simplify vt_kdgkbsent Jiri Slaby
2020-10-16 12:24 ` [PATCH 3/3] vt: keyboard, extend func_buf_lock to readers Jiri Slaby
2020-10-16 13:20   ` Greg KH
2020-10-19  8:00     ` Jiri Slaby
2020-10-16 14:43 kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.