diff --git a/include/ioctl.h b/include/ioctl.h index 255ae2297..cc8533608 100644 --- a/include/ioctl.h +++ b/include/ioctl.h @@ -19,6 +19,7 @@ typedef struct { unsigned long request; + unsigned long size; char data[]; } ioctl_in_t; diff --git a/posix/posix.c b/posix/posix.c index 4f9e7a4f3..3c0cbae54 100644 --- a/posix/posix.c +++ b/posix/posix.c @@ -1643,22 +1643,15 @@ int posix_fcntl(int fd, unsigned int cmd, u8 *ustack) #define IOCPARM_MASK 0x1fffUL #define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK) -#define IOC_OUT 0x40000000UL -#define IOC_IN 0x80000000UL -#define IOC_INOUT (IOC_IN | IOC_OUT) -#define _IOC(inout, group, num, len) ((unsigned long)((inout) | (((len) & IOCPARM_MASK) << 16) | (((unsigned int)(group)) << 8) | (num))) +#define IOC_VOID 0x20000000 +#define IOC_OUT 0x40000000 +#define IOC_IN 0x80000000 +#define IOC_INOUT (IOC_IN | IOC_OUT) -#define SIOCGIFCONF _IOC(IOC_INOUT, 'S', 0x12U, sizeof(struct ifconf)) -#define SIOCADDRT _IOC(IOC_IN, 'S', 0x44U, sizeof(struct rtentry)) -#define SIOCDELRT _IOC(IOC_IN, 'S', 0x45U, sizeof(struct rtentry)) - -static void ioctl_pack(msg_t *msg, unsigned long request, void *data, oid_t *oid) +static void ioctl_pack(msg_t *msg, unsigned long request, void *data, size_t size, oid_t *oid) { - size_t size = IOCPARM_LEN(request); ioctl_in_t *ioctl = (ioctl_in_t *)msg->i.raw; - struct ifconf *ifc; - struct rtentry *rt; hal_memcpy(&msg->oid, oid, sizeof(*oid)); msg->type = mtDevCtl; @@ -1668,6 +1661,7 @@ static void ioctl_pack(msg_t *msg, unsigned long request, void *data, oid_t *oid msg->o.size = 0; ioctl->request = request; + ioctl->size = size; if ((request & IOC_INOUT) != 0U) { if ((request & IOC_IN) != 0U) { @@ -1690,35 +1684,12 @@ static void ioctl_pack(msg_t *msg, unsigned long request, void *data, oid_t *oid size = min(size, sizeof(void *)); hal_memcpy(ioctl->data, &data, size); } - else { - /* No action required */ - } - - - /* ioctl special case: arg is structure with pointer - has to be custom-packed into message */ - if (request == SIOCGIFCONF) { - ifc = (struct ifconf *)data; - msg->o.data = ifc->ifc_buf; - msg->o.size = ifc->ifc_len; - } - else if ((request == SIOCADDRT) || (request == SIOCDELRT)) { - rt = (struct rtentry *)data; - if (rt->rt_dev != NULL) { - msg->o.data = rt->rt_dev; - msg->o.size = hal_strlen(rt->rt_dev) + 1U; - } - } - else { - /* No action required */ - } } -static int ioctl_processResponse(const msg_t *msg, unsigned long request, void *data) +int ioctl_processResponse(const msg_t *msg, unsigned long request, void *data, size_t size) { - size_t size = IOCPARM_LEN(request); int err; - struct ifconf *ifc; err = msg->o.err; @@ -1726,11 +1697,6 @@ static int ioctl_processResponse(const msg_t *msg, unsigned long request, void * hal_memcpy(data, msg->o.raw, size); } - if (request == SIOCGIFCONF) { /* restore overridden userspace pointer */ - ifc = (struct ifconf *)data; - ifc->ifc_buf = msg->o.data; - } - return err; } @@ -1743,12 +1709,34 @@ int posix_ioctl(int fildes, unsigned long request, u8 *ustack) int err; msg_t msg; void *data = NULL; + size_t size = IOCPARM_LEN(request); err = posix_getOpenFile(fildes, &f); if (err == 0) { - /* TODO: handle POSIX defined requests with `switch (request)` */ - if (((request & IOC_INOUT) != 0U) || (IOCPARM_LEN(request) > 0U)) { + /* TODO: handle POSIX defined requests */ + if (((request & IOC_INOUT) != 0) || (size > 0)) { GETFROMSTACK(ustack, void *, data, 2); + /* the actual size of the pointed-to structure: >= IOCPARM_LEN(request) */ + GETFROMSTACK(ustack, size_t, size, 3); + + if ((request & IOC_VOID) == 0) { + if (data == NULL) { + err = -EFAULT; + break; + } + + if (vm_mapBelongs(proc_current()->process, data, size) < 0) { + err = -EFAULT; + break; + } + } + } + + ioctl_pack(&msg, request, data, size, &f->oid); + + err = proc_send(f->oid.port, &msg); + if (err == EOK) { + err = ioctl_processResponse(&msg, request, data, size); } ioctl_pack(&msg, request, data, &f->oid); diff --git a/posix/posix_private.h b/posix/posix_private.h index 5ad9e1a6f..79b873e89 100644 --- a/posix/posix_private.h +++ b/posix/posix_private.h @@ -123,26 +123,6 @@ typedef struct _process_info_t { } process_info_t; -/* SIOCGIFCONF ioctl special case: arg is structure with pointer */ -struct ifconf { - unsigned int ifc_len; /* size of buffer */ - char *ifc_buf; /* buffer address */ -}; - -/* SIOADDRT and SIOCDELRT ioctls special case: arg is structure with pointer */ -struct rtentry { - struct sockaddr rt_dst; - struct sockaddr rt_gateway; - struct sockaddr rt_genmask; - short rt_flags; - short rt_metric; - char *rt_dev; - unsigned long rt_mss; - unsigned long rt_window; - unsigned short rt_irtt; -}; - - int posix_fileDeref(open_file_t *f); diff --git a/syscalls.c b/syscalls.c index 9516efc2d..4c818a452 100644 --- a/syscalls.c +++ b/syscalls.c @@ -1714,6 +1714,7 @@ int syscalls_sys_ioctl(u8 *ustack) GETFROMSTACK(ustack, int, fildes, 0); GETFROMSTACK(ustack, unsigned long, request, 1); + /* vm_mapBelongs on optional data pointer checked in posix_ioctl */ return posix_ioctl(fildes, request, ustack); }