Bug 73422 - portmap forks ad infinitum when the NIS domain name is set, probably a bug in the RPC library
Summary: portmap forks ad infinitum when the NIS domain name is set, probably a bug in...
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 4.10-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-11-02 16:00 UTC by Trond Endrestøl
Modified: 2017-12-31 22:36 UTC (History)
0 users

See Also:


Attachments
file.diff (1015 bytes, patch)
2004-11-02 16:00 UTC, Trond Endrestøl
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Trond Endrestøl 2004-11-02 16:00:49 UTC
I'm in the process of setting up NIS in my home and I've found a
problem that I believe resides in the RPC library.  I'm running
4.10-RELEASE and I've followed the instructions in the Handbook.
I've used FreeBSD since 1998, but I have only recently turned my
interest to NIS.

(Speaking of the Handbook, has anyone tried these instructions lately
and verified that you'll actually achieve the goal? Is NIS tested when
a new -RELEASE is rolled out?)

When portmap receives a request, any request, portmap uses the RPC
library to maintain the port mappings.  When the RPC library discovers
the NIS domain name is set, it tries to get the port of the NIS client
(i.e. ypbind).  As a result, if ypbind is not registered, ypbind might
even be in the process of registering with portmap right now, another
portmap process is created to service the request.  The new portmap
process is still using the very same RPC library, which in turn
discovers again the name of the NIS domain and tries to get hold of
the port belonging to the NIS client, and next, the snowball is
rolling and rolling, and soon the system has hundreds, if not
thousands, of portmap processes getting nowhere.

I've changed ypbind slightly so that it does not check the NIS domain
name before checking the command line, see the patch below.
Note: This is a very poor workaround! The real problem is still in the
RPC library.

My computers are all set up to be NIS servers, master or slaves, and
are therefore commanded to bind to themselves.  When the NIS servers
and clients (i.e. ypserv and ypbind) are finally up and running, I can
set the NIS domain name using domainname, and everything is OK unless
ypbind dies.

Should ypbind die, I need to unset the NIS domain name in order not to
trigger this nasty problem in the RPC library, restart ypbind, and set
the NIS domain name again.

Can someone fix the RPC library?  I guess the RPC library shouldn't
create and post requests on its own when processing other requests.

If no one corrects the RPC library, then part of the Handbook should
be rewritten, at least make a note that the RPC system, and thus NIS,
is broken.  RPC and NFS is still working though.

Fix: Patch for ypbind.c follows:
How-To-Repeat: 
Run portmap with a NIS domain name set, and try engaging portmap
by the use of rpcinfo, mountd, nfsd, whatever.
Comment 1 Trond Endrestøl 2004-11-12 13:42:45 UTC
This is a followup to the original PR.  I have done some further
investigations and believe to have isolated the problem.

>Submitter-Id:	current-users
>Originator:	Trond Endrestøl
>Organization:	Private
>Confidential:	no
>Synopsis:	portmap forks ad infinitum if verbose logging is turned on and NIS domainname is set
>Severity:	serious
>Priority:	high
>Category:	bin
>Class:		sw-bug
>Release:	FreeBSD 4.10-RELEASE i386
>Environment:
System: FreeBSD sovereign.bsd.net 4.10-RELEASE FreeBSD 4.10-RELEASE #0: Fri Oct 22 22:31:31 CEST 2004 root@sovereign.bsd.net:/usr/src/sys/compile/SOVEREIGN i386


	Pentium 133 MHz running FreeBSD 4.10-RELEASE
>Description:
	1. If portmap is running with verbose logging (-v) and the NIS
	   domain name is set, it will try to resolve RPC program numbers
	   into names using getrpcbynumber() in logit() in pmap_check.c

	2. This results in a new request to portmap about the port number
	   for ypbind.  ypbind may not have registered yet with portmap,
	   and due to the verbose logging, portmap attempts another call
	   to getrpcbynumber(). As portmap does the logging by forking
	   a child to do the work, this leads to hundreds, if not
	   thousands, of portmap processes getting nowhere.

	3. End result is a utmost slow system, with a non-functioning
	   portmapper, and a system in desperate need of operator attention.
>How-To-Repeat:
	Run portmap with verbose logging turned on (-v) and
	with the NIS domain name set to a valid value
	(e.g. nisdomainname="blah.blah.blah").
