Blame nss/tst-nss-files-alias-leak.c

Packit Service c6350a
/* Check for file descriptor leak in alias :include: processing (bug 23521).
Packit Service c6350a
   Copyright (C) 2018 Free Software Foundation, Inc.
Packit Service c6350a
   This file is part of the GNU C Library.
Packit Service c6350a
Packit Service c6350a
   The GNU C Library is free software; you can redistribute it and/or
Packit Service c6350a
   modify it under the terms of the GNU Lesser General Public
Packit Service c6350a
   License as published by the Free Software Foundation; either
Packit Service c6350a
   version 2.1 of the License, or (at your option) any later version.
Packit Service c6350a
Packit Service c6350a
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service c6350a
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service c6350a
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service c6350a
   Lesser General Public License for more details.
Packit Service c6350a
Packit Service c6350a
   You should have received a copy of the GNU Lesser General Public
Packit Service c6350a
   License along with the GNU C Library; if not, see
Packit Service c6350a
   <http://www.gnu.org/licenses/>.  */
Packit Service c6350a
Packit Service c6350a
#include <aliases.h>
Packit Service c6350a
#include <array_length.h>
Packit Service c6350a
#include <dlfcn.h>
Packit Service c6350a
#include <errno.h>
Packit Service c6350a
#include <gnu/lib-names.h>
Packit Service c6350a
#include <nss.h>
Packit Service c6350a
#include <stdlib.h>
Packit Service c6350a
#include <string.h>
Packit Service c6350a
#include <support/check.h>
Packit Service c6350a
#include <support/namespace.h>
Packit Service c6350a
#include <support/support.h>
Packit Service c6350a
#include <support/temp_file.h>
Packit Service c6350a
#include <support/test-driver.h>
Packit Service c6350a
#include <support/xstdio.h>
Packit Service c6350a
#include <support/xunistd.h>
Packit Service c6350a
Packit Service c6350a
static struct support_chroot *chroot_env;
Packit Service c6350a
Packit Service c6350a
/* Number of the aliases for the "many" user.  This must be large
Packit Service c6350a
   enough to trigger reallocation for the pointer array, but result in
Packit Service c6350a
   answers below the maximum size tried in do_test.  */
Packit Service c6350a
enum { many_aliases = 30 };
Packit Service c6350a
Packit Service c6350a
static void
Packit Service c6350a
prepare (int argc, char **argv)
Packit Service c6350a
{
Packit Service c6350a
  chroot_env = support_chroot_create
Packit Service c6350a
    ((struct support_chroot_configuration) { } );
Packit Service c6350a
Packit Service c6350a
  char *path = xasprintf ("%s/etc/aliases", chroot_env->path_chroot);
Packit Service c6350a
  add_temp_file (path);
Packit Service c6350a
  support_write_file_string
Packit Service c6350a
    (path,
Packit Service c6350a
     "user1: :include:/etc/aliases.user1\n"
Packit Service c6350a
     "user2: :include:/etc/aliases.user2\n"
Packit Service c6350a
     "comment: comment1, :include:/etc/aliases.comment\n"
Packit Service c6350a
     "many: :include:/etc/aliases.many\n");
Packit Service c6350a
  free (path);
Packit Service c6350a
Packit Service c6350a
  path = xasprintf ("%s/etc/aliases.user1", chroot_env->path_chroot);
Packit Service c6350a
  add_temp_file (path);
Packit Service c6350a
  support_write_file_string (path, "alias1\n");
Packit Service c6350a
  free (path);
Packit Service c6350a
Packit Service c6350a
  path = xasprintf ("%s/etc/aliases.user2", chroot_env->path_chroot);
Packit Service c6350a
  add_temp_file (path);
Packit Service c6350a
  support_write_file_string (path, "alias1a, alias2\n");
Packit Service c6350a
  free (path);
Packit Service c6350a
Packit Service c6350a
  path = xasprintf ("%s/etc/aliases.comment", chroot_env->path_chroot);
Packit Service c6350a
  add_temp_file (path);
Packit Service c6350a
  support_write_file_string
Packit Service c6350a
    (path,
Packit Service c6350a
     /* The line must be longer than the line with the :include:
Packit Service c6350a
        directive in /etc/aliases.  */
Packit Service c6350a
     "# Long line.  ##############################################\n"
Packit Service c6350a
     "comment2\n");
Packit Service c6350a
  free (path);
Packit Service c6350a
Packit Service c6350a
  path = xasprintf ("%s/etc/aliases.many", chroot_env->path_chroot);
Packit Service c6350a
  add_temp_file (path);
Packit Service c6350a
  FILE *fp = xfopen (path, "w");
Packit Service c6350a
  for (int i = 0; i < many_aliases; ++i)
Packit Service c6350a
    fprintf (fp, "a%d\n", i);
Packit Service c6350a
  TEST_VERIFY_EXIT (! ferror (fp));
Packit Service c6350a
  xfclose (fp);
Packit Service c6350a
  free (path);
Packit Service c6350a
}
Packit Service c6350a
Packit Service c6350a
/* The names of the users to test.  */
Packit Service c6350a
static const char *users[] = { "user1", "user2", "comment", "many" };
Packit Service c6350a
Packit Service c6350a
static void
Packit Service c6350a
check_aliases (int id, const struct aliasent *e)
Packit Service c6350a
{
Packit Service c6350a
  TEST_VERIFY_EXIT (id >= 0 || id < array_length (users));
Packit Service c6350a
  const char *name = users[id];
Packit Service c6350a
  TEST_COMPARE_BLOB (e->alias_name, strlen (e->alias_name),
Packit Service c6350a
                     name, strlen (name));
Packit Service c6350a
Packit Service c6350a
  switch (id)
Packit Service c6350a
    {
Packit Service c6350a
    case 0:
Packit Service c6350a
      TEST_COMPARE (e->alias_members_len, 1);
Packit Service c6350a
      TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
Packit Service c6350a
                         "alias1", strlen ("alias1"));
Packit Service c6350a
      break;
Packit Service c6350a
Packit Service c6350a
    case 1:
Packit Service c6350a
      TEST_COMPARE (e->alias_members_len, 2);
Packit Service c6350a
      TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
Packit Service c6350a
                         "alias1a", strlen ("alias1a"));
