Bug 78295 - rresvport wraps socket number
Summary: rresvport wraps socket number
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: glibc
Version: 7.3
Hardware: All
OS: Linux
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact: Brian Brock
Depends On:
TreeView+ depends on / blocked
Reported: 2002-11-20 21:04 UTC by Ben Woodard
Modified: 2016-11-24 15:05 UTC (History)
4 users (show)

Fixed In Version: 2.3.2-27.9
Doc Type: Bug Fix
Doc Text:
Clone Of:
Last Closed: 2003-04-22 07:39:33 UTC

Attachments (Terms of Use)

Description Ben Woodard 2002-11-20 21:04:24 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021003

Description of problem:
When all the reserved ports below 512 are already in use and you pass a
suggested port number below 512 to rresvport then rresvport will assign you a
non-reserved port. 

Version-Release number of selected component (if applicable):

How reproducible:

Steps to Reproduce:
1.write a program that calls rresvport 513 times with a parameter less than 512

Actual Results:  a non reserved port

Expected Results:  -1 & errno set to EAGAIN

Additional info:

Comment 1 Ben Woodard 2002-11-20 21:10:24 UTC
The bug is easy to see in rresvport:

In glibc/inet/rcmd.c in the function rresvport_af:

   454          for (;;) {
   455                  *sport = htons((uint16_t) *alport);
   456                  if (bind(s, (struct sockaddr *)&ss, len) >= 0)
   457                          return s;
   458                  if (errno != EADDRINUSE) {
   459                          (void)__close(s);
   460                          return -1;
   461                  }
   462                  (*alport)--;
   463                  if (*alport == IPPORT_RESERVED/2)
   464                          break;
   465          }

In line 463 you can see that if you pass a port number < IPPORT_RESERVED/2 into
the function the loop doesn't terminate and *alport can become less than 0 in
which case a non reserved port is assigned.

An appropriate fix may be something like:

if (*alport == IPPORT_RESERVED/2 || *alport < 0 )

Comment 2 Jakub Jelinek 2003-02-19 17:59:37 UTC
E.g. http://www.mkssoftware.com/docs/man3/rcmd.3.asp documents that the caller
must pass an argument between 512 and 1023 inclusive.
Likewise http://conx.bu.edu/cgi-bin/perl/manscript?ruserok(3)
Don't know if it wouldn't be better to add if (*alport < IPPORT_RESERVED / 2 || *alport >= IPPORT_RESERVED) { errno = EINVAL; return -1; }
early in the function (and change (*alport)--; if (*alport == IPPORT_RESERVED/2)
to if ((*alport--) == IPPORT_RESERVED / 2) so that a) it is possible to call
rresvport with *alpost == 512 and it tries even port 512.

Comment 3 Roland McGrath 2003-02-19 18:57:39 UTC
Traditional BSD behavior (rresvport is a 4.2BSD invention) tries the given port
value and if that exact port is not available it ignores it and selects without
regard to the original value.  Hence some traditional callers might not even
initialize the value.  Such uses might already be broken, but I am leary
of adding a new errno return that wasn't possible before.

Comment 4 Jakub Jelinek 2003-02-19 19:01:41 UTC
Ok, then what about instead of errno = EINVAL; return -1; just *alport = 1023; ?
Binding ports in 0 .. 511 area is a bad idea, since legitimate services could
not be started later on due the port taken by rresvport.

Comment 5 Roland McGrath 2003-02-19 19:56:31 UTC
By the currently documented spec, returning EAGAIN is ok.
Wrapping up to 1023 seems fine to me.

Comment 6 Ulrich Drepper 2003-02-21 01:54:12 UTC
I've checked in a change which normalizes the input and wraps around after
looking at port 512.  int/rcmd.c revision 1.64.

Comment 7 Ulrich Drepper 2003-04-22 07:39:33 UTC
glibc 2.3.2-27.9 should behave as we intend it to.  If this is still not what
you want you might have to adjust your expectations.  Give it a try.

Note You need to log in before you can comment on or make changes to this bug.