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