1 /* 2 * Copyright (c) 2002, Intel Corporation. All rights reserved. 3 * Copyright (c) 2012, Cyril Hrubis <chrubis (at) suse.cz> 4 * 5 * This file is licensed under the GPL license. For the full content 6 * of this license, see the COPYING file at the top level of this 7 * source tree. 8 * 9 * The mmap() function shall fail if: 10 * ML [EAGAIN] The mapping could not be locked in memory, 11 * if required by mlockall(), due to a lack of resources. 12 * 13 * Test Steps: 14 * 1. Call mlockall(), setting MCL_FUTURE; 15 * 2. Call setrlimit(), set rlim_cur of resource RLIMIT_MEMLOCK to a 16 * certain value. 17 * 3. Change user to non-root user seteuid() 18 * 4. Map a shared memory object, with size larger than the 19 * rlim_cur value set in step 2 20 * 5. Should get EAGAIN. 21 * 6. Change user to root seteuid() 22 */ 23 24 #define _XOPEN_SOURCE 600 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <unistd.h> 28 #include <sys/mman.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <sys/resource.h> 32 #include <fcntl.h> 33 #include <pwd.h> 34 #include <string.h> 35 #include <errno.h> 36 #include "posixtest.h" 37 38 /* Set the euid of this process to a non-root uid */ 39 int set_nonroot(void) 40 { 41 struct passwd *pw; 42 setpwent(); 43 /* search for the first user which is non root */ 44 while ((pw = getpwent()) != NULL) 45 if (strcmp(pw->pw_name, "root")) 46 break; 47 endpwent(); 48 if (pw == NULL) { 49 printf("There is no other user than current and root.\n"); 50 return 1; 51 } 52 53 if (seteuid(pw->pw_uid) != 0) { 54 if (errno == EPERM) { 55 printf 56 ("You don't have permission to change your UID.\n"); 57 return 1; 58 } 59 perror("An error occurs when calling seteuid()"); 60 return 1; 61 } 62 63 printf("Testing with user '%s' (uid: %d)\n", 64 pw->pw_name, (int)geteuid()); 65 return 0; 66 } 67 68 int main(void) 69 { 70 char tmpfname[256]; 71 72 /* size of shared memory object */ 73 size_t shm_size; 74 75 void *pa; 76 size_t len; 77 int fd; 78 79 size_t memlock_size; 80 struct rlimit rlim = {.rlim_max = RLIM_INFINITY }; 81 82 /* Lock all memory page to be mapped */ 83 if (mlockall(MCL_FUTURE) == -1) { 84 printf("Error at mlockall(): %s\n", strerror(errno)); 85 return PTS_UNRESOLVED; 86 } 87 88 /* Set rlim.rlim_cur < len */ 89 len = 1024 * 1024; 90 memlock_size = len / 2; 91 rlim.rlim_cur = memlock_size; 92 93 /* We don't care of the size of the actual shared memory object */ 94 shm_size = 1024; 95 96 if (setrlimit(RLIMIT_MEMLOCK, &rlim) == -1) { 97 printf("Error at setrlimit(): %s\n", strerror(errno)); 98 return PTS_UNRESOLVED; 99 } 100 101 snprintf(tmpfname, sizeof(tmpfname), "pts_mmap_18_1_%d", getpid()); 102 103 /* Create shared object */ 104 shm_unlink(tmpfname); 105 fd = shm_open(tmpfname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 106 if (fd == -1) { 107 printf("Error at shm_open(): %s\n", strerror(errno)); 108 return PTS_UNRESOLVED; 109 } 110 shm_unlink(tmpfname); 111 if (ftruncate(fd, shm_size) == -1) { 112 printf("Error at ftruncate(): %s\n", strerror(errno)); 113 return PTS_UNRESOLVED; 114 } 115 116 /* This test should be run under standard user permissions */ 117 if (getuid() == 0) { 118 if (set_nonroot() != 0) { 119 printf("Cannot run this test as non-root user\n"); 120 return PTS_UNTESTED; 121 } 122 } 123 124 /* 125 * EAGAIN: 126 * Lock all the memory by mlockall(). 127 * Set resource limit setrlimit() 128 * Change the user to non-root then only setrmilit is applicable. 129 */ 130 pa = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 131 if (pa == MAP_FAILED && errno == EAGAIN) { 132 printf("Got EAGAIN: %s\n", strerror(errno)); 133 printf("Test PASSED\n"); 134 /* Change user to root */ 135 seteuid(0); 136 close(fd); 137 munmap(pa, len); 138 return PTS_PASS; 139 } 140 141 if (pa == MAP_FAILED) 142 perror("Error at mmap()"); 143 close(fd); 144 munmap(pa, len); 145 printf("Test FAILED: Did not get EAGAIN as expected\n"); 146 return PTS_FAIL; 147 } 148