Date: Wed, 20 Jan 2021 20:10:46 GMT From: Vladimir Kondratyev <wulf@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 7a810290b8f6 - main - evdev: Make variable-size ioctls return actual length of copyouted data Message-ID: <202101202010.10KKAklL045103@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by wulf: URL: https://cgit.FreeBSD.org/src/commit/?id=7a810290b8f6c6885fdb9917cf590d46fa270a61 commit 7a810290b8f6c6885fdb9917cf590d46fa270a61 Author: Vladimir Kondratyev <wulf@FreeBSD.org> AuthorDate: 2021-01-20 20:10:07 +0000 Commit: Vladimir Kondratyev <wulf@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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101202010.10KKAklL045103>