Packit Service c6350a
      TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]),
Packit Service c6350a
                         "alias2", strlen ("alias2"));
Packit Service c6350a
      break;
Packit Service c6350a
Packit Service c6350a
    case 2:
Packit Service c6350a
      TEST_COMPARE (e->alias_members_len, 2);
Packit Service c6350a
      TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
Packit Service c6350a
                         "comment1", strlen ("comment1"));
Packit Service c6350a
      TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]),
Packit Service c6350a
                         "comment2", strlen ("comment2"));
Packit Service c6350a
      break;
Packit Service c6350a
Packit Service c6350a
    case 3:
Packit Service c6350a
      TEST_COMPARE (e->alias_members_len, many_aliases);
Packit Service c6350a
      for (int i = 0; i < e->alias_members_len; ++i)
Packit Service c6350a
        {
Packit Service c6350a
          char alias[30];
Packit Service c6350a
          int len = snprintf (alias, sizeof (alias), "a%d", i);
Packit Service c6350a
          TEST_VERIFY_EXIT (len > 0);
Packit Service c6350a
          TEST_COMPARE_BLOB (e->alias_members[i], strlen (e->alias_members[i]),
Packit Service c6350a
                             alias, len);
Packit Service c6350a
        }
Packit Service c6350a
      break;
Packit Service c6350a
    }
Packit Service c6350a
}
Packit Service c6350a
Packit Service c6350a
static int
Packit Service c6350a
do_test (void)
Packit Service c6350a
{
Packit Service c6350a
  /* Make sure we don't try to load the module in the chroot.  */
Packit Service c6350a
  if (dlopen (LIBNSS_FILES_SO, RTLD_NOW) == NULL)
Packit Service c6350a
    FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO ": %s", dlerror ());
Packit Service c6350a
Packit Service c6350a
  /* Some of these descriptors will become unavailable if there is a
Packit Service c6350a
     file descriptor leak.  10 is chosen somewhat arbitrarily.  The
Packit Service c6350a
     array must be longer than the number of files opened by nss_files
Packit Service c6350a
     at the same time (currently that number is 2).  */
Packit Service c6350a
  int next_descriptors[10];
Packit Service c6350a
  for (size_t i = 0; i < array_length (next_descriptors); ++i)
Packit Service c6350a
    {
Packit Service c6350a
      next_descriptors[i] = dup (0);
Packit Service c6350a
      TEST_VERIFY_EXIT (next_descriptors[i] > 0);
Packit Service c6350a
    }
