162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Author: Aleksa Sarai <cyphar@cyphar.com> 462306a36Sopenharmony_ci * Copyright (C) 2018-2019 SUSE LLC. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#define _GNU_SOURCE 862306a36Sopenharmony_ci#include <errno.h> 962306a36Sopenharmony_ci#include <fcntl.h> 1062306a36Sopenharmony_ci#include <stdbool.h> 1162306a36Sopenharmony_ci#include <string.h> 1262306a36Sopenharmony_ci#include <syscall.h> 1362306a36Sopenharmony_ci#include <limits.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "helpers.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cibool needs_openat2(const struct open_how *how) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci return how->resolve != 0; 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciint raw_openat2(int dfd, const char *path, void *how, size_t size) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci int ret = syscall(__NR_openat2, dfd, path, how, size); 2562306a36Sopenharmony_ci return ret >= 0 ? ret : -errno; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciint sys_openat2(int dfd, const char *path, struct open_how *how) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci return raw_openat2(dfd, path, how, sizeof(*how)); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciint sys_openat(int dfd, const char *path, struct open_how *how) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci int ret = openat(dfd, path, how->flags, how->mode); 3662306a36Sopenharmony_ci return ret >= 0 ? ret : -errno; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciint sys_renameat2(int olddirfd, const char *oldpath, 4062306a36Sopenharmony_ci int newdirfd, const char *newpath, unsigned int flags) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci int ret = syscall(__NR_renameat2, olddirfd, oldpath, 4362306a36Sopenharmony_ci newdirfd, newpath, flags); 4462306a36Sopenharmony_ci return ret >= 0 ? ret : -errno; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciint touchat(int dfd, const char *path) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci int fd = openat(dfd, path, O_CREAT, 0700); 5062306a36Sopenharmony_ci if (fd >= 0) 5162306a36Sopenharmony_ci close(fd); 5262306a36Sopenharmony_ci return fd; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cichar *fdreadlink(int fd) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci char *target, *tmp; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci E_asprintf(&tmp, "/proc/self/fd/%d", fd); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci target = malloc(PATH_MAX); 6262306a36Sopenharmony_ci if (!target) 6362306a36Sopenharmony_ci ksft_exit_fail_msg("fdreadlink: malloc failed\n"); 6462306a36Sopenharmony_ci memset(target, 0, PATH_MAX); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci E_readlink(tmp, target, PATH_MAX); 6762306a36Sopenharmony_ci free(tmp); 6862306a36Sopenharmony_ci return target; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cibool fdequal(int fd, int dfd, const char *path) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci char *fdpath, *dfdpath, *other; 7462306a36Sopenharmony_ci bool cmp; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci fdpath = fdreadlink(fd); 7762306a36Sopenharmony_ci dfdpath = fdreadlink(dfd); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!path) 8062306a36Sopenharmony_ci E_asprintf(&other, "%s", dfdpath); 8162306a36Sopenharmony_ci else if (*path == '/') 8262306a36Sopenharmony_ci E_asprintf(&other, "%s", path); 8362306a36Sopenharmony_ci else 8462306a36Sopenharmony_ci E_asprintf(&other, "%s/%s", dfdpath, path); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci cmp = !strcmp(fdpath, other); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci free(fdpath); 8962306a36Sopenharmony_ci free(dfdpath); 9062306a36Sopenharmony_ci free(other); 9162306a36Sopenharmony_ci return cmp; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cibool openat2_supported = false; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid __attribute__((constructor)) init(void) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct open_how how = {}; 9962306a36Sopenharmony_ci int fd; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct open_how) != OPEN_HOW_SIZE_VER0); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Check openat2(2) support. */ 10462306a36Sopenharmony_ci fd = sys_openat2(AT_FDCWD, ".", &how); 10562306a36Sopenharmony_ci openat2_supported = (fd >= 0); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (fd >= 0) 10862306a36Sopenharmony_ci close(fd); 10962306a36Sopenharmony_ci} 110