All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] net/ip_sock: ioctl: fix unsafe accesses from/to userspace
@ 2019-06-06 12:42 Sebastian Smolorz
  2019-06-12 15:27 ` Jan Kiszka
  0 siblings, 1 reply; 2+ messages in thread
From: Sebastian Smolorz @ 2019-06-06 12:42 UTC (permalink / raw)
  To: jan.kiszka; +Cc: xenomai

Signed-off-by: Sebastian Smolorz <sebastian.smolorz@gmx.de>
---
 kernel/drivers/net/stack/ipv4/ip_sock.c | 127 ++++++++++++++++--------
 1 file changed, 88 insertions(+), 39 deletions(-)

diff --git a/kernel/drivers/net/stack/ipv4/ip_sock.c b/kernel/drivers/net/stack/ipv4/ip_sock.c
index 20f27feff..1ae3a9eeb 100644
--- a/kernel/drivers/net/stack/ipv4/ip_sock.c
+++ b/kernel/drivers/net/stack/ipv4/ip_sock.c
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2003       Hans-Peter Bock <hpbock@avaapgh.de>
  *                2004, 2005 Jan Kiszka <jan.kiszka@web.de>
+ *                2019       Sebastian Smolorz <sebastian.smolorz@gmx.de>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -28,11 +29,11 @@
 #include <rtnet_socket.h>


-int rt_ip_setsockopt(struct rtsocket *s, int level, int optname,
-		     const void *optval, socklen_t optlen)
+int rt_ip_setsockopt(struct rtdm_fd *fd, struct rtsocket *s, int level,
+		     int optname, const void __user *optval, socklen_t optlen)
 {
     int err = 0;
-
+    unsigned int _tos, *tos;

     if (level != SOL_IP)
 	return -ENOPROTOOPT;
@@ -42,7 +43,11 @@ int rt_ip_setsockopt(struct rtsocket *s, int level, int optname,

     switch (optname) {
 	case IP_TOS:
-	    s->prot.inet.tos = *(unsigned int *)optval;
+	    tos = rtnet_get_arg(fd, &_tos, optval, sizeof(_tos));
+	    if (IS_ERR(tos))
+		return PTR_ERR(tos);
+	    else
+		s->prot.inet.tos = *tos;
 	    break;

 	default:
@@ -55,19 +60,29 @@ int rt_ip_setsockopt(struct rtsocket *s, int level, int optname,



-int rt_ip_getsockopt(struct rtsocket *s, int level, int optname,
-		     void *optval, socklen_t *optlen)
+int rt_ip_getsockopt(struct rtdm_fd *fd, struct rtsocket *s, int level,
+		     int optname, void __user *optval,
+		     socklen_t __user *optlen)
 {
     int err = 0;
+    unsigned int tos;
+    socklen_t _len, *len;

+    len = rtnet_get_arg(fd, &_len, optlen, sizeof(_len));
+    if (IS_ERR(len))
+	return PTR_ERR(len);

-    if (*optlen < sizeof(unsigned int))
+    if (*len < sizeof(unsigned int))
 	return -EINVAL;

     switch (optname) {
 	case IP_TOS:
-	    *(unsigned int *)optval = s->prot.inet.tos;
-	    *optlen = sizeof(unsigned int);
+	    tos = s->prot.inet.tos;
+	    err = rtnet_put_arg(fd, optval, &tos, sizeof(tos));
+	    if (!err) {
+		*len = sizeof(unsigned int);
+		err = rtnet_put_arg(fd, optlen, len, sizeof(socklen_t));
+	    }
 	    break;

 	default:
@@ -80,72 +95,106 @@ int rt_ip_getsockopt(struct rtsocket *s, int level, int optname,



-int rt_ip_getsockname(struct rtsocket *s, struct sockaddr *addr,
-		      socklen_t *addrlen)
+int rt_ip_getsockname(struct rtdm_fd *fd, struct rtsocket *s,
+		      struct sockaddr __user *addr,
+		      socklen_t __user *addrlen)
 {
-    struct sockaddr_in *usin = (struct sockaddr_in *)addr;
+    struct sockaddr_in _sin;
+    socklen_t *len, _len;
+    int ret;

+    len = rtnet_get_arg(fd, &_len, addrlen, sizeof(_len));
+    if (IS_ERR(len))
+	return PTR_ERR(len);

-    if (*addrlen < sizeof(struct sockaddr_in))
+    if (*len < sizeof(struct sockaddr_in))
 	return -EINVAL;

-    usin->sin_family      = AF_INET;
-    usin->sin_addr.s_addr = s->prot.inet.saddr;
-    usin->sin_port        = s->prot.inet.sport;
-
-    memset(usin->sin_zero, 0, sizeof(usin->sin_zero));
+    _sin.sin_family      = AF_INET;
+    _sin.sin_addr.s_addr = s->prot.inet.saddr;
+    _sin.sin_port        = s->prot.inet.sport;
+    memset(&_sin.sin_zero, 0, sizeof(_sin.sin_zero));
+    ret = rtnet_put_arg(fd, addr, &_sin, sizeof(_sin));
+    if (ret)
+	return ret;

-    *addrlen = sizeof(struct sockaddr_in);
+    *len = sizeof(struct sockaddr_in);
+    ret = rtnet_put_arg(fd, addrlen, len, sizeof(socklen_t));

-    return 0;
+    return ret;
 }



-int rt_ip_getpeername(struct rtsocket *s, struct sockaddr *addr,
-		      socklen_t *addrlen)
+int rt_ip_getpeername(struct rtdm_fd *fd, struct rtsocket *s,
+		      struct sockaddr __user *addr,
+		      socklen_t __user *addrlen)
 {
-    struct sockaddr_in *usin = (struct sockaddr_in *)addr;
+    struct sockaddr_in _sin;
+    socklen_t *len, _len;
+    int ret;

+    len = rtnet_get_arg(fd, &_len, addrlen, sizeof(_len));
+    if (IS_ERR(len))
+	return PTR_ERR(len);

-    if (*addrlen < sizeof(struct sockaddr_in))
+    if (*len < sizeof(struct sockaddr_in))
 	return -EINVAL;

-    usin->sin_family      = AF_INET;
-    usin->sin_addr.s_addr = s->prot.inet.daddr;
-    usin->sin_port        = s->prot.inet.dport;
+    _sin.sin_family      = AF_INET;
+    _sin.sin_addr.s_addr = s->prot.inet.daddr;
+    _sin.sin_port        = s->prot.inet.dport;
+    memset(&_sin.sin_zero, 0, sizeof(_sin.sin_zero));
+    ret = rtnet_put_arg(fd, addr, &_sin, sizeof(_sin));
+    if (ret)
+	return ret;

-    memset(usin->sin_zero, 0, sizeof(usin->sin_zero));
+    *len = sizeof(struct sockaddr_in);
+    ret = rtnet_put_arg(fd, addrlen, len, sizeof(socklen_t));

-    *addrlen = sizeof(struct sockaddr_in);
-
-    return 0;
+    return ret;
 }



-int rt_ip_ioctl(struct rtdm_fd *fd, int request, void *arg)
+int rt_ip_ioctl(struct rtdm_fd *fd, int request, void __user *arg)
 {
     struct rtsocket *sock = rtdm_fd_to_private(fd);
-    struct _rtdm_getsockaddr_args   *getaddr = arg;
-    struct _rtdm_getsockopt_args    *getopt  = arg;
-    struct _rtdm_setsockopt_args    *setopt  = arg;
+    struct _rtdm_getsockaddr_args   _getaddr, *getaddr;
+    struct _rtdm_getsockopt_args    _getopt, *getopt;
+    struct _rtdm_setsockopt_args    _setopt, *setopt;


     switch (request) {
 	case _RTIOC_SETSOCKOPT:
-	    return rt_ip_setsockopt(sock, setopt->level, setopt->optname,
+	    setopt = rtnet_get_arg(fd, &_setopt, arg, sizeof(_setopt));
+	    if (IS_ERR(setopt))
+		return PTR_ERR(setopt);
+
+	    return rt_ip_setsockopt(fd, sock, setopt->level, setopt->optname,
 				    setopt->optval, setopt->optlen);

 	case _RTIOC_GETSOCKOPT:
-	    return rt_ip_getsockopt(sock, getopt->level, getopt->optname,
+	    getopt = rtnet_get_arg(fd, &_getopt, arg, sizeof(_getopt));
+	    if (IS_ERR(getopt))
+		return PTR_ERR(getopt);
+
+	    return rt_ip_getsockopt(fd, sock, getopt->level, getopt->optname,
 				    getopt->optval, getopt->optlen);

 	case _RTIOC_GETSOCKNAME:
-	    return rt_ip_getsockname(sock, getaddr->addr, getaddr->addrlen);
+	    getaddr = rtnet_get_arg(fd, &_getaddr, arg, sizeof(_getaddr));
+	    if (IS_ERR(getaddr))
+		return PTR_ERR(getaddr);
+
+	    return rt_ip_getsockname(fd, sock, getaddr->addr, getaddr->addrlen);

 	case _RTIOC_GETPEERNAME:
-	    return rt_ip_getpeername(sock, getaddr->addr, getaddr->addrlen);
+	    getaddr = rtnet_get_arg(fd, &_getaddr, arg, sizeof(_getaddr));
+	    if (IS_ERR(getaddr))
+		return PTR_ERR(getaddr);
+
+	    return rt_ip_getpeername(fd, sock, getaddr->addr, getaddr->addrlen);

 	default:
 	    return rt_socket_if_ioctl(fd, request, arg);
--
2.19.1



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] net/ip_sock: ioctl: fix unsafe accesses from/to userspace
  2019-06-06 12:42 [PATCH] net/ip_sock: ioctl: fix unsafe accesses from/to userspace Sebastian Smolorz
@ 2019-06-12 15:27 ` Jan Kiszka
  0 siblings, 0 replies; 2+ messages in thread