>Fix:

	Simplest solution:

	Advice users to run portmap without verbose logging if running NIS.
	I.e., make a point of this in the FreeBSD Handbook if nothing
	further is done to correct the issue.


	A better solution:

	Change ypbind to check the NIS domain name after processing
	the command line.  The domain name may have been set by using
	-S domain,nisserver1,nisserver2,...
	See patch below for ypbind.c.

	Change portmap not to resolve RPC program numbers into names
	when doing verbose logging.  See patch below for pmap_check.c.
	If possible to resolve RPC program numbers using something
	other than NIS even if the NIS domain name is set, use that
	approach.

	Change /etc/rc.network to unset the NIS domain name early in
	network_pass1().  This helps if the user recently went from
	multiuser mode to single user mode, and wants to go back
	to multiuser mode.  Otherwise, programs such as named tries to
	contact portmap and may suspend the booting process for
	a minute or so.  Let /etc/rc.network set the NIS domain name
	just prior to launching ypserv and other NIS related servers.
	See patch below for /etc/rc.network.

	If nothing is done with pmap_check.c as described above,
	still let /etc/rc.network unset the NIS domain name at
	the beginning of execution, and set the NIS domain name after
	ypbind is launched.  Programs such as rpc.yppasswdd and ypbind
	need to be told the NIS domain name using command line
	options.

	Patches follows:

*** ypbind.c.orig	Fri Feb 15 01:46:59 2002
--- ypbind.c	Tue Nov  2 15:54:05 2004
***************
*** 403,413 ****
  	if (flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
  		errx(1, "another ypbind is already running. Aborting");

- 	/* XXX domainname will be overriden if we use restricted mode */
- 	yp_get_default_domain(&domain_name);
- 	if (domain_name[0] == '\0')
- 		errx(1, "domainname not set. Aborting");
-
  	for (i = 1; i<argc; i++) {
  		if (strcmp("-ypset", argv[i]) == 0)
  			ypsetmode = YPSET_ALL;
--- 403,408 ----
***************
*** 419,424 ****
--- 414,426 ----
  			yp_restricted_mode(argv[i+1]);
  		else if (strcmp("-m", argv[i]) == 0)
  			yp_manycast++;
+ 	}
+
+ 	if (domain_name == NULL || domain_name[0] == '\0') {
+ 		/* XXX domainname will be overriden if we use restricted mode */
+ 		yp_get_default_domain(&domain_name);
+ 		if (domain_name[0] == '\0')
+ 			errx(1, "domainname not set. Aborting");
  	}

  	/* blow away everything in BINDINGDIR (if it exists) */

*** pmap_check.c.orig	Sun Jan 16 00:08:28 2000
--- pmap_check.c	Fri Nov 12 12:32:35 2004
***************
*** 238,246 ****

  	if (prognum == 0) {
  	    progname = "";
! 	} else if ((rpc = getrpcbynumber((int) prognum))) {
  	    progname = rpc->r_name;
! 	} else {
  	    sprintf(progbuf, "%lu", prognum);
  	    progname = progbuf;
  	}
--- 238,246 ----

  	if (prognum == 0) {
  	    progname = "";
! 	} /* else if ((rpc = getrpcbynumber((int) prognum))) {
  	    progname = rpc->r_name;
! 	} */ else {
  	    sprintf(progbuf, "%lu", prognum);
  	    progname = progbuf;
  	}

*** rc.network.orig	Tue May 25 23:28:42 2004
--- rc.network	Fri Nov 12 13:38:42 2004
***************
*** 133,148 ****
  		;;
  	esac

! 	# Set the domainname if we're using NIS
  	#
! 	case ${nisdomainname} in
! 	[Nn][Oo] | '')
! 		;;
! 	*)
! 		domainname ${nisdomainname}
! 		echo -n ' domain'
! 		;;
! 	esac

  	echo '.'

--- 133,142 ----
  		;;
  	esac

! 	# Unset the domainname, it will be set later if requested
  	#
! 	domainname ''
! 	echo -n ' domain (unset)'

  	echo '.'

***************
*** 579,584 ****
--- 573,589 ----
  	case ${portmap_enable} in
  	[Yy][Ee][Ss])
  		echo -n ' portmap';	${portmap_program:-/usr/sbin/portmap} ${portmap_flags}
+ 		;;
+ 	esac
+
+ 	# Set the domainname if we're using NIS
+ 	#
+ 	case ${nisdomainname} in
+ 	[Nn][Oo] | '')
+ 		;;
+ 	*)
+ 		domainname ${nisdomainname}
+ 		echo -n " domain (${nisdomainname})"
  		;;
  	esac

