diff options
author | Jiri Slaby <jslaby@suse.cz> | 2020-10-29 12:32:11 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-11-04 16:43:38 +0100 |
commit | fe6416e126cc17c0454c9c32d06b81a4e58ed8b7 (patch) | |
tree | 0ee04a96a3859ce1cd261264f0922087e9f7c96e /drivers/tty/vt/keyboard.c | |
parent | vt: keyboard, clean up max_vals (diff) | |
download | linux-fe6416e126cc17c0454c9c32d06b81a4e58ed8b7.tar.xz linux-fe6416e126cc17c0454c9c32d06b81a4e58ed8b7.zip |
vt: keyboard, extract vt_kdgkbent and vt_kdskbent
Split vt_do_kdsk_ioctl into three functions:
* getter (KDGKBENT/vt_kdgkbent)
* setter (KDSKBENT/vt_kdskbent)
* switch-case helper (vt_do_kdsk_ioctl)
This eliminates the need of ugly one-letter macros as we use parameters
now:
* i aka tmp.kb_index -> idx
* s aka tmp.kb_table -> map
* v aka tmp.kb_value -> val
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Link: https://lore.kernel.org/r/20201029113222.32640-6-jslaby@suse.cz
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/vt/keyboard.c')
-rw-r--r-- | drivers/tty/vt/keyboard.c | 189 |
1 files changed, 102 insertions, 87 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 4545afd3ef2f..c1709b8dbb52 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1897,114 +1897,129 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, return kc; } -#define i (tmp.kb_index) -#define s (tmp.kb_table) -#define v (tmp.kb_value) - -int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, - int console) +static unsigned short vt_kdgkbent(unsigned char kbdmode, unsigned char idx, + unsigned char map) { - struct kbd_struct *kb = kbd_table + console; - struct kbentry tmp; - ushort *key_map, *new_map, val, ov; + unsigned short *key_map, val; unsigned long flags; - if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) - return -EFAULT; + /* Ensure another thread doesn't free it under us */ + spin_lock_irqsave(&kbd_event_lock, flags); + key_map = key_maps[map]; + if (key_map) { + val = U(key_map[idx]); + if (kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + val = K_HOLE; + } else + val = idx ? K_HOLE : K_NOSUCHMAP; + spin_unlock_irqrestore(&kbd_event_lock, flags); - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; + return val; +} - switch (cmd) { - case KDGKBENT: - /* Ensure another thread doesn't free it under us */ +static int vt_kdskbent(unsigned char kbdmode, unsigned char idx, + unsigned char map, unsigned short val) +{ + unsigned long flags; + unsigned short *key_map, *new_map, oldval; + + if (!idx && val == K_NOSUCHMAP) { spin_lock_irqsave(&kbd_event_lock, flags); - key_map = key_maps[s]; - if (key_map) { - val = U(key_map[i]); - if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) - val = K_HOLE; - } else - val = (i ? K_HOLE : K_NOSUCHMAP); - spin_unlock_irqrestore(&kbd_event_lock, flags); - return put_user(val, &user_kbe->kb_value); - case KDSKBENT: - if (!perm) - return -EPERM; - if (!i && v == K_NOSUCHMAP) { - spin_lock_irqsave(&kbd_event_lock, flags); - /* deallocate map */ - key_map = key_maps[s]; - if (s && key_map) { - key_maps[s] = NULL; - if (key_map[0] == U(K_ALLOCATED)) { - kfree(key_map); - keymap_count--; - } + /* deallocate map */ + key_map = key_maps[map]; + if (map && key_map) { + key_maps[map] = NULL; + if (key_map[0] == U(K_ALLOCATED)) { + kfree(key_map); + keymap_count--; } - spin_unlock_irqrestore(&kbd_event_lock, flags); - break; } + spin_unlock_irqrestore(&kbd_event_lock, flags); - if (KTYP(v) < NR_TYPES) { - if (KVAL(v) > max_vals[KTYP(v)]) - return -EINVAL; - } else - if (kb->kbdmode != VC_UNICODE) - return -EINVAL; + return 0; + } - /* ++Geert: non-PC keyboards may generate keycode zero */ + if (KTYP(val) < NR_TYPES) { + if (KVAL(val) > max_vals[KTYP(val)]) + return -EINVAL; + } else if (kbdmode != VC_UNICODE) + return -EINVAL; + + /* ++Geert: non-PC keyboards may generate keycode zero */ #if !defined(__mc68000__) && !defined(__powerpc__) - /* assignment to entry 0 only tests validity of args */ - if (!i) - break; + /* assignment to entry 0 only tests validity of args */ + if (!idx) + return 0; #endif - new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); - if (!new_map) - return -ENOMEM; - spin_lock_irqsave(&kbd_event_lock, flags); - key_map = key_maps[s]; - if (key_map == NULL) { - int j; - - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && - !capable(CAP_SYS_RESOURCE)) { - spin_unlock_irqrestore(&kbd_event_lock, flags); - kfree(new_map); - return -EPERM; - } - key_maps[s] = new_map; - key_map = new_map; - key_map[0] = U(K_ALLOCATED); - for (j = 1; j < NR_KEYS; j++) - key_map[j] = U(K_HOLE); - keymap_count++; - } else - kfree(new_map); + new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); + if (!new_map) + return -ENOMEM; - ov = U(key_map[i]); - if (v == ov) - goto out; - /* - * Attention Key. - */ - if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) { + spin_lock_irqsave(&kbd_event_lock, flags); + key_map = key_maps[map]; + if (key_map == NULL) { + int j; + + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && + !capable(CAP_SYS_RESOURCE)) { spin_unlock_irqrestore(&kbd_event_lock, flags); + kfree(new_map); return -EPERM; } - key_map[i] = U(v); - if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) - do_compute_shiftstate(); -out: + key_maps[map] = new_map; + key_map = new_map; + key_map[0] = U(K_ALLOCATED); + for (j = 1; j < NR_KEYS; j++) + key_map[j] = U(K_HOLE); + keymap_count++; + } else + kfree(new_map); + + oldval = U(key_map[idx]); + if (val == oldval) + goto out; + + /* Attention Key */ + if ((oldval == K_SAK || val == K_SAK) && !capable(CAP_SYS_ADMIN)) { spin_unlock_irqrestore(&kbd_event_lock, flags); - break; + return -EPERM; + } + + key_map[idx] = U(val); + if (!map && (KTYP(oldval) == KT_SHIFT || KTYP(val) == KT_SHIFT)) + do_compute_shiftstate(); +out: + spin_unlock_irqrestore(&kbd_event_lock, flags); + + return 0; +} + +int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, + int console) +{ + struct kbd_struct *kb = kbd_table + console; + struct kbentry kbe; + + if (copy_from_user(&kbe, user_kbe, sizeof(struct kbentry))) + return -EFAULT; + + if (!capable(CAP_SYS_TTY_CONFIG)) + perm = 0; + + switch (cmd) { + case KDGKBENT: + return put_user(vt_kdgkbent(kb->kbdmode, kbe.kb_index, + kbe.kb_table), + &user_kbe->kb_value); + case KDSKBENT: + if (!perm) + return -EPERM; + return vt_kdskbent(kb->kbdmode, kbe.kb_index, kbe.kb_table, + kbe.kb_value); } return 0; } -#undef i -#undef s -#undef v /* FIXME: This one needs untangling */ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) |