1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-08 21:17:47 +03:00

Merge pull request #19997 from keszybz/selinux-opt

Drop libselinux dependency from libsystemd
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-06-24 15:07:29 +02:00 committed by GitHub
commit c1e4c62235
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 1015 additions and 1123 deletions

3
docs/.gitignore vendored
View File

@ -1 +1,2 @@
_site
/_site/
/.jekyll-cache/

View File

@ -1707,7 +1707,6 @@ install_libsystemd_static = static_library(
libcap,
libblkid,
libmount,
libselinux,
libgcrypt],
c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC']))

View File

@ -1,40 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "dlfcn-util.h"
int dlsym_many_and_warn(void *dl, int level, ...) {
va_list ap;
int r;
/* Tries to resolve a bunch of function symbols, and logs errors about the ones it cannot
* resolve. Note that this function possibly modifies the supplied function pointers if the whole
* operation fails */
va_start(ap, level);
for (;;) {
void (**fn)(void);
void (*tfn)(void);
const char *symbol;
fn = va_arg(ap, typeof(fn));
if (!fn)
break;
symbol = va_arg(ap, typeof(symbol));
tfn = (typeof(tfn)) dlsym(dl, symbol);
if (!tfn) {
r = log_full_errno(level,
SYNTHETIC_ERRNO(ELIBBAD),
"Can't find symbol %s: %s", symbol, dlerror());
va_end(ap);
return r;
}
*fn = tfn;
}
va_end(ap);
return 0;
}

View File

@ -1,16 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dlfcn.h>
#include "macro.h"
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(void*, dlclose, NULL);
int dlsym_many_and_warn(void *dl, int level, ...);
/* Macro useful for putting together variable/symbol name pairs when calling dlsym_many_and_warn(). Assumes
* that each library symbol to resolve will be placed in a variable with the "sym_" prefix, i.e. a symbol
* "foobar" is loaded into a variable "sym_foobar". */
#define DLSYM_ARG(arg) \
&sym_##arg, STRINGIFY(arg)

View File

