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