1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 Google, Inc.
4 *
5 * Architectures may provide up to three syscalls that have been used to
6 * implement getrlimit(2) in different libc implementations. These syscalls
7 * differ in the size and signedness of rlim_t:
8 *
9 * - __NR_getrlimit uses long or unsigned long, depending on the
10 * architecture
11 *
12 * - __NR_ugetrlimit uses unsigned long, and only exists on
13 * architectures where __NR_getrlimit is signed
14 *
15 * - __NR_prlimit64 uses uint64_t
16 *
17 * This test compares the results returned by all three syscalls, confirming
18 * that they either match or were appropriately capped at the respective
19 * RLIM_INFINITY constant.
20 */
21
22 #include <inttypes.h>
23 #include <stdint.h>
24 #include <sys/time.h>
25 #include <sys/resource.h>
26
27 #include "tst_test.h"
28 #include "lapi/syscalls.h"
29 #include "lapi/abisize.h"
30
31 /**
32 * Linux provides an "old" getrlimit syscall handler that uses signed long,
33 * and a "new" getrlimit syscall handler that uses unsigned long.
34 *
35 * The underlying syscall names vary across architectures, depending on whether
36 * the architecture predates the "new" handler. For clarity, this test
37 * will call them getrlimit_long and getlimit_ulong internally.
38 */
39 #define SIGNED_GETRLIMIT (__NR_ugetrlimit != __LTP__NR_INVALID_SYSCALL)
40 #if SIGNED_GETRLIMIT
41 #define __NR_getrlimit_ulong __NR_ugetrlimit
42 #define __NR_getrlimit_ulong_str "__NR_ugetrlimit"
43 #else
44 #define __NR_getrlimit_ulong __NR_getrlimit
45 #define __NR_getrlimit_ulong_str "__NR_getrlimit"
46 #endif
47
48 #ifndef HAVE_STRUCT_RLIMIT64
49 struct rlimit64 {
50 uint64_t rlim_cur;
51 uint64_t rlim_max;
52 };
53 #endif
54 const uint64_t RLIM_INFINITY_U64 = UINT64_MAX;
55
getrlimit_u64(int resource,struct rlimit64 * rlim)56 static int getrlimit_u64(int resource, struct rlimit64 *rlim)
57 {
58 return tst_syscall(__NR_prlimit64, 0, resource, NULL, rlim);
59 }
60
61 struct rlimit_ulong {
62 unsigned long rlim_cur;
63 unsigned long rlim_max;
64 };
65
66 #if defined(__mips__) && defined(TST_ABI32)
67 const unsigned long RLIM_INFINITY_UL = 0x7fffffffUL;
68 #else
69 const unsigned long RLIM_INFINITY_UL = ULONG_MAX;
70 #endif
71
getrlimit_ulong(int resource,struct rlimit_ulong * rlim)72 static int getrlimit_ulong(int resource, struct rlimit_ulong *rlim)
73 {
74 return syscall(__NR_getrlimit_ulong, resource, rlim);
75 }
76
77 #if SIGNED_GETRLIMIT
78 struct rlimit_long {
79 long rlim_cur;
80 long rlim_max;
81 };
82 const long RLIM_INFINITY_L = LONG_MAX;
83
getrlimit_long(int resource,struct rlimit_long * rlim)84 static int getrlimit_long(int resource, struct rlimit_long *rlim)
85 {
86 return syscall(__NR_getrlimit, resource, rlim);
87 }
88 #endif
89
compare_retval(int resource,int ret_u64,int errno_u64,int ret_other,int errno_other,const char * other_syscall)90 static int compare_retval(int resource, int ret_u64, int errno_u64,
91 int ret_other, int errno_other,
92 const char *other_syscall)
93 {
94 if (ret_u64 != ret_other || errno_u64 != errno_other) {
95 tst_res(TFAIL, "__NR_prlimit64(%d) returned %d (%s) but %s(%d) returned %d (%s)",
96 resource, ret_u64, tst_strerrno(errno_u64),
97 other_syscall, resource, ret_other,
98 tst_strerrno(errno_other));
99 return -1;
100 }
101
102 return 0;
103 }
104
compare_u64_ulong(int resource,uint64_t val_u64,unsigned long val_ul,const char * kind)105 static int compare_u64_ulong(int resource, uint64_t val_u64,
106 unsigned long val_ul, const char *kind)
107 {
108 if ((val_u64 > RLIM_INFINITY_UL && val_ul != RLIM_INFINITY_UL) ||
109 (val_u64 <= RLIM_INFINITY_UL && val_ul != val_u64)) {
110 tst_res(TFAIL, "__NR_prlimit64(%d) had %s = %" PRIx64 " but " __NR_getrlimit_ulong_str "(%d) had %s = %lx",
111 resource, kind, val_u64,
112 resource, kind, val_ul);
113 return -1;
114 }
115
116 return 0;
117 }
118
119 #if SIGNED_GETRLIMIT
compare_u64_long(int resource,uint64_t val_u64,long val_l,const char * kind)120 static int compare_u64_long(int resource, uint64_t val_u64, long val_l,
121 const char *kind)
122 {
123 if ((val_u64 > (uint64_t)RLIM_INFINITY_L && val_l != RLIM_INFINITY_L) ||
124 (val_u64 <= (uint64_t)RLIM_INFINITY_L && val_l != (long)val_u64)) {
125 tst_res(TFAIL, "__NR_prlimit64(%d) had %s = %" PRIx64 " but __NR_getrlimit(%d) had %s = %lx",
126 resource, kind, val_u64,
127 resource, kind, val_l);
128 return -1;
129 }
130
131 return 0;
132 }
133 #endif
134
run(unsigned int resource)135 static void run(unsigned int resource)
136 {
137 struct rlimit64 rlim_u64;
138 int ret_u64;
139 int errno_u64;
140
141 struct rlimit_ulong rlim_ul;
142 int ret_ul;
143 int errno_ul;
144
145 #if SIGNED_GETRLIMIT
146 struct rlimit_long rlim_l;
147 int ret_l;
148 int errno_l;
149 #endif
150
151 errno = 0;
152 ret_u64 = getrlimit_u64(resource, &rlim_u64);
153 errno_u64 = errno;
154
155 errno = 0;
156 ret_ul = getrlimit_ulong(resource, &rlim_ul);
157 errno_ul = errno;
158
159 if (compare_retval(resource, ret_u64, errno_u64, ret_ul, errno_ul,
160 __NR_getrlimit_ulong_str) ||
161 compare_u64_ulong(resource, rlim_u64.rlim_cur, rlim_ul.rlim_cur,
162 "rlim_cur") ||
163 compare_u64_ulong(resource, rlim_u64.rlim_max, rlim_ul.rlim_max,
164 "rlim_max"))
165 return;
166
167 tst_res(TPASS, "__NR_prlimit64(%d) and %s(%d) gave consistent results",
168 resource, __NR_getrlimit_ulong_str, resource);
169
170 #if SIGNED_GETRLIMIT
171 errno = 0;
172 ret_l = getrlimit_long(resource, &rlim_l);
173 errno_l = errno;
174 if (errno_l == ENOSYS) {
175 tst_res(TCONF | TERRNO,
176 "__NR_getrlimit(%d) not implemented", __NR_getrlimit);
177 return;
178 }
179
180 if (compare_retval(resource, ret_u64, errno_u64, ret_l, errno_l,
181 "__NR_getrlimit") ||
182 compare_u64_long(resource, rlim_u64.rlim_cur, rlim_l.rlim_cur,
183 "rlim_cur") ||
184 compare_u64_long(resource, rlim_u64.rlim_max, rlim_l.rlim_max,
185 "rlim_max"))
186 return;
187
188 tst_res(TPASS, "__NR_prlimit64(%d) and __NR_getrlimit(%d) gave "
189 "consistent results", resource, resource);
190 #endif
191 }
192
193 static struct tst_test test = {
194 .tcnt = RLIM_NLIMITS,
195 .test = run,
196 };
197