This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] Don't bind to registered ports in bindresvport
- From: Dan Nicholson <dbn dot lists at gmail dot com>
- To: libc-alpha at sourceware dot org
- Date: Thu, 31 May 2012 08:32:41 -0700
- Subject: [PATCH] Don't bind to registered ports in bindresvport
When bindresvport binds to a random port, there's a good chance it will
pick one already registered in services. That's bad since the point of
services is to define well known ports so random programs know which
ones to avoid. The current behavior causes lots of downstream bugs and
requires hacky solutions like running programs early in boot to bind to
desired ports and handing them off when the actual services start.
https://bugzilla.redhat.com/show_bug.cgi?id=103401
Let's just fix the problem at the source. On my fedora system, 295 of
the 541 ports between 512 and 1023 are unregistered. There's plenty of
space to pick a smarter port. If there are systems that require more
random ports than that, bindresvport is probably not the right API to
use.
2012-05-31 Dan Nicholson <dbn.lists@gmail.com>
* sunrpc/bindrsvprt.c (bindresvport): Before binding the port,
make sure it's not registered in services.
---
sunrpc/bindrsvprt.c | 19 ++++++++++++++++---
1 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/sunrpc/bindrsvprt.c b/sunrpc/bindrsvprt.c
index d493c9f..8594b33 100644
--- a/sunrpc/bindrsvprt.c
+++ b/sunrpc/bindrsvprt.c
@@ -35,6 +35,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <netdb.h>
/*
* Bind a socket to a privileged IP port
@@ -74,15 +75,27 @@ bindresvport (int sd, struct sockaddr_in *sin)
int nports = ENDPORT - startport + 1;
int endport = ENDPORT;
+ struct servent serv, *s;
+ char buf[1024];
again:
for (i = 0; i < nports; ++i)
{
sin->sin_port = htons (port++);
if (port > endport)
port = startport;
- res = __bind (sd, sin, sizeof (struct sockaddr_in));
- if (res >= 0 || errno != EADDRINUSE)
- break;
+ __getservbyport_r (sin->sin_port, NULL, &serv, buf, sizeof (buf), &s);
+ if (s != NULL)
+ {
+ /* This port is registered. Fake a return and try the next. */
+ res = -1;
+ __set_errno (EADDRINUSE);
+ }
+ else
+ {
+ res = __bind (sd, sin, sizeof (struct sockaddr_in));
+ if (res >= 0 || errno != EADDRINUSE)
+ break;
+ }
}
if (i == nports && startport != LOWPORT)
--
1.7.7.6