1/* 2 * Copyright (C) 2012 Linux Test Project, Inc. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of version 2 of the GNU General Public 6 * License as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Further, this software is distributed without any warranty that it 13 * is free of the rightful claim of any third person regarding 14 * infringement or the like. Any license provided herein, whether 15 * implied or otherwise, applies only to this software file. Patent 16 * licenses, if any, provided herein do not apply to combinations of 17 * this program with other software, or any other product whatsoever. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 22 * 02110-1301, USA. 23 */ 24 25/* 26 * errno tests for migrate_pages() syscall 27 */ 28#include <sys/types.h> 29#include <sys/syscall.h> 30#include <sys/wait.h> 31#include <sys/mman.h> 32#include <errno.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <unistd.h> 37#include <pwd.h> 38 39#include "test.h" 40#include "safe_macros.h" 41#include "lapi/syscalls.h" 42#include "numa_helper.h" 43#include "migrate_pages_common.h" 44 45char *TCID = "migrate_pages01"; 46int TST_TOTAL = 1; 47 48option_t options[] = { 49 {NULL, NULL, NULL} 50}; 51 52#ifdef HAVE_NUMA_V2 53 54static unsigned long *sane_old_nodes; 55static unsigned long *sane_new_nodes; 56static int sane_nodemask_size; 57static int sane_max_node; 58 59static void setup(void); 60static void cleanup(void); 61 62static void test_sane_nodes(void) 63{ 64 tst_resm(TINFO, "test_empty_mask"); 65 TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, 66 sane_old_nodes, sane_new_nodes)); 67 check_ret(0); 68} 69 70static void test_invalid_pid(void) 71{ 72 pid_t invalid_pid = -1; 73 74 tst_resm(TINFO, "test_invalid_pid -1"); 75 TEST(tst_syscall(__NR_migrate_pages, invalid_pid, sane_max_node, 76 sane_old_nodes, sane_new_nodes)); 77 check_ret(-1); 78 check_errno(ESRCH); 79 80 tst_resm(TINFO, "test_invalid_pid unused pid"); 81 invalid_pid = tst_get_unused_pid(cleanup); 82 TEST(tst_syscall(__NR_migrate_pages, invalid_pid, sane_max_node, 83 sane_old_nodes, sane_new_nodes)); 84 check_ret(-1); 85 check_errno(ESRCH); 86} 87 88static void test_invalid_masksize(void) 89{ 90 tst_resm(TINFO, "test_invalid_masksize"); 91 TEST(tst_syscall(__NR_migrate_pages, 0, -1, sane_old_nodes, 92 sane_new_nodes)); 93 check_ret(-1); 94 check_errno(EINVAL); 95} 96 97static void test_invalid_mem(void) 98{ 99 unsigned long *p; 100 101 tst_resm(TINFO, "test_invalid_mem -1"); 102 TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, -1, -1)); 103 check_ret(-1); 104 check_errno(EFAULT); 105 106 tst_resm(TINFO, "test_invalid_mem invalid prot"); 107 p = mmap(NULL, getpagesize(), PROT_NONE, 108 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 109 if (p == MAP_FAILED) 110 tst_brkm(TBROK | TERRNO, cleanup, "mmap"); 111 TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, p, p)); 112 check_ret(-1); 113 check_errno(EFAULT); 114 115 SAFE_MUNMAP(cleanup, p, getpagesize()); 116 tst_resm(TINFO, "test_invalid_mem unmmaped"); 117 TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, p, p)); 118 check_ret(-1); 119 check_errno(EFAULT); 120} 121 122static void test_invalid_nodes(void) 123{ 124 int *nodes; 125 int num_nodes, ret, i; 126 int invalid_node = 0; 127 unsigned long *old_nodes, *new_nodes; 128 129 tst_resm(TINFO, "test_invalid_nodes"); 130 ret = get_allowed_nodes_arr(NH_MEMS, &num_nodes, &nodes); 131 if (ret < 0) 132 tst_brkm(TBROK | TERRNO, cleanup, 133 "get_allowed_nodes_arr: %d", ret); 134 135 /* get first node which is not in nodes */ 136 for (i = 0; i < num_nodes; i++, invalid_node++) 137 if (invalid_node != nodes[i]) 138 break; 139 if (invalid_node < sane_max_node) { 140 old_nodes = SAFE_MALLOC(NULL, sane_nodemask_size); 141 new_nodes = SAFE_MALLOC(NULL, sane_nodemask_size); 142 memcpy(old_nodes, sane_old_nodes, sane_nodemask_size); 143 memset(new_nodes, 0, sane_nodemask_size); 144 set_bit(new_nodes, invalid_node, 1); 145 146 TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, 147 old_nodes, new_nodes)); 148 check_ret(-1); 149 check_errno(EINVAL); 150 free(old_nodes); 151 free(new_nodes); 152 } else { 153 tst_resm(TCONF, "All possible nodes are present"); 154 } 155 156 free(nodes); 157} 158 159static void test_invalid_perm(void) 160{ 161 char nobody_uid[] = "nobody"; 162 struct passwd *ltpuser; 163 int status; 164 pid_t child_pid; 165 pid_t parent_pid; 166 int ret = 0; 167 168 tst_resm(TINFO, "test_invalid_perm"); 169 parent_pid = getpid(); 170 fflush(stdout); 171 child_pid = fork(); 172 switch (child_pid) { 173 case -1: 174 tst_brkm(TBROK | TERRNO, cleanup, "fork"); 175 break; 176 case 0: 177 ltpuser = getpwnam(nobody_uid); 178 if (ltpuser == NULL) 179 tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed"); 180 SAFE_SETUID(NULL, ltpuser->pw_uid); 181 TEST(tst_syscall(__NR_migrate_pages, parent_pid, 182 sane_max_node, sane_old_nodes, sane_new_nodes)); 183 ret |= check_ret(-1); 184 ret |= check_errno(EPERM); 185 exit(ret); 186 default: 187 SAFE_WAITPID(cleanup, child_pid, &status, 0); 188 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 189 tst_resm(TFAIL, "child returns %d", status); 190 } 191} 192 193int main(int argc, char *argv[]) 194{ 195 int lc; 196 197 tst_parse_opts(argc, argv, options, NULL); 198 199 setup(); 200 for (lc = 0; TEST_LOOPING(lc); lc++) { 201 tst_count = 0; 202 test_sane_nodes(); 203 test_invalid_pid(); 204 test_invalid_masksize(); 205 test_invalid_mem(); 206 test_invalid_nodes(); 207 test_invalid_perm(); 208 } 209 cleanup(); 210 tst_exit(); 211} 212 213static void setup(void) 214{ 215 int node, ret; 216 217 tst_require_root(); 218 TEST(tst_syscall(__NR_migrate_pages, 0, 0, NULL, NULL)); 219 220 if (!is_numa(NULL, NH_MEMS, 1)) 221 tst_brkm(TCONF, NULL, "requires NUMA with at least 1 node"); 222 223 ret = get_allowed_nodes(NH_MEMS, 1, &node); 224 if (ret < 0) 225 tst_brkm(TBROK | TERRNO, NULL, "get_allowed_nodes_arr: %d", 226 ret); 227 228 sane_max_node = LTP_ALIGN(get_max_node(), sizeof(unsigned long)*8); 229 sane_nodemask_size = sane_max_node / 8; 230 sane_old_nodes = SAFE_MALLOC(NULL, sane_nodemask_size); 231 sane_new_nodes = SAFE_MALLOC(NULL, sane_nodemask_size); 232 memset(sane_old_nodes, 0, sane_nodemask_size); 233 memset(sane_new_nodes, 0, sane_nodemask_size); 234 235 set_bit(sane_old_nodes, node, 1); 236 set_bit(sane_new_nodes, node, 1); 237 238 TEST_PAUSE; 239} 240 241static void cleanup(void) 242{ 243 free(sane_old_nodes); 244 free(sane_new_nodes); 245} 246 247#else 248int main(void) 249{ 250 tst_brkm(TCONF, NULL, NUMA_ERROR_MSG); 251} 252#endif 253