1/* 2 * Copyright (C) 2017 Red Hat, Inc. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of 7 * the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it would be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 */ 15 16/* 17 * Based on Linux/tools/testing/selftests/memfd/memfd_test.c 18 * by David Herrmann <dh.herrmann@gmail.com> 19 * 20 * 24/02/2017 Port to LTP <jracek@redhat.com> 21 */ 22 23#define _GNU_SOURCE 24 25#include <errno.h> 26#include "tst_test.h" 27#include "memfd_create_common.h" 28 29/* 30 * Do few basic sealing tests to see whether setting/retrieving seals works. 31 */ 32static void test_basic(int fd) 33{ 34 /* add basic seals */ 35 CHECK_MFD_HAS_SEALS(fd, 0); 36 CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK | F_SEAL_WRITE); 37 CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK | F_SEAL_WRITE); 38 39 /* add them again */ 40 CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK | F_SEAL_WRITE); 41 CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK | F_SEAL_WRITE); 42 43 /* add more seals and seal against sealing */ 44 CHECK_MFD_ADD_SEALS(fd, F_SEAL_GROW | F_SEAL_SEAL); 45 CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK | F_SEAL_GROW | 46 F_SEAL_WRITE | F_SEAL_SEAL); 47 48 /* verify that sealing no longer works */ 49 CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_GROW); 50 CHECK_MFD_FAIL_ADD_SEALS(fd, 0); 51} 52 53/* 54 * Verify that no sealing is possible when memfd is created without 55 * MFD_ALLOW_SEALING flag. 56 */ 57static void test_no_sealing_without_flag(int fd) 58{ 59 CHECK_MFD_HAS_SEALS(fd, F_SEAL_SEAL); 60 CHECK_MFD_FAIL_ADD_SEALS(fd, 61 F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); 62 CHECK_MFD_HAS_SEALS(fd, F_SEAL_SEAL); 63} 64 65/* 66 * Test SEAL_WRITE 67 * Test whether SEAL_WRITE actually prevents modifications. 68 */ 69static void test_seal_write(int fd) 70{ 71 CHECK_MFD_HAS_SEALS(fd, 0); 72 CHECK_MFD_ADD_SEALS(fd, F_SEAL_WRITE); 73 CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE); 74 75 CHECK_MFD_READABLE(fd); 76 CHECK_MFD_NON_WRITEABLE(fd); 77 CHECK_MFD_SHRINKABLE(fd); 78 CHECK_MFD_GROWABLE(fd); 79 CHECK_MFD_NON_GROWABLE_BY_WRITE(fd); 80} 81 82/* 83 * Test SEAL_SHRINK 84 * Test whether SEAL_SHRINK actually prevents shrinking 85 */ 86static void test_seal_shrink(int fd) 87{ 88 CHECK_MFD_HAS_SEALS(fd, 0); 89 CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK); 90 CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK); 91 92 CHECK_MFD_READABLE(fd); 93 CHECK_MFD_WRITEABLE(fd); 94 CHECK_MFD_NON_SHRINKABLE(fd); 95 CHECK_MFD_GROWABLE(fd); 96 CHECK_MFD_GROWABLE_BY_WRITE(fd); 97} 98 99/* 100 * Test SEAL_GROW 101 * Test whether SEAL_GROW actually prevents growing 102 */ 103static void test_seal_grow(int fd) 104{ 105 CHECK_MFD_HAS_SEALS(fd, 0); 106 CHECK_MFD_ADD_SEALS(fd, F_SEAL_GROW); 107 CHECK_MFD_HAS_SEALS(fd, F_SEAL_GROW); 108 109 CHECK_MFD_READABLE(fd); 110 CHECK_MFD_WRITEABLE(fd); 111 CHECK_MFD_SHRINKABLE(fd); 112 CHECK_MFD_NON_GROWABLE(fd); 113 CHECK_MFD_NON_GROWABLE_BY_WRITE(fd); 114} 115 116/* 117 * Test SEAL_SHRINK | SEAL_GROW 118 * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing 119 */ 120static void test_seal_resize(int fd) 121{ 122 CHECK_MFD_HAS_SEALS(fd, 0); 123 CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK | F_SEAL_GROW); 124 CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK | F_SEAL_GROW); 125 126 CHECK_MFD_READABLE(fd); 127 CHECK_MFD_WRITEABLE(fd); 128 CHECK_MFD_NON_SHRINKABLE(fd); 129 CHECK_MFD_NON_GROWABLE(fd); 130 CHECK_MFD_NON_GROWABLE_BY_WRITE(fd); 131} 132 133/* 134 * Test sharing via dup() 135 * Test that seals are shared between dupped FDs and they're all equal. 136 */ 137static void test_share_dup(int fd) 138{ 139 int fd2; 140 141 CHECK_MFD_HAS_SEALS(fd, 0); 142 143 fd2 = SAFE_DUP(fd); 144 CHECK_MFD_HAS_SEALS(fd2, 0); 145 146 CHECK_MFD_ADD_SEALS(fd, F_SEAL_WRITE); 147 CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE); 148 CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE); 149 150 CHECK_MFD_ADD_SEALS(fd2, F_SEAL_SHRINK); 151 CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 152 CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 153 154 CHECK_MFD_ADD_SEALS(fd, F_SEAL_SEAL); 155 CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 156 CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 157 158 CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_GROW); 159 CHECK_MFD_FAIL_ADD_SEALS(fd2, F_SEAL_GROW); 160 CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_SEAL); 161 CHECK_MFD_FAIL_ADD_SEALS(fd2, F_SEAL_SEAL); 162 163 SAFE_CLOSE(fd2); 164 165 CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_GROW); 166} 167 168/* 169 * Test sealing with active mmap()s 170 * Modifying seals is only allowed if no other mmap() refs exist. 171 */ 172static void test_share_mmap(int fd) 173{ 174 void *p; 175 176 CHECK_MFD_HAS_SEALS(fd, 0); 177 178 /* shared/writable ref prevents sealing WRITE, but allows others */ 179 p = SAFE_MMAP(NULL, MFD_DEF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, 180 fd, 0); 181 182 CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_WRITE); 183 CHECK_MFD_HAS_SEALS(fd, 0); 184 CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK); 185 CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK); 186 SAFE_MUNMAP(p, MFD_DEF_SIZE); 187 188 /* readable ref allows sealing */ 189 p = SAFE_MMAP(NULL, MFD_DEF_SIZE, PROT_READ, MAP_PRIVATE, fd, 0); 190 CHECK_MFD_ADD_SEALS(fd, F_SEAL_WRITE); 191 CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 192 SAFE_MUNMAP(p, MFD_DEF_SIZE); 193} 194 195/* 196 * Test sealing with open(/proc/self/fd/%d) 197 * Via /proc we can get access to a separate file-context for the same memfd. 198 * This is *not* like dup(), but like a real separate open(). Make sure the 199 * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR. 200 */ 201static void test_share_open(int fd) 202{ 203 int fd2; 204 205 CHECK_MFD_HAS_SEALS(fd, 0); 206 207 fd2 = CHECK_MFD_OPEN(fd, O_RDWR, 0); 208 CHECK_MFD_ADD_SEALS(fd, F_SEAL_WRITE); 209 CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE); 210 CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE); 211 212 CHECK_MFD_ADD_SEALS(fd2, F_SEAL_SHRINK); 213 CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 214 CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 215 216 SAFE_CLOSE(fd); 217 fd = CHECK_MFD_OPEN(fd2, O_RDONLY, 0); 218 219 CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_SEAL); 220 CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 221 CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 222 223 SAFE_CLOSE(fd2); 224} 225 226 227static const struct tcase { 228 int flags; 229 void (*func)(int fd); 230 const char *desc; 231} tcases[] = { 232 {MFD_ALLOW_SEALING, &test_basic, "Basic tests + set/get seals"}, 233 {0, &test_no_sealing_without_flag, "Disabled sealing"}, 234 235 {MFD_ALLOW_SEALING, &test_seal_write, "Write seal"}, 236 {MFD_ALLOW_SEALING, &test_seal_shrink, "Shrink seal"}, 237 {MFD_ALLOW_SEALING, &test_seal_grow, "Grow seal"}, 238 {MFD_ALLOW_SEALING, &test_seal_resize, "Resize seal"}, 239 240 {MFD_ALLOW_SEALING, &test_share_dup, "Seals shared for dup"}, 241 {MFD_ALLOW_SEALING, &test_share_mmap, "Seals shared for mmap"}, 242 {MFD_ALLOW_SEALING, &test_share_open, "Seals shared for open"}, 243}; 244 245static void verify_memfd_create(unsigned int n) 246{ 247 int fd; 248 const struct tcase *tc; 249 250 tc = &tcases[n]; 251 252 tst_res(TINFO, "%s", tc->desc); 253 254 fd = CHECK_MFD_NEW(TCID, MFD_DEF_SIZE, tc->flags); 255 256 tc->func(fd); 257 258 SAFE_CLOSE(fd); 259} 260 261static void setup(void) 262{ 263 /* 264 * For now, all tests in this file require MFD_ALLOW_SEALING flag 265 * to be implemented, even though that flag isn't always set when 266 * memfd is created. So don't check anything else and TCONF right away 267 * is this flag is missing. 268 */ 269 if (!MFD_FLAGS_AVAILABLE(MFD_ALLOW_SEALING)) { 270 tst_brk(TCONF | TTERRNO, 271 "memfd_create(%u) not implemented", MFD_ALLOW_SEALING); 272 } 273} 274 275static struct tst_test test = { 276 .test = verify_memfd_create, 277 .tcnt = ARRAY_SIZE(tcases), 278 .setup = setup, 279}; 280