[Bug 861989] New: libwrap0 gives invalid ipv4 checks -- disabling security required
https://bugzilla.novell.com/show_bug.cgi?id=861989 https://bugzilla.novell.com/show_bug.cgi?id=861989#c0 Summary: libwrap0 gives invalid ipv4 checks -- disabling security required Classification: openSUSE Product: openSUSE 13.1 Version: Final Platform: All OS/Version: openSUSE 13.1 Status: NEW Severity: Major Priority: P5 - None Component: Security AssignedTo: security-team@suse.de ReportedBy: suse@tlinx.org QAContact: qa-bugs@suse.de Found By: --- Blocker: --- User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.28) Gecko/20120306 Firefox/3.6.28 libwrap0 gives invalid results for ipv4 checks. This requires turning the host wrapper checks into warnings, which compromises security. Example: Since I upgraded to the new libwrap0 (I had patched this and noted this problem before, but the patch didn't make it into the new version): Jan 31 18:51:40 Ishtar sshd[51467]: warning: /etc/hosts.allow, line 63: host name mismatch: Ishtar.tlinx.org != (null) (::ffff:192.168.3.1) Jan 31 18:51:40 Ishtar sshd[51469]: warning: /etc/hosts.allow, line 63: host name mismatch: Ishtar.tlinx.org != (null) (::ffff:192.168.3.1) Jan 31 18:51:42 Ishtar xinetd[51471]: warning: /etc/hosts.allow, line 63: host name mismatch: Ishtar.tlinx.org != (null) (::ffff:192.168.3.1) Jan 31 18:51:42 Ishtar xinetd[51472]: warning: /etc/hosts.allow, line 63: host name mismatch: Ishtar.tlinx.org != (null) (::ffff:192.168.3.1) Jan 31 19:46:51 Ishtar sshd[57295]: warning: /etc/hosts.allow, line 63: host name mismatch: Athenae != (null) (::ffff:192.168.4.12) Feb 1 23:32:57 Ishtar sshd[20335]: warning: /etc/hosts.allow, line 63: host name mismatch: Athenae != (null) (::ffff:192.168.4.12) Feb 2 10:59:50 Ishtar sshd[31950]: warning: /etc/hosts.allow, line 63: host name mismatch: Athenae != (null) (::ffff:192.168.4.12) Feb 3 10:51:02 Ishtar sshd[6633]: warning: /etc/hosts.allow, line 63: host name mismatch: Athenae != (null) (::ffff:192.168.4.12) ---- I do not have ipv6 enabled and do not have ipv6 addresses being returned from my bind/named server. Athenae properly resolves:
dig +short Athenae 192.168.4.12 As does Ishtar.tlinx.org dig +short Ishtar.tlinx.org 173.164.175.65
What I am not sure of since libwrap shows Ishtar.tlinx.org as mapping to null is if it really meant Ishtar:
dig +short Ishtar 192.168.4.1
-- 192.168.3.1 is also valid from some machines -- so that mapping doesn't bother me so much -- but the thing is, with libwrap0 having to be set to warn-only due to the above bug, it won't fail on wrong resolutions. I.e. because of the bogus check output -- it has to be set to warn -- which may be allowing things to pass that shouldn't. Reproducible: Always Steps to Reproduce: 1. 2. 3. It might require a kernel with IPv6 disabled/not compiled in -- not sure. named should only return ipv4 records as they are the ones that are being mangled In my /etc/hosts.allow, I have: ALL: LOCAL, 192.168.4.0/255.255.255.0, 192.168.3.0/255.255.255.0 : ALLOW Actual Results: actual results are the bogus warning. Note -- from the tcpd manpage -- If the sources are compiled with -DPARANOID, tcpd will drop the connec- tion in case of a host name/address mismatch. Otherwise, the hostname can be matched with the PARANOID wildcard, after which suitable action can be taken. ---------- I.e. I seem to remember that with paranoid wildcard, it would drop instead of warn. Expected Results: no errors on valid hostsnames.. For some reason I can't get the attachment function to work... so will have to include it manually, but the "attachment" is a patch for the tcpd source from 13.1 (spec file had added: Patch30: socket-tcp.diff %patch30 at appropriate places (after #29)... diff file included in additional information. --- socket.c 2013-05-23 14:08:58.000000000 -0700 +++ socket.c 2013-05-23 16:28:40.415779720 -0700 @@ -22,6 +22,8 @@ /* System libraries. */ #include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> #include <sys/param.h> #include <sys/socket.h> #include <netinet/in.h> @@ -38,6 +40,21 @@ #include "tcpd.h" + +static int ipv6_cached = -1; + +int ipv6 () { + int errstat; + struct stat buf; + if (ipv6_cached==-1) { + errstat=stat("/proc/sys/net/ipv6", &buf); + if (errstat==0 /* && (buf->mode_t & S_IFDIR)*/) ipv6_cached=1; + else ipv6_cached=0; + } + return ipv6_cached; +} + + /* Forward declarations. */ static void sock_sink(); @@ -66,10 +83,10 @@ } else { sprintf(dot_name, "%s.", name); hp = gethostbyname(dot_name); - if (hp) - return hp; - else - return (gethostbyname(name)); + if (hp) + return hp; + else + return (gethostbyname(name)); } } @@ -79,15 +96,15 @@ /* sock_host - look up endpoint addresses and install conversion methods */ void sock_host(request) -struct request_info *request; -{ -#ifdef INET6 - static struct sockaddr_storage client; - static struct sockaddr_storage server; -#else +struct request_info *request; { + static struct sockaddr_storage client6; + static struct sockaddr_storage server6; static struct sockaddr_in client; static struct sockaddr_in server; -#endif + + void * clientx = ipv6() ? &client6 : &client; + void * serverx = ipv6() ? &server6 : &server; + int len; char buf[BUFSIZ]; int fd = request->fd; @@ -103,12 +120,12 @@ * broken library code. */ - len = sizeof(client); - if (getpeername(fd, (struct sockaddr *) & client, &len) < 0) { + len = ipv6() ? sizeof(client6) : sizeof(client); + if (getpeername(fd, (struct sockaddr *) clientx, &len) < 0) { request->sink = sock_sink; - len = sizeof(client); + len = ipv6() ? sizeof(client6) : sizeof(client); if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK, - (struct sockaddr *) & client, &len) < 0) { + (struct sockaddr *) clientx, &len) < 0) { tcpd_warn("can't get client address: %m"); return; /* give up */ } @@ -116,11 +133,8 @@ memset(buf, 0 sizeof(buf)); #endif } -#ifdef INET6 - request->client->sin = (struct sockaddr *)&client; -#else - request->client->sin = &client; -#endif + + request->client->sin = (struct sockaddr *)clientx; /* * Determine the server binding. This is used for client username @@ -128,16 +142,13 @@ * address or name. */ - len = sizeof(server); - if (getsockname(fd, (struct sockaddr *) & server, &len) < 0) { + len = ipv6() ? sizeof(server6) : sizeof(server); + if (getsockname(fd, (struct sockaddr *) serverx, &len) < 0) { tcpd_warn("getsockname: %m"); return; } -#ifdef INET6 - request->server->sin = (struct sockaddr *)&server; -#else - request->server->sin = &server; -#endif + + request->server->sin = (struct sockaddr *)serverx; } @@ -156,34 +167,35 @@ * field is empty or unknown, use the address field to get the sockaddr * and hostname. */ if (strlen(request->client->addr) && - HOSTNAME_KNOWN(request->client->addr) && - (!strlen(request->client->addr) || - !HOSTNAME_KNOWN(request->client->name))) - host = request->client->addr; + HOSTNAME_KNOWN(request->client->addr) && + (!strlen(request->client->addr) || + !HOSTNAME_KNOWN(request->client->name))) + host = request->client->addr; else - return; + return; memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; + + hints.ai_family = ipv6() ? AF_INET6 : AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; ret = getaddrinfo(host, NULL, &hints, &res); if (ret != 0) { - hints.ai_family = AF_INET; - ret = getaddrinfo(host, NULL, &hints, &res); + hints.ai_family = AF_INET; + ret = getaddrinfo(host, NULL, &hints, &res); } if (ret != 0) { - tcpd_warn("can't resolve hostname (%s): %s", host, gai_strerror(ret)); + tcpd_warn("can't resolve hostname (%s): %s", host, gai_strerror(ret)); } else { - sock_methods(request); + sock_methods(request); - memcpy(&client, res->ai_addr, res->ai_addrlen); - request->client->sin = (struct sockaddr *)&client; - freeaddrinfo(res); + memcpy(&client, res->ai_addr, res->ai_addrlen); + request->client->sin = (struct sockaddr *)&client; + freeaddrinfo(res); - request->client->name[0] = 0; + request->client->name[0] = 0; } } @@ -192,39 +204,37 @@ void sock_hostaddr(host) struct host_info *host; { -#ifdef INET6 - struct sockaddr *sin = host->sin; - char *ap; - int alen; + if (ipv6()) { + struct sockaddr *sin = host->sin; + char *ap; + int alen; - if (!sin) - return; - switch (sin->sa_family) { - case AF_INET: - ap = (char *)&((struct sockaddr_in *)sin)->sin_addr; - alen = sizeof(struct in_addr); - break; - case AF_INET6: - ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr; - alen = sizeof(struct in6_addr); - break; - default: + if (!sin) return; - } - host->addr[0] = '\0'; - inet_ntop(sin->sa_family, ap, host->addr, sizeof(host->addr)); -#else - struct sockaddr_in *sin = host->sin; + switch (sin->sa_family) { + case AF_INET: + ap = (char *)&((struct sockaddr_in *)sin)->sin_addr; + alen = sizeof(struct in_addr); + break; + case AF_INET6: + ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr; + alen = sizeof(struct in6_addr); + break; + default: + return; + } + host->addr[0] = '\0'; + inet_ntop(sin->sa_family, ap, host->addr, sizeof(host->addr)); + } else { + struct sockaddr_in *sin = host->sin; - if (sin != 0) - STRN_CPY(host->addr, inet_ntoa(sin->sin_addr), sizeof(host->addr)); -#endif + if (sin != 0) + STRN_CPY(host->addr, inet_ntoa(sin->sin_addr), sizeof(host->addr)); + } } -#ifdef INET6 /* sock_hostname - map endpoint address to host name */ -void -sock_hostname(struct host_info *host) +void sock_hostname6(struct host_info *host) { struct addrinfo hints, *res, *resbase; struct sockaddr *sa = host->sin; @@ -330,7 +340,7 @@ host->name, inet_ntop2 (sin6->sin6_family, &sin6->sin6_addr)); strncpy(host->name, paranoid, sizeof(host->name)); - freeaddrinfo (resbase); + freeaddrinfo (resbase); return; } @@ -344,8 +354,8 @@ freeaddrinfo (resbase); return; } -#else /* INET6 */ -void sock_hostname(host) + +void sock_hostname4(host) struct host_info *host; { struct sockaddr_in *sin = host->sin; @@ -428,7 +438,10 @@ strcpy(host->name, paranoid); /* name is bad, clobber it */ } } -#endif /* INET6 */ + +void sock_hostname(struct host_info *host) { + ipv6()? sock_hostname6(host) :sock_hostname4(host); +} /* sock_sink - absorb unreceived IP datagram */ @@ -436,17 +449,18 @@ int fd; { char buf[BUFSIZ]; -#ifdef INET6 - struct sockaddr_storage sin; -#else + + struct sockaddr_storage sin6; struct sockaddr_in sin; -#endif - int size = sizeof(sin); + + void * sinx = ipv6() ? &sin6 : &sin; + + int size = ipv6()? sizeof(sin6): sizeof(sin); /* * Eat up the not-yet received datagram. Some systems insist on a * non-zero source address argument in the recvfrom() call below. */ - (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & sin, &size); + (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) sinx, &size); } -- Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug.
https://bugzilla.novell.com/show_bug.cgi?id=861989 https://bugzilla.novell.com/show_bug.cgi?id=861989#c Marcus Meissner <meissner@suse.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |meissner@suse.com AssignedTo|security-team@suse.de |prusnak@opensuse.org -- Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug.
https://bugzilla.novell.com/show_bug.cgi?id=861989 https://bugzilla.novell.com/show_bug.cgi?id=861989#c1 --- Comment #1 from Pavol Rusnak <prusnak@opensuse.org> 2014-02-04 10:48:13 UTC --- patching file socket.c Hunk #3 FAILED at 83. Hunk #8 FAILED at 167. Hunk #10 FAILED at 339. Could you please rebase your patch? Thanks! -- Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug.
https://bugzilla.novell.com/show_bug.cgi?id=861989 https://bugzilla.novell.com/show_bug.cgi?id=861989#c2 L. A. Walsh <suse@tlinx.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Priority|P5 - None |P2 - High --- Comment #2 from L. A. Walsh <suse@tlinx.org> 2014-02-04 04:12:25 PST --- My patch applied cleaning against socket from 2011 when I first reported it. It also applied cleanly to the 13.1 source. What source are you using? FWIW, my patch applies AFTER all of the other patches have been applied in the rpm. I.e. there were 29 other patches in front of mine. I didn't want to disturb existing patches, so if you are trying to apply it by not modifying the spec to make my 'diff' patch #30 and applying it in that manner, there is a fair chance it won't apply cleanly. Otherwise, if you want it faster, you might apply my patch to the version from 13.1, the diff the resulting file from the new file (assuming they are applying the bulk of information patches 1-29... if it has been restructured and no other patches are applied (i.e. 1-29 are no longer applied in the suse rpm, their would be a fair chance the code was re-arranged enough not to patch. In which case where would I obtain the rpm source you want it to patch into? Your best chance of applying it would be to apply it last (on the premise that I didn't want to mess up any one else's patches applying. Perhaps you are trying to apply it in standalone w/o suse's preceding 29 patches? I did try to mention that the ".spec" file had to have my patch put in as patch #30 after the 1st 29 patches......sorry if that wasn't clear. -- Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug.
participants (1)
-
bugzilla_noreply@novell.com