s390/keyboard: sanitize array index in do_kdsk_ioctl
The kbd_ioctl uses two user controlled indexes for KDGKBENT/KDSKBENT. Use array_index_nospec to prevent any out of bounds speculation. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
aeaf7002a7
commit
054732837c
|
@ -334,37 +334,41 @@ do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe,
|
||||||
int cmd, int perm)
|
int cmd, int perm)
|
||||||
{
|
{
|
||||||
struct kbentry tmp;
|
struct kbentry tmp;
|
||||||
|
unsigned long kb_index, kb_table;
|
||||||
ushort *key_map, val, ov;
|
ushort *key_map, val, ov;
|
||||||
|
|
||||||
if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
|
if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
kb_index = (unsigned long) tmp.kb_index;
|
||||||
#if NR_KEYS < 256
|
#if NR_KEYS < 256
|
||||||
if (tmp.kb_index >= NR_KEYS)
|
if (kb_index >= NR_KEYS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
#endif
|
#endif
|
||||||
|
kb_table = (unsigned long) tmp.kb_table;
|
||||||
#if MAX_NR_KEYMAPS < 256
|
#if MAX_NR_KEYMAPS < 256
|
||||||
if (tmp.kb_table >= MAX_NR_KEYMAPS)
|
if (kb_table >= MAX_NR_KEYMAPS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
kb_table = array_index_nospec(kb_table , MAX_NR_KEYMAPS);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case KDGKBENT:
|
case KDGKBENT:
|
||||||
key_map = kbd->key_maps[tmp.kb_table];
|
key_map = kbd->key_maps[kb_table];
|
||||||
if (key_map) {
|
if (key_map) {
|
||||||
val = U(key_map[tmp.kb_index]);
|
val = U(key_map[kb_index]);
|
||||||
if (KTYP(val) >= KBD_NR_TYPES)
|
if (KTYP(val) >= KBD_NR_TYPES)
|
||||||
val = K_HOLE;
|
val = K_HOLE;
|
||||||
} else
|
} else
|
||||||
val = (tmp.kb_index ? K_HOLE : K_NOSUCHMAP);
|
val = (kb_index ? K_HOLE : K_NOSUCHMAP);
|
||||||
return put_user(val, &user_kbe->kb_value);
|
return put_user(val, &user_kbe->kb_value);
|
||||||
case KDSKBENT:
|
case KDSKBENT:
|
||||||
if (!perm)
|
if (!perm)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (!tmp.kb_index && tmp.kb_value == K_NOSUCHMAP) {
|
if (!kb_index && tmp.kb_value == K_NOSUCHMAP) {
|
||||||
/* disallocate map */
|
/* disallocate map */
|
||||||
key_map = kbd->key_maps[tmp.kb_table];
|
key_map = kbd->key_maps[kb_table];
|
||||||
if (key_map) {
|
if (key_map) {
|
||||||
kbd->key_maps[tmp.kb_table] = NULL;
|
kbd->key_maps[kb_table] = NULL;
|
||||||
kfree(key_map);
|
kfree(key_map);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -375,18 +379,18 @@ do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe,
|
||||||
if (KVAL(tmp.kb_value) > kbd_max_vals[KTYP(tmp.kb_value)])
|
if (KVAL(tmp.kb_value) > kbd_max_vals[KTYP(tmp.kb_value)])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!(key_map = kbd->key_maps[tmp.kb_table])) {
|
if (!(key_map = kbd->key_maps[kb_table])) {
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
key_map = kmalloc(sizeof(plain_map),
|
key_map = kmalloc(sizeof(plain_map),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!key_map)
|
if (!key_map)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
kbd->key_maps[tmp.kb_table] = key_map;
|
kbd->key_maps[kb_table] = key_map;
|
||||||
for (j = 0; j < NR_KEYS; j++)
|
for (j = 0; j < NR_KEYS; j++)
|
||||||
key_map[j] = U(K_HOLE);
|
key_map[j] = U(K_HOLE);
|
||||||
}
|
}
|
||||||
ov = U(key_map[tmp.kb_index]);
|
ov = U(key_map[kb_index]);
|
||||||
if (tmp.kb_value == ov)
|
if (tmp.kb_value == ov)
|
||||||
break; /* nothing to do */
|
break; /* nothing to do */
|
||||||
/*
|
/*
|
||||||
|
@ -395,7 +399,7 @@ do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe,
|
||||||
if (((ov == K_SAK) || (tmp.kb_value == K_SAK)) &&
|
if (((ov == K_SAK) || (tmp.kb_value == K_SAK)) &&
|
||||||
!capable(CAP_SYS_ADMIN))
|
!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
key_map[tmp.kb_index] = U(tmp.kb_value);
|
key_map[kb_index] = U(tmp.kb_value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue