diff options
author | Michael Adam <obnox@samba.org> | 2014-06-03 15:12:34 +0200 |
---|---|---|
committer | Michael Adam <obnox@samba.org> | 2014-06-05 23:57:10 +0200 |
commit | 8f28674b50e68e4f7815cd843088f54be3d074a4 (patch) | |
tree | a37e26fb03fa27b1cfba6ba0bc8d4622e138566b /lib/socket_wrapper | |
parent | 3700a4625cdf9b5fa6a665157ddb13b60ed61869 (diff) | |
download | samba-8f28674b50e68e4f7815cd843088f54be3d074a4.tar.gz |
swrap: extend input checks in swrap_bind()
Not only check family, but depending on family, also check the length.
Signed-off-by: Michael Adam <obnox@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Diffstat (limited to 'lib/socket_wrapper')
-rw-r--r-- | lib/socket_wrapper/socket_wrapper.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/lib/socket_wrapper/socket_wrapper.c b/lib/socket_wrapper/socket_wrapper.c index 523b32a780e..0303b210434 100644 --- a/lib/socket_wrapper/socket_wrapper.c +++ b/lib/socket_wrapper/socket_wrapper.c @@ -853,6 +853,7 @@ static const char *socket_wrapper_dir(void) if (s == NULL) { return NULL; } + /* TODO use realpath(3) here, when we add support for threads */ if (strncmp(s, "./", 2) == 0) { s += 2; } @@ -2724,13 +2725,59 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen) int ret; struct sockaddr_un un_addr; struct socket_info *si = find_socket_info(s); + int bind_error = 0; if (!si) { return libc_bind(s, myaddr, addrlen); } - if (si->family != myaddr->sa_family) { - errno = EAFNOSUPPORT; + switch (si->family) { + case AF_INET: { + const struct sockaddr_in *sin; + if (addrlen < sizeof(struct sockaddr_in)) { + bind_error = EINVAL; + break; + } + + sin = (struct sockaddr_in *)myaddr; + + if (sin->sin_family != AF_INET) { + bind_error = EAFNOSUPPORT; + } + + /* special case for AF_UNSPEC */ + if (sin->sin_family == AF_UNSPEC && + (sin->sin_addr.s_addr == htonl(INADDR_ANY))) + { + bind_error = 0; + } + + break; + } +#ifdef HAVE_IPV6 + case AF_INET6: { + const struct sockaddr_in6 *sin6; + if (addrlen < sizeof(struct sockaddr_in6)) { + bind_error = EINVAL; + break; + } + + sin6 = (struct sockaddr_in6 *)myaddr; + + if (sin6->sin6_family != AF_INET6) { + bind_error = EAFNOSUPPORT; + } + + break; + } +#endif + default: + bind_error = EINVAL; + break; + } + + if (bind_error != 0) { + errno = bind_error; return -1; } |