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