git: 7a810290b8f6 - main - evdev: Make variable-size ioctls return actual length of copyouted data

Vladimir Kondratyev wulf at FreeBSD.org
Wed Jan 20 20:10:48 UTC 2021


The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=7a810290b8f6c6885fdb9917cf590d46fa270a61

commit 7a810290b8f6c6885fdb9917cf590d46fa270a61
Author:     Vladimir Kondratyev <wulf at FreeBSD.org>
AuthorDate: 2021-01-20 20:10:07 +0000
Commit:     Vladimir Kondratyev <wulf at FreeBSD.org>
CommitDate: 2021-01-20 20:10:07 +0000

    evdev: Make variable-size ioctls return actual length of copyouted data
    
    on success instead of 0 to match Linux.
    Imprivata binary depends on this.
    
    Submitted by:   Shunchao Hu <ankohuu_outlook.com>
    Reviewed by:    wulf
    Differential revision:  https://reviews.freebsd.org/D28218
---
 sys/dev/evdev/cdev.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/sys/dev/evdev/cdev.c b/sys/dev/evdev/cdev.c
index 91536c119fb4..66d00ad16aee 100644
--- a/sys/dev/evdev/cdev.c
+++ b/sys/dev/evdev/cdev.c
@@ -78,7 +78,8 @@ static d_kqfilter_t	evdev_kqfilter;
 static int evdev_kqread(struct knote *kn, long hint);
 static void evdev_kqdetach(struct knote *kn);
 static void evdev_dtor(void *);
-static int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t);
+static int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t,
+    struct thread *);
 static void evdev_client_filter_queue(struct evdev_client *, uint16_t);
 
 static struct cdevsw evdev_cdevsw = {
@@ -576,29 +577,38 @@ evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
 	/* evdev variable-length ioctls handling */
 	switch (IOCBASECMD(cmd)) {
 	case EVIOCGNAME(0):
-		strlcpy(data, evdev->ev_name, len);
+		/* Linux evdev does not terminate truncated strings with 0 */
+		limit = MIN(strlen(evdev->ev_name) + 1, len);
+		memcpy(data, evdev->ev_name, limit);
+		td->td_retval[0] = limit;
 		return (0);
 
 	case EVIOCGPHYS(0):
 		if (evdev->ev_shortname[0] == 0)
 			return (ENOENT);
 
-		strlcpy(data, evdev->ev_shortname, len);
+		limit = MIN(strlen(evdev->ev_shortname) + 1, len);
+		memcpy(data, evdev->ev_shortname, limit);
+		td->td_retval[0] = limit;
 		return (0);
 
 	case EVIOCGUNIQ(0):
 		if (evdev->ev_serial[0] == 0)
 			return (ENOENT);
 
-		strlcpy(data, evdev->ev_serial, len);
+		limit = MIN(strlen(evdev->ev_serial) + 1, len);
+		memcpy(data, evdev->ev_serial, limit);
+		td->td_retval[0] = limit;
 		return (0);
 
 	case EVIOCGPROP(0):
 		limit = MIN(len, bitstr_size(INPUT_PROP_CNT));
 		memcpy(data, evdev->ev_prop_flags, limit);
+		td->td_retval[0] = limit;
 		return (0);
 
 	case EVIOCGMTSLOTS(0):
+		/* EVIOCGMTSLOTS always returns 0 on success */
 		if (evdev->ev_mt == NULL)
 			return (EINVAL);
 		if (len < sizeof(uint32_t))
@@ -620,6 +630,7 @@ evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
 		evdev_client_filter_queue(client, EV_KEY);
 		memcpy(data, evdev->ev_key_states, limit);
 		EVDEV_UNLOCK(evdev);
+		td->td_retval[0] = limit;
 		return (0);
 
 	case EVIOCGLED(0):
@@ -628,6 +639,7 @@ evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
 		evdev_client_filter_queue(client, EV_LED);
 		memcpy(data, evdev->ev_led_states, limit);
 		EVDEV_UNLOCK(evdev);
+		td->td_retval[0] = limit;
 		return (0);
 
 	case EVIOCGSND(0):
@@ -636,6 +648,7 @@ evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
 		evdev_client_filter_queue(client, EV_SND);
 		memcpy(data, evdev->ev_snd_states, limit);
 		EVDEV_UNLOCK(evdev);
+		td->td_retval[0] = limit;
 		return (0);
 
 	case EVIOCGSW(0):
@@ -644,20 +657,22 @@ evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
 		evdev_client_filter_queue(client, EV_SW);
 		memcpy(data, evdev->ev_sw_states, limit);
 		EVDEV_UNLOCK(evdev);
+		td->td_retval[0] = limit;
 		return (0);
 
 	case EVIOCGBIT(0, 0) ... EVIOCGBIT(EV_MAX, 0):
 		type_num = IOCBASECMD(cmd) - EVIOCGBIT(0, 0);
 		debugf(client, "EVIOCGBIT(%d): data=%p, len=%d", type_num,
 		    data, len);
-		return (evdev_ioctl_eviocgbit(evdev, type_num, len, data));
+		return (evdev_ioctl_eviocgbit(evdev, type_num, len, data, td));
 	}
 
 	return (EINVAL);
 }
 
 static int
-evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data)
+evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data,
+    struct thread *td)
 {
 	unsigned long *bitmap;
 	int limit;
@@ -701,6 +716,7 @@ evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data)
 		 * just fake it returning only zeros.
 		 */
 		bzero(data, len);
+		td->td_retval[0] = len;
 		return (0);
 	default:
 		return (ENOTTY);
@@ -715,6 +731,7 @@ evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data)
 	limit = bitstr_size(limit);
 	len = MIN(limit, len);
 	memcpy(data, bitmap, len);
+	td->td_retval[0] = len;
 	return (0);
 }
 


More information about the dev-commits-src-all mailing list