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