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