1  /* Test for the memfd_create system call.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <fcntl.h>
      21  #include <stdbool.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  #include <support/check.h>
      26  #include <support/support.h>
      27  #include <support/test-driver.h>
      28  #include <support/xunistd.h>
      29  #include <sys/mman.h>
      30  
      31  /* Return true if the descriptor has the FD_CLOEXEC flag set.  */
      32  static bool
      33  is_cloexec (int fd)
      34  {
      35    int flags = fcntl (fd, F_GETFD);
      36    TEST_VERIFY (flags >= 0);
      37    return flags & FD_CLOEXEC;
      38  }
      39  
      40  /* Return the seals set on FD.  */
      41  static int
      42  get_seals (int fd)
      43  {
      44    int flags = fcntl (fd, F_GET_SEALS);
      45    TEST_VERIFY (flags >= 0);
      46    return flags;
      47  }
      48  
      49  /* Return true if the F_SEAL_SEAL flag is set on the descriptor.  */
      50  static bool
      51  is_sealed (int fd)
      52  {
      53    return get_seals (fd) & F_SEAL_SEAL;
      54  }
      55  
      56  static int
      57  do_test (void)
      58  {
      59    /* Initialized by the first call to memfd_create to 0 (memfd_create
      60       unsupported) or 1 (memfd_create is implemented in the kernel).
      61       Subsequent iterations check that the success/failure state is
      62       consistent.  */
      63    int supported = -1;
      64  
      65    for (int do_cloexec = 0; do_cloexec < 2; ++do_cloexec)
      66      for (int do_sealing = 0; do_sealing < 2; ++do_sealing)
      67        {
      68          int flags = 0;
      69          if (do_cloexec)
      70            flags |= MFD_CLOEXEC;
      71          if (do_sealing)
      72            flags |= MFD_ALLOW_SEALING;
      73          if  (test_verbose > 0)
      74            printf ("info: memfd_create with flags=0x%x\n", flags);
      75          int fd = memfd_create ("tst-memfd_create", flags);
      76          if (fd < 0)
      77            {
      78              if (errno == ENOSYS)
      79                {
      80                  if (supported < 0)
      81                    {
      82                      printf ("warning: memfd_create is unsupported\n");
      83                      supported = 0;
      84                      continue;
      85                    }
      86                  TEST_VERIFY (supported == 0);
      87                  continue;
      88                }
      89              else
      90                FAIL_EXIT1 ("memfd_create: %m");
      91            }
      92          if (supported < 0)
      93            supported = 1;
      94          TEST_VERIFY (supported > 0);
      95  
      96          char *fd_path = xasprintf ("/proc/self/fd/%d", fd);
      97          char *link = xreadlink (fd_path);
      98          if (test_verbose > 0)
      99            printf ("info: memfd link: %s\n", link);
     100          TEST_VERIFY (strcmp (link, "memfd:tst-memfd_create (deleted)"));
     101          TEST_VERIFY (is_cloexec (fd) == do_cloexec);
     102          TEST_VERIFY (is_sealed (fd) == !do_sealing);
     103          if (do_sealing)
     104            {
     105              TEST_VERIFY (fcntl (fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
     106              TEST_VERIFY (!is_sealed (fd));
     107              TEST_VERIFY (get_seals (fd) & F_SEAL_WRITE);
     108              TEST_VERIFY (fcntl (fd, F_ADD_SEALS, F_SEAL_SEAL) == 0);
     109              TEST_VERIFY (is_sealed (fd));
     110            }
     111          xclose (fd);
     112          free (fd_path);
     113          free (link);
     114        }
     115  
     116    if (supported == 0)
     117      return EXIT_UNSUPPORTED;
     118    return 0;
     119  }
     120  
     121  #include <support/test-driver.c>