1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci/* 7f08c3bdfSopenharmony_ci * Description: 8f08c3bdfSopenharmony_ci * Check various errnos for mlock2(2) since kernel v2.6.9: 9f08c3bdfSopenharmony_ci * 1) mlock2() fails and returns EINVAL if unknown flag is specified. 10f08c3bdfSopenharmony_ci * 2) mlock2() fails and returns ENOMEM if the caller is not 11f08c3bdfSopenharmony_ci * privileged(CAP_IPC_LOCK) and tries to lock more memory than the 12f08c3bdfSopenharmony_ci * RLIMIT_MEMLOCK limit. 13f08c3bdfSopenharmony_ci * 3) mlock2() fails and returns EPERM if the caller is not 14f08c3bdfSopenharmony_ci * privileged(CAP_IPC_LOCK) and its RLIMIT_MEMLOCK limit is 0. 15f08c3bdfSopenharmony_ci * 4) mlock2() fails and returns ENOMEM if some of the specified address 16f08c3bdfSopenharmony_ci * range does not correspond to mapped pages in the address space 17f08c3bdfSopenharmony_ci * of the caller. 18f08c3bdfSopenharmony_ci */ 19f08c3bdfSopenharmony_ci#include <errno.h> 20f08c3bdfSopenharmony_ci#include <unistd.h> 21f08c3bdfSopenharmony_ci#include <sys/mman.h> 22f08c3bdfSopenharmony_ci#include <sys/time.h> 23f08c3bdfSopenharmony_ci#include <sys/resource.h> 24f08c3bdfSopenharmony_ci#include <pwd.h> 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#include "tst_test.h" 27f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 28f08c3bdfSopenharmony_ci 29f08c3bdfSopenharmony_ci#define PAGES 8 30f08c3bdfSopenharmony_ci 31f08c3bdfSopenharmony_cistatic size_t pgsz; 32f08c3bdfSopenharmony_cistatic size_t max_sz1, max_sz2; 33f08c3bdfSopenharmony_cistatic char *addr, *unmapped_addr; 34f08c3bdfSopenharmony_cistatic struct passwd *nobody; 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_cistatic struct tcase { 37f08c3bdfSopenharmony_ci char **taddr; 38f08c3bdfSopenharmony_ci int flag; 39f08c3bdfSopenharmony_ci size_t *max_size; 40f08c3bdfSopenharmony_ci /* 1: nobody 0: root */ 41f08c3bdfSopenharmony_ci int user; 42f08c3bdfSopenharmony_ci int exp_err; 43f08c3bdfSopenharmony_ci} tcases[] = { 44f08c3bdfSopenharmony_ci {&addr, -1, NULL, 0, EINVAL}, 45f08c3bdfSopenharmony_ci {&addr, 0, &max_sz1, 1, ENOMEM}, 46f08c3bdfSopenharmony_ci {&addr, 0, &max_sz2, 1, EPERM}, 47f08c3bdfSopenharmony_ci {&unmapped_addr, 0, NULL, 0, ENOMEM}, 48f08c3bdfSopenharmony_ci}; 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_cistatic void verify_mlock2(unsigned int n) 51f08c3bdfSopenharmony_ci{ 52f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 53f08c3bdfSopenharmony_ci struct rlimit orig_limit, new_limit; 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_ci if (tc->user) { 56f08c3bdfSopenharmony_ci SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &orig_limit); 57f08c3bdfSopenharmony_ci new_limit.rlim_cur = *tc->max_size; 58f08c3bdfSopenharmony_ci new_limit.rlim_max = *tc->max_size; 59f08c3bdfSopenharmony_ci SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &new_limit); 60f08c3bdfSopenharmony_ci SAFE_SETEUID(nobody->pw_uid); 61f08c3bdfSopenharmony_ci } 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci TEST(tst_syscall(__NR_mlock2, *tc->taddr, pgsz, tc->flag)); 64f08c3bdfSopenharmony_ci if (TST_RET != -1) { 65f08c3bdfSopenharmony_ci tst_res(TFAIL, "mlock2() succeeded"); 66f08c3bdfSopenharmony_ci SAFE_MUNLOCK(*tc->taddr, pgsz); 67f08c3bdfSopenharmony_ci goto end; 68f08c3bdfSopenharmony_ci } 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci if (TST_ERR != tc->exp_err) { 71f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, 72f08c3bdfSopenharmony_ci "mlock2() failed unexpectedly, expected %s", 73f08c3bdfSopenharmony_ci tst_strerrno(tc->exp_err)); 74f08c3bdfSopenharmony_ci } else { 75f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, "mlock2() failed as expected"); 76f08c3bdfSopenharmony_ci } 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_ciend: 79f08c3bdfSopenharmony_ci if (tc->user) { 80f08c3bdfSopenharmony_ci SAFE_SETEUID(0); 81f08c3bdfSopenharmony_ci SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &orig_limit); 82f08c3bdfSopenharmony_ci } 83f08c3bdfSopenharmony_ci} 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_cistatic void setup(void) 86f08c3bdfSopenharmony_ci{ 87f08c3bdfSopenharmony_ci pgsz = getpagesize(); 88f08c3bdfSopenharmony_ci nobody = SAFE_GETPWNAM("nobody"); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci addr = SAFE_MMAP(NULL, pgsz, PROT_WRITE, 91f08c3bdfSopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 92f08c3bdfSopenharmony_ci unmapped_addr = SAFE_MMAP(NULL, pgsz * PAGES, PROT_READ, 93f08c3bdfSopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 94f08c3bdfSopenharmony_ci SAFE_MUNMAP(unmapped_addr, pgsz * PAGES); 95f08c3bdfSopenharmony_ci unmapped_addr = unmapped_addr + pgsz * PAGES / 2; 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci max_sz1 = pgsz - 1; 98f08c3bdfSopenharmony_ci} 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_cistatic void cleanup(void) 101f08c3bdfSopenharmony_ci{ 102f08c3bdfSopenharmony_ci if (addr) 103f08c3bdfSopenharmony_ci SAFE_MUNMAP(addr, pgsz); 104f08c3bdfSopenharmony_ci} 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_cistatic struct tst_test test = { 107f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 108f08c3bdfSopenharmony_ci .test = verify_mlock2, 109f08c3bdfSopenharmony_ci .setup = setup, 110f08c3bdfSopenharmony_ci .cleanup = cleanup, 111f08c3bdfSopenharmony_ci .needs_root = 1, 112f08c3bdfSopenharmony_ci}; 113