tty: vt/keyboard: use __free()

The vt/keyboard code can use __free to ensure the temporary buffers are
freed. Perform the switch.

And even one non-temporary in kbd_connect(). There are fail paths, so
ensure the buffer is freed in them and not when returning 0 -- by
retain_and_null_ptr().

Signed-off-by: Jiri Slaby (SUSE) <jirislaby@kernel.org>
Link: https://patch.msgid.link/20251119100140.830761-7-jirislaby@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Jiri Slaby (SUSE)
2025-11-19 11:01:36 +01:00
committed by Greg Kroah-Hartman
parent 1c7736dc68
commit bfb24564b5

View File

@@ -1566,10 +1566,9 @@ static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
static int kbd_connect(struct input_handler *handler, struct input_dev *dev, static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id) const struct input_device_id *id)
{ {
struct input_handle *handle;
int error; int error;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); struct input_handle __free(kfree) *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (!handle) if (!handle)
return -ENOMEM; return -ENOMEM;
@@ -1579,18 +1578,18 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
error = input_register_handle(handle); error = input_register_handle(handle);
if (error) if (error)
goto err_free_handle; return error;
error = input_open_device(handle); error = input_open_device(handle);
if (error) if (error)
goto err_unregister_handle; goto err_unregister_handle;
retain_and_null_ptr(handle);
return 0; return 0;
err_unregister_handle: err_unregister_handle:
input_unregister_handle(handle); input_unregister_handle(handle);
err_free_handle:
kfree(handle);
return error; return error;
} }
@@ -1683,17 +1682,15 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
{ {
unsigned long flags; unsigned long flags;
int asize; int asize;
int ret = 0;
switch (cmd) { switch (cmd) {
case KDGKBDIACR: case KDGKBDIACR:
{ {
struct kbdiacrs __user *a = udp; struct kbdiacrs __user *a = udp;
struct kbdiacr *dia;
int i; int i;
dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr), struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr),
GFP_KERNEL); GFP_KERNEL);
if (!dia) if (!dia)
return -ENOMEM; return -ENOMEM;
@@ -1713,20 +1710,17 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
spin_unlock_irqrestore(&kbd_event_lock, flags); spin_unlock_irqrestore(&kbd_event_lock, flags);
if (put_user(asize, &a->kb_cnt)) if (put_user(asize, &a->kb_cnt))
ret = -EFAULT; return -EFAULT;
else if (copy_to_user(a->kbdiacr, dia, if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr)))
asize * sizeof(struct kbdiacr))) return -EFAULT;
ret = -EFAULT; return 0;
kfree(dia);
return ret;
} }
case KDGKBDIACRUC: case KDGKBDIACRUC:
{ {
struct kbdiacrsuc __user *a = udp; struct kbdiacrsuc __user *a = udp;
void *buf;
buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc), void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc),
GFP_KERNEL); GFP_KERNEL);
if (buf == NULL) if (buf == NULL)
return -ENOMEM; return -ENOMEM;
@@ -1740,18 +1734,17 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
spin_unlock_irqrestore(&kbd_event_lock, flags); spin_unlock_irqrestore(&kbd_event_lock, flags);
if (put_user(asize, &a->kb_cnt)) if (put_user(asize, &a->kb_cnt))
ret = -EFAULT; return -EFAULT;
else if (copy_to_user(a->kbdiacruc, buf, if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc)))
asize*sizeof(struct kbdiacruc))) return -EFAULT;
ret = -EFAULT;
kfree(buf); return 0;
return ret;
} }
case KDSKBDIACR: case KDSKBDIACR:
{ {
struct kbdiacrs __user *a = udp; struct kbdiacrs __user *a = udp;
struct kbdiacr *dia = NULL; struct kbdiacr __free(kfree) *dia = NULL;
unsigned int ct; unsigned int ct;
int i; int i;
@@ -1780,7 +1773,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
conv_8bit_to_uni(dia[i].result); conv_8bit_to_uni(dia[i].result);
} }
spin_unlock_irqrestore(&kbd_event_lock, flags); spin_unlock_irqrestore(&kbd_event_lock, flags);
kfree(dia);
return 0; return 0;
} }
@@ -1788,7 +1781,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
{ {
struct kbdiacrsuc __user *a = udp; struct kbdiacrsuc __user *a = udp;
unsigned int ct; unsigned int ct;
void *buf = NULL; void __free(kfree) *buf = NULL;
if (!perm) if (!perm)
return -EPERM; return -EPERM;
@@ -1811,11 +1804,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
ct * sizeof(struct kbdiacruc)); ct * sizeof(struct kbdiacruc));
accent_table_size = ct; accent_table_size = ct;
spin_unlock_irqrestore(&kbd_event_lock, flags); spin_unlock_irqrestore(&kbd_event_lock, flags);
kfree(buf);
return 0; return 0;
} }
} }
return ret; return 0;
} }
/** /**
@@ -1934,7 +1926,7 @@ static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
unsigned char map, unsigned short val) unsigned char map, unsigned short val)
{ {
unsigned long flags; unsigned long flags;
unsigned short *key_map, *new_map, oldval; unsigned short *key_map, oldval;
if (!idx && val == K_NOSUCHMAP) { if (!idx && val == K_NOSUCHMAP) {
spin_lock_irqsave(&kbd_event_lock, flags); spin_lock_irqsave(&kbd_event_lock, flags);
@@ -1965,7 +1957,7 @@ static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
return 0; return 0;
#endif #endif
new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); unsigned short __free(kfree) *new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
if (!new_map) if (!new_map)
return -ENOMEM; return -ENOMEM;
@@ -1977,17 +1969,14 @@ static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
!capable(CAP_SYS_RESOURCE)) { !capable(CAP_SYS_RESOURCE)) {
spin_unlock_irqrestore(&kbd_event_lock, flags); spin_unlock_irqrestore(&kbd_event_lock, flags);
kfree(new_map);
return -EPERM; return -EPERM;
} }
key_maps[map] = new_map; key_map = key_maps[map] = no_free_ptr(new_map);
key_map = new_map;
key_map[0] = U(K_ALLOCATED); key_map[0] = U(K_ALLOCATED);
for (j = 1; j < NR_KEYS; j++) for (j = 1; j < NR_KEYS; j++)
key_map[j] = U(K_HOLE); key_map[j] = U(K_HOLE);
keymap_count++; keymap_count++;
} else }
kfree(new_map);
oldval = U(key_map[idx]); oldval = U(key_map[idx]);
if (val == oldval) if (val == oldval)
@@ -2050,8 +2039,6 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
{ {
unsigned char kb_func; unsigned char kb_func;
unsigned long flags; unsigned long flags;
char *kbs;
int ret;
if (get_user(kb_func, &user_kdgkb->kb_func)) if (get_user(kb_func, &user_kdgkb->kb_func))
return -EFAULT; return -EFAULT;
@@ -2063,7 +2050,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
/* size should have been a struct member */ /* size should have been a struct member */
ssize_t len = sizeof(user_kdgkb->kb_string); ssize_t len = sizeof(user_kdgkb->kb_string);
kbs = kmalloc(len, GFP_KERNEL); char __free(kfree) *kbs = kmalloc(len, GFP_KERNEL);
if (!kbs) if (!kbs)
return -ENOMEM; return -ENOMEM;
@@ -2071,20 +2058,20 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
len = strscpy(kbs, func_table[kb_func] ? : "", len); len = strscpy(kbs, func_table[kb_func] ? : "", len);
spin_unlock_irqrestore(&func_buf_lock, flags); spin_unlock_irqrestore(&func_buf_lock, flags);
if (len < 0) { if (len < 0)
ret = -ENOSPC; return -ENOSPC;
break;
} if (copy_to_user(user_kdgkb->kb_string, kbs, len + 1))
ret = copy_to_user(user_kdgkb->kb_string, kbs, len + 1) ? return -EFAULT;
-EFAULT : 0;
break; return 0;
} }
case KDSKBSENT: case KDSKBSENT:
if (!perm || !capable(CAP_SYS_TTY_CONFIG)) if (!perm || !capable(CAP_SYS_TTY_CONFIG))
return -EPERM; return -EPERM;
kbs = strndup_user(user_kdgkb->kb_string, char __free(kfree) *kbs = strndup_user(user_kdgkb->kb_string,
sizeof(user_kdgkb->kb_string)); sizeof(user_kdgkb->kb_string));
if (IS_ERR(kbs)) if (IS_ERR(kbs))
return PTR_ERR(kbs); return PTR_ERR(kbs);
@@ -2092,13 +2079,10 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
kbs = vt_kdskbsent(kbs, kb_func); kbs = vt_kdskbsent(kbs, kb_func);
spin_unlock_irqrestore(&func_buf_lock, flags); spin_unlock_irqrestore(&func_buf_lock, flags);
ret = 0; return 0;
break;
} }
kfree(kbs); return 0;
return ret;
} }
int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm) int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm)