Compare commits

..

No commits in common. "9929fe8c950cee84bf901ebf50920a078d45a27f" and "a0b7f198762184630af28ccf75e5f573f5205ec2" have entirely different histories.

7 changed files with 140 additions and 72 deletions

8
TODO
View File

@ -378,6 +378,8 @@ Features:
* show whether a service has out-of-date configuration in "systemctl status" by
using mtime data of ConfigurationDirectory=.
* replace all remaining uses of fgets() + LINE_MAX by read_line()
* Add AddUser= setting to unit files, similar to DynamicUser=1 which however
creates a static, persistent user rather than a dynamic, transient user. We
can leverage code from sysusers.d for this.
@ -458,6 +460,8 @@ Features:
* define gpt header bits to select volatility mode
* ProtectKernelLogs= (drops CAP_SYSLOG, add seccomp for syslog() syscall, and DeviceAllow to /dev/kmsg) in service files
* ProtectClock= (drops CAP_SYS_TIMES, adds seecomp filters for settimeofday, adjtimex), sets DeviceAllow o /dev/rtc
* ProtectTracing= (drops CAP_SYS_PTRACE, blocks ptrace syscall, makes /sys/kernel/tracing go away)
@ -515,7 +519,7 @@ Features:
* when we detect that there are waiting jobs but no running jobs, do something
* push CPUAffinity= also into the "cpuset" cgroup controller
* push CPUAffinity= also into the "cpuset" cgroup controller (only after the cpuset controller got ported to the unified hierarchy)
* PID 1 should send out sd_notify("WATCHDOG=1") messages (for usage in the --user mode, and when run via nspawn)
@ -576,6 +580,8 @@ Features:
* what to do about udev db binary stability for apps? (raw access is not an option)
* man: maybe use the word "inspect" rather than "introspect"?
* systemctl: if some operation fails, show log output?
* systemctl edit: use equivalent of cat() to insert existing config as a comment, prepended with #.

View File

@ -1340,8 +1340,9 @@ int safe_fork_full(
}
} else if (flags & FORK_STDOUT_TO_STDERR) {
if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
log_full_errno(prio, errno, "Failed to connect stdout to stderr: %m");
log_full_errno(prio, r, "Failed to connect stdout to stderr: %m");
_exit(EXIT_FAILURE);
}
}

View File

@ -18,15 +18,57 @@
#include "fd-util.h"
#include "format-util.h"
#include "log.h"
#include "main-func.h"
#include "missing_fs.h"
#include "mountpoint-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "pretty-print.h"
#include "resize-fs.h"
#include "stat-util.h"
#include "strv.h"
#include "util.h"
static const char *arg_target = NULL;
static bool arg_dry_run = false;
static int resize_ext4(const char *path, int mountfd, int devfd, uint64_t numblocks, uint64_t blocksize) {
assert((uint64_t) (int) blocksize == blocksize);
if (arg_dry_run)
return 0;
if (ioctl(mountfd, EXT4_IOC_RESIZE_FS, &numblocks) != 0)
return log_error_errno(errno, "Failed to resize \"%s\" to %"PRIu64" blocks (ext4): %m",
path, numblocks);
return 0;
}
static int resize_btrfs(const char *path, int mountfd, int devfd, uint64_t numblocks, uint64_t blocksize) {
struct btrfs_ioctl_vol_args args = {};
int r;
assert((uint64_t) (int) blocksize == blocksize);
/* https://bugzilla.kernel.org/show_bug.cgi?id=118111 */
if (numblocks * blocksize < 256*1024*1024) {
log_warning("%s: resizing of btrfs volumes smaller than 256M is not supported", path);
return -EOPNOTSUPP;
}
r = snprintf(args.name, sizeof(args.name), "%"PRIu64, numblocks * blocksize);
/* The buffer is large enough for any number to fit... */
assert((size_t) r < sizeof(args.name));
if (arg_dry_run)
return 0;
if (ioctl(mountfd, BTRFS_IOC_RESIZE, &args) != 0)
return log_error_errno(errno, "Failed to resize \"%s\" to %"PRIu64" blocks (btrfs): %m",
path, numblocks);
return 0;
}
#if HAVE_LIBCRYPTSETUP
static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_devno) {
_cleanup_free_ char *devpath = NULL, *main_devpath = NULL;
@ -117,7 +159,7 @@ static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
return resize_crypt_luks_device(devno, fstype, main_devno);
#endif
log_debug("Don't know how to resize %s of type %s, ignoring.", devpath, strnull(fstype));
log_debug("Don't know how to resize %s of type %s, ignoring", devpath, strnull(fstype));
return 0;
}
@ -189,64 +231,100 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
static int run(int argc, char *argv[]) {
int main(int argc, char *argv[]) {
_cleanup_close_ int mountfd = -1, devfd = -1;
_cleanup_free_ char *devpath = NULL;
uint64_t size, newsize;
uint64_t size, numblocks;
char fb[FORMAT_BYTES_MAX];
struct statfs sfs;
dev_t devno;
int blocksize;
int r;
log_setup_service();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
if (r < 0)
return EXIT_FAILURE;
if (r == 0)
return EXIT_SUCCESS;
r = path_is_mount_point(arg_target, NULL, 0);
if (r < 0)
return log_error_errno(r, "Failed to check if \"%s\" is a mount point: %m", arg_target);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "\"%s\" is not a mount point: %m", arg_target);
if (r < 0) {
log_error_errno(r, "Failed to check if \"%s\" is a mount point: %m", arg_target);
return EXIT_FAILURE;
}
if (r == 0) {
log_error_errno(r, "\"%s\" is not a mount point: %m", arg_target);
return EXIT_FAILURE;
}
r = get_block_device(arg_target, &devno);
if (r < 0)
return log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target);
if (r < 0) {
log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target);
return EXIT_FAILURE;
}
r = maybe_resize_slave_device(arg_target, devno);
if (r < 0)
return r;
return EXIT_FAILURE;
mountfd = open(arg_target, O_RDONLY|O_CLOEXEC);
if (mountfd < 0)
return log_error_errno(errno, "Failed to open \"%s\": %m", arg_target);
r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
if (r < 0)
return log_error_errno(r, "Failed to format device major/minor path: %m");
devfd = open(devpath, O_RDONLY|O_CLOEXEC);
if (devfd < 0)
return log_error_errno(errno, "Failed to open \"%s\": %m", devpath);
if (ioctl(devfd, BLKGETSIZE64, &size) != 0)
return log_error_errno(errno, "Failed to query size of \"%s\": %m", devpath);
log_debug("Resizing \"%s\" to %"PRIu64" bytes...", arg_target, size);
r = resize_fs(mountfd, size, &newsize);
if (r < 0)
return log_error_errno(r, "Failed to resize \"%s\" to %"PRIu64" bytes: %m",
arg_target, size);
if (newsize == size)
log_info("Successfully resized \"%s\" to %s bytes.",
arg_target,
format_bytes(fb, sizeof fb, newsize));
else
log_info("Successfully resized \"%s\" to %s bytes (%"PRIu64" bytes lost due to blocksize).",
arg_target,
format_bytes(fb, sizeof fb, newsize),
size - newsize);
return 0;
if (mountfd < 0) {
log_error_errno(errno, "Failed to open \"%s\": %m", arg_target);
return EXIT_FAILURE;
}
DEFINE_MAIN_FUNCTION(run);
r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
if (r < 0) {
log_error_errno(r, "Failed to format device major/minor path: %m");
return EXIT_FAILURE;
}
devfd = open(devpath, O_RDONLY|O_CLOEXEC);
if (devfd < 0) {
log_error_errno(errno, "Failed to open \"%s\": %m", devpath);
return EXIT_FAILURE;
}
if (ioctl(devfd, BLKBSZGET, &blocksize) != 0) {
log_error_errno(errno, "Failed to query block size of \"%s\": %m", devpath);
return EXIT_FAILURE;
}
if (ioctl(devfd, BLKGETSIZE64, &size) != 0) {
log_error_errno(errno, "Failed to query size of \"%s\": %m", devpath);
return EXIT_FAILURE;
}
if (size % blocksize != 0)
log_notice("Partition size %"PRIu64" is not a multiple of the blocksize %d,"
" ignoring %"PRIu64" bytes", size, blocksize, size % blocksize);
numblocks = size / blocksize;
if (fstatfs(mountfd, &sfs) < 0) {
log_error_errno(errno, "Failed to stat file system \"%s\": %m", arg_target);
return EXIT_FAILURE;
}
switch(sfs.f_type) {
case EXT4_SUPER_MAGIC:
r = resize_ext4(arg_target, mountfd, devfd, numblocks, blocksize);
break;
case BTRFS_SUPER_MAGIC:
r = resize_btrfs(arg_target, mountfd, devfd, numblocks, blocksize);
break;
default:
log_error("Don't know how to resize fs %llx on \"%s\"",
(long long unsigned) sfs.f_type, arg_target);
return EXIT_FAILURE;
}
if (r < 0)
return EXIT_FAILURE;
log_info("Successfully resized \"%s\" to %s bytes (%"PRIu64" blocks of %d bytes).",
arg_target, format_bytes(fb, sizeof fb, size), numblocks, blocksize);
return EXIT_SUCCESS;
}

View File

