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. */
32struct Array
33{
34 size_t length;
35 void *ptr;
36};
37
38static int error_count;
39
40__attribute__ ((noclone, noinline))
41struct Array
42allocate (size_t bytes)
43{
44 if (!bytes)
45 return __extension__ (struct Array) {0, 0};
46
47 void *p = mmap (addr: 0x0, len: bytes, PROT_READ | PROT_WRITE,
48 MAP_PRIVATE | MAP_ANON, fd: -1, offset: 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))
56void
57deallocate (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 (addr: b.ptr, len: b.length))
63 {
64 printf (format: "munmap error: %m\n");
65 error_count++;
66 }
67}
68
69__attribute__ ((noclone, noinline))
70void *
71do_mmap (void *addr, size_t length)
72{
73 return mmap (addr: addr, len: length, PROT_READ | PROT_WRITE,
74 MAP_PRIVATE | MAP_ANON, fd: -1, offset: 0);
75}
76
77__attribute__ ((noclone, noinline))
78void *
79reallocate (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 (addr: b.ptr, length: b.length);
86 return NULL;
87}
88
89__attribute__ ((noclone, noinline))
90void
91protect (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 (addr: b.ptr, len: b.length,
99 PROT_READ | PROT_WRITE | PROT_EXEC))
100 {
101 printf (format: "mprotect error: %m\n");
102 error_count++;
103 }
104 }
105}
106
107__attribute__ ((noclone, noinline))
108ssize_t
109do_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))
120ssize_t
121do_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
131static int
132do_test (void)
133{
134 struct Array array;
135
136 array = allocate (bytes: 1);
137 protect (b: array);
138 deallocate (b: array);
139 void *p = reallocate (b: array);
140 if (p == MAP_FAILED)
141 {
142 printf (format: "mmap error: %m\n");
143 error_count++;
144 }
145 array.ptr = p;
146 protect (b: array);
147 deallocate (b: array);
148
149 int fd = xopen (path: "/dev/null", O_RDWR, 0);
150 char buf[2];
151 array.ptr = buf;
152 if (do_read (fd, ptr: array.ptr, b: array) == -1)
153 {
154 printf (format: "read error: %m\n");
155 error_count++;
156 }
157 if (do_write (fd, ptr: array.ptr, b: array) == -1)
158 {
159 printf (format: "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

source code of glibc/misc/tst-syscalls.c