> On Jan 9, 2018, at 7:49 PM, Guillem Jover <gjover@xxxxxxxxxxx> wrote: > > When using the bindresvport() function a privileged port will be looked > for and bound to a socket. The problem is that any service using a static > privileged port registered in the /etc/services file, can get its port > taken over by libtirpc users, making the other service fail to start. > > Starting the other service before libtircp users is not an option as > this does not cover restart situations, for example during package > upgrades or HA switchovers and similar. > > In addition honoring the /etc/services registry is already done for > example by rpc.statd, so it seems obvious to make libtirpc follow this > same pattern too. Does the glibc version of bindresvport(3) skip ports? I ask because this hasn't been a noted problem before. Which service exactly is causing the difficulty? Usually applications that grab a privileged port are short-lived. statd is careful to avoid ports in /etc/services because it allocates one socket with a privileged port for contacting the kernel, and keeps it in place. > Signed-off-by: Guillem Jover <gjover@xxxxxxxxxxx> > --- > src/bindresvport.c | 28 +++++++++++++++++++++++++++- > 1 file changed, 27 insertions(+), 1 deletion(-) > > diff --git a/src/bindresvport.c b/src/bindresvport.c > index 2d8f2bc..98e5f40 100644 > --- a/src/bindresvport.c > +++ b/src/bindresvport.c > @@ -40,6 +40,7 @@ > #include <netinet/in.h> > > #include <errno.h> > +#include <netdb.h> > #include <string.h> > #include <unistd.h> > > @@ -73,12 +74,15 @@ bindresvport_sa(sd, sa) > int sd; > struct sockaddr *sa; > { > - int res, af; > + int res, af, so_proto; > + socklen_t so_proto_len; > struct sockaddr_storage myaddr; > struct sockaddr_in *sin; > #ifdef INET6 > struct sockaddr_in6 *sin6; > #endif > + struct servent *se; > + const char *se_proto; > u_int16_t *portp; > static u_int16_t port; > static short startport = STARTPORT; > @@ -125,6 +129,25 @@ bindresvport_sa(sd, sa) > } > sa->sa_family = af; > > + so_proto_len = sizeof(so_proto); > + if (getsockopt(sd, SOL_SOCKET, SO_PROTOCOL, &so_proto, &so_proto_len) == -1) { > + mutex_unlock(&port_lock); > + return -1; /* errno is correctly set */ > + } > + switch (so_proto) { > + case IPPROTO_UDP: > + case IPPROTO_UDPLITE: What is UDPLITE? Would it require a separate netid or other infrastructure? IMO it's not correct to add this transport protocol in this patch. If you resend, please remove this line. > + se_proto = "udp"; > + break; > + case IPPROTO_TCP: > + se_proto = "tcp"; > + break; > + default: > + errno = ENOPROTOOPT; > + mutex_unlock(&port_lock); > + return -1; > + } > + > if (port == 0) { > port = (getpid() % NPORTS) + STARTPORT; > } > @@ -135,6 +158,9 @@ bindresvport_sa(sd, sa) > *portp = htons(port++); > if (port > endport) > port = startport; > + se = getservbyport(*portp, se_proto); > + if (se != NULL) > + continue; > res = bind(sd, sa, salen); > if (res >= 0 || errno != EADDRINUSE) > break; > -- > 2.15.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Chuck Lever -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html