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