ACK: [PATCH 2/2] vt: keyboard, extend func_buf_lock to readers

Thadeu Lima de Souza Cascardo cascardo at canonical.com
Mon Feb 22 20:47:57 UTC 2021


On Mon, Feb 22, 2021 at 12:39:22PM -0700, Tim Gardner wrote:
> From: Jiri Slaby <jslaby at suse.cz>
> 
> 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. Use already allocated, but unused
> 'kbs->kb_string' for that purpose.
> 
> Note that the program above needs at least CAP_SYS_TTY_CONFIG.
> 
> This depends on the previous patch and on the func_buf_lock lock added
> in commit 46ca3f735f34 (tty/vt: fix write/write race in ioctl(KDSKBSENT)
> handler) in 5.2.
> 
> Likely fixes CVE-2020-25656.
> 
> Cc: <stable at vger.kernel.org>
> Reported-by: Minh Yuan <yuanmingbuaa at gmail.com>
> Signed-off-by: Jiri Slaby <jslaby at suse.cz>
> Link: https://lore.kernel.org/r/20201019085517.10176-2-jslaby@suse.cz
> Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> (cherry picked from commit 82e61c3909db51d91b9d3e2071557b6435018b80)
> CVE-2020-25656
> Signed-off-by: Tim Gardner <tim.gardner at canonical.com>

Acked-by: Thadeu Lima de Souza Cascardo <cascardo at canonical.com>

> ---
>  drivers/tty/vt/keyboard.c | 17 +++++++++++++----
>  1 file changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
> index e64e3a7aa2f1..b6e78fdbfdff 100644
> --- a/drivers/tty/vt/keyboard.c
> +++ b/drivers/tty/vt/keyboard.c
> @@ -742,8 +742,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);
>  }
> @@ -1990,7 +1995,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)
>  {
>  	struct kbsentry *kbs;
> @@ -2022,10 +2027,14 @@ 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] ? : "";
> +		ssize_t len = sizeof(user_kdgkb->kb_string);
> +
> +		spin_lock_irqsave(&func_buf_lock, flags);
> +		len = strlcpy(kbs->kb_string, func_table[i] ? : "", len);
> +		spin_unlock_irqrestore(&func_buf_lock, flags);
>  
> -		ret = copy_to_user(user_kdgkb->kb_string, from,
> -				strlen(from) + 1) ? -EFAULT : 0;
> +		ret = copy_to_user(user_kdgkb->kb_string, kbs->kb_string,
> +				len + 1) ? -EFAULT : 0;
>  
>  		goto reterr;
>  	}
> -- 
> 2.17.1
> 
> 
> -- 
> kernel-team mailing list
> kernel-team at lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team



More information about the kernel-team mailing list