Packit Service c6350a
  for (size_t i = 0; i < array_length (next_descriptors); ++i)
Packit Service c6350a
    xclose (next_descriptors[i]);
Packit Service c6350a
Packit Service c6350a
  support_become_root ();
Packit Service c6350a
  if (!support_can_chroot ())
Packit Service c6350a
    return EXIT_UNSUPPORTED;
Packit Service c6350a
Packit Service c6350a
  __nss_configure_lookup ("aliases", "files");
Packit Service c6350a
Packit Service c6350a
  xchroot (chroot_env->path_chroot);
Packit Service c6350a
Packit Service c6350a
  /* Attempt various buffer sizes.  If the operation succeeds, we
Packit Service c6350a
     expect correct data.  */
Packit Service c6350a
  for (int id = 0; id < array_length (users); ++id)
Packit Service c6350a
    {
Packit Service c6350a
      bool found = false;
Packit Service c6350a
      for (size_t size = 1; size <= 1000; ++size)
Packit Service c6350a
        {
Packit Service c6350a
          void *buffer = malloc (size);
Packit Service c6350a
          struct aliasent result;
Packit Service c6350a
          struct aliasent *res;
Packit Service c6350a
          errno = EINVAL;
Packit Service c6350a
          int ret = getaliasbyname_r (users[id], &result, buffer, size, &res;;
Packit Service c6350a
          if (ret == 0)
Packit Service c6350a
            {
Packit Service c6350a
              if (res != NULL)
Packit Service c6350a
                {
Packit Service c6350a
                  found = true;
Packit Service c6350a
                  check_aliases (id, res);
Packit Service c6350a
                }
Packit Service c6350a
              else
Packit Service c6350a
                {
Packit Service c6350a
                  support_record_failure ();
Packit Service c6350a
                  printf ("error: failed lookup for user \"%s\", size %zu\n",
Packit Service c6350a
                          users[id], size);
Packit Service c6350a
                }
Packit Service c6350a
            }
Packit Service c6350a
          else if (ret != ERANGE)
Packit Service c6350a
            {
Packit Service c6350a
              support_record_failure ();
Packit Service c6350a
              printf ("error: invalid return code %d (user \%s\", size %zu)\n",
Packit Service c6350a
                      ret, users[id], size);
Packit Service c6350a
            }
Packit Service c6350a
          free (buffer);
Packit Service c6350a
Packit Service c6350a
          /* Make sure that we did not have a file descriptor leak.  */
Packit Service c6350a
          for (size_t i = 0; i < array_length (next_descriptors); ++i)
Packit Service c6350a
            {
Packit Service c6350a
              int new_fd = dup (0);
Packit Service c6350a
              if (new_fd != next_descriptors[i])
Packit Service c6350a
                {
Packit Service c6350a
                  support_record_failure ();
Packit Service c6350a
                  printf ("error: descriptor %d at index %zu leaked"
Packit Service c6350a
                          " (user \"%s\", size %zu)\n",
Packit Service c6350a
                          next_descriptors[i], i, users[id], size);
Packit Service c6350a
Packit Service c6350a
                  /* Close unexpected descriptor, the leak probing
Packit Service c6350a
                     descriptors, and the leaked descriptor
Packit Service c6350a
                     next_descriptors[i].  */
Packit Service c6350a
                  xclose (new_fd);
Packit Service c6350a
                  for (size_t j = 0; j <= i; ++j)
Packit Service c6350a
                    xclose (next_descriptors[j]);
Packit Service c6350a
                  goto next_size;
Packit Service c6350a
                }
Packit Service c6350a
            }
Packit Service c6350a
          for (size_t i = 0; i < array_length (next_descriptors); ++i)
Packit Service c6350a
            xclose (next_descriptors[i]);
Packit Service c6350a
Packit Service c6350a
        next_size:
Packit Service c6350a
          ;
Packit Service c6350a
        }
Packit Service c6350a
      if (!found)
Packit Service c6350a
        {
Packit Service c6350a
          support_record_failure ();
Packit Service c6350a
          printf ("error: user %s not found\n", users[id]);
Packit Service c6350a
        }
Packit Service c6350a
    }
Packit Service c6350a
Packit Service c6350a
  support_chroot_free (chroot_env);
Packit Service c6350a
  return 0;
Packit Service c6350a
}
Packit Service c6350a
Packit Service c6350a
#define PREPARE prepare
Packit Service c6350a
#include <support/test-driver.c>