1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 #include <errno.h> 5 #include <fcntl.h> 6 #include <inttypes.h> 7 #include <limits.h> 8 #include <linux/types.h> 9 #include <linux/wait.h> 10 #include <sched.h> 11 #include <signal.h> 12 #include <stdbool.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <syscall.h> 17 #include <sys/mount.h> 18 #include <sys/prctl.h> 19 #include <sys/wait.h> 20 #include <unistd.h> 21 22 #include "pidfd.h" 23 #include "../kselftest.h" 24 25 static inline int sys_pidfd_open(pid_t pid, unsigned int flags) 26 { 27 return syscall(__NR_pidfd_open, pid, flags); 28 } 29 30 static int safe_int(const char *numstr, int *converted) 31 { 32 char *err = NULL; 33 long sli; 34 35 errno = 0; 36 sli = strtol(numstr, &err, 0); 37 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) 38 return -ERANGE; 39 40 if (errno != 0 && sli == 0) 41 return -EINVAL; 42 43 if (err == numstr || *err != '\0') 44 return -EINVAL; 45 46 if (sli > INT_MAX || sli < INT_MIN) 47 return -ERANGE; 48 49 *converted = (int)sli; 50 return 0; 51 } 52 53 static int char_left_gc(const char *buffer, size_t len) 54 { 55 size_t i; 56 57 for (i = 0; i < len; i++) { 58 if (buffer[i] == ' ' || 59 buffer[i] == '\t') 60 continue; 61 62 return i; 63 } 64 65 return 0; 66 } 67 68 static int char_right_gc(const char *buffer, size_t len) 69 { 70 int i; 71 72 for (i = len - 1; i >= 0; i--) { 73 if (buffer[i] == ' ' || 74 buffer[i] == '\t' || 75 buffer[i] == '\n' || 76 buffer[i] == '\0') 77 continue; 78 79 return i + 1; 80 } 81 82 return 0; 83 } 84 85 static char *trim_whitespace_in_place(char *buffer) 86 { 87 buffer += char_left_gc(buffer, strlen(buffer)); 88 buffer[char_right_gc(buffer, strlen(buffer))] = '\0'; 89 return buffer; 90 } 91 92 static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen) 93 { 94 int ret; 95 char path[512]; 96 FILE *f; 97 size_t n = 0; 98 pid_t result = -1; 99 char *line = NULL; 100 101 snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd); 102 103 f = fopen(path, "re"); 104 if (!f) 105 return -1; 106 107 while (getline(&line, &n, f) != -1) { 108 char *numstr; 109 110 if (strncmp(line, key, keylen)) 111 continue; 112 113 numstr = trim_whitespace_in_place(line + 4); 114 ret = safe_int(numstr, &result); 115 if (ret < 0) 116 goto out; 117 118 break; 119 } 120 121 out: 122 free(line); 123 fclose(f); 124 return result; 125 } 126 127 int main(int argc, char **argv) 128 { 129 int pidfd = -1, ret = 1; 130 pid_t pid; 131 132 ksft_set_plan(3); 133 134 pidfd = sys_pidfd_open(-1, 0); 135 if (pidfd >= 0) { 136 ksft_print_msg( 137 "%s - succeeded to open pidfd for invalid pid -1\n", 138 strerror(errno)); 139 goto on_error; 140 } 141 ksft_test_result_pass("do not allow invalid pid test: passed\n"); 142 143 pidfd = sys_pidfd_open(getpid(), 1); 144 if (pidfd >= 0) { 145 ksft_print_msg( 146 "%s - succeeded to open pidfd with invalid flag value specified\n", 147 strerror(errno)); 148 goto on_error; 149 } 150 ksft_test_result_pass("do not allow invalid flag test: passed\n"); 151 152 pidfd = sys_pidfd_open(getpid(), 0); 153 if (pidfd < 0) { 154 ksft_print_msg("%s - failed to open pidfd\n", strerror(errno)); 155 goto on_error; 156 } 157 ksft_test_result_pass("open a new pidfd test: passed\n"); 158 159 pid = get_pid_from_fdinfo_file(pidfd, "Pid:", sizeof("Pid:") - 1); 160 ksft_print_msg("pidfd %d refers to process with pid %d\n", pidfd, pid); 161 162 ret = 0; 163 164 on_error: 165 if (pidfd >= 0) 166 close(pidfd); 167 168 return !ret ? ksft_exit_pass() : ksft_exit_fail(); 169 } 170