|
@@ -67,6 +67,18 @@
|
|
|
|
|
|
static int rebase_on_lo __attribute_migratable = -1;
|
|
|
|
|
|
+static int minimal_addrlen (int domain)
|
|
|
+{
|
|
|
+ switch(domain) {
|
|
|
+ case AF_INET:
|
|
|
+ return sizeof(struct sockaddr_in);
|
|
|
+ case AF_INET6:
|
|
|
+ return sizeof(struct sockaddr_in6);
|
|
|
+ default:
|
|
|
+ return sizeof(struct sockaddr);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int init_port_rebase (void)
|
|
|
{
|
|
|
if (rebase_on_lo != -1)
|
|
@@ -326,26 +338,25 @@ static inline void unix_copy_addr (struct sockaddr * saddr,
|
|
|
memcpy(un->sun_path, path, size + 1);
|
|
|
}
|
|
|
|
|
|
-static bool inet_check_addr (int domain, struct sockaddr * addr, int addrlen)
|
|
|
+static int inet_check_addr (int domain, struct sockaddr * addr, int addrlen)
|
|
|
{
|
|
|
if (domain == AF_INET) {
|
|
|
- if (addr->sa_family != AF_INET ||
|
|
|
- addrlen != sizeof(struct sockaddr_in))
|
|
|
- return false;
|
|
|
- return true;
|
|
|
+ if (addr->sa_family != AF_INET)
|
|
|
+ return -EAFNOSUPPORT;
|
|
|
+ if (addrlen != sizeof(struct sockaddr_in))
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
if (domain == AF_INET6) {
|
|
|
if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
|
|
|
- return false;
|
|
|
- if (addrlen != ((addr->sa_family == AF_INET) ?
|
|
|
- sizeof(struct sockaddr_in) :
|
|
|
- sizeof(struct sockaddr_in6)))
|
|
|
- return false;
|
|
|
- return true;
|
|
|
+ return -EAFNOSUPPORT;
|
|
|
+ if (addrlen != minimal_addrlen(addr->sa_family))
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
- return false;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
static int inet_copy_addr (int domain, struct sockaddr * saddr,
|
|
@@ -447,6 +458,9 @@ static int create_socket_uri (struct shim_handle * hdl)
|
|
|
|
|
|
int shim_do_bind (int sockfd, struct sockaddr * addr, socklen_t addrlen)
|
|
|
{
|
|
|
+ if (!addr || test_user_memory(addr, addrlen, false))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
struct shim_handle * hdl = get_fd_handle(sockfd, NULL, NULL);
|
|
|
int ret = -EINVAL;
|
|
|
if (!hdl)
|
|
@@ -496,7 +510,7 @@ int shim_do_bind (int sockfd, struct sockaddr * addr, socklen_t addrlen)
|
|
|
sock->addr.un.dentry = dent;
|
|
|
|
|
|
} else if (sock->domain == AF_INET || sock->domain == AF_INET6) {
|
|
|
- if (!inet_check_addr(sock->domain, addr, addrlen))
|
|
|
+ if ((ret = inet_check_addr(sock->domain, addr, addrlen)) < 0)
|
|
|
goto out;
|
|
|
inet_save_addr(sock->domain, &sock->addr.in.bind, addr);
|
|
|
inet_rebase_port(false, sock->domain, &sock->addr.in.bind, true);
|
|
@@ -698,6 +712,9 @@ out:
|
|
|
*/
|
|
|
int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
|
|
|
{
|
|
|
+ if (!addr || test_user_memory(addr, addrlen, false))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
struct shim_handle * hdl = get_fd_handle(sockfd, NULL, NULL);
|
|
|
|
|
|
if (!hdl)
|
|
@@ -727,6 +744,7 @@ int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
|
|
|
}
|
|
|
|
|
|
debug("shim_connect: reconnect on a stream socket\n");
|
|
|
+ ret = -EISCONN;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -772,7 +790,7 @@ int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
|
|
|
}
|
|
|
|
|
|
if (sock->domain != AF_UNIX) {
|
|
|
- if (!inet_check_addr(sock->domain, addr, addrlen))
|
|
|
+ if ((ret = inet_check_addr(sock->domain, addr, addrlen)) < 0)
|
|
|
goto out;
|
|
|
inet_save_addr(sock->domain, &sock->addr.in.conn, addr);
|
|
|
inet_rebase_port(false, sock->domain, &sock->addr.in.conn, false);
|
|
@@ -789,7 +807,7 @@ int shim_do_connect (int sockfd, struct sockaddr * addr, int addrlen)
|
|
|
hdl->flags & O_NONBLOCK);
|
|
|
|
|
|
if (!pal_hdl) {
|
|
|
- ret = -PAL_ERRNO;
|
|
|
+ ret = (PAL_NATIVE_ERRNO == PAL_ERROR_DENIED) ? -ECONNREFUSED : -PAL_ERRNO;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -862,6 +880,17 @@ int __do_accept (struct shim_handle * hdl, int flags, struct sockaddr * addr,
|
|
|
return -EOPNOTSUPP;
|
|
|
}
|
|
|
|
|
|
+ if (addr) {
|
|
|
+ if (!addrlen || test_user_memory(addrlen, sizeof(*addrlen), false))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (*addrlen < minimal_addrlen(sock->domain))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (test_user_memory(addr, *addrlen, true))
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
lock(hdl->lock);
|
|
|
|
|
|
if (sock->sock_state != SOCK_LISTENED) {
|
|
@@ -950,10 +979,10 @@ int __do_accept (struct shim_handle * hdl, int flags, struct sockaddr * addr,
|
|
|
if (addr) {
|
|
|
inet_copy_addr(sock->domain, addr, &sock->addr.in.conn);
|
|
|
|
|
|
- if (addrlen)
|
|
|
- *addrlen = (sock->domain == AF_INET) ?
|
|
|
- sizeof(struct sockaddr_in) :
|
|
|
- sizeof(struct sockaddr_in6);
|
|
|
+ if (addrlen) {
|
|
|
+ assert(sock->domain == AF_INET || sock->domain == AF_INET6);
|
|
|
+ *addrlen = minimal_addrlen(sock->domain);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1004,14 +1033,25 @@ static ssize_t do_sendmsg (int fd, struct iovec * bufs, int nbufs, int flags,
|
|
|
if (!hdl)
|
|
|
return -EBADF;
|
|
|
|
|
|
- int ret = -EINVAL;
|
|
|
+ int ret = -ENOTSOCK;
|
|
|
+ if (hdl->type != TYPE_SOCK)
|
|
|
+ goto out;
|
|
|
|
|
|
- if (hdl->type != TYPE_SOCK) {
|
|
|
- ret = -ENOTSOCK;
|
|
|
+ struct shim_sock_handle * sock = &hdl->info.sock;
|
|
|
+
|
|
|
+ ret = -EFAULT;
|
|
|
+ if (addr && test_user_memory((void *) addr, addrlen, false))
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (!bufs || test_user_memory(bufs, sizeof(*bufs) * nbufs, false))
|
|
|
goto out;
|
|
|
+
|
|
|
+ for (int i = 0 ; i < nbufs ; i++) {
|
|
|
+ if (!bufs[i].iov_base ||
|
|
|
+ test_user_memory(bufs[i].iov_base, bufs[i].iov_len, false))
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
- struct shim_sock_handle * sock = &hdl->info.sock;
|
|
|
lock(hdl->lock);
|
|
|
|
|
|
PAL_HANDLE pal_hdl = hdl->pal_handle;
|
|
@@ -1156,14 +1196,34 @@ static ssize_t do_recvmsg (int fd, struct iovec * bufs, int nbufs, int flags,
|
|
|
if (!hdl)
|
|
|
return -EBADF;
|
|
|
|
|
|
- int ret = 0;
|
|
|
+ int ret = -ENOTSOCK;
|
|
|
+ if (hdl->type != TYPE_SOCK)
|
|
|
+ goto out;
|
|
|
|
|
|
- if (hdl->type != TYPE_SOCK) {
|
|
|
- ret = -ENOTSOCK;
|
|
|
+ struct shim_sock_handle * sock = &hdl->info.sock;
|
|
|
+
|
|
|
+ if (addr) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ if (!addrlen || test_user_memory(addrlen, sizeof(*addrlen), false))
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (*addrlen < minimal_addrlen(sock->domain))
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (test_user_memory(addr, *addrlen, true))
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = -EFAULT;
|
|
|
+ if (!bufs || test_user_memory(bufs, sizeof(*bufs) * nbufs, false))
|
|
|
goto out;
|
|
|
+
|
|
|
+ for (int i = 0 ; i < nbufs ; i++) {
|
|
|
+ if (!bufs[i].iov_base ||
|
|
|
+ test_user_memory(bufs[i].iov_base, bufs[i].iov_len, true))
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
- struct shim_sock_handle * sock = &hdl->info.sock;
|
|
|
lock(hdl->lock);
|
|
|
|
|
|
PAL_HANDLE pal_hdl = hdl->pal_handle;
|
|
@@ -1361,6 +1421,9 @@ int shim_do_getsockname (int sockfd, struct sockaddr * addr, int * addrlen)
|
|
|
if (*addrlen <= 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ if (test_user_memory(addr, *addrlen, true))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
struct shim_handle * hdl = get_fd_handle(sockfd, NULL, NULL);
|
|
|
if (!hdl)
|
|
|
return -EBADF;
|
|
@@ -1398,6 +1461,9 @@ int shim_do_getpeername (int sockfd, struct sockaddr * addr, int * addrlen)
|
|
|
if (*addrlen <= 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ if (test_user_memory(addr, *addrlen, true))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
struct shim_handle * hdl = get_fd_handle(sockfd, NULL, NULL);
|
|
|
if (!hdl)
|
|
|
return -EBADF;
|