1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) International Business Machines Corp., 2012 4 * Copyright (c) Linux Test Project, 2012 5 * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> 6 */ 7 8/*\ 9 * [Description] 10 * 11 * Fork two children, one child allocates memory and initializes it; 12 * then the other one calls process_vm_readv and reads from the same 13 * memory location, it then verifies if process_vm_readv returns 14 * correct data. 15 */ 16 17#include <stdio.h> 18#include <sys/types.h> 19#include <sys/wait.h> 20#include "tst_test.h" 21#include "lapi/syscalls.h" 22 23static uintptr_t *data_ptr; 24 25static void child_alloc(const char *data) 26{ 27 char *foo; 28 29 foo = strdup(data); 30 *data_ptr = (uintptr_t)foo; 31 32 tst_res(TINFO, "child 0: memory allocated and initialized"); 33 34 /* wake and wait until child_invoke is done reading from our VM */ 35 TST_CHECKPOINT_WAKE_AND_WAIT(0); 36} 37 38static void child_invoke(const char *data, int length, pid_t pid_alloc) 39{ 40 char *lp; 41 struct iovec local, remote; 42 43 lp = SAFE_MALLOC(length); 44 local.iov_base = lp; 45 local.iov_len = length; 46 remote.iov_base = (void *)*data_ptr; 47 remote.iov_len = length; 48 49 tst_res(TINFO, "child 1: reading string from same memory location"); 50 51 TEST(tst_syscall(__NR_process_vm_readv, pid_alloc, &local, 1UL, &remote, 52 1UL, 0UL)); 53 54 if (TST_RET != length) 55 tst_brk(TBROK, "process_vm_readv: %s", tst_strerrno(-TST_RET)); 56 57 if (strncmp(lp, data, length) != 0) 58 tst_res(TFAIL, "child 1: expected string: %s, received string: %256s", 59 data, lp); 60 else 61 tst_res(TPASS, "expected string received"); 62} 63 64static void setup(void) 65{ 66 /* Just a sanity check of the existence of syscall */ 67 tst_syscall(__NR_process_vm_readv, getpid(), NULL, 0UL, NULL, 0UL, 0UL); 68 69 data_ptr = SAFE_MMAP(NULL, sizeof(uintptr_t), PROT_READ | PROT_WRITE, 70 MAP_SHARED | MAP_ANONYMOUS, -1, 0); 71} 72 73static void cleanup(void) 74{ 75 if (data_ptr) 76 SAFE_MUNMAP(data_ptr, sizeof(uintptr_t)); 77} 78 79static void run(void) 80{ 81 const char *data = "test"; 82 pid_t pid_alloc; 83 pid_t pid_invoke; 84 int length; 85 int status; 86 87 length = strlen(data); 88 89 pid_alloc = SAFE_FORK(); 90 if (!pid_alloc) { 91 child_alloc(data); 92 return; 93 } 94 95 /* wait until child_alloc has allocated VM */ 96 TST_CHECKPOINT_WAIT(0); 97 98 pid_invoke = SAFE_FORK(); 99 if (!pid_invoke) { 100 child_invoke(data, length, pid_alloc); 101 return; 102 } 103 104 /* wait until child_invoke reads from child_alloc's VM */ 105 SAFE_WAITPID(pid_invoke, &status, 0); 106 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 107 tst_res(TFAIL, "child 1: %s", tst_strstatus(status)); 108 109 /* child_alloc is free to exit now */ 110 TST_CHECKPOINT_WAKE(0); 111 112 SAFE_WAITPID(pid_alloc, &status, 0); 113 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 114 tst_res(TFAIL, "child 0: %s", tst_strstatus(status)); 115} 116 117static struct tst_test test = { 118 .test_all = run, 119 .setup = setup, 120 .cleanup = cleanup, 121 .forks_child = 1, 122 .needs_checkpoints = 1, 123}; 124