summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Adam <obnox@samba.org>2014-06-03 15:12:34 +0200
committerMichael Adam <obnox@samba.org>2014-06-05 23:57:10 +0200
commit8f28674b50e68e4f7815cd843088f54be3d074a4 (patch)
treea37e26fb03fa27b1cfba6ba0bc8d4622e138566b
parent3700a4625cdf9b5fa6a665157ddb13b60ed61869 (diff)
downloadsamba-8f28674b50e68e4f7815cd843088f54be3d074a4.tar.gz
samba-8f28674b50e68e4f7815cd843088f54be3d074a4.tar.xz
samba-8f28674b50e68e4f7815cd843088f54be3d074a4.zip
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>
-rw-r--r--lib/socket_wrapper/socket_wrapper.c51
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;
}