(root)/
glibc-2.38/
misc/
tst-syscalls.c
       1  /* Test for syscall interfaces.
       2     Copyright (C) 2020-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  /* This test verifies that the x32 system call handling zero-extends
      20     unsigned 32-bit arguments to the 64-bit argument registers for
      21     system calls (bug 25810).  The bug is specific to x32, but the test
      22     should pass on all architectures.  */
      23  
      24  #include <stdio.h>
      25  #include <stdlib.h>
      26  #include <fcntl.h>
      27  #include <sys/mman.h>
      28  #include <support/check.h>
      29  #include <support/xunistd.h>
      30  
      31  /* On x32, this can be passed in a single 64-bit integer register.  */
      32  struct Array
      33  {
      34    size_t length;
      35    void *ptr;
      36  };
      37  
      38  static int error_count;
      39  
      40  __attribute__ ((noclone, noinline))
      41  struct Array
      42  allocate (size_t bytes)
      43  {
      44    if (!bytes)
      45      return __extension__ (struct Array) {0, 0};
      46  
      47    void *p = mmap (0x0, bytes, PROT_READ | PROT_WRITE,
      48  		  MAP_PRIVATE | MAP_ANON, -1, 0);
      49    if (p == MAP_FAILED)
      50      return __extension__ (struct Array) {0, 0};
      51  
      52    return __extension__ (struct Array) {bytes, p};
      53  }
      54  
      55  __attribute__ ((noclone, noinline))
      56  void
      57  deallocate (struct Array b)
      58  {
      59    /* On x32, the 64-bit integer register containing `b' may be copied
      60       to another 64-bit integer register to pass the second argument to
      61       munmap.  */
      62    if (b.length && munmap (b.ptr, b.length))
      63      {
      64        printf ("munmap error: %m\n");
      65        error_count++;
      66      }
      67  }
      68  
      69  __attribute__ ((noclone, noinline))
      70  void *
      71  do_mmap (void *addr, size_t length)
      72  {
      73    return mmap (addr, length, PROT_READ | PROT_WRITE,
      74  	       MAP_PRIVATE | MAP_ANON, -1, 0);
      75  }
      76  
      77  __attribute__ ((noclone, noinline))
      78  void *
      79  reallocate (struct Array b)
      80  {
      81    /* On x32, the 64-bit integer register containing `b' may be copied
      82       to another 64-bit integer register to pass the second argument to
      83       do_mmap.  */
      84    if (b.length)
      85      return do_mmap (b.ptr, b.length);
      86    return NULL;
      87  }
      88  
      89  __attribute__ ((noclone, noinline))
      90  void
      91  protect (struct Array b)
      92  {
      93    if (b.length)
      94      {
      95        /* On x32, the 64-bit integer register containing `b' may be copied
      96  	 to another 64-bit integer register to pass the second argument
      97  	 to mprotect.  */
      98        if (mprotect (b.ptr, b.length,
      99  		    PROT_READ | PROT_WRITE | PROT_EXEC))
     100  	{
     101  	  printf ("mprotect error: %m\n");
     102  	  error_count++;
     103  	}
     104      }
     105  }
     106  
     107  __attribute__ ((noclone, noinline))
     108  ssize_t
     109  do_read (int fd, void *ptr, struct Array b)
     110  {
     111    /* On x32, the 64-bit integer register containing `b' may be copied
     112       to another 64-bit integer register to pass the second argument to
     113       read.  */
     114    if (b.length)
     115      return read (fd, ptr, b.length);
     116    return 0;
     117  }
     118  
     119  __attribute__ ((noclone, noinline))
     120  ssize_t
     121  do_write (int fd, void *ptr, struct Array b)
     122  {
     123    /* On x32, the 64-bit integer register containing `b' may be copied
     124       to another 64-bit integer register to pass the second argument to
     125       write.  */
     126    if (b.length)
     127      return write (fd, ptr, b.length);
     128    return 0;
     129  }
     130  
     131  static int
     132  do_test (void)
     133  {
     134    struct Array array;
     135  
     136    array = allocate (1);
     137    protect (array);
     138    deallocate (array);
     139    void *p = reallocate (array);
     140    if (p == MAP_FAILED)
     141      {
     142        printf ("mmap error: %m\n");
     143        error_count++;
     144      }
     145    array.ptr = p;
     146    protect (array);
     147    deallocate (array);
     148  
     149    int fd = xopen ("/dev/null", O_RDWR, 0);
     150    char buf[2];
     151    array.ptr = buf;
     152    if (do_read (fd, array.ptr, array) == -1)
     153      {
     154        printf ("read error: %m\n");
     155        error_count++;
     156      }
     157    if (do_write (fd, array.ptr, array) == -1)
     158      {
     159        printf ("write error: %m\n");
     160        error_count++;
     161      }
     162    xclose (fd);
     163  
     164    return error_count ? EXIT_FAILURE : EXIT_SUCCESS;
     165  }
     166  
     167  #include <support/test-driver.c>