From: Jan Kiszka @ 2019-06-12 15:27 UTC (permalink / raw)
  To: Sebastian Smolorz; +Cc: xenomai

On 06.06.19 14:42, Sebastian Smolorz wrote:
> Signed-off-by: Sebastian Smolorz <sebastian.smolorz@gmx.de>
> ---
>   kernel/drivers/net/stack/ipv4/ip_sock.c | 127 ++++++++++++++++--------
>   1 file changed, 88 insertions(+), 39 deletions(-)
> 
> diff --git a/kernel/drivers/net/stack/ipv4/ip_sock.c b/kernel/drivers/net/stack/ipv4/ip_sock.c
> index 20f27feff..1ae3a9eeb 100644
> --- a/kernel/drivers/net/stack/ipv4/ip_sock.c
> +++ b/kernel/drivers/net/stack/ipv4/ip_sock.c
> @@ -4,6 +4,7 @@
>    *
>    *  Copyright (C) 2003       Hans-Peter Bock <hpbock@avaapgh.de>
>    *                2004, 2005 Jan Kiszka <jan.kiszka@web.de>
> + *                2019       Sebastian Smolorz <sebastian.smolorz@gmx.de>
>    *
>    *  This program is free software; you can redistribute it and/or modify
>    *  it under the terms of the GNU General Public License as published by
> @@ -28,11 +29,11 @@
>   #include <rtnet_socket.h>
> 
> 
> -int rt_ip_setsockopt(struct rtsocket *s, int level, int optname,
> -		     const void *optval, socklen_t optlen)
> +int rt_ip_setsockopt(struct rtdm_fd *fd, struct rtsocket *s, int level,
> +		     int optname, const void __user *optval, socklen_t optlen)
>   {
>       int err = 0;
> -
> +    unsigned int _tos, *tos;
> 
>       if (level != SOL_IP)
>   	return -ENOPROTOOPT;
> @@ -42,7 +43,11 @@ int rt_ip_setsockopt(struct rtsocket *s, int level, int optname,
> 
>       switch (optname) {
>   	case IP_TOS:
> -	    s->prot.inet.tos = *(unsigned int *)optval;
> +	    tos = rtnet_get_arg(fd, &_tos, optval, sizeof(_tos));
> +	    if (IS_ERR(tos))
> +		return PTR_ERR(tos);
> +	    else
> +		s->prot.inet.tos = *tos;
>   	    break;
> 
>   	default:
> @@ -55,19 +60,29 @@ int rt_ip_setsockopt(struct rtsocket *s, int level, int optname,
> 
> 
> 
> -int rt_ip_getsockopt(struct rtsocket *s, int level, int optname,
> -		     void *optval, socklen_t *optlen)
> +int rt_ip_getsockopt(struct rtdm_fd *fd, struct rtsocket *s, int level,
> +		     int optname, void __user *optval,
> +		     socklen_t __user *optlen)
>   {
>       int err = 0;
> +    unsigned int tos;
> +    socklen_t _len, *len;
> 
> +    len = rtnet_get_arg(fd, &_len, optlen, sizeof(_len));
> +    if (IS_ERR(len))
> +	return PTR_ERR(len);
> 
> -    if (*optlen < sizeof(unsigned int))
> +    if (*len < sizeof(unsigned int))
>   	return -EINVAL;
> 
>       switch (optname) {
>   	case IP_TOS:
> -	    *(unsigned int *)optval = s->prot.inet.tos;
> -	    *optlen = sizeof(unsigned int);
> +	    tos = s->prot.inet.tos;
> +	    err = rtnet_put_arg(fd, optval, &tos, sizeof(tos));
> +	    if (!err) {
> +		*len = sizeof(unsigned int);
> +		err = rtnet_put_arg(fd, optlen, len, sizeof(socklen_t));
> +	    }
>   	    break;
> 
>   	default:
> @@ -80,72 +95,106 @@ int rt_ip_getsockopt(struct rtsocket *s, int level, int optname,
> 
> 
> 
> -int rt_ip_getsockname(struct rtsocket *s, struct sockaddr *addr,
> -		      socklen_t *addrlen)
> +int rt_ip_getsockname(struct rtdm_fd *fd, struct rtsocket *s,
> +		      struct sockaddr __user *addr,
> +		      socklen_t __user *addrlen)
>   {
> -    struct sockaddr_in *usin = (struct sockaddr_in *)addr;
> +    struct sockaddr_in _sin;
> +    socklen_t *len, _len;
> +    int ret;
> 
> +    len = rtnet_get_arg(fd, &_len, addrlen, sizeof(_len));
> +    if (IS_ERR(len))
> +	return PTR_ERR(len);
> 
> -    if (*addrlen < sizeof(struct sockaddr_in))
> +    if (*len < sizeof(struct sockaddr_in))
>   	return -EINVAL;
> 
> -    usin->sin_family      = AF_INET;
> -    usin->sin_addr.s_addr = s->prot.inet.saddr;
> -    usin->sin_port        = s->prot.inet.sport;
> -
> -    memset(usin->sin_zero, 0, sizeof(usin->sin_zero));
> +    _sin.sin_family      = AF_INET;
> +    _sin.sin_addr.s_addr = s->prot.inet.saddr;
> +    _sin.sin_port        = s->prot.inet.sport;
> +    memset(&_sin.sin_zero, 0, sizeof(_sin.sin_zero));
> +    ret = rtnet_put_arg(fd, addr, &_sin, sizeof(_sin));
> +    if (ret)
> +	return ret;
> 
> -    *addrlen = sizeof(struct sockaddr_in);
> +    *len = sizeof(struct sockaddr_in);
> +    ret = rtnet_put_arg(fd, addrlen, len, sizeof(socklen_t));
> 
> -    return 0;
> +    return ret;
>   }
> 
> 
> 
> -int rt_ip_getpeername(struct rtsocket *s, struct sockaddr *addr,
> -		      socklen_t *addrlen)
> +int rt_ip_getpeername(struct rtdm_fd *fd, struct rtsocket *s,
> +		      struct sockaddr __user *addr,
> +		      socklen_t __user *addrlen)
>   {
> -    struct sockaddr_in *usin = (struct sockaddr_in *)addr;
> +    struct sockaddr_in _sin;
> +    socklen_t *len, _len;
> +    int ret;
> 
> +    len = rtnet_get_arg(fd, &_len, addrlen, sizeof(_len));
> +    if (IS_ERR(len))
> +	return PTR_ERR(len);
> 
> -    if (*addrlen < sizeof(struct sockaddr_in))
> +    if (*len < sizeof(struct sockaddr_in))
>   	return -EINVAL;
> 
> -    usin->sin_family      = AF_INET;
> -    usin->sin_addr.s_addr = s->prot.inet.daddr;
> -    usin->sin_port        = s->prot.inet.dport;
> +    _sin.sin_family      = AF_INET;
> +    _sin.sin_addr.s_addr = s->prot.inet.daddr;
> +    _sin.sin_port        = s->prot.inet.dport;
> +    memset(&_sin.sin_zero, 0, sizeof(_sin.sin_zero));
> +    ret = rtnet_put_arg(fd, addr, &_sin, sizeof(_sin));
> +    if (ret)
> +	return ret;
> 
> -    memset(usin->sin_zero, 0, sizeof(usin->sin_zero));
> +    *len = sizeof(struct sockaddr_in);
> +    ret = rtnet_put_arg(fd, addrlen, len, sizeof(socklen_t));
> 
> -    *addrlen = sizeof(struct sockaddr_in);
> -
> -    return 0;
> +    return ret;
>   }
> 
> 
> 
> -int rt_ip_ioctl(struct rtdm_fd *fd, int request, void *arg)
> +int rt_ip_ioctl(struct rtdm_fd *fd, int request, void __user *arg)
>   {
>       struct rtsocket *sock = rtdm_fd_to_private(fd);
> -    struct _rtdm_getsockaddr_args   *getaddr = arg;
> -    struct _rtdm_getsockopt_args    *getopt  = arg;
> -    struct _rtdm_setsockopt_args    *setopt  = arg;
> +    struct _rtdm_getsockaddr_args   _getaddr, *getaddr;
> +    struct _rtdm_getsockopt_args    _getopt, *getopt;
> +    struct _rtdm_setsockopt_args    _setopt, *setopt;
> 
> 
>       switch (request) {
>   	case _RTIOC_SETSOCKOPT:
> -	    return rt_ip_setsockopt(sock, setopt->level, setopt->optname,
> +	    setopt = rtnet_get_arg(fd, &_setopt, arg, sizeof(_setopt));
> +	    if (IS_ERR(setopt))
> +		return PTR_ERR(setopt);
> +
> +	    return rt_ip_setsockopt(fd, sock, setopt->level, setopt->optname,
>   				    setopt->optval, setopt->optlen);
> 
>   	case _RTIOC_GETSOCKOPT:
> -	    return rt_ip_getsockopt(sock, getopt->level, getopt->optname,
> +	    getopt = rtnet_get_arg(fd, &_getopt, arg, sizeof(_getopt));
> +	    if (IS_ERR(getopt))
> +		return PTR_ERR(getopt);
> +
> +	    return rt_ip_getsockopt(fd, sock, getopt->level, getopt->optname,
>   				    getopt->optval, getopt->optlen);
> 
>   	case _RTIOC_GETSOCKNAME:
> -	    return rt_ip_getsockname(sock, getaddr->addr, getaddr->addrlen);
> +	    getaddr = rtnet_get_arg(fd, &_getaddr, arg, sizeof(_getaddr));
> +	    if (IS_ERR(getaddr))
> +		return PTR_ERR(getaddr);
> +
> +	    return rt_ip_getsockname(fd, sock, getaddr->addr, getaddr->addrlen);
> 
>   	case _RTIOC_GETPEERNAME:
> -	    return rt_ip_getpeername(sock, getaddr->addr, getaddr->addrlen);
> +	    getaddr = rtnet_get_arg(fd, &_getaddr, arg, sizeof(_getaddr));
> +	    if (IS_ERR(getaddr))
> +		return PTR_ERR(getaddr);
> +
> +	    return rt_ip_getpeername(fd, sock, getaddr->addr, getaddr->addrlen);
> 
>   	default:
>   	    return rt_socket_if_ioctl(fd, request, arg);
> --
> 2.19.1
> 

Thanks, applied to next.

Jan

-- 
Siemens AG, Corporate Technology, CT RDA IOT SES-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-06-12 15:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-06 12:42 [PATCH] net/ip_sock: ioctl: fix unsafe accesses from/to userspace Sebastian Smolorz
2019-06-12 15:27 ` Jan Kiszka

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.