From 463503e46623ffe2aa1cf3b3a3ce070e9e539400d6c62a8d4222f79eca2e6bd8 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Tue, 22 Feb 2011 05:08:58 +0000 Subject: [PATCH] - Use correct source address on replies [bnc#587934,bnc#587811] - Prevent bindresvport from binding to blacklisted ports [bnc#579315] OBS-URL: https://build.opensuse.org/package/show/Base:System/libtirpc?expand=0&rev=14 --- libtirpc-bindresvport_blacklist.patch | 137 ++++++++++++ ...c-use-correct-source-addr-on-replies.patch | 195 ++++++++++++++++++ libtirpc.changes | 6 + libtirpc.spec | 6 +- 4 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 libtirpc-bindresvport_blacklist.patch create mode 100644 libtirpc-use-correct-source-addr-on-replies.patch diff --git a/libtirpc-bindresvport_blacklist.patch b/libtirpc-bindresvport_blacklist.patch new file mode 100644 index 0000000..15b29a3 --- /dev/null +++ b/libtirpc-bindresvport_blacklist.patch @@ -0,0 +1,137 @@ +From: Olaf Kirch +Subject: make libtirpc honor /etc/bindresvport.blacklist + +Signed-off-by: Olaf Kirch + +Index: libtirpc-0.1.9/src/bindresvport.c +=================================================================== +--- libtirpc-0.1.9.orig/src/bindresvport.c ++++ libtirpc-0.1.9/src/bindresvport.c +@@ -40,7 +40,10 @@ + + #include + ++#include ++#include + #include ++#include + #include + #include + +@@ -66,6 +69,80 @@ bindresvport(sd, sin) + #define ENDPORT (IPPORT_RESERVED - 1) + #define NPORTS (ENDPORT - STARTPORT + 1) + ++/* ++ * Read the file /etc/bindresvport.blacklist, so that we don't bind ++ * to these ports. ++ */ ++ ++static int blacklist_read; ++static int *list; ++static int list_size = 0; ++ ++static void ++load_blacklist (void) ++{ ++ FILE *fp; ++ char *buf = NULL; ++ size_t buflen = 0; ++ int size = 0, ptr = 0; ++ ++ blacklist_read = 1; ++ ++ fp = fopen ("/etc/bindresvport.blacklist", "r"); ++ if (NULL == fp) ++ return; ++ ++ while (!feof (fp)) ++ { ++ unsigned long port; ++ char *tmp, *cp; ++ ssize_t n = getline (&buf, &buflen, fp); ++ if (n < 1) ++ break; ++ ++ cp = buf; ++ tmp = strchr (cp, '#'); /* remove comments */ ++ if (tmp) ++ *tmp = '\0'; ++ while (isspace ((int)*cp)) /* remove spaces and tabs */ ++ ++cp; ++ if (*cp == '\0') /* ignore empty lines */ ++ continue; ++ if (cp[strlen (cp) - 1] == '\n') ++ cp[strlen (cp) - 1] = '\0'; ++ ++ port = strtoul (cp, &tmp, 0); ++ while (isspace(*tmp)) ++ ++tmp; ++ if (*tmp != '\0' || (port == ULONG_MAX && errno == ERANGE)) ++ continue; ++ ++ /* Don't bother with out-of-range ports */ ++ if (port < LOWPORT || port > ENDPORT) ++ continue; ++ ++ if (ptr >= size) ++ { ++ size += 10; ++ list = realloc (list, size * sizeof (int)); ++ if (list == NULL) ++ { ++ free (buf); ++ return; ++ } ++ } ++ ++ list[ptr++] = port; ++ } ++ ++ fclose (fp); ++ ++ if (buf) ++ free (buf); ++ ++ list_size = ptr; ++} ++ + int + bindresvport_sa(sd, sa) + int sd; +@@ -85,6 +162,9 @@ bindresvport_sa(sd, sa) + int endport = ENDPORT; + int i; + ++ if (!blacklist_read) ++ load_blacklist(); ++ + if (sa == NULL) { + salen = sizeof(myaddr); + sa = (struct sockaddr *)&myaddr; +@@ -125,12 +205,21 @@ bindresvport_sa(sd, sa) + errno = EADDRINUSE; + again: + for (i = 0; i < nports; ++i) { +- *portp = htons(port++); +- if (port > endport) +- port = startport; +- res = bind(sd, sa, salen); ++ int j; ++ ++ /* Check if this port is not blacklisted. */ ++ for (j = 0; j < list_size; j++) ++ if (port == list[j]) ++ goto try_next_port; ++ ++ *portp = htons(port); ++ res = bind(sd, sa, salen); + if (res >= 0 || errno != EADDRINUSE) + break; ++ ++try_next_port: ++ if (++port > endport) ++ port = startport; + } + if (i == nports && startport != LOWPORT) { + startport = LOWPORT; diff --git a/libtirpc-use-correct-source-addr-on-replies.patch b/libtirpc-use-correct-source-addr-on-replies.patch new file mode 100644 index 0000000..c4659dd --- /dev/null +++ b/libtirpc-use-correct-source-addr-on-replies.patch @@ -0,0 +1,195 @@ + +Patch by Olaf Kirch and Leonardo Chiquitto as attached with id 348693 +at https://bugzilla.novell.com/show_bug.cgi?id=587934 + +diff --git a/src/svc_dg.c b/src/svc_dg.c +index 7df470e..edf7d17 100644 +--- a/src/svc_dg.c ++++ b/src/svc_dg.c +@@ -76,6 +76,8 @@ static bool_t svc_dg_control(SVCXPRT *, const u_int, void *); + static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *); + static void cache_set(SVCXPRT *, size_t); + int svc_dg_enablecache(SVCXPRT *, u_int); ++static void svc_dg_enable_pktinfo(int, const struct __rpc_sockinfo *); ++static int svc_dg_valid_pktinfo(struct msghdr *); + + /* + * Usage: +@@ -142,6 +144,9 @@ svc_dg_create(fd, sendsize, recvsize) + goto freedata; + __rpc_set_netbuf(&xprt->xp_ltaddr, &ss, slen); + ++ /* Enable reception of IP*_PKTINFO control msgs */ ++ svc_dg_enable_pktinfo(fd, &si); ++ + xprt_register(xprt); + return (xprt); + freedata: +@@ -171,19 +176,37 @@ svc_dg_recv(xprt, msg) + XDR *xdrs = &(su->su_xdrs); + char *reply; + struct sockaddr_storage ss; ++ struct msghdr *mesgp; ++ struct iovec iov; + socklen_t alen; + size_t replylen; + ssize_t rlen; + + again: +- alen = sizeof (struct sockaddr_storage); +- rlen = recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, 0, +- (struct sockaddr *)(void *)&ss, &alen); ++ iov.iov_base = rpc_buffer(xprt); ++ iov.iov_len = su->su_iosz; ++ mesgp = &su->su_msghdr; ++ memset(mesgp, 0, sizeof(*mesgp)); ++ mesgp->msg_iov = &iov; ++ mesgp->msg_iovlen = 1; ++ mesgp->msg_name = (struct sockaddr *)(void *) &ss; ++ mesgp->msg_namelen = sizeof (struct sockaddr_storage); ++ mesgp->msg_control = su->su_cmsg; ++ mesgp->msg_controllen = sizeof(su->su_cmsg); ++ ++ rlen = recvmsg(xprt->xp_fd, mesgp, 0); + if (rlen == -1 && errno == EINTR) + goto again; + if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t)))) + return (FALSE); +- __rpc_set_netbuf(&xprt->xp_rtaddr, &ss, alen); ++ __rpc_set_netbuf(&xprt->xp_rtaddr, &ss, mesgp->msg_namelen); ++ ++ /* Check whether there's an IP_PKTINFO or IP6_PKTINFO control message. ++ * If yes, preserve it for svc_dg_reply; otherwise just zap an cmsgs */ ++ if (!svc_dg_valid_pktinfo(mesgp)) { ++ mesgp->msg_control = NULL; ++ mesgp->msg_controllen = 0; ++ } + + __xprt_set_raddr(xprt, &ss); + xdrs->x_op = XDR_DECODE; +@@ -194,8 +217,9 @@ again: + su->su_xid = msg->rm_xid; + if (su->su_cache != NULL) { + if (cache_get(xprt, msg, &reply, &replylen)) { +- (void)sendto(xprt->xp_fd, reply, replylen, 0, +- (struct sockaddr *)(void *)&ss, alen); ++ iov.iov_base = reply; ++ iov.iov_len = replylen; ++ (void) sendmsg(xprt->xp_fd, mesgp, 0); + return (FALSE); + } + } +@@ -216,10 +240,18 @@ svc_dg_reply(xprt, msg) + XDR_SETPOS(xdrs, 0); + msg->rm_xid = su->su_xid; + if (xdr_replymsg(xdrs, msg)) { +- slen = XDR_GETPOS(xdrs); +- if (sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0, +- (struct sockaddr *)xprt->xp_rtaddr.buf, +- (socklen_t)xprt->xp_rtaddr.len) == (ssize_t) slen) { ++ struct msghdr *msg = &su->su_msghdr; ++ struct iovec iov; ++ ++ iov.iov_base = rpc_buffer(xprt); ++ iov.iov_len = slen = XDR_GETPOS(xdrs); ++ msg->msg_iov = &iov; ++ msg->msg_iovlen = 1; ++ msg->msg_name = (struct sockaddr *)(void *) xprt->xp_rtaddr.buf; ++ msg->msg_namelen = xprt->xp_rtaddr.len; ++ /* cmsg already set in svc_dg_recv */ ++ ++ if (sendmsg(xprt->xp_fd, msg, 0) == (ssize_t) slen) { + stat = TRUE; + if (su->su_cache) + cache_set(xprt, slen); +@@ -583,3 +615,76 @@ cache_get(xprt, msg, replyp, replylenp) + mutex_unlock(&dupreq_lock); + return (0); + } ++ ++/* ++ * Enable reception of PKTINFO control messages ++ */ ++void ++svc_dg_enable_pktinfo(int fd, const struct __rpc_sockinfo *si) ++{ ++ int val = 1; ++ ++ switch (si->si_af) { ++ case AF_INET: ++ (void) setsockopt(fd, SOL_IP, IP_PKTINFO, &val, sizeof(val)); ++ break; ++ ++ case AF_INET6: ++ (void) setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &val, sizeof(val)); ++ break; ++ } ++} ++ ++/* ++ * When given a control message received from the socket ++ * layer, check whether it contains valid PKTINFO data matching ++ * the address family of the peer address. ++ */ ++int ++svc_dg_valid_pktinfo(struct msghdr *msg) ++{ ++ struct cmsghdr *cmsg; ++ ++ if (!msg->msg_name) ++ return 0; ++ ++ if (msg->msg_flags & MSG_CTRUNC) ++ return 0; ++ ++ cmsg = CMSG_FIRSTHDR(msg); ++ if (cmsg == NULL || CMSG_NXTHDR(msg, cmsg) != NULL) ++ return 0; ++ ++ switch (((struct sockaddr *) msg->msg_name)->sa_family) { ++ case AF_INET: ++ if (cmsg->cmsg_level != SOL_IP ++ || cmsg->cmsg_type != IP_PKTINFO ++ || cmsg->cmsg_len < CMSG_LEN(sizeof (struct in_pktinfo))) { ++ return 0; ++ } else { ++ struct in_pktinfo *pkti; ++ ++ pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); ++ pkti->ipi_ifindex = 0; ++ } ++ break; ++ ++ case AF_INET6: ++ if (cmsg->cmsg_level != SOL_IPV6 ++ || cmsg->cmsg_type != IPV6_PKTINFO ++ || cmsg->cmsg_len < CMSG_LEN(sizeof (struct in6_pktinfo))) { ++ return 0; ++ } else { ++ struct in6_pktinfo *pkti; ++ ++ pkti = (struct in6_pktinfo *) CMSG_DATA (cmsg); ++ pkti->ipi6_ifindex = 0; ++ } ++ break; ++ ++ default: ++ return 0; ++ } ++ ++ return 1; ++} +diff --git a/tirpc/rpc/svc_dg.h b/tirpc/rpc/svc_dg.h +index 67d2564..88e7df7 100644 +--- a/tirpc/rpc/svc_dg.h ++++ b/tirpc/rpc/svc_dg.h +@@ -46,6 +46,9 @@ struct svc_dg_data { + XDR su_xdrs; /* XDR handle */ + char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ + void *su_cache; /* cached data, NULL if none */ ++ ++ struct msghdr su_msghdr; /* msghdr received from clnt */ ++ unsigned char su_cmsg[64]; /* cmsghdr received from clnt */ + }; + + #define __rpcb_get_dg_xidp(x) (&((struct svc_dg_data *)(x)->xp_p2)->su_xid) diff --git a/libtirpc.changes b/libtirpc.changes index 5d2378d..b368f0a 100644 --- a/libtirpc.changes +++ b/libtirpc.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Feb 22 05:07:13 UTC 2011 - nfbrown@novell.com + +- Use correct source address on replies [bnc#587934,bnc#587811] +- Prevent bindresvport from binding to blacklisted ports [bnc#579315] + ------------------------------------------------------------------- Sun Oct 31 12:37:02 UTC 2010 - jengelh@medozas.de diff --git a/libtirpc.spec b/libtirpc.spec index 54bff2c..6e55a6d 100644 --- a/libtirpc.spec +++ b/libtirpc.spec @@ -24,7 +24,7 @@ License: Other uncritical OpenSource License ; Sun Industry Standards Sou Group: System/Libraries AutoReqProv: on Version: 0.2.1_git201005272057 -Release: 3 +Release: 4 Summary: Transport Independent RPC Library Url: http://sourceforge.net/projects/libtirpc/ Source: %{name}-%{version}.tar.bz2 @@ -32,6 +32,8 @@ Patch21: libtirpc-clnt_broadcast_fix.patch Patch22: libtirpc-rpc_broadcast_misformed_replies.patch Patch31: libtirpc-getpmaphandle.patch Patch32: libtirpc-pmap-setunset.patch +Patch33: libtirpc-use-correct-source-addr-on-replies.patch +Patch34: libtirpc-bindresvport_blacklist.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build %define debug_package_requires libtirpc1 = %{version}-%{release} @@ -91,6 +93,8 @@ Authors: %patch22 -p1 %patch31 -p1 %patch32 -p1 +%patch33 -p1 +%patch34 -p1 %build mkdir m4 #bug