1b28a10aeSAleksa Sarai // SPDX-License-Identifier: GPL-2.0-or-later
2b28a10aeSAleksa Sarai /*
3b28a10aeSAleksa Sarai  * Author: Aleksa Sarai <cyphar@cyphar.com>
4b28a10aeSAleksa Sarai  * Copyright (C) 2018-2019 SUSE LLC.
5b28a10aeSAleksa Sarai  */
6b28a10aeSAleksa Sarai 
7b28a10aeSAleksa Sarai #define _GNU_SOURCE
8b28a10aeSAleksa Sarai #include <errno.h>
9b28a10aeSAleksa Sarai #include <fcntl.h>
10b28a10aeSAleksa Sarai #include <stdbool.h>
11b28a10aeSAleksa Sarai #include <string.h>
12b28a10aeSAleksa Sarai #include <syscall.h>
13b28a10aeSAleksa Sarai #include <limits.h>
14b28a10aeSAleksa Sarai 
15b28a10aeSAleksa Sarai #include "helpers.h"
16b28a10aeSAleksa Sarai 
needs_openat2(const struct open_how * how)17b28a10aeSAleksa Sarai bool needs_openat2(const struct open_how *how)
18b28a10aeSAleksa Sarai {
19b28a10aeSAleksa Sarai 	return how->resolve != 0;
20b28a10aeSAleksa Sarai }
21b28a10aeSAleksa Sarai 
raw_openat2(int dfd,const char * path,void * how,size_t size)22b28a10aeSAleksa Sarai int raw_openat2(int dfd, const char *path, void *how, size_t size)
23b28a10aeSAleksa Sarai {
24b28a10aeSAleksa Sarai 	int ret = syscall(__NR_openat2, dfd, path, how, size);
25b28a10aeSAleksa Sarai 	return ret >= 0 ? ret : -errno;
26b28a10aeSAleksa Sarai }
27b28a10aeSAleksa Sarai 
sys_openat2(int dfd,const char * path,struct open_how * how)28b28a10aeSAleksa Sarai int sys_openat2(int dfd, const char *path, struct open_how *how)
29b28a10aeSAleksa Sarai {
30b28a10aeSAleksa Sarai 	return raw_openat2(dfd, path, how, sizeof(*how));
31b28a10aeSAleksa Sarai }
32b28a10aeSAleksa Sarai 
sys_openat(int dfd,const char * path,struct open_how * how)33b28a10aeSAleksa Sarai int sys_openat(int dfd, const char *path, struct open_how *how)
34b28a10aeSAleksa Sarai {
35b28a10aeSAleksa Sarai 	int ret = openat(dfd, path, how->flags, how->mode);
36b28a10aeSAleksa Sarai 	return ret >= 0 ? ret : -errno;
37b28a10aeSAleksa Sarai }
38b28a10aeSAleksa Sarai 
sys_renameat2(int olddirfd,const char * oldpath,int newdirfd,const char * newpath,unsigned int flags)39b28a10aeSAleksa Sarai int sys_renameat2(int olddirfd, const char *oldpath,
40b28a10aeSAleksa Sarai 		  int newdirfd, const char *newpath, unsigned int flags)
41b28a10aeSAleksa Sarai {
42b28a10aeSAleksa Sarai 	int ret = syscall(__NR_renameat2, olddirfd, oldpath,
43b28a10aeSAleksa Sarai 					  newdirfd, newpath, flags);
44b28a10aeSAleksa Sarai 	return ret >= 0 ? ret : -errno;
45b28a10aeSAleksa Sarai }
46b28a10aeSAleksa Sarai 
touchat(int dfd,const char * path)47b28a10aeSAleksa Sarai int touchat(int dfd, const char *path)
48b28a10aeSAleksa Sarai {
499a0584f0SAleksa Sarai 	int fd = openat(dfd, path, O_CREAT, 0700);
50b28a10aeSAleksa Sarai 	if (fd >= 0)
51b28a10aeSAleksa Sarai 		close(fd);
52b28a10aeSAleksa Sarai 	return fd;
53b28a10aeSAleksa Sarai }
54b28a10aeSAleksa Sarai 
fdreadlink(int fd)55b28a10aeSAleksa Sarai char *fdreadlink(int fd)
56b28a10aeSAleksa Sarai {
57b28a10aeSAleksa Sarai 	char *target, *tmp;
58b28a10aeSAleksa Sarai 
59b28a10aeSAleksa Sarai 	E_asprintf(&tmp, "/proc/self/fd/%d", fd);
60b28a10aeSAleksa Sarai 
61b28a10aeSAleksa Sarai 	target = malloc(PATH_MAX);
62b28a10aeSAleksa Sarai 	if (!target)
63b28a10aeSAleksa Sarai 		ksft_exit_fail_msg("fdreadlink: malloc failed\n");
64b28a10aeSAleksa Sarai 	memset(target, 0, PATH_MAX);
65b28a10aeSAleksa Sarai 
66b28a10aeSAleksa Sarai 	E_readlink(tmp, target, PATH_MAX);
67b28a10aeSAleksa Sarai 	free(tmp);
68b28a10aeSAleksa Sarai 	return target;
69b28a10aeSAleksa Sarai }
70b28a10aeSAleksa Sarai 
fdequal(int fd,int dfd,const char * path)71b28a10aeSAleksa Sarai bool fdequal(int fd, int dfd, const char *path)
72b28a10aeSAleksa Sarai {
73b28a10aeSAleksa Sarai 	char *fdpath, *dfdpath, *other;
74b28a10aeSAleksa Sarai 	bool cmp;
75b28a10aeSAleksa Sarai 
76b28a10aeSAleksa Sarai 	fdpath = fdreadlink(fd);
77b28a10aeSAleksa Sarai 	dfdpath = fdreadlink(dfd);
78b28a10aeSAleksa Sarai 
79b28a10aeSAleksa Sarai 	if (!path)
80b28a10aeSAleksa Sarai 		E_asprintf(&other, "%s", dfdpath);
81b28a10aeSAleksa Sarai 	else if (*path == '/')
82b28a10aeSAleksa Sarai 		E_asprintf(&other, "%s", path);
83b28a10aeSAleksa Sarai 	else
84b28a10aeSAleksa Sarai 		E_asprintf(&other, "%s/%s", dfdpath, path);
85b28a10aeSAleksa Sarai 
86b28a10aeSAleksa Sarai 	cmp = !strcmp(fdpath, other);
87b28a10aeSAleksa Sarai 
88b28a10aeSAleksa Sarai 	free(fdpath);
89b28a10aeSAleksa Sarai 	free(dfdpath);
90b28a10aeSAleksa Sarai 	free(other);
91b28a10aeSAleksa Sarai 	return cmp;
92b28a10aeSAleksa Sarai }
93b28a10aeSAleksa Sarai 
94b28a10aeSAleksa Sarai bool openat2_supported = false;
95b28a10aeSAleksa Sarai 
init(void)96b28a10aeSAleksa Sarai void __attribute__((constructor)) init(void)
97b28a10aeSAleksa Sarai {
98b28a10aeSAleksa Sarai 	struct open_how how = {};
99b28a10aeSAleksa Sarai 	int fd;
100b28a10aeSAleksa Sarai 
101b28a10aeSAleksa Sarai 	BUILD_BUG_ON(sizeof(struct open_how) != OPEN_HOW_SIZE_VER0);
102b28a10aeSAleksa Sarai 
103b28a10aeSAleksa Sarai 	/* Check openat2(2) support. */
104b28a10aeSAleksa Sarai 	fd = sys_openat2(AT_FDCWD, ".", &how);
105b28a10aeSAleksa Sarai 	openat2_supported = (fd >= 0);
106b28a10aeSAleksa Sarai 
107b28a10aeSAleksa Sarai 	if (fd >= 0)
108b28a10aeSAleksa Sarai 		close(fd);
109b28a10aeSAleksa Sarai }
110