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

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