Linux Audio

Check our new training course

Linux BSP upgrade and security maintenance

Need help to get security updates for your Linux BSP?
Loading...
Note: File does not exist in v3.5.6.
  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/ioctl.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#ifndef PIDFS_IOCTL_MAGIC
 26#define PIDFS_IOCTL_MAGIC 0xFF
 27#endif
 28
 29#ifndef PIDFD_GET_INFO
 30#define PIDFD_GET_INFO _IOWR(PIDFS_IOCTL_MAGIC, 11, struct pidfd_info)
 31#define PIDFD_INFO_CGROUPID		(1UL << 0)
 32
 33struct pidfd_info {
 34	__u64 request_mask;
 35	__u64 cgroupid;
 36	__u32 pid;
 37	__u32 tgid;
 38	__u32 ppid;
 39	__u32 ruid;
 40	__u32 rgid;
 41	__u32 euid;
 42	__u32 egid;
 43	__u32 suid;
 44	__u32 sgid;
 45	__u32 fsuid;
 46	__u32 fsgid;
 47	__u32 spare0[1];
 48};
 49#endif
 50
 51static int safe_int(const char *numstr, int *converted)
 52{
 53	char *err = NULL;
 54	long sli;
 55
 56	errno = 0;
 57	sli = strtol(numstr, &err, 0);
 58	if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
 59		return -ERANGE;
 60
 61	if (errno != 0 && sli == 0)
 62		return -EINVAL;
 63
 64	if (err == numstr || *err != '\0')
 65		return -EINVAL;
 66
 67	if (sli > INT_MAX || sli < INT_MIN)
 68		return -ERANGE;
 69
 70	*converted = (int)sli;
 71	return 0;
 72}
 73
 74static int char_left_gc(const char *buffer, size_t len)
 75{
 76	size_t i;
 77
 78	for (i = 0; i < len; i++) {
 79		if (buffer[i] == ' ' ||
 80		    buffer[i] == '\t')
 81			continue;
 82
 83		return i;
 84	}
 85
 86	return 0;
 87}
 88
 89static int char_right_gc(const char *buffer, size_t len)
 90{
 91	int i;
 92
 93	for (i = len - 1; i >= 0; i--) {
 94		if (buffer[i] == ' '  ||
 95		    buffer[i] == '\t' ||
 96		    buffer[i] == '\n' ||
 97		    buffer[i] == '\0')
 98			continue;
 99
100		return i + 1;
101	}
102
103	return 0;
104}
105
106static char *trim_whitespace_in_place(char *buffer)
107{
108	buffer += char_left_gc(buffer, strlen(buffer));
109	buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
110	return buffer;
111}
112
113static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen)
114{
115	int ret;
116	char path[512];
117	FILE *f;
118	size_t n = 0;
119	pid_t result = -1;
120	char *line = NULL;
121
122	snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
123
124	f = fopen(path, "re");
125	if (!f)
126		return -1;
127
128	while (getline(&line, &n, f) != -1) {
129		char *numstr;
130
131		if (strncmp(line, key, keylen))
132			continue;
133
134		numstr = trim_whitespace_in_place(line + 4);
135		ret = safe_int(numstr, &result);
136		if (ret < 0)
137			goto out;
138
139		break;
140	}
141
142out:
143	free(line);
144	fclose(f);
145	return result;
146}
147
148int main(int argc, char **argv)
149{
150	struct pidfd_info info = {
151		.request_mask = PIDFD_INFO_CGROUPID,
152	};
153	int pidfd = -1, ret = 1;
154	pid_t pid;
155
156	ksft_set_plan(4);
157
158	pidfd = sys_pidfd_open(-1, 0);
159	if (pidfd >= 0) {
160		ksft_print_msg(
161			"%s - succeeded to open pidfd for invalid pid -1\n",
162			strerror(errno));
163		goto on_error;
164	}
165	ksft_test_result_pass("do not allow invalid pid test: passed\n");
166
167	pidfd = sys_pidfd_open(getpid(), 1);
168	if (pidfd >= 0) {
169		ksft_print_msg(
170			"%s - succeeded to open pidfd with invalid flag value specified\n",
171			strerror(errno));
172		goto on_error;
173	}
174	ksft_test_result_pass("do not allow invalid flag test: passed\n");
175
176	pidfd = sys_pidfd_open(getpid(), 0);
177	if (pidfd < 0) {
178		ksft_print_msg("%s - failed to open pidfd\n", strerror(errno));
179		goto on_error;
180	}
181	ksft_test_result_pass("open a new pidfd test: passed\n");
182
183	pid = get_pid_from_fdinfo_file(pidfd, "Pid:", sizeof("Pid:") - 1);
184	ksft_print_msg("pidfd %d refers to process with pid %d\n", pidfd, pid);
185
186	if (ioctl(pidfd, PIDFD_GET_INFO, &info) < 0) {
187		ksft_print_msg("%s - failed to get info from pidfd\n", strerror(errno));
188		goto on_error;
189	}
190	if (info.pid != pid) {
191		ksft_print_msg("pid from fdinfo file %d does not match pid from ioctl %d\n",
192			       pid, info.pid);
193		goto on_error;
194	}
195	if (info.ppid != getppid()) {
196		ksft_print_msg("ppid %d does not match ppid from ioctl %d\n",
197			       pid, info.pid);
198		goto on_error;
199	}
200	if (info.ruid != getuid()) {
201		ksft_print_msg("uid %d does not match uid from ioctl %d\n",
202			       getuid(), info.ruid);
203		goto on_error;
204	}
205	if (info.rgid != getgid()) {
206		ksft_print_msg("gid %d does not match gid from ioctl %d\n",
207			       getgid(), info.rgid);
208		goto on_error;
209	}
210	if (info.euid != geteuid()) {
211		ksft_print_msg("euid %d does not match euid from ioctl %d\n",
212			       geteuid(), info.euid);
213		goto on_error;
214	}
215	if (info.egid != getegid()) {
216		ksft_print_msg("egid %d does not match egid from ioctl %d\n",
217			       getegid(), info.egid);
218		goto on_error;
219	}
220	if (info.suid != geteuid()) {
221		ksft_print_msg("suid %d does not match suid from ioctl %d\n",
222			       geteuid(), info.suid);
223		goto on_error;
224	}
225	if (info.sgid != getegid()) {
226		ksft_print_msg("sgid %d does not match sgid from ioctl %d\n",
227			       getegid(), info.sgid);
228		goto on_error;
229	}
230	if ((info.request_mask & PIDFD_INFO_CGROUPID) && info.cgroupid == 0) {
231		ksft_print_msg("cgroupid should not be 0 when PIDFD_INFO_CGROUPID is set\n");
232		goto on_error;
233	}
234	ksft_test_result_pass("get info from pidfd test: passed\n");
235
236	ret = 0;
237
238on_error:
239	if (pidfd >= 0)
240		close(pidfd);
241
242	if (ret)
243		ksft_exit_fail();
244	ksft_exit_pass();
245}