Bug 7684 - nis/ypclnt.c leaks file descriptors if ypbind is called
nis/ypclnt.c leaks file descriptors if ypbind is called
Status: CLOSED RAWHIDE
Product: Red Hat Linux
Classification: Retired
Component: glibc (Show other bugs)
6.1
All Linux
medium Severity medium
: ---
: ---
Assigned To: Cristian Gafton
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 1999-12-08 11:44 EST by Scott Sutherland
Modified: 2008-05-01 11:37 EDT (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2000-03-08 15:17:04 EST
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Scott Sutherland 1999-12-08 11:44:37 EST
The file ypclnt.c in the glibc-2.1 distribution has a file descriptor leak.
In particular, if ypbind is called prior to any other NIS calls (except
ypunbind), each subsequent call will leave a UDP connection open.  This is
because ypbind caches the connection, but the subsequent calls overwrite it
with a new one each time.  If you don't call ypbind first, there is no
problem.  A patch which fixes the trouble is at the end of this message.

The problem also exists in RedHat 6.0, and probably other versions.

(note that this bug was also submitted by email.  Sorry if I created a
duplicate)

The following C program demonstrates the problem.

/*****************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpcsvc/nis.h>
#include <rpcsvc/yp.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/ypupd.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <bits/libc-lock.h>

main () {
  char  domain[YPMAXDOMAIN];
  unsigned int order;
  int yp_order_result;
  int i;
#define NUMCHECKS 10
  char *master;
  char *mapname = "services.byname";
  unsigned char openfile[5*NUMCHECKS];
  int fd;
  struct stat fdstat;
  char **mapkey;
  int  mapkeylen[NUMCHECKS];
  char  *mapval;
  int   mapvallen;

  mapkey = (char **)malloc(NUMCHECKS*(sizeof(char *)));

  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (fstat(fd, &fdstat) == 0) {
      openfile[fd] = 1;
    } else {
      openfile[fd] = 0;
    }
  }

  if (getdomainname(domain, sizeof(domain)) < 0) {
    fprintf(stderr,"NIS not running\n");
    exit(1);
  }


  if (  yp_bind(domain) ) {
    fprintf(stderr,"cant bind to domain %s\n");
    exit(1);
  }
  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (!openfile[fd] && fstat(fd, &fdstat) == 0) {
      printf("fd %d left open by ypbind (this is to be expected)\n",fd);
      openfile[fd] = 1;
    }
  }


  yp_order(domain, mapname, &order);
  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (!openfile[fd] && fstat(fd, &fdstat) == 0) {
      printf("fd %d left open by yp_order\n", fd);
      openfile[fd] = 1;
    }
  }


  yp_first(domain, mapname, mapkey, mapkeylen, &mapval, &mapvallen);
  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (!openfile[fd] && fstat(fd, &fdstat) == 0) {
      printf("fd %d left open by yp_first\n",fd);
      openfile[fd] = 1;
    }
  }

  for (i=1; i<NUMCHECKS; i++) {
    if (YPERR_NOMORE == yp_next(domain, mapname,
                                mapkey[i-1], mapkeylen[i-1],
                                &(mapkey[i]), &(mapkeylen[i]),
                                &mapval, &mapvallen))
      break;
  }
  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (!openfile[fd] && fstat(fd, &fdstat) == 0) {
      printf("fd %d left open by yp_next\n",fd);
      openfile[fd] = 1;
    }
  }

}
 /*****************************************************************/

Solution: A patch which remedies the problem is below.  It also fixes a
typo
 in a comment (exits was written as exists, which was worse than no
comment!)

nesconset <nis> diff -c2 ypclnt.c.orig ypclnt.c
*** glibc-2.1/nis/ypclnt.c.orig       Wed Jun 30 11:59:21 1999
--- glibc-2.1/nis/ypclnt.c    Wed Dec  8 10:12:32 1999
***************
*** 202,208 ****
          }

!       ysd->dom_socket = RPC_ANYSOCK;
!       ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG,
YPVERS,
!                                         UDPTIMEOUT, &ysd->dom_socket);
        if (ysd->dom_client == NULL)
          ysd->dom_vers = -1;
--- 202,212 ----
          }

!       /* if we don't already have a socket from a previous call, get one
*/
!       if ( ysd->dom_socket < 1 ) {
!       ysd->dom_socket = RPC_ANYSOCK;
!       ysd->dom_client = clntudp_create (&ysd->dom_server_addr,
!                                         YPPROG, YPVERS, UDPTIMEOUT,
!                                         &ysd->dom_socket);
!       }
        if (ysd->dom_client == NULL)
          ysd->dom_vers = -1;
***************
*** 211,215 ****
    while (ysd->dom_client == NULL);

!   /* If the program exists, close the socket */
    if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
      perror ("fcntl: F_SETFD");
--- 215,219 ----
    while (ysd->dom_client == NULL);

!   /* If the program exits, close the socket */
    if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
      perror ("fcntl: F_SETFD");
Comment 1 Jeff Johnson 2000-03-08 15:17:59 EST
This problem appears to be resolved (ypc.c is the test program above, run
on ultrasparc):
bash$ cc     ypc.c   -o ypc -lnsl
bash$ ./ypc
fd 4 left open by ypbind (this is to be expected)
bash$ rpm -qf /usr/lib/libnsl.a
glibc-devel-2.1.3-15

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