1 /* Test for syscall interfaces.
2    Copyright (C) 2020-2022 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
allocate(size_t bytes)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
deallocate(struct Array b)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 *
do_mmap(void * addr,size_t length)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 *
reallocate(struct Array b)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
protect(struct Array b)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
do_read(int fd,void * ptr,struct Array b)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
do_write(int fd,void * ptr,struct Array b)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
do_test(void)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>
168