1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2021 SUSE LLC <mdoucha@suse.cz> 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci/*\ 7f08c3bdfSopenharmony_ci * [Description] 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Check for potential issues in writev() if the first iovec entry is NULL 10f08c3bdfSopenharmony_ci * and the next one is not present in RAM. This can result in a brief window 11f08c3bdfSopenharmony_ci * where writev() first writes uninitialized data into the file (possibly 12f08c3bdfSopenharmony_ci * exposing internal kernel structures) and then overwrites it with the real 13f08c3bdfSopenharmony_ci * iovec contents later. 14f08c3bdfSopenharmony_ci */ 15f08c3bdfSopenharmony_ci 16f08c3bdfSopenharmony_ci/* 17f08c3bdfSopenharmony_ci * Bugs fixed in: 18f08c3bdfSopenharmony_ci * commit d4690f1e1cdabb4d61207b6787b1605a0dc0aeab 19f08c3bdfSopenharmony_ci * Author: Al Viro <viro@ZenIV.linux.org.uk> 20f08c3bdfSopenharmony_ci * Date: Fri Sep 16 00:11:45 2016 +0100 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * fix iov_iter_fault_in_readable() 23f08c3bdfSopenharmony_ci */ 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#include <sys/uio.h> 26f08c3bdfSopenharmony_ci#include "tst_test.h" 27f08c3bdfSopenharmony_ci#include "tst_atomic.h" 28f08c3bdfSopenharmony_ci#include "tst_fuzzy_sync.h" 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_ci#define CHUNK_SIZE 256 31f08c3bdfSopenharmony_ci#define BUF_SIZE (2 * CHUNK_SIZE) 32f08c3bdfSopenharmony_ci#define MNTPOINT "mntpoint" 33f08c3bdfSopenharmony_ci#define TEMPFILE MNTPOINT "/test_file" 34f08c3bdfSopenharmony_ci#define MAPFILE MNTPOINT "/map_file" 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_cistatic unsigned char buf[BUF_SIZE], *map_ptr; 37f08c3bdfSopenharmony_cistatic int mapfd = -1, writefd = -1, readfd = -1; 38f08c3bdfSopenharmony_cistatic int written; 39f08c3bdfSopenharmony_cistatic struct tst_fzsync_pair fzsync_pair; 40f08c3bdfSopenharmony_cistruct iovec iov[5]; 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_cistatic void setup(void) 43f08c3bdfSopenharmony_ci{ 44f08c3bdfSopenharmony_ci int i; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci for (i = 0; i < BUF_SIZE; i++) 47f08c3bdfSopenharmony_ci buf[i] = i & 0xff; 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci mapfd = SAFE_OPEN(MAPFILE, O_CREAT|O_RDWR|O_TRUNC, 0644); 50f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, mapfd, buf, BUF_SIZE); 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_ci tst_fzsync_pair_init(&fzsync_pair); 53f08c3bdfSopenharmony_ci} 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_cistatic void *thread_run(void *arg) 56f08c3bdfSopenharmony_ci{ 57f08c3bdfSopenharmony_ci while (tst_fzsync_run_b(&fzsync_pair)) { 58f08c3bdfSopenharmony_ci writefd = SAFE_OPEN(TEMPFILE, O_CREAT|O_WRONLY|O_TRUNC, 0644); 59f08c3bdfSopenharmony_ci written = BUF_SIZE; 60f08c3bdfSopenharmony_ci tst_fzsync_wait_b(&fzsync_pair); 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci /* 63f08c3bdfSopenharmony_ci * Do *NOT* preload the data using MAP_POPULATE or touching 64f08c3bdfSopenharmony_ci * the mapped range. We're testing whether writev() handles 65f08c3bdfSopenharmony_ci * fault-in correctly. 66f08c3bdfSopenharmony_ci */ 67f08c3bdfSopenharmony_ci map_ptr = SAFE_MMAP(NULL, BUF_SIZE, PROT_READ, MAP_SHARED, 68f08c3bdfSopenharmony_ci mapfd, 0); 69f08c3bdfSopenharmony_ci iov[1].iov_base = map_ptr; 70f08c3bdfSopenharmony_ci iov[1].iov_len = CHUNK_SIZE; 71f08c3bdfSopenharmony_ci iov[3].iov_base = map_ptr + CHUNK_SIZE; 72f08c3bdfSopenharmony_ci iov[3].iov_len = CHUNK_SIZE; 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci tst_fzsync_start_race_b(&fzsync_pair); 75f08c3bdfSopenharmony_ci tst_atomic_store(writev(writefd, iov, ARRAY_SIZE(iov)), 76f08c3bdfSopenharmony_ci &written); 77f08c3bdfSopenharmony_ci tst_fzsync_end_race_b(&fzsync_pair); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci SAFE_MUNMAP(map_ptr, BUF_SIZE); 80f08c3bdfSopenharmony_ci map_ptr = NULL; 81f08c3bdfSopenharmony_ci SAFE_CLOSE(writefd); 82f08c3bdfSopenharmony_ci } 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci return arg; 85f08c3bdfSopenharmony_ci} 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_cistatic void run(void) 88f08c3bdfSopenharmony_ci{ 89f08c3bdfSopenharmony_ci int total_read; 90f08c3bdfSopenharmony_ci unsigned char readbuf[BUF_SIZE + 1]; 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci tst_fzsync_pair_reset(&fzsync_pair, thread_run); 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci while (tst_fzsync_run_a(&fzsync_pair)) { 95f08c3bdfSopenharmony_ci tst_fzsync_wait_a(&fzsync_pair); 96f08c3bdfSopenharmony_ci readfd = SAFE_OPEN(TEMPFILE, O_RDONLY); 97f08c3bdfSopenharmony_ci tst_fzsync_start_race_a(&fzsync_pair); 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci for (total_read = 0; total_read < tst_atomic_load(&written);) { 100f08c3bdfSopenharmony_ci total_read += SAFE_READ(0, readfd, readbuf+total_read, 101f08c3bdfSopenharmony_ci BUF_SIZE + 1 - total_read); 102f08c3bdfSopenharmony_ci } 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_ci tst_fzsync_end_race_a(&fzsync_pair); 105f08c3bdfSopenharmony_ci SAFE_CLOSE(readfd); 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_ci if (total_read > BUF_SIZE) 108f08c3bdfSopenharmony_ci tst_brk(TBROK, "writev() wrote too much data"); 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ci if (total_read <= 0) 111f08c3bdfSopenharmony_ci continue; 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci if (memcmp(readbuf, buf, total_read)) { 114f08c3bdfSopenharmony_ci tst_res(TFAIL, "writev() wrote invalid data"); 115f08c3bdfSopenharmony_ci return; 116f08c3bdfSopenharmony_ci } 117f08c3bdfSopenharmony_ci } 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci tst_res(TPASS, "writev() handles page fault-in correctly"); 120f08c3bdfSopenharmony_ci} 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_cistatic void cleanup(void) 123f08c3bdfSopenharmony_ci{ 124f08c3bdfSopenharmony_ci if (map_ptr && map_ptr != MAP_FAILED) 125f08c3bdfSopenharmony_ci SAFE_MUNMAP(map_ptr, BUF_SIZE); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci if (mapfd >= 0) 128f08c3bdfSopenharmony_ci SAFE_CLOSE(mapfd); 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci if (readfd >= 0) 131f08c3bdfSopenharmony_ci SAFE_CLOSE(readfd); 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci if (writefd >= 0) 134f08c3bdfSopenharmony_ci SAFE_CLOSE(writefd); 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_ci tst_fzsync_pair_cleanup(&fzsync_pair); 137f08c3bdfSopenharmony_ci} 138f08c3bdfSopenharmony_ci 139f08c3bdfSopenharmony_cistatic struct tst_test test = { 140f08c3bdfSopenharmony_ci .test_all = run, 141f08c3bdfSopenharmony_ci .needs_root = 1, 142f08c3bdfSopenharmony_ci .mount_device = 1, 143f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 144f08c3bdfSopenharmony_ci .all_filesystems = 1, 145f08c3bdfSopenharmony_ci .min_cpus = 2, 146f08c3bdfSopenharmony_ci .setup = setup, 147f08c3bdfSopenharmony_ci .cleanup = cleanup, 148f08c3bdfSopenharmony_ci .max_runtime = 75, 149f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 150f08c3bdfSopenharmony_ci {"linux-git", "d4690f1e1cda"}, 151f08c3bdfSopenharmony_ci {} 152f08c3bdfSopenharmony_ci } 153f08c3bdfSopenharmony_ci}; 154