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