@ -2,19 +2,20 @@
#include <errno.h>
#include <fcntl.h>
#include <linux/btrfs.h>
#include <linux/magic.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <unistd.h>
#include "alloc-util.h"
#include "copy.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "io-util.h"
#include "macro.h"
#include "memfd-util.h"
#include "missing_fcntl.h"
#include "missing_syscall.h"
#include "parse-util.h"
@ -520,343 +521,6 @@ int move_fd(int from, int to, int cloexec) {
return to;
}
int acquire_data_fd(const void *data, size_t size, unsigned flags) {
_cleanup_close_pair_ int pipefds[2] = { -1, -1 };
char pattern[] = "/dev/shm/data-fd-XXXXXX";
_cleanup_close_ int fd = -1;
int isz = 0, r;
ssize_t n;
off_t f;
assert(data || size == 0);
/* Acquire a read-only file descriptor that when read from returns the specified data. This is much more
* complex than I wish it was. But here's why:
*
* a) First we try to use memfds. They are the best option, as we can seal them nicely to make them
* read-only. Unfortunately they require kernel 3.17, and at the time of writing we still support 3.14.
*
* b) Then, we try classic pipes. They are the second best options, as we can close the writing side, retaining
* a nicely read-only fd in the reading side. However, they are by default quite small, and unprivileged
* clients can only bump their size to a system-wide limit, which might be quite low.
*
* c) Then, we try an O_TMPFILE file in /dev/shm (that dir is the only suitable one known to exist from
* earliest boot on). To make it read-only we open the fd a second time with O_RDONLY via
* /proc/self/<fd>. Unfortunately O_TMPFILE is not available on older kernels on tmpfs.
*
* d) Finally, we try creating a regular file in /dev/shm, which we then delete.
*
* It sucks a bit that depending on the situation we return very different objects here, but that's Linux I
* figure. */
if (size == 0 && ((flags & ACQUIRE_NO_DEV_NULL) == 0)) {
/* As a special case, return /dev/null if we have been called for an empty data block */
r = open("/dev/null", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (r < 0)
return -errno;
return r;
}
if ((flags & ACQUIRE_NO_MEMFD) == 0) {
fd = memfd_new("data-fd");
if (fd < 0)
goto try_pipe;
n = write(fd, data, size);
if (n < 0)
return -errno;
if ((size_t) n != size)
return -EIO;
f = lseek(fd, 0, SEEK_SET);
if (f != 0)
return -errno;
r = memfd_set_sealed(fd);
if (r < 0)
return r;
return TAKE_FD(fd);
}
try_pipe:
if ((flags & ACQUIRE_NO_PIPE) == 0) {
if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
return -errno;
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
if ((size_t) isz < size) {
isz = (int) size;
if (isz < 0 || (size_t) isz != size)
return -E2BIG;
/* Try to bump the pipe size */
(void) fcntl(pipefds[1], F_SETPIPE_SZ, isz);
/* See if that worked */
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
if ((size_t) isz < size)
goto try_dev_shm;
}
n = write(pipefds[1], data, size);
if (n < 0)
return -errno;
if ((size_t) n != size)
return -EIO;
(void) fd_nonblock(pipefds[0], false);
return TAKE_FD(pipefds[0]);
}
try_dev_shm:
if ((flags & ACQUIRE_NO_TMPFILE) == 0) {
fd = open("/dev/shm", O_RDWR|O_TMPFILE|O_CLOEXEC, 0500);
if (fd < 0)
goto try_dev_shm_without_o_tmpfile;
n = write(fd, data, size);
if (n < 0)
return -errno;
if ((size_t) n != size)
return -EIO;
/* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
return fd_reopen(fd, O_RDONLY|O_CLOEXEC);
}
try_dev_shm_without_o_tmpfile:
if ((flags & ACQUIRE_NO_REGULAR) == 0) {
fd = mkostemp_safe(pattern);
if (fd < 0)
return fd;
n = write(fd, data, size);
if (n < 0) {
r = -errno;
goto unlink_and_return;
}
if ((size_t) n != size) {
r = -EIO;
goto unlink_and_return;
}
/* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
r = open(pattern, O_RDONLY|O_CLOEXEC);
if (r < 0)
r = -errno;
unlink_and_return:
(void) unlink(pattern);
return r;
}
return -EOPNOTSUPP;
}
/* When the data is smaller or equal to 64K, try to place the copy in a memfd/pipe */
#define DATA_FD_MEMORY_LIMIT (64U*1024U)
/* If memfd/pipe didn't work out, then let's use a file in /tmp up to a size of 1M. If it's large than that use /var/tmp instead. */
#define DATA_FD_TMP_LIMIT (1024U*1024U)
int fd_duplicate_data_fd(int fd) {
_cleanup_close_ int copy_fd = -1, tmp_fd = -1;
_cleanup_free_ void *remains = NULL;
size_t remains_size = 0;
const char *td;
struct stat st;
int r;
/* Creates a 'data' fd from the specified source fd, containing all the same data in a read-only fashion, but
* independent of it (i.e. the source fd can be closed and unmounted after this call succeeded). Tries to be
* somewhat smart about where to place the data. In the best case uses a memfd(). If memfd() are not supported
* uses a pipe instead. For larger data will use an unlinked file in /tmp, and for even larger data one in
* /var/tmp. */
if (fstat(fd, &st) < 0)
return -errno;
/* For now, let's only accept regular files, sockets, pipes and char devices */
if (S_ISDIR(st.st_mode))
return -EISDIR;
if (S_ISLNK(st.st_mode))
return -ELOOP;
if (!S_ISREG(st.st_mode) && !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode) && !S_ISCHR(st.st_mode))
return -EBADFD;
/* If we have reason to believe the data is bounded in size, then let's use memfds or pipes as backing fd. Note
* that we use the reported regular file size only as a hint, given that there are plenty special files in
* /proc and /sys which report a zero file size but can be read from. */
if (!S_ISREG(st.st_mode) || st.st_size < DATA_FD_MEMORY_LIMIT) {
/* Try a memfd first */
copy_fd = memfd_new("data-fd");
if (copy_fd >= 0) {
off_t f;
r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, 0);
if (r < 0)
return r;
f = lseek(copy_fd, 0, SEEK_SET);
if (f != 0)
return -errno;
if (r == 0) {
/* Did it fit into the limit? If so, we are done. */
r = memfd_set_sealed(copy_fd);
if (r < 0)
return r;
return TAKE_FD(copy_fd);
}
/* Hmm, pity, this didn't fit. Let's fall back to /tmp then, see below */
} else {
_cleanup_(close_pairp) int pipefds[2] = { -1, -1 };
int isz;
/* If memfds aren't available, use a pipe. Set O_NONBLOCK so that we will get EAGAIN rather
* then block indefinitely when we hit the pipe size limit */
if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
return -errno;
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
/* Try to enlarge the pipe size if necessary */
if ((size_t) isz < DATA_FD_MEMORY_LIMIT) {
(void) fcntl(pipefds[1], F_SETPIPE_SZ, DATA_FD_MEMORY_LIMIT);
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
}
if ((size_t) isz >= DATA_FD_MEMORY_LIMIT) {
r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size, NULL, NULL);
if (r < 0 && r != -EAGAIN)
return r; /* If we get EAGAIN it could be because of the source or because of
* the destination fd, we can't know, as sendfile() and friends won't
* tell us. Hence, treat this as reason to fall back, just to be
* sure. */
if (r == 0) {
/* Everything fit in, yay! */
(void) fd_nonblock(pipefds[0], false);
return TAKE_FD(pipefds[0]);
}
/* Things didn't fit in. But we read data into the pipe, let's remember that, so that
* when writing the new file we incorporate this first. */
copy_fd = TAKE_FD(pipefds[0]);
}
}
}
/* If we have reason to believe this will fit fine in /tmp, then use that as first fallback. */
if ((!S_ISREG(st.st_mode) || st.st_size < DATA_FD_TMP_LIMIT) &&
(DATA_FD_MEMORY_LIMIT + remains_size) < DATA_FD_TMP_LIMIT) {
off_t f;
tmp_fd = open_tmpfile_unlinkable(NULL /* NULL as directory means /tmp */, O_RDWR|O_CLOEXEC);
if (tmp_fd < 0)
return tmp_fd;
if (copy_fd >= 0) {
/* If we tried a memfd/pipe first and it ended up being too large, then copy this into the
* temporary file first. */
r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, 0);
if (r < 0)
return r;
assert(r == 0);
}
if (remains_size > 0) {
/* If there were remaining bytes (i.e. read into memory, but not written out yet) from the
* failed copy operation, let's flush them out next. */
r = loop_write(tmp_fd, remains, remains_size, false);
if (r < 0)
return r;
}
r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT - remains_size, COPY_REFLINK);
if (r < 0)
return r;
if (r == 0)
goto finish; /* Yay, it fit in */
/* It didn't fit in. Let's not forget to use what we already used */
f = lseek(tmp_fd, 0, SEEK_SET);
if (f != 0)
return -errno;
CLOSE_AND_REPLACE(copy_fd, tmp_fd);
remains = mfree(remains);
remains_size = 0;
}
/* As last fallback use /var/tmp */
r = var_tmp_dir(&td);
if (r < 0)
return r;
tmp_fd = open_tmpfile_unlinkable(td, O_RDWR|O_CLOEXEC);
if (tmp_fd < 0)
return tmp_fd;
if (copy_fd >= 0) {
/* If we tried a memfd/pipe first, or a file in /tmp, and it ended up being too large, than copy this
* into the temporary file first. */
r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
if (r < 0)
return r;
assert(r == 0);
}
if (remains_size > 0) {
/* Then, copy in any read but not yet written bytes. */
r = loop_write(tmp_fd, remains, remains_size, false);
if (r < 0)
return r;
}
/* Copy in the rest */
r = copy_bytes(fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
if (r < 0)
return r;
assert(r == 0);
finish:
/* Now convert the O_RDWR file descriptor into an O_RDONLY one (and as side effect seek to the beginning of the
* file again */
return fd_reopen(tmp_fd, O_RDONLY|O_CLOEXEC);
}
int fd_move_above_stdio(int fd) {
int flags, copy;
PROTECT_ERRNO;
@ -1057,3 +721,20 @@ int read_nr_open(void) {
/* If we fail, fall back to the hard-coded kernel limit of 1024 * 1024. */
return 1024 * 1024;
}
/* This is here because it's fd-related and is called from sd-journal code. Other btrfs-related utilities are
* in src/shared, but libsystemd must not link to libsystemd-shared, see docs/ARCHITECTURE.md. */
int btrfs_defrag_fd(int fd) {
int r;
assert(fd >= 0);
r = fd_verify_regular(fd);
if (r < 0)
return r;
if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
return -errno;
return 0;
}

View File

@ -76,10 +76,6 @@ enum {
ACQUIRE_NO_REGULAR = 1 << 4,
};
int acquire_data_fd(const void *data, size_t size, unsigned flags);
int fd_duplicate_data_fd(int fd);
int fd_move_above_stdio(int fd);
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd);
@ -107,5 +103,5 @@ static inline int make_null_stdio(void) {
int fd_reopen(int fd, int flags);
int read_nr_open(void);
int btrfs_defrag_fd(int fd);

View File

@ -8,7 +8,6 @@
#include <unistd.h>
#include "alloc-util.h"
#include "blockdev-util.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
@ -1504,91 +1503,6 @@ int open_parent(const char *path, int flags, mode_t mode) {
return fd;
}
static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
_cleanup_free_ char *p = NULL, *uuids = NULL;
_cleanup_closedir_ DIR *d = NULL;
int r, found_encrypted = false;
assert(sysfs_path);
if (depth_left == 0)
return -EINVAL;
p = path_join(sysfs_path, "dm/uuid");
if (!p)
return -ENOMEM;
r = read_one_line_file(p, &uuids);
if (r != -ENOENT) {
if (r < 0)
return r;
/* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */
if (startswith(uuids, "CRYPT-"))
return true;
}
/* Not a dm-crypt device itself. But maybe it is on top of one? Follow the links in the "slaves/"
* subdir. */
p = mfree(p);
p = path_join(sysfs_path, "slaves");
if (!p)
return -ENOMEM;
d = opendir(p);
if (!d) {
if (errno == ENOENT) /* Doesn't have underlying devices */
return false;
return -errno;
}
for (;;) {
_cleanup_free_ char *q = NULL;
struct dirent *de;
errno = 0;
de = readdir_no_dot(d);
if (!de) {
if (errno != 0)
return -errno;
break; /* No more underlying devices */
}
q = path_join(p, de->d_name);
if (!q)
return -ENOMEM;
r = blockdev_is_encrypted(q, depth_left - 1);
if (r < 0)
return r;
if (r == 0) /* we found one that is not encrypted? then propagate that immediately */
return false;
found_encrypted = true;
}
return found_encrypted;
}
int path_is_encrypted(const char *path) {
char p[SYS_BLOCK_PATH_MAX(NULL)];
dev_t devt;
int r;
r = get_block_device(path, &devt);
if (r < 0)
return r;
if (r == 0) /* doesn't have a block device */
return false;
xsprintf_sys_block_path(p, NULL, devt);
return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
}
int conservative_renameat(
int olddirfd, const char *oldpath,
int newdirfd, const char *newpath) {

View File

@ -145,8 +145,6 @@ int syncfs_path(int atfd, const char *path);
int open_parent(const char *path, int flags, mode_t mode);
int path_is_encrypted(const char *path);
int conservative_renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
static inline int conservative_rename(const char *oldpath, const char *newpath) {
return conservative_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath);

View File

@ -15,10 +15,6 @@ basic_sources = files('''
async.h
audit-util.c
audit-util.h
blockdev-util.c
blockdev-util.h
btrfs-util.c
btrfs-util.h
build.c
build.h
bus-label.c
@ -33,15 +29,11 @@ basic_sources = files('''
chattr-util.h
conf-files.c
conf-files.h
copy.c
copy.h
creds-util.c
creds-util.h
def.h
dirent-util.c
dirent-util.h
dlfcn-util.c
dlfcn-util.h
dns-def.h
efivars.c
efivars.h
@ -85,8 +77,6 @@ basic_sources = files('''
ioprio.h
khash.c
khash.h
label.c
label.h
limits-util.c
limits-util.h
linux/btrfs.h
@ -157,7 +147,6 @@ basic_sources = files('''
missing_syscall.h
missing_timerfd.h
missing_type.h
mkdir-label.c
mkdir.c
mkdir.h
mountpoint-util.c
@ -188,8 +177,6 @@ basic_sources = files('''
procfs-util.c
procfs-util.h
pthread-util.h
quota-util.c
quota-util.h
random-util.c
random-util.h
ratelimit.c
@ -202,10 +189,6 @@ basic_sources = files('''
replace-var.h
rlimit-util.c
rlimit-util.h
rm-rf.c
rm-rf.h
selinux-util.c
selinux-util.h
set.h
sigbus.c
sigbus.h
@ -213,9 +196,6 @@ basic_sources = files('''
signal-util.h
siphash24.c
siphash24.h
smack-util.c
smack-util.h
socket-label.c
socket-util.c
socket-util.h
sort-util.c
@ -394,10 +374,7 @@ libbasic = static_library(
dependencies : [versiondep,
threads,
libcap,
libseccomp,
libselinux,
libm,
libdl],
libm],
c_args : ['-fvisibility=default'],
install : false)

View File

@ -8,7 +8,6 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "label.h"
#include "missing_stat.h"
#include "missing_syscall.h"
#include "mkdir.h"
@ -510,25 +509,3 @@ int mount_propagation_flags_from_string(const char *name, unsigned long *ret) {
return -EINVAL;
return 0;
}
int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode) {
assert(st);
assert(dest);
if (S_ISDIR(st->st_mode))
return mkdir_label(dest, mode);
else
return mknod(dest, S_IFREG|(mode & ~0111), 0);
}
int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode) {
struct stat st;
assert(source);
assert(dest);
if (stat(source, &st) < 0)
return -errno;
return make_mount_point_inode_from_stat(&st, dest, mode);
}

View File

@ -23,7 +23,3 @@ int dev_is_devtmpfs(void);
const char *mount_propagation_flags_to_string(unsigned long flags);
int mount_propagation_flags_from_string(const char *name, unsigned long *ret);
/* Creates a mount point (not parents) based on the source path or stat - ie, a file or a directory */
int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode);
int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode);

View File

@ -21,7 +21,6 @@
#include <unistd.h>
#include "alloc-util.h"
#include "copy.h"
#include "def.h"
#include "env-util.h"
#include "fd-util.h"

View File

@ -11,6 +11,7 @@
#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-log-control-api.h"
#include "data-fd-util.h"
#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-job.h"

View File

@ -46,6 +46,7 @@
#include "cgroup-setup.h"
#include "chown-recursive.h"
#include "cpu-set-util.h"
#include "data-fd-util.h"
#include "def.h"
#include "env-file.h"
#include "env-util.h"

View File

@ -11,6 +11,7 @@
#include "blockdev-util.h"
#include "btrfs-util.h"
#include "bus-common-errors.h"
#include "data-fd-util.h"
#include "env-util.h"
#include "errno-list.h"
#include "errno-util.h"

View File

@ -3,6 +3,7 @@
#include <stddef.h>
#include <sys/mount.h>
#include "blockdev-util.h"
#include "chown-recursive.h"
#include "copy.h"
#include "fd-util.h"

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "dlfcn-util.h"
#include "log.h"
#include "pcre2-dlopen.h"
#if HAVE_PCRE2
@ -16,17 +16,6 @@ int (*sym_pcre2_match)(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, u
PCRE2_SIZE* (*sym_pcre2_get_ovector_pointer)(pcre2_match_data *);
int dlopen_pcre2(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (pcre2_dl)
return 0; /* Already loaded */
dl = dlopen("libpcre2-8.so.0", RTLD_LAZY);
if (!dl)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"PCRE2 support is not installed: %s", dlerror());
/* So here's something weird: PCRE2 actually renames the symbols exported by the library via C
* macros, so that the exported symbols carry a suffix "_8" but when used from C the suffix is
* gone. In the argument list below we ignore this mangling. Surprisingly (at least to me), we
@ -35,25 +24,15 @@ int dlopen_pcre2(void) {
* string actually contains the "_8" suffix already due to that and we don't have to append it
* manually anymore. C is weird. 🤯 */
r = dlsym_many_and_warn(
dl,
LOG_ERR,
return dlopen_many_sym_or_warn(
&pcre2_dl, "libpcre2-8.so.0", LOG_ERR,
DLSYM_ARG(pcre2_match_data_create),
DLSYM_ARG(pcre2_match_data_free),
DLSYM_ARG(pcre2_code_free),
DLSYM_ARG(pcre2_compile),
DLSYM_ARG(pcre2_get_error_message),
DLSYM_ARG(pcre2_match),
DLSYM_ARG(pcre2_get_ovector_pointer),
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
pcre2_dl = TAKE_PTR(dl);
return 1;
DLSYM_ARG(pcre2_get_ovector_pointer));
}
#else

View File

@ -131,8 +131,6 @@ libsystemd_sources = files('''
sd-device/device-util.h
sd-device/sd-device.c
sd-hwdb/hwdb-internal.h
sd-hwdb/hwdb-util.c
sd-hwdb/hwdb-util.h
sd-hwdb/sd-hwdb.c
sd-netlink/generic-netlink.c
sd-netlink/generic-netlink.h

View File

@ -22,7 +22,6 @@
#include "path-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "stdio-util.h"
#include "string-util.h"

View File

@ -3,10 +3,27 @@
#include <stdint.h>
#include "def.h"
#include "hashmap.h"
#include "sparse-endian.h"
#define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' }
struct sd_hwdb {
unsigned n_ref;
FILE *f;
struct stat st;
union {
struct trie_header_f *head;
const char *map;
};
OrderedHashmap *properties;
Iterator properties_iterator;
bool properties_modified;
};
/* on-disk trie objects */
struct trie_header_f {
uint8_t signature[8];
@ -63,3 +80,10 @@ struct trie_value_entry2_f {
le16_t file_priority;
le16_t padding;
} _packed_;
#define hwdb_bin_paths \
"/etc/systemd/hwdb/hwdb.bin\0" \
"/etc/udev/hwdb.bin\0" \
"/usr/lib/systemd/hwdb/hwdb.bin\0" \
_CONF_PATHS_SPLIT_USR_NULSTR("systemd/hwdb/hwdb.bin") \
UDEVLIBEXECDIR "/hwdb.bin\0"

View File

@ -17,26 +17,10 @@
#include "fd-util.h"
#include "hashmap.h"
#include "hwdb-internal.h"
#include "hwdb-util.h"
#include "nulstr-util.h"
#include "string-util.h"
#include "time-util.h"
struct sd_hwdb {
unsigned n_ref;
FILE *f;
struct stat st;
union {
struct trie_header_f *head;
const char *map;
};
OrderedHashmap *properties;
Iterator properties_iterator;
bool properties_modified;
};
struct linebuf {
char bytes[LINE_MAX];
size_t size;
@ -296,15 +280,6 @@ static int trie_search_f(sd_hwdb *hwdb, const char *search) {
return 0;
}
static const char hwdb_bin_paths[] =
"/etc/systemd/hwdb/hwdb.bin\0"
"/etc/udev/hwdb.bin\0"
"/usr/lib/systemd/hwdb/hwdb.bin\0"
#if HAVE_SPLIT_USR
"/lib/systemd/hwdb/hwdb.bin\0"
#endif
UDEVLIBEXECDIR "/hwdb.bin\0";
_public_ int sd_hwdb_new(sd_hwdb **ret) {
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
const char *hwdb_bin_path;
@ -372,30 +347,6 @@ static sd_hwdb *hwdb_free(sd_hwdb *hwdb) {
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_hwdb, sd_hwdb, hwdb_free)
bool hwdb_validate(sd_hwdb *hwdb) {
bool found = false;
const char* p;
struct stat st;
if (!hwdb)
return false;
if (!hwdb->f)
return false;
/* if hwdb.bin doesn't exist anywhere, we need to update */
NULSTR_FOREACH(p, hwdb_bin_paths)
if (stat(p, &st) >= 0) {
found = true;
break;
}
if (!found)
return true;
if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim))
return true;
return false;
}
static int properties_prepare(sd_hwdb *hwdb, const char *modalias) {
assert(hwdb);
assert(modalias);

View File

@ -3,6 +3,7 @@
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/magic.h>
#include <pthread.h>
#include <stddef.h>
#include <sys/mman.h>
@ -13,7 +14,6 @@
#include "sd-event.h"
#include "alloc-util.h"
#include "btrfs-util.h"
#include "chattr-util.h"
#include "compress.h"
#include "env-util.h"
@ -3379,7 +3379,7 @@ static int journal_file_warn_btrfs(JournalFile *f) {
* expense of data integrity features (which shouldn't be too
* bad, given that we do our own checksumming). */
r = btrfs_is_filesystem(f->fd);
r = fd_is_fs_type(f->fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return log_warning_errno(r, "Failed to determine if journal is on btrfs: %m");
if (!r)

View File

@ -4,6 +4,7 @@
#include "bus-common-errors.h"
#include "bus-polkit.h"
#include "data-fd-util.h"
#include "fd-util.h"
#include "oomd-manager-bus.h"
#include "oomd-manager.h"

View File

@ -6,6 +6,7 @@
#include "bus-error.h"
#include "conf-files.h"
#include "copy.h"
#include "data-fd-util.h"
#include "def.h"
#include "dirent-util.h"
#include "discover-image.h"
@ -153,7 +154,7 @@ static int send_item(
assert(name);
assert(fd >= 0);
data_fd = fd_duplicate_data_fd(fd);
data_fd = copy_data_fd(fd);
if (data_fd < 0)
return data_fd;

View File

@ -256,3 +256,88 @@ int blockdev_partscan_enabled(int fd) {
return !FLAGS_SET(ull, GENHD_FL_NO_PART_SCAN);
}
static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
_cleanup_free_ char *p = NULL, *uuids = NULL;
_cleanup_closedir_ DIR *d = NULL;
int r, found_encrypted = false;
assert(sysfs_path);
if (depth_left == 0)
return -EINVAL;
p = path_join(sysfs_path, "dm/uuid");
if (!p)
return -ENOMEM;
r = read_one_line_file(p, &uuids);
if (r != -ENOENT) {
if (r < 0)
return r;
/* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */
if (startswith(uuids, "CRYPT-"))
return true;
}
/* Not a dm-crypt device itself. But maybe it is on top of one? Follow the links in the "slaves/"
* subdir. */
p = mfree(p);
p = path_join(sysfs_path, "slaves");
if (!p)
return -ENOMEM;
d = opendir(p);
if (!d) {
if (errno == ENOENT) /* Doesn't have underlying devices */
return false;
return -errno;
}
for (;;) {
_cleanup_free_ char *q = NULL;
struct dirent *de;
errno = 0;
de = readdir_no_dot(d);
if (!de) {
if (errno != 0)
return -errno;
break; /* No more underlying devices */
}
q = path_join(p, de->d_name);
if (!q)
return -ENOMEM;
r = blockdev_is_encrypted(q, depth_left - 1);
if (r < 0)
return r;
if (r == 0) /* we found one that is not encrypted? then propagate that immediately */
return false;
found_encrypted = true;
}
return found_encrypted;
}
int path_is_encrypted(const char *path) {
char p[SYS_BLOCK_PATH_MAX(NULL)];
dev_t devt;
int r;
r = get_block_device(path, &devt);
if (r < 0)
return r;
if (r == 0) /* doesn't have a block device */
return false;
xsprintf_sys_block_path(p, NULL, devt);
return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
}

View File

@ -22,3 +22,5 @@ int get_block_device_harder(const char *path, dev_t *dev);
int lock_whole_block_device(dev_t devt, int operation);
int blockdev_partscan_enabled(int fd);
int path_is_encrypted(const char *path);

View File

@ -1,8 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "dlfcn-util.h"
#include "bpf-dlopen.h"
#include "log.h"
#if HAVE_LIBBPF
static void *bpf_dl = NULL;
@ -24,20 +24,8 @@ bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
const char* (*sym_bpf_program__name)(const struct bpf_program *);
int dlopen_bpf(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (bpf_dl)
return 0; /* Already loaded */
dl = dlopen("libbpf.so.0", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libbpf is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
return dlopen_many_sym_or_warn(
&bpf_dl, "libbpf.so.0", LOG_DEBUG,
DLSYM_ARG(bpf_link__destroy),
DLSYM_ARG(bpf_link__fd),
DLSYM_ARG(bpf_map__fd),
@ -52,15 +40,7 @@ int dlopen_bpf(void) {
DLSYM_ARG(bpf_probe_prog_type),
DLSYM_ARG(bpf_program__attach_cgroup),
DLSYM_ARG(bpf_program__name),
DLSYM_ARG(libbpf_get_error),
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
bpf_dl = TAKE_PTR(dl);
return 1;
DLSYM_ARG(libbpf_get_error));
}
#else

View File

@ -69,17 +69,6 @@ static int extract_subvolume_name(const char *path, const char **subvolume) {
return 0;
}
int btrfs_is_filesystem(int fd) {
struct statfs sfs;
assert(fd >= 0);
if (fstatfs(fd, &sfs) < 0)
return -errno;
return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
}
int btrfs_is_subvol_fd(int fd) {
struct stat st;
@ -93,7 +82,7 @@ int btrfs_is_subvol_fd(int fd) {
if (!btrfs_might_be_subvol(&st))
return 0;
return btrfs_is_filesystem(fd);
return fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
}
int btrfs_is_subvol(const char *path) {
@ -286,7 +275,7 @@ int btrfs_get_block_device_fd(int fd, dev_t *dev) {
assert(fd >= 0);
assert(dev);
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)
@ -361,7 +350,7 @@ int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
assert(fd >= 0);
assert(ret);
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)
@ -481,7 +470,7 @@ int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) {
if (r < 0)
return r;
} else {
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)
@ -575,7 +564,7 @@ int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
if (r < 0)
return r;
} else {
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)
@ -762,21 +751,6 @@ int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQu
return btrfs_subvol_get_subtree_quota_fd(fd, subvol_id, ret);
}
int btrfs_defrag_fd(int fd) {
int r;
assert(fd >= 0);
r = fd_verify_regular(fd);
if (r < 0)
return r;
if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
return -errno;
return 0;
}
int btrfs_defrag(const char *p) {
_cleanup_close_ int fd = -1;
@ -795,7 +769,7 @@ int btrfs_quota_enable_fd(int fd, bool b) {
assert(fd >= 0);
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)
@ -832,7 +806,7 @@ int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max
if (r < 0)
return r;
} else {
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)
@ -924,7 +898,7 @@ static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) {
};
int r;
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (r == 0)
@ -1042,7 +1016,7 @@ static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t pa
};
int r;
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (r == 0)
@ -1269,7 +1243,7 @@ int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupi
int r;
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)
@ -1738,7 +1712,7 @@ int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
if (r < 0)
return r;
} else {
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)
@ -1979,7 +1953,7 @@ int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) {
if (r < 0)
return r;
} else {
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (!r)

View File

@ -42,8 +42,6 @@ typedef enum BtrfsRemoveFlags {
BTRFS_REMOVE_QUOTA = 1 << 1,
} BtrfsRemoveFlags;
int btrfs_is_filesystem(int fd);
int btrfs_is_subvol_fd(int fd);
int btrfs_is_subvol(const char *path);
@ -53,7 +51,6 @@ int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset
int btrfs_get_block_device_fd(int fd, dev_t *dev);
int btrfs_get_block_device(const char *path, dev_t *dev);
int btrfs_defrag_fd(int fd);
int btrfs_defrag(const char *p);
int btrfs_quota_enable_fd(int fd, bool b);

View File

@ -17,6 +17,7 @@
#include "apparmor-util.h"
#include "architecture.h"
#include "audit-util.h"
#include "blockdev-util.h"
#include "cap-list.h"
#include "cgroup-util.h"
#include "condition.h"

View File

@ -51,20 +51,10 @@ crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, c
int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
int dlopen_cryptsetup(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (cryptsetup_dl)
return 0; /* Already loaded */
dl = dlopen("libcryptsetup.so.12", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libcryptsetup support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
r = dlopen_many_sym_or_warn(
&cryptsetup_dl, "libcryptsetup.so.12", LOG_DEBUG,
DLSYM_ARG(crypt_activate_by_passphrase),
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
DLSYM_ARG(crypt_activate_by_signed_key),
@ -104,15 +94,10 @@ int dlopen_cryptsetup(void) {
DLSYM_ARG(crypt_token_max),
#endif
DLSYM_ARG(crypt_token_status),
DLSYM_ARG(crypt_volume_key_get),
NULL);
if (r < 0)
DLSYM_ARG(crypt_volume_key_get));
if (r <= 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
cryptsetup_dl = TAKE_PTR(dl);
/* Redirect the default logging calls of libcryptsetup to our own logging infra. (Note that
* libcryptsetup also maintains per-"struct crypt_device" log functions, which we'll also set
* whenever allocating a "struct crypt_device" context. Why set both? To be defensive: maybe some

350
src/shared/data-fd-util.c Normal file
View File

@ -0,0 +1,350 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "alloc-util.h"
#include "copy.h"
#include "data-fd-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "io-util.h"
#include "memfd-util.h"
#include "tmpfile-util.h"
/* When the data is smaller or equal to 64K, try to place the copy in a memfd/pipe */
#define DATA_FD_MEMORY_LIMIT (64U*1024U)
/* If memfd/pipe didn't work out, then let's use a file in /tmp up to a size of 1M. If it's large than that use /var/tmp instead. */
#define DATA_FD_TMP_LIMIT (1024U*1024U)
int acquire_data_fd(const void *data, size_t size, unsigned flags) {
_cleanup_close_pair_ int pipefds[2] = { -1, -1 };
char pattern[] = "/dev/shm/data-fd-XXXXXX";
_cleanup_close_ int fd = -1;
int isz = 0, r;
ssize_t n;
off_t f;
assert(data || size == 0);
/* Acquire a read-only file descriptor that when read from returns the specified data. This is much more
* complex than I wish it was. But here's why:
*
* a) First we try to use memfds. They are the best option, as we can seal them nicely to make them
* read-only. Unfortunately they require kernel 3.17, and at the time of writing we still support 3.14.
*
* b) Then, we try classic pipes. They are the second best options, as we can close the writing side, retaining
* a nicely read-only fd in the reading side. However, they are by default quite small, and unprivileged
* clients can only bump their size to a system-wide limit, which might be quite low.
*
* c) Then, we try an O_TMPFILE file in /dev/shm (that dir is the only suitable one known to exist from
* earliest boot on). To make it read-only we open the fd a second time with O_RDONLY via
* /proc/self/<fd>. Unfortunately O_TMPFILE is not available on older kernels on tmpfs.
*
* d) Finally, we try creating a regular file in /dev/shm, which we then delete.
*
* It sucks a bit that depending on the situation we return very different objects here, but that's Linux I
* figure. */
if (size == 0 && ((flags & ACQUIRE_NO_DEV_NULL) == 0)) {
/* As a special case, return /dev/null if we have been called for an empty data block */
r = open("/dev/null", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (r < 0)
return -errno;
return r;
}
if ((flags & ACQUIRE_NO_MEMFD) == 0) {
fd = memfd_new("data-fd");
if (fd < 0)
goto try_pipe;
n = write(fd, data, size);
if (n < 0)
return -errno;
if ((size_t) n != size)
return -EIO;
f = lseek(fd, 0, SEEK_SET);
if (f != 0)
return -errno;
r = memfd_set_sealed(fd);
if (r < 0)
return r;
return TAKE_FD(fd);
}
try_pipe:
if ((flags & ACQUIRE_NO_PIPE) == 0) {
if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
return -errno;
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
if ((size_t) isz < size) {
isz = (int) size;
if (isz < 0 || (size_t) isz != size)
return -E2BIG;
/* Try to bump the pipe size */
(void) fcntl(pipefds[1], F_SETPIPE_SZ, isz);
/* See if that worked */
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
if ((size_t) isz < size)
goto try_dev_shm;
}
n = write(pipefds[1], data, size);
if (n < 0)
return -errno;
if ((size_t) n != size)
return -EIO;
(void) fd_nonblock(pipefds[0], false);
return TAKE_FD(pipefds[0]);
}
try_dev_shm:
if ((flags & ACQUIRE_NO_TMPFILE) == 0) {
fd = open("/dev/shm", O_RDWR|O_TMPFILE|O_CLOEXEC, 0500);
if (fd < 0)
goto try_dev_shm_without_o_tmpfile;
n = write(fd, data, size);
if (n < 0)
return -errno;
if ((size_t) n != size)
return -EIO;
/* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
return fd_reopen(fd, O_RDONLY|O_CLOEXEC);
}
try_dev_shm_without_o_tmpfile:
if ((flags & ACQUIRE_NO_REGULAR) == 0) {
fd = mkostemp_safe(pattern);
if (fd < 0)
return fd;
n = write(fd, data, size);
if (n < 0) {
r = -errno;
goto unlink_and_return;
}
if ((size_t) n != size) {
r = -EIO;
goto unlink_and_return;
}
/* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
r = open(pattern, O_RDONLY|O_CLOEXEC);
if (r < 0)
r = -errno;
unlink_and_return:
(void) unlink(pattern);
return r;
}
return -EOPNOTSUPP;
}
int copy_data_fd(int fd) {
_cleanup_close_ int copy_fd = -1, tmp_fd = -1;
_cleanup_free_ void *remains = NULL;
size_t remains_size = 0;
const char *td;
struct stat st;
int r;
/* Creates a 'data' fd from the specified source fd, containing all the same data in a read-only fashion, but
* independent of it (i.e. the source fd can be closed and unmounted after this call succeeded). Tries to be
* somewhat smart about where to place the data. In the best case uses a memfd(). If memfd() are not supported
* uses a pipe instead. For larger data will use an unlinked file in /tmp, and for even larger data one in
* /var/tmp. */
if (fstat(fd, &st) < 0)
return -errno;
/* For now, let's only accept regular files, sockets, pipes and char devices */
if (S_ISDIR(st.st_mode))
return -EISDIR;
if (S_ISLNK(st.st_mode))
return -ELOOP;
if (!S_ISREG(st.st_mode) && !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode) && !S_ISCHR(st.st_mode))
return -EBADFD;
/* If we have reason to believe the data is bounded in size, then let's use memfds or pipes as backing fd. Note
* that we use the reported regular file size only as a hint, given that there are plenty special files in
* /proc and /sys which report a zero file size but can be read from. */
if (!S_ISREG(st.st_mode) || st.st_size < DATA_FD_MEMORY_LIMIT) {
/* Try a memfd first */
copy_fd = memfd_new("data-fd");
if (copy_fd >= 0) {
off_t f;
r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, 0);
if (r < 0)
return r;
f = lseek(copy_fd, 0, SEEK_SET);
if (f != 0)
return -errno;
if (r == 0) {
/* Did it fit into the limit? If so, we are done. */
r = memfd_set_sealed(copy_fd);
if (r < 0)
return r;
return TAKE_FD(copy_fd);
}
/* Hmm, pity, this didn't fit. Let's fall back to /tmp then, see below */
} else {
_cleanup_(close_pairp) int pipefds[2] = { -1, -1 };
int isz;
/* If memfds aren't available, use a pipe. Set O_NONBLOCK so that we will get EAGAIN rather
* then block indefinitely when we hit the pipe size limit */
if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
return -errno;
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
/* Try to enlarge the pipe size if necessary */
if ((size_t) isz < DATA_FD_MEMORY_LIMIT) {
(void) fcntl(pipefds[1], F_SETPIPE_SZ, DATA_FD_MEMORY_LIMIT);
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
}
if ((size_t) isz >= DATA_FD_MEMORY_LIMIT) {
r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size, NULL, NULL);
if (r < 0 && r != -EAGAIN)
return r; /* If we get EAGAIN it could be because of the source or because of
* the destination fd, we can't know, as sendfile() and friends won't
* tell us. Hence, treat this as reason to fall back, just to be
* sure. */
if (r == 0) {
/* Everything fit in, yay! */
(void) fd_nonblock(pipefds[0], false);
return TAKE_FD(pipefds[0]);
}
/* Things didn't fit in. But we read data into the pipe, let's remember that, so that
* when writing the new file we incorporate this first. */
copy_fd = TAKE_FD(pipefds[0]);
}
}
}
/* If we have reason to believe this will fit fine in /tmp, then use that as first fallback. */
if ((!S_ISREG(st.st_mode) || st.st_size < DATA_FD_TMP_LIMIT) &&
(DATA_FD_MEMORY_LIMIT + remains_size) < DATA_FD_TMP_LIMIT) {
off_t f;
tmp_fd = open_tmpfile_unlinkable(NULL /* NULL as directory means /tmp */, O_RDWR|O_CLOEXEC);
if (tmp_fd < 0)
return tmp_fd;
if (copy_fd >= 0) {
/* If we tried a memfd/pipe first and it ended up being too large, then copy this into the
* temporary file first. */
r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, 0);
if (r < 0)
return r;
assert(r == 0);
}
if (remains_size > 0) {
/* If there were remaining bytes (i.e. read into memory, but not written out yet) from the
* failed copy operation, let's flush them out next. */
r = loop_write(tmp_fd, remains, remains_size, false);
if (r < 0)
return r;
}
r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT - remains_size, COPY_REFLINK);
if (r < 0)
return r;
if (r == 0)
goto finish; /* Yay, it fit in */
/* It didn't fit in. Let's not forget to use what we already used */
f = lseek(tmp_fd, 0, SEEK_SET);
if (f != 0)
return -errno;
CLOSE_AND_REPLACE(copy_fd, tmp_fd);
remains = mfree(remains);
remains_size = 0;
}
/* As last fallback use /var/tmp */
r = var_tmp_dir(&td);
if (r < 0)
return r;
tmp_fd = open_tmpfile_unlinkable(td, O_RDWR|O_CLOEXEC);
if (tmp_fd < 0)
return tmp_fd;
if (copy_fd >= 0) {
/* If we tried a memfd/pipe first, or a file in /tmp, and it ended up being too large, than copy this
* into the temporary file first. */
r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
if (r < 0)
return r;
assert(r == 0);
}
if (remains_size > 0) {
/* Then, copy in any read but not yet written bytes. */
r = loop_write(tmp_fd, remains, remains_size, false);
if (r < 0)
return r;
}
/* Copy in the rest */
r = copy_bytes(fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
if (r < 0)
return r;
assert(r == 0);
finish:
/* Now convert the O_RDWR file descriptor into an O_RDONLY one (and as side effect seek to the beginning of the
* file again */
return fd_reopen(tmp_fd, O_RDONLY|O_CLOEXEC);
}

View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stddef.h>
int acquire_data_fd(const void *data, size_t size, unsigned flags);
int copy_data_fd(int fd);

View File

@ -4,6 +4,7 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/loop.h>
#include <linux/magic.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
@ -34,6 +35,7 @@
#include "os-util.h"
#include "path-util.h"
#include "rm-rf.h"
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
@ -262,7 +264,7 @@ static int image_make(
if (btrfs_might_be_subvol(st)) {
r = btrfs_is_filesystem(fd);
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return r;
if (r) {

64
src/shared/dlfcn-util.c Normal file
View File

@ -0,0 +1,64 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "dlfcn-util.h"
static int dlsym_many_or_warnv(void *dl, int log_level, va_list ap) {
void (**fn)(void);
/* Tries to resolve a bunch of function symbols, and logs an error about if it cannot resolve one of
* them. Note that this function possibly modifies the supplied function pointers if the whole
* operation fails. */
while ((fn = va_arg(ap, typeof(fn)))) {
void (*tfn)(void);
const char *symbol;
symbol = va_arg(ap, typeof(symbol));
tfn = (typeof(tfn)) dlsym(dl, symbol);
if (!tfn)
return log_full_errno(log_level,
SYNTHETIC_ERRNO(ELIBBAD),
"Can't find symbol %s: %s", symbol, dlerror());
*fn = tfn;
}
return 0;
}
int dlsym_many_or_warn_sentinel(void *dl, int log_level, ...) {
va_list ap;
int r;
va_start(ap, log_level);
r = dlsym_many_or_warnv(dl, log_level, ap);
va_end(ap);
return r;
}
int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, int log_level, ...) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (*dlp)
return 0; /* Already loaded */
dl = dlopen(filename, RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"%s is not installed: %s", filename, dlerror());
va_list ap;
va_start(ap, log_level);
r = dlsym_many_or_warnv(dl, log_level, ap);
va_end(ap);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to. After all this
* was traditionally a regular shared library dependency which lives forever too. */
*dlp = TAKE_PTR(dl);
return 1;
}

22
src/shared/dlfcn-util.h Normal file
View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dlfcn.h>
#include "macro.h"
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(void*, dlclose, NULL);
int dlsym_many_or_warn_sentinel(void *dl, int log_level, ...) _sentinel_;
int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, int log_level, ...) _sentinel_;
#define dlsym_many_or_warn(dl, log_level, ...) \
dlsym_many_or_warn_sentinel(dl, log_level, __VA_ARGS__, NULL)
#define dlopen_many_sym_or_warn(dlp, filename, log_level, ...) \
dlopen_many_sym_or_warn_sentinel(dlp, filename, log_level, __VA_ARGS__, NULL)
/* Macro useful for putting together variable/symbol name pairs when calling dlsym_many_or_warn(). Assumes
* that each library symbol to resolve will be placed in a variable with the "sym_" prefix, i.e. a symbol
* "foobar" is loaded into a variable "sym_foobar". */
#define DLSYM_ARG(arg) \
&sym_##arg, STRINGIFY(arg)

View File

@ -13,6 +13,7 @@
#include "hwdb-util.h"
#include "label.h"
#include "mkdir.h"
#include "nulstr-util.h"
#include "path-util.h"
#include "sort-util.h"
#include "strbuf.h"
@ -586,10 +587,10 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
uint16_t file_priority = 1;
int r = 0, err;
/* The argument 'compat' controls the format version of database. If false, then hwdb.bin will be created with
* additional information such that priority, line number, and filename of database source. If true, then hwdb.bin
* will be created without the information. systemd-hwdb command should set the argument false, and 'udevadm hwdb'
* command should set it true. */
/* The argument 'compat' controls the format version of database. If false, then hwdb.bin will be
* created with additional information such that priority, line number, and filename of database
* source. If true, then hwdb.bin will be created without the information. systemd-hwdb command
* should set the argument false, and 'udevadm hwdb' command should set it true. */
trie = new0(struct trie, 1);
if (!trie)
@ -666,3 +667,27 @@ int hwdb_query(const char *modalias) {
return 0;
}
bool hwdb_validate(sd_hwdb *hwdb) {
bool found = false;
const char* p;
struct stat st;
if (!hwdb)
return false;
if (!hwdb->f)
return false;
/* if hwdb.bin doesn't exist anywhere, we need to update */
NULSTR_FOREACH(p, hwdb_bin_paths)
if (stat(p, &st) >= 0) {
found = true;
break;
}
if (!found)
return true;
if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim))
return true;
return false;
}

View File

@ -21,32 +21,11 @@ const char *(*sym_idn2_strerror)(int rc) = NULL;
int (*sym_idn2_to_unicode_8z8z)(const char * input, char ** output, int flags) = NULL;
int dlopen_idn(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (idn_dl)
return 0; /* Already loaded */
dl = dlopen("libidn2.so.0", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libidn2 support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
return dlopen_many_sym_or_warn(
&idn_dl, "libidn2.so.0", LOG_DEBUG,
DLSYM_ARG(idn2_lookup_u8),
DLSYM_ARG(idn2_strerror),
DLSYM_ARG(idn2_to_unicode_8z8z),
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
idn_dl = TAKE_PTR(dl);
return 1;
DLSYM_ARG(idn2_to_unicode_8z8z));
}
#endif
@ -73,14 +52,13 @@ int dlopen_idn(void) {
"libidn support is not installed: %s", dlerror());
}
r = dlsym_many_and_warn(
r = dlsym_many_or_warn(
dl,
LOG_DEBUG,
DLSYM_ARG(idna_to_ascii_4i),
DLSYM_ARG(idna_to_unicode_44i),
DLSYM_ARG(stringprep_ucs4_to_utf8),
DLSYM_ARG(stringprep_utf8_to_ucs4),
NULL);
DLSYM_ARG(stringprep_utf8_to_ucs4));
if (r < 0)
return r;

View File

@ -61,20 +61,8 @@ int (*sym_fido_dev_open)(fido_dev_t *, const char *) = NULL;
const char* (*sym_fido_strerr)(int) = NULL;
int dlopen_libfido2(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (libfido2_dl)
return 0; /* Already loaded */
dl = dlopen("libfido2.so.1", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libfido2 support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
return dlopen_many_sym_or_warn(
&libfido2_dl, "libfido2.so.1", LOG_DEBUG,
DLSYM_ARG(fido_assert_allow_cred),
DLSYM_ARG(fido_assert_free),
DLSYM_ARG(fido_assert_hmac_secret_len),
@ -118,15 +106,7 @@ int dlopen_libfido2(void) {
DLSYM_ARG(fido_dev_make_cred),
DLSYM_ARG(fido_dev_new),
DLSYM_ARG(fido_dev_open),
DLSYM_ARG(fido_strerr),
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
libfido2_dl = TAKE_PTR(dl);
return 1;
DLSYM_ARG(fido_strerr));
}
static int verify_features(

View File

@ -17,6 +17,8 @@ shared_sources = files('''
bitmap.c
bitmap.h
blkid-util.h
blockdev-util.c
blockdev-util.h
bond-util.c
bond-util.h
boot-timestamps.c
@ -29,6 +31,8 @@ shared_sources = files('''
bpf-program.h
bridge-util.c
bridge-util.h
btrfs-util.c
btrfs-util.h
bus-get-properties.c
bus-get-properties.h
bus-locator.c
@ -71,6 +75,8 @@ shared_sources = files('''
condition.h
conf-parser.c
conf-parser.h
copy.c
copy.h
coredump-util.c
coredump-util.h
cpu-set-util.c
@ -78,6 +84,8 @@ shared_sources = files('''
cryptsetup-util.c
cryptsetup-util.h
daemon-util.h
data-fd-util.c
data-fd-util.h
dev-setup.c
dev-setup.h
device-nodes.c
@ -87,6 +95,8 @@ shared_sources = files('''
discover-image.h
dissect-image.c
dissect-image.h
dlfcn-util.c
dlfcn-util.h
dm-util.c
dm-util.h
dns-domain.c
@ -129,6 +139,8 @@ shared_sources = files('''
group-record.h
hostname-setup.c
hostname-setup.h
hwdb-util.c
hwdb-util.h
id128-print.c
id128-print.h
idn-util.c
@ -142,10 +154,10 @@ shared_sources = files('''
install-printf.h
install.c
install.h
ipvlan-util.c
ipvlan-util.h
ip-protocol-list.c
ip-protocol-list.h
ipvlan-util.c
ipvlan-util.h
journal-importer.c
journal-importer.h
journal-util.c
@ -157,6 +169,8 @@ shared_sources = files('''
kbd-util.h
killall.c
killall.h
label.c
label.h
libcrypt-util.c
libcrypt-util.h
libfido2-util.c
@ -186,6 +200,7 @@ shared_sources = files('''
macvlan-util.c
macvlan-util.h
main-func.h
mkdir-label.c
mkfs-util.c
mkfs-util.h
module-util.h
@ -223,21 +238,30 @@ shared_sources = files('''
pwquality-util.h
qrcode-util.c
qrcode-util.h
quota-util.c
quota-util.h
reboot-util.c
reboot-util.h
resize-fs.c
resize-fs.h
resolve-util.c
resolve-util.h
rm-rf.c
rm-rf.h
seccomp-util.h
securebits-util.c
securebits-util.h
selinux-util.c
selinux-util.h
serialize.c
serialize.h
service-util.c
service-util.h
sleep-config.c
sleep-config.h
smack-util.c
smack-util.h
socket-label.c
socket-netlink.c
socket-netlink.h
spawn-ask-password-agent.c
@ -264,10 +288,10 @@ shared_sources = files('''
user-record-show.h
user-record.c
user-record.h
userdb.c
userdb.h
userdb-dropin.c
userdb-dropin.h
userdb.c
userdb.h
utmp-wtmp.h
varlink.c
varlink.h

View File

@ -16,6 +16,7 @@
#include "fileio.h"
#include "fs-util.h"
#include "hashmap.h"
#include "label.h"
#include "libmount-util.h"
#include "missing_mount.h"
#include "missing_syscall.h"
@ -1071,3 +1072,25 @@ int remount_idmap(
return 0;
}
int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode) {
assert(st);
assert(dest);
if (S_ISDIR(st->st_mode))
return mkdir_label(dest, mode);
else
return mknod(dest, S_IFREG|(mode & ~0111), 0);
}
int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode) {
struct stat st;
assert(source);
assert(dest);
if (stat(source, &st) < 0)
return -errno;
return make_mount_point_inode_from_stat(&st, dest, mode);
}

View File

@ -3,6 +3,7 @@
#include <mntent.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include "alloc-util.h"
@ -108,3 +109,7 @@ int mount_image_in_namespace(pid_t target, const char *propagate_path, const cha
int make_mount_point(const char *path);
int remount_idmap(const char *p, uid_t uid_shift, uid_t uid_range);
/* Creates a mount point (not parents) based on the source path or stat - ie, a file or a directory */
int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode);
int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode);

View File

@ -24,20 +24,8 @@ int (*sym_pwquality_set_int_value)(pwquality_settings_t *pwq, int setting, int v
const char* (*sym_pwquality_strerror)(char *buf, size_t len, int errcode, void *auxerror);
int dlopen_pwquality(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (pwquality_dl)
return 0; /* Already loaded */
dl = dlopen("libpwquality.so.1", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libpwquality support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
return dlopen_many_sym_or_warn(
&pwquality_dl, "libpwquality.so.1", LOG_DEBUG,
DLSYM_ARG(pwquality_check),
DLSYM_ARG(pwquality_default_settings),
DLSYM_ARG(pwquality_free_settings),
@ -45,15 +33,7 @@ int dlopen_pwquality(void) {
DLSYM_ARG(pwquality_get_str_value),
DLSYM_ARG(pwquality_read_config),
DLSYM_ARG(pwquality_set_int_value),
DLSYM_ARG(pwquality_strerror),
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
pwquality_dl = TAKE_PTR(dl);
return 1;
DLSYM_ARG(pwquality_strerror));
}
void pwq_maybe_disable_dictionary(pwquality_settings_t *pwq) {

View File

@ -5,9 +5,9 @@
#if HAVE_QRENCODE
#include <qrencode.h>
#include "alloc-util.h"
#include "dlfcn-util.h"
#include "locale-util.h"
#include "log.h"
#include "terminal-util.h"
#define ANSI_WHITE_ON_BLACK "\033[40;37;1m"
@ -18,30 +18,10 @@ static QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecL
static void (*sym_QRcode_free)(QRcode *qrcode) = NULL;
int dlopen_qrencode(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (qrcode_dl)
return 0; /* Already loaded */
dl = dlopen("libqrencode.so.4", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libqrcode support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
return dlopen_many_sym_or_warn(
&qrcode_dl, "libqrencode.so.4", LOG_DEBUG,
DLSYM_ARG(QRcode_encodeString),
DLSYM_ARG(QRcode_free),
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
qrcode_dl = TAKE_PTR(dl);
return 1;
DLSYM_ARG(QRcode_free));
}
static void print_border(FILE *output, unsigned width) {

View File

@ -36,9 +36,9 @@ static int mac_selinux_reload(int seqno);
static int cached_use = -1;
static bool initialized = false;
static int (*enforcing_status_func)(void) = security_getenforce;
static int last_policyload = 0;
static struct selabel_handle *label_hnd = NULL;
static bool have_status_page = false;
#define log_enforcing(...) \
log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
@ -70,11 +70,19 @@ bool mac_selinux_use(void) {
}
bool mac_selinux_enforcing(void) {
int r = 0;
#if HAVE_SELINUX
return enforcing_status_func() != 0;
#else
return false;
/* If the SELinux status page has been successfully opened, retrieve the enforcing
* status over it to avoid system calls in security_getenforce(). */
if (have_status_page)
r = selinux_status_getenforce();
else
r = security_getenforce();
#endif
return r != 0;
}
void mac_selinux_retest(void) {
@ -142,7 +150,6 @@ static int open_label_db(void) {
int mac_selinux_init(void) {
#if HAVE_SELINUX
int r;
bool have_status_page = false;
if (initialized)
return 0;
@ -170,11 +177,6 @@ int mac_selinux_init(void) {
* first call without any actual change. */
last_policyload = selinux_status_policyload();
if (have_status_page)
/* Now that the SELinux status page has been successfully opened, retrieve the enforcing
* status over it (to avoid system calls in security_getenforce()). */
enforcing_status_func = selinux_status_getenforce;
initialized = true;
#endif
return 0;
@ -215,9 +217,8 @@ void mac_selinux_finish(void) {
label_hnd = NULL;
}
enforcing_status_func = security_getenforce;
selinux_status_close();
have_status_page = false;
initialized = false;
#endif

View File

@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/magic.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/ioctl.h>
@ -28,6 +29,7 @@
#include "parse-util.h"
#include "path-util.h"
#include "sleep-config.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
@ -232,7 +234,7 @@ static int calculate_swap_file_offset(const SwapEntry *swap, uint64_t *ret_offse
_cleanup_close_ int fd = -1;
_cleanup_free_ struct fiemap *fiemap = NULL;
struct stat sb;
int r, btrfs;
int r;
assert(swap);
assert(swap->device);
@ -245,10 +247,10 @@ static int calculate_swap_file_offset(const SwapEntry *swap, uint64_t *ret_offse
if (fstat(fd, &sb) < 0)
return log_debug_errno(errno, "Failed to stat %s: %m", swap->device);
btrfs = btrfs_is_filesystem(fd);
if (btrfs < 0)
return log_debug_errno(btrfs, "Error checking %s for Btrfs filesystem: %m", swap->device);
if (btrfs > 0) {
r = fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
if (r < 0)
return log_debug_errno(r, "Error checking %s for Btrfs filesystem: %m", swap->device);
if (r > 0) {
log_debug("%s: detection of swap file offset on Btrfs is not supported", swap->device);
*ret_offset = UINT64_MAX;
return 0;

View File

@ -42,84 +42,38 @@ TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Marshal)(TPM2B_PUBLIC const *src, uint8_t buf
TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PUBLIC *dest) = NULL;
int dlopen_tpm2(void) {
int r, k = 0;
int r;
if (!libtss2_esys_dl) {
_cleanup_(dlclosep) void *dl = NULL;
r = dlopen_many_sym_or_warn(
&libtss2_esys_dl, "libtss2-esys.so.0", LOG_DEBUG,
DLSYM_ARG(Esys_Create),
DLSYM_ARG(Esys_CreatePrimary),
DLSYM_ARG(Esys_Finalize),
DLSYM_ARG(Esys_FlushContext),
DLSYM_ARG(Esys_Free),
DLSYM_ARG(Esys_GetRandom),
DLSYM_ARG(Esys_Initialize),
DLSYM_ARG(Esys_Load),
DLSYM_ARG(Esys_PolicyGetDigest),
DLSYM_ARG(Esys_PolicyPCR),
DLSYM_ARG(Esys_StartAuthSession),
DLSYM_ARG(Esys_Startup),
DLSYM_ARG(Esys_Unseal));
if (r < 0)
return r;
dl = dlopen("libtss2-esys.so.0", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 support is not installed: %s", dlerror());
r = dlopen_many_sym_or_warn(
&libtss2_rc_dl, "libtss2-rc.so.0", LOG_DEBUG,
DLSYM_ARG(Tss2_RC_Decode));
if (r < 0)
return r;
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
DLSYM_ARG(Esys_Create),
DLSYM_ARG(Esys_CreatePrimary),
DLSYM_ARG(Esys_Finalize),
DLSYM_ARG(Esys_FlushContext),
DLSYM_ARG(Esys_Free),
DLSYM_ARG(Esys_GetRandom),
DLSYM_ARG(Esys_Initialize),
DLSYM_ARG(Esys_Load),
DLSYM_ARG(Esys_PolicyGetDigest),
DLSYM_ARG(Esys_PolicyPCR),
DLSYM_ARG(Esys_StartAuthSession),
DLSYM_ARG(Esys_Startup),
DLSYM_ARG(Esys_Unseal),
NULL);
if (r < 0)
return r;
libtss2_esys_dl = TAKE_PTR(dl);
k++;
}
if (!libtss2_rc_dl) {
_cleanup_(dlclosep) void *dl = NULL;
dl = dlopen("libtss2-rc.so.0", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
DLSYM_ARG(Tss2_RC_Decode),
NULL);
if (r < 0)
return r;
libtss2_rc_dl = TAKE_PTR(dl);
k++;
}
if (!libtss2_mu_dl) {
_cleanup_(dlclosep) void *dl = NULL;
dl = dlopen("libtss2-mu.so.0", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Marshal),
DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Unmarshal),
DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Marshal),
DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal),
NULL);
if (r < 0)
return r;
libtss2_mu_dl = TAKE_PTR(dl);
k++;
}
return k;
return dlopen_many_sym_or_warn(
&libtss2_mu_dl, "libtss2-mu.so.0", LOG_DEBUG,
DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Marshal),
DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Unmarshal),
DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Marshal),
DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal));
}
struct tpm2_context {

View File

@ -146,6 +146,8 @@ tests += [
[['src/test/test-utf8.c']],
[['src/test/test-blockdev-util.c']],
[['src/test/test-dev-setup.c']],
[['src/test/test-capability.c'],
@ -159,6 +161,8 @@ tests += [
[['src/test/test-copy.c']],
[['src/test/test-data-fd-util.c']],
[['src/test/test-static-destruct.c']],
[['src/test/test-sigbus.c']],

View File

@ -0,0 +1,43 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "blockdev-util.h"
#include "errno-util.h"
#include "tests.h"
static void test_path_is_encrypted_one(const char *p, int expect) {
int r;
r = path_is_encrypted(p);
if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) /* This might fail, if btrfs is used and we run in a
* container. In that case we cannot resolve the device node paths that
* BTRFS_IOC_DEV_INFO returns, because the device nodes are unlikely to exist in
* the container. But if we can't stat() them we cannot determine the dev_t of
* them, and thus cannot figure out if they are enrypted. Hence let's just ignore
* ENOENT here. Also skip the test if we lack privileges. */
return;
assert_se(r >= 0);
log_info("%s encrypted: %s", p, yes_no(r));
assert_se(expect < 0 || ((r > 0) == (expect > 0)));
}
static void test_path_is_encrypted(void) {
int booted = sd_booted(); /* If this is run in build environments such as koji, /dev might be a
* reguar fs. Don't assume too much if not running under systemd. */
log_info("/* %s (sd_booted=%d) */", __func__, booted);
test_path_is_encrypted_one("/home", -1);
test_path_is_encrypted_one("/var", -1);
test_path_is_encrypted_one("/", -1);
test_path_is_encrypted_one("/proc", false);
test_path_is_encrypted_one("/sys", false);
test_path_is_encrypted_one("/dev", booted > 0 ? false : -1);
}
int main(int argc, char **argv) {
test_setup_logging(LOG_INFO);
test_path_is_encrypted();
}

View File

@ -0,0 +1,154 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "data-fd-util.h"
#include "fd-util.h"
#include "memory-util.h"
#include "process-util.h"
#include "tests.h"
#include "random-util.h"
static void test_acquire_data_fd_one(unsigned flags) {
char wbuffer[196*1024 - 7];
char rbuffer[sizeof(wbuffer)];
int fd;
fd = acquire_data_fd("foo", 3, flags);
assert_se(fd >= 0);
zero(rbuffer);
assert_se(read(fd, rbuffer, sizeof(rbuffer)) == 3);
assert_se(streq(rbuffer, "foo"));
fd = safe_close(fd);
fd = acquire_data_fd("", 0, flags);
assert_se(fd >= 0);
zero(rbuffer);
assert_se(read(fd, rbuffer, sizeof(rbuffer)) == 0);
assert_se(streq(rbuffer, ""));
fd = safe_close(fd);
random_bytes(wbuffer, sizeof(wbuffer));
fd = acquire_data_fd(wbuffer, sizeof(wbuffer), flags);
assert_se(fd >= 0);
zero(rbuffer);
assert_se(read(fd, rbuffer, sizeof(rbuffer)) == sizeof(rbuffer));
assert_se(memcmp(rbuffer, wbuffer, sizeof(rbuffer)) == 0);
fd = safe_close(fd);
}
static void test_acquire_data_fd(void) {
test_acquire_data_fd_one(0);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL);
test_acquire_data_fd_one(ACQUIRE_NO_MEMFD);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD);
test_acquire_data_fd_one(ACQUIRE_NO_PIPE);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_PIPE);
test_acquire_data_fd_one(ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE|ACQUIRE_NO_TMPFILE);
}
static void assert_equal_fd(int fd1, int fd2) {
for (;;) {
uint8_t a[4096], b[4096];
ssize_t x, y;
x = read(fd1, a, sizeof(a));
assert_se(x >= 0);
y = read(fd2, b, sizeof(b));
assert_se(y >= 0);
assert_se(x == y);
if (x == 0)
break;
assert_se(memcmp(a, b, x) == 0);
}
}
static void test_copy_data_fd(void) {
_cleanup_close_ int fd1 = -1, fd2 = -1;
_cleanup_(close_pairp) int sfd[2] = { -1, -1 };
_cleanup_(sigkill_waitp) pid_t pid = -1;
int r;
fd1 = open("/etc/fstab", O_RDONLY|O_CLOEXEC);
if (fd1 >= 0) {
fd2 = copy_data_fd(fd1);
assert_se(fd2 >= 0);
assert_se(lseek(fd1, 0, SEEK_SET) == 0);
assert_equal_fd(fd1, fd2);
}
fd1 = safe_close(fd1);
fd2 = safe_close(fd2);
fd1 = acquire_data_fd("hallo", 6, 0);
assert_se(fd1 >= 0);
fd2 = copy_data_fd(fd1);
assert_se(fd2 >= 0);
safe_close(fd1);
fd1 = acquire_data_fd("hallo", 6, 0);
assert_se(fd1 >= 0);
assert_equal_fd(fd1, fd2);
fd1 = safe_close(fd1);
fd2 = safe_close(fd2);
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sfd) >= 0);
r = safe_fork("(sd-pipe)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
assert_se(r >= 0);
if (r == 0) {
/* child */
sfd[0] = safe_close(sfd[0]);
for (uint64_t i = 0; i < 1536*1024 / sizeof(uint64_t); i++)
assert_se(write(sfd[1], &i, sizeof(i)) == sizeof(i));
sfd[1] = safe_close(sfd[1]);
_exit(EXIT_SUCCESS);
}
sfd[1] = safe_close(sfd[1]);
fd2 = copy_data_fd(sfd[0]);
assert_se(fd2 >= 0);
uint64_t j;
for (uint64_t i = 0; i < 1536*1024 / sizeof(uint64_t); i++) {
assert_se(read(fd2, &j, sizeof(j)) == sizeof(j));
assert_se(i == j);
}
assert_se(read(fd2, &j, sizeof(j)) == 0);
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_acquire_data_fd();
test_copy_data_fd();
return 0;
}

View File

@ -4,6 +4,7 @@
#include <unistd.h>
#include "alloc-util.h"
#include "data-fd-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "macro.h"
@ -95,54 +96,6 @@ static void test_open_serialization_fd(void) {
assert_se(write(fd, "test\n", 5) == 5);
}
static void test_acquire_data_fd_one(unsigned flags) {
char wbuffer[196*1024 - 7];
char rbuffer[sizeof(wbuffer)];
int fd;
fd = acquire_data_fd("foo", 3, flags);
assert_se(fd >= 0);
zero(rbuffer);
assert_se(read(fd, rbuffer, sizeof(rbuffer)) == 3);
assert_se(streq(rbuffer, "foo"));
fd = safe_close(fd);
fd = acquire_data_fd("", 0, flags);
assert_se(fd >= 0);
zero(rbuffer);
assert_se(read(fd, rbuffer, sizeof(rbuffer)) == 0);
assert_se(streq(rbuffer, ""));
fd = safe_close(fd);
random_bytes(wbuffer, sizeof(wbuffer));
fd = acquire_data_fd(wbuffer, sizeof(wbuffer), flags);
assert_se(fd >= 0);
zero(rbuffer);
assert_se(read(fd, rbuffer, sizeof(rbuffer)) == sizeof(rbuffer));
assert_se(memcmp(rbuffer, wbuffer, sizeof(rbuffer)) == 0);
fd = safe_close(fd);
}
static void test_acquire_data_fd(void) {
test_acquire_data_fd_one(0);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL);
test_acquire_data_fd_one(ACQUIRE_NO_MEMFD);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD);
test_acquire_data_fd_one(ACQUIRE_NO_PIPE);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_PIPE);
test_acquire_data_fd_one(ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE);
test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE|ACQUIRE_NO_TMPFILE);
}
static void test_fd_move_above_stdio(void) {
int original_stdin, new_fd;
@ -227,93 +180,6 @@ static void test_rearrange_stdio(void) {
}
}
static void assert_equal_fd(int fd1, int fd2) {
for (;;) {
uint8_t a[4096], b[4096];
ssize_t x, y;
x = read(fd1, a, sizeof(a));
assert_se(x >= 0);
y = read(fd2, b, sizeof(b));
assert_se(y >= 0);
assert_se(x == y);
if (x == 0)
break;
assert_se(memcmp(a, b, x) == 0);
}
}
static void test_fd_duplicate_data_fd(void) {
_cleanup_close_ int fd1 = -1, fd2 = -1;
_cleanup_(close_pairp) int sfd[2] = { -1, -1 };
_cleanup_(sigkill_waitp) pid_t pid = -1;
uint64_t i, j;
int r;
fd1 = open("/etc/fstab", O_RDONLY|O_CLOEXEC);
if (fd1 >= 0) {
fd2 = fd_duplicate_data_fd(fd1);
assert_se(fd2 >= 0);
assert_se(lseek(fd1, 0, SEEK_SET) == 0);
assert_equal_fd(fd1, fd2);
}
fd1 = safe_close(fd1);
fd2 = safe_close(fd2);
fd1 = acquire_data_fd("hallo", 6, 0);
assert_se(fd1 >= 0);
fd2 = fd_duplicate_data_fd(fd1);
assert_se(fd2 >= 0);
safe_close(fd1);
fd1 = acquire_data_fd("hallo", 6, 0);
assert_se(fd1 >= 0);
assert_equal_fd(fd1, fd2);
fd1 = safe_close(fd1);
fd2 = safe_close(fd2);
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sfd) >= 0);
r = safe_fork("(sd-pipe)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
assert_se(r >= 0);
if (r == 0) {
/* child */
sfd[0] = safe_close(sfd[0]);
for (i = 0; i < 1536*1024 / sizeof(uint64_t); i++)
assert_se(write(sfd[1], &i, sizeof(i)) == sizeof(i));
sfd[1] = safe_close(sfd[1]);
_exit(EXIT_SUCCESS);
}
sfd[1] = safe_close(sfd[1]);
fd2 = fd_duplicate_data_fd(sfd[0]);
assert_se(fd2 >= 0);
for (i = 0; i < 1536*1024 / sizeof(uint64_t); i++) {
assert_se(read(fd2, &j, sizeof(j)) == sizeof(j));
assert_se(i == j);
}
assert_se(read(fd2, &j, sizeof(j)) == 0);
}
static void test_read_nr_open(void) {
log_info("nr-open: %i", read_nr_open());
}
@ -420,10 +286,8 @@ int main(int argc, char *argv[]) {
test_close_nointr();
test_same_fd();
test_open_serialization_fd();
test_acquire_data_fd();
test_fd_move_above_stdio();
test_rearrange_stdio();
test_fd_duplicate_data_fd();
test_read_nr_open();
test_close_all_fds();

View File

@ -805,38 +805,6 @@ static void test_chmod_and_chown(void) {
assert_se(S_ISLNK(st.st_mode));
}
static void test_path_is_encrypted_one(const char *p, int expect) {
int r;
r = path_is_encrypted(p);
if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) /* This might fail, if btrfs is used and we run in a
* container. In that case we cannot resolve the device node paths that
* BTRFS_IOC_DEV_INFO returns, because the device nodes are unlikely to exist in
* the container. But if we can't stat() them we cannot determine the dev_t of
* them, and thus cannot figure out if they are enrypted. Hence let's just ignore
* ENOENT here. Also skip the test if we lack privileges. */
return;
assert_se(r >= 0);
log_info("%s encrypted: %s", p, yes_no(r));
assert_se(expect < 0 || ((r > 0) == (expect > 0)));
}
static void test_path_is_encrypted(void) {
int booted = sd_booted(); /* If this is run in build environments such as koji, /dev might be a
* reguar fs. Don't assume too much if not running under systemd. */
log_info("/* %s (sd_booted=%d) */", __func__, booted);
test_path_is_encrypted_one("/home", -1);
test_path_is_encrypted_one("/var", -1);
test_path_is_encrypted_one("/", -1);
test_path_is_encrypted_one("/proc", false);
test_path_is_encrypted_one("/sys", false);
test_path_is_encrypted_one("/dev", booted > 0 ? false : -1);
}
static void create_binary_file(const char *p, const void *data, size_t l) {
_cleanup_close_ int fd = -1;
@ -914,7 +882,6 @@ int main(int argc, char *argv[]) {
test_fsync_directory_of_file();
test_rename_noreplace();
test_chmod_and_chown();
test_path_is_encrypted();
test_conservative_rename();
return 0;

View File

@ -7,7 +7,9 @@
#include "capability-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "missing_mount.h"
#include "mkdir.h"
#include "mount-util.h"
#include "namespace-util.h"
#include "path-util.h"
@ -217,6 +219,52 @@ static void test_bind_remount_one(void) {
assert_se(wait_for_terminate_and_check("test-remount-one", pid, WAIT_LOG) == EXIT_SUCCESS);
}
static void test_make_mount_point_inode(void) {
_cleanup_(rm_rf_physical_and_freep) char *d = NULL;
const char *src_file, *src_dir, *dst_file, *dst_dir;
struct stat st;
log_info("/* %s */", __func__);
assert_se(mkdtemp_malloc(NULL, &d) >= 0);
src_file = strjoina(d, "/src/file");
src_dir = strjoina(d, "/src/dir");
dst_file = strjoina(d, "/dst/file");
dst_dir = strjoina(d, "/dst/dir");
assert_se(mkdir_p(src_dir, 0755) >= 0);
assert_se(mkdir_parents(dst_file, 0755) >= 0);
assert_se(touch(src_file) >= 0);
assert_se(make_mount_point_inode_from_path(src_file, dst_file, 0755) >= 0);
assert_se(make_mount_point_inode_from_path(src_dir, dst_dir, 0755) >= 0);
assert_se(stat(dst_dir, &st) == 0);
assert_se(S_ISDIR(st.st_mode));
assert_se(stat(dst_file, &st) == 0);
assert_se(S_ISREG(st.st_mode));
assert_se(!(S_IXUSR & st.st_mode));
assert_se(!(S_IXGRP & st.st_mode));
assert_se(!(S_IXOTH & st.st_mode));
assert_se(unlink(dst_file) == 0);
assert_se(rmdir(dst_dir) == 0);
assert_se(stat(src_file, &st) == 0);
assert_se(make_mount_point_inode_from_stat(&st, dst_file, 0755) >= 0);
assert_se(stat(src_dir, &st) == 0);
assert_se(make_mount_point_inode_from_stat(&st, dst_dir, 0755) >= 0);
assert_se(stat(dst_dir, &st) == 0);
assert_se(S_ISDIR(st.st_mode));
assert_se(stat(dst_file, &st) == 0);
assert_se(S_ISREG(st.st_mode));
assert_se(!(S_IXUSR & st.st_mode));
assert_se(!(S_IXGRP & st.st_mode));
assert_se(!(S_IXOTH & st.st_mode));
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@ -224,6 +272,7 @@ int main(int argc, char *argv[]) {
test_mount_flags_to_string();
test_bind_remount_recursive();
test_bind_remount_one();
test_make_mount_point_inode();
return 0;
}

View File

@ -8,10 +8,8 @@
#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "hashmap.h"
#include "log.h"
#include "mkdir.h"
#include "mountpoint-util.h"
#include "path-util.h"
#include "rm-rf.h"
@ -290,52 +288,6 @@ static void test_fd_is_mount_point(void) {
assert_se(IN_SET(fd_is_mount_point(fd, "root/", 0), -ENOENT, 0));
}
static void test_make_mount_point_inode(void) {
_cleanup_(rm_rf_physical_and_freep) char *d = NULL;
const char *src_file, *src_dir, *dst_file, *dst_dir;
struct stat st;
log_info("/* %s */", __func__);
assert_se(mkdtemp_malloc(NULL, &d) >= 0);
src_file = strjoina(d, "/src/file");
src_dir = strjoina(d, "/src/dir");
dst_file = strjoina(d, "/dst/file");
dst_dir = strjoina(d, "/dst/dir");
assert_se(mkdir_p(src_dir, 0755) >= 0);
assert_se(mkdir_parents(dst_file, 0755) >= 0);
assert_se(touch(src_file) >= 0);
assert_se(make_mount_point_inode_from_path(src_file, dst_file, 0755) >= 0);
assert_se(make_mount_point_inode_from_path(src_dir, dst_dir, 0755) >= 0);
assert_se(stat(dst_dir, &st) == 0);
assert_se(S_ISDIR(st.st_mode));
assert_se(stat(dst_file, &st) == 0);
assert_se(S_ISREG(st.st_mode));
assert_se(!(S_IXUSR & st.st_mode));
assert_se(!(S_IXGRP & st.st_mode));
assert_se(!(S_IXOTH & st.st_mode));
assert_se(unlink(dst_file) == 0);
assert_se(rmdir(dst_dir) == 0);
assert_se(stat(src_file, &st) == 0);
assert_se(make_mount_point_inode_from_stat(&st, dst_file, 0755) >= 0);
assert_se(stat(src_dir, &st) == 0);
assert_se(make_mount_point_inode_from_stat(&st, dst_dir, 0755) >= 0);
assert_se(stat(dst_dir, &st) == 0);
assert_se(S_ISDIR(st.st_mode));
assert_se(stat(dst_file, &st) == 0);
assert_se(S_ISREG(st.st_mode));
assert_se(!(S_IXUSR & st.st_mode));
assert_se(!(S_IXGRP & st.st_mode));
assert_se(!(S_IXOTH & st.st_mode));
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@ -360,7 +312,6 @@ int main(int argc, char *argv[]) {
test_mnt_id();
test_path_is_mount_point();
test_fd_is_mount_point();
test_make_mount_point_inode();
return 0;
}