-- 
----------------------------------------------------------------------
Trond Endrestøl                          |    trond@ramstind.gtf.ol.no
Patron of The Art of Computer Programming|   FreeBSD 4.8-S & Pine 4.55
Comment 2 Kai Storbeck 2005-08-03 14:12:38 UTC
Hello,

We're having trouble with our nis servers running in the same problems as
the above problems, though we are running *without* the -v option.

Having a look at the endless problem reports on portmap I can only come
to the conclusioin that one shouldn't try to do any conversion of
portnumbers to names in the logit() function. Or even, which flabbergasted
me even more, a call to getnameinfo() in freebsd5's rpcbind.

I surely can see that one can stall the process on purpose this way.

The thing is that this only triggers when a lot of logging is done. Ofcourse
"a lot of logging" isn't supposed to happen that often, but when it does,
as with the '-v' option, it triggers this bug.

I therefore suggest the following patches to rpcbind in
usr.sbin/rpcbind/security.c, and the almost identical patch to portmap in
usr.sbin/portmap/pmap_check.c.

Regards,

Kai Storbeck
XS4ALL Internet

--- security.c.orig     Wed Aug  3 14:48:24 2005
+++ security.c  Wed Aug  3 14:59:03 2005
@@ -165,7 +165,7 @@
        char    procbuf[32];
        char   *progname;
        char    progbuf[32];
-       char fromname[NI_MAXHOST];
+       /* char fromname[NI_MAXHOST]; */
        struct rpcent *rpc;
        static const char *procmap[] = {
        /* RPCBPROC_NULL */             "null",
@@ -195,8 +195,9 @@
 
                if (prognum == 0) {
                        progname = "";
-               } else if ((rpc = getrpcbynumber((int) prognum))) {
-                       progname = rpc->r_name;
+               /* } else if ((rpc = getrpcbynumber((int) prognum))) {
+                *      progname = rpc->r_name;
+                */
                } else {
                        snprintf(progname = progbuf, sizeof(progbuf), "%u",
                            (unsigned)prognum);
@@ -213,14 +214,15 @@
 
                /* Write syslog record. */
 
-               if (addr->sa_family == AF_LOCAL)
-                       strcpy(fromname, "local");
-               else
-                       getnameinfo(addr, addr->sa_len, fromname,
-                           sizeof fromname, NULL, 0, NI_NUMERICHOST);
+               /* if (addr->sa_family == AF_LOCAL)
+                *      strcpy(fromname, "local");
+                * else
+                *      getnameinfo(addr, addr->sa_len, fromname,
+                *          sizeof fromname, NULL, 0, NI_NUMERICHOST);
+                */
 
                syslog(severity, "connect from %s to %s(%s)%s",
-                       fromname, procname, progname, text);
+                       inet_ntoa(addr->sin_addr), procname, progname,
text);
                _exit(0);
        }
 }



