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

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