@ -13,7 +13,7 @@
#include "resize-fs.h"
#include "stat-util.h"
int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
int resize_fs(int fd, uint64_t sz) {
struct statfs sfs;
int r;
@ -38,9 +38,6 @@ int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
if (ioctl(fd, EXT4_IOC_RESIZE_FS, &u) < 0)
return -errno;
if (ret_size)
*ret_size = u * sfs.f_bsize;
} else if (is_fs_type(&sfs, BTRFS_SUPER_MAGIC)) {
struct btrfs_ioctl_vol_args args = {};
@ -52,17 +49,12 @@ int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
if (sz < BTRFS_MINIMAL_SIZE)
return -ERANGE;
sz -= sz % sfs.f_bsize;
r = snprintf(args.name, sizeof(args.name), "%" PRIu64, sz);
assert((size_t) r < sizeof(args.name));
if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
return -errno;
if (ret_size)
*ret_size = sz;
} else if (is_fs_type(&sfs, XFS_SB_MAGIC)) {
xfs_fsop_geom_t geo;
xfs_growfs_data_t d;
@ -81,9 +73,6 @@ int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
if (ioctl(fd, XFS_IOC_FSGROWFSDATA, &d) < 0)
return -errno;
if (ret_size)
*ret_size = d.newblocks * geo.blocksize;
} else
return -EOPNOTSUPP;

View File

@ -5,7 +5,7 @@
#include "stat-util.h"
int resize_fs(int fd, uint64_t sz, uint64_t *ret_size);
int resize_fs(int fd, uint64_t sz);
#define BTRFS_MINIMAL_SIZE (256U*1024U*1024U)
#define XFS_MINIMAL_SIZE (14U*1024U*1024U)

View File

@ -1584,7 +1584,6 @@ assert_cc(SCMP_SYS(shmdt) > 0);
int seccomp_memory_deny_write_execute(void) {
uint32_t arch;
int r;
int loaded = 0;
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
@ -1594,23 +1593,22 @@ int seccomp_memory_deny_write_execute(void) {
switch (arch) {
/* Note that on some architectures shmat() isn't available, and the call is multiplexed through ipc().
* We ignore that here, which means there's still a way to get writable/executable
* memory, if an IPC key is mapped like this. That's a pity, but no total loss. */
case SCMP_ARCH_X86:
case SCMP_ARCH_S390:
filter_syscall = SCMP_SYS(mmap2);
block_syscall = SCMP_SYS(mmap);
/* shmat multiplexed, see above */
shmat_syscall = SCMP_SYS(shmat);
break;
case SCMP_ARCH_PPC:
case SCMP_ARCH_PPC64:
case SCMP_ARCH_PPC64LE:
case SCMP_ARCH_S390X:
filter_syscall = SCMP_SYS(mmap);
/* shmat multiplexed, see above */
/* Note that shmat() isn't available, and the call is multiplexed through ipc().
* We ignore that here, which means there's still a way to get writable/executable
* memory, if an IPC key is mapped like this. That's a pity, but no total loss. */
break;
case SCMP_ARCH_ARM:
@ -1621,7 +1619,8 @@ int seccomp_memory_deny_write_execute(void) {
case SCMP_ARCH_X86_64:
case SCMP_ARCH_X32:
case SCMP_ARCH_AARCH64:
filter_syscall = SCMP_SYS(mmap); /* amd64, x32 and arm64 have only mmap */
case SCMP_ARCH_S390X:
filter_syscall = SCMP_SYS(mmap); /* amd64, x32, s390x, and arm64 have only mmap */
shmat_syscall = SCMP_SYS(shmat);
break;
@ -1667,7 +1666,7 @@ int seccomp_memory_deny_write_execute(void) {
#endif
if (shmat_syscall > 0) {
r = add_seccomp_syscall_filter(seccomp, arch, shmat_syscall,
r = add_seccomp_syscall_filter(seccomp, arch, SCMP_SYS(shmat),
1,
SCMP_A2(SCMP_CMP_MASKED_EQ, SHM_EXEC, SHM_EXEC));
if (r < 0)
@ -1679,13 +1678,9 @@ int seccomp_memory_deny_write_execute(void) {
return r;
if (r < 0)
log_debug_errno(r, "Failed to install MemoryDenyWriteExecute= rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
loaded++;
}
if (loaded == 0)
log_debug_errno(r, "Failed to install any seccomp rules for MemoryDenyWriteExecute=");
return loaded;
return 0;
}
int seccomp_restrict_archs(Set *archs) {

View File

@ -535,11 +535,10 @@ static void test_memory_deny_write_execute_mmap(void) {
#if defined(__x86_64__) || defined(__i386__) || defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__)
assert_se(p == MAP_FAILED);
assert_se(errno == EPERM);
#else /* unknown architectures */
assert_se(p != MAP_FAILED);
assert_se(munmap(p, page_size()) >= 0);
#endif
/* Depending on kernel, libseccomp, and glibc versions, other architectures
* might fail or not. Let's not assert success. */
if (p != MAP_FAILED)
assert_se(munmap(p, page_size()) == 0);
p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
assert_se(p != MAP_FAILED);