--- pmap_check.c.orig   Wed Aug  3 15:00:28 2005
+++ pmap_check.c        Wed Aug  3 15:02:37 2005
@@ -238,8 +238,9 @@
 
        if (prognum == 0) {
            progname = "";
-       } else if ((rpc = getrpcbynumber((int) prognum))) {
-           progname = rpc->r_name;
+       /* } else if ((rpc = getrpcbynumber((int) prognum))) {
+        *    progname = rpc->r_name;
+        */
        } else {
            sprintf(progbuf, "%lu", prognum);
            progname = progbuf;
Comment 3 Mark Linimon 2006-04-04 19:31:54 UTC
Forwarding from a post to -stable:

----- Forwarded message from Trond Endrestøl <Trond.Endrestol@fagskolen.gjovik.no> -----

I took a look at 6.1-PRE to see if the nasty NIS bugs are still present, and
I believe they are.

I present the following four patches and I hope you'll consider making
them part of the upcoming 6.1-RELEASE.

Trond Endrestøl.

----

*** /etc/rc.d/nisdomain.orig	Wed Feb  1 21:43:28 2006
--- /etc/rc.d/nisdomain	Mon Mar 27 08:30:07 2006
***************
*** 34,40 ****

  name="nisdomain"
  start_cmd="nisdomain_start"
! stop_cmd=":"

  nisdomain_start()
  {
--- 34,40 ----

  name="nisdomain"
  start_cmd="nisdomain_start"
! stop_cmd="nisdomain_stop"

  nisdomain_start()
  {
***************
*** 48,53 ****
--- 48,61 ----
  		echo "Setting NIS domain: `/bin/domainname`."
  		;;
  	esac
+ }
+
+ nisdomain_stop()
+ {
+ 	# Unset the domainname in any case
+ 	#
+ 	domainname ''
+ 	echo "Unsetting NIS domain."
  }

  load_rc_config $name

*** /usr/src/usr.sbin/rpcbind/Makefile.orig	Thu Mar 16 21:52:31 2006
--- /usr/src/usr.sbin/rpcbind/Makefile	Tue Mar 28 16:47:41 2006
***************
*** 19,24 ****
--- 19,28 ----
  CFLAGS+= -DINET6
  .endif

+ .if defined(NO_NIS)
+ CFLAGS+= -DNO_NIS
+ .endif
+
  DPADD=	${LIBWRAP} ${LIBUTIL}
  LDADD=	-lwrap -lutil

*** /usr/src/usr.sbin/rpcbind/security.c.orig	Mon Dec 16 23:24:26 2002
--- /usr/src/usr.sbin/rpcbind/security.c	Tue Mar 28 16:52:21 2006
***************
*** 165,171 ****
--- 165,173 ----
  	char	procbuf[32];
  	char   *progname;
  	char	progbuf[32];
+ #ifdef NO_NIS
  	char fromname[NI_MAXHOST];
+ #endif
  	struct rpcent *rpc;
  	static const char *procmap[] = {
  	/* RPCBPROC_NULL */		"null",
***************
*** 193,198 ****
--- 195,201 ----

  		/* Try to map program number to name. */

+ #ifdef NO_NIS
  		if (prognum == 0) {
  			progname = "";
  		} else if ((rpc = getrpcbynumber((int) prognum))) {
***************
*** 201,206 ****
--- 204,217 ----
  			snprintf(progname = progbuf, sizeof(progbuf), "%u",
  			    (unsigned)prognum);
  		}
+ #else
+ 		if (prognum == 0) {
+ 			progname = "";
+ 		} else {
+ 			snprintf(progname = progbuf, sizeof(progbuf), "%u",
+ 			    (unsigned)prognum);
+ 		}
+ #endif

  		/* Try to map procedure number to name. */

***************
*** 213,226 ****
--- 224,244 ----

  		/* Write syslog record. */

+ #ifdef NO_NIS
  		if (addr->sa_family == AF_LOCAL)
  			strcpy(fromname, "local");
  		else
  			getnameinfo(addr, addr->sa_len, fromname,
  			    sizeof fromname, NULL, 0, NI_NUMERICHOST);
+ #endif

+ #ifdef NO_NIS
  		syslog(severity, "connect from %s to %s(%s)%s",
  			fromname, procname, progname, text);
+ #else
+ 		syslog(severity, "connect from %s to %s(%s)%s",
+ 			inet_ntoa(((struct sockaddr_in *)addr)->sin_addr), procname, progname, text);
+ #endif
  		_exit(0);
  	}
  }

*** /usr/src/usr.sbin/ypbind/ypbind.c.orig	Sun Oct 17 21:33:33 2004
--- /usr/src/usr.sbin/ypbind/ypbind.c	Mon Mar 27 08:23:09 2006
***************
*** 388,398 ****
  	if (flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
  		errx(1, "another ypbind is already running. Aborting");

- 	/* XXX domainname will be overriden if we use restricted mode */
- 	yp_get_default_domain(&domain_name);
- 	if (domain_name[0] == '\0')
- 		errx(1, "domainname not set. Aborting");
-
  	for (i = 1; i<argc; i++) {
  		if (strcmp("-ypset", argv[i]) == 0)
  			ypsetmode = YPSET_ALL;
--- 388,393 ----
***************
*** 406,411 ****
--- 401,413 ----
  			yp_manycast++;
  		else
  			errx(1, "unknown option: %s", argv[i]);
+ 	}
+
+ 	if (domain_name == NULL || domain_name[0] == '\0') {
+ 		/* XXX domainname will be overriden if we use restricted mode */
+ 		yp_get_default_domain(&domain_name);
+ 		if (domain_name[0] == '\0')
+ 			errx(1, "domainname not set. Aborting");
  	}

  	/* blow away everything in BINDINGDIR (if it exists) */

----
-- 
----------------------------------------------------------------------
Trond Endrestøl                          |   trond@fagskolen.gjovik.no
Patron of The Art of Computer Programming|   FreeBSD 4.8-S & Pine 4.55
Comment 4 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 08:00:17 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped