From: Lennart Poettering Date: Mon, 21 Jun 2021 09:17:10 +0000 (+0200) Subject: chattr-util: generalize chattr manipulation for files with secrets from journalctl X-Git-Tag: v250-rc1~980^2~10 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c1631ee124a30abfb9c71e2a1534b8afffc3b6a7;p=thirdparty%2Fsystemd.git chattr-util: generalize chattr manipulation for files with secrets from journalctl This moves the code for setting chattr file attributes appropriate for "secrets" files from journalctl into generic chattr-util.c code so that we can use it elsewhere. Also, let's reuse the "bitwise" logic already implemented in the chattr code, instead of doing it again. --- diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c index 10e59875ad2..b5658754a56 100644 --- a/src/basic/chattr-util.c +++ b/src/basic/chattr-util.c @@ -7,10 +7,19 @@ #include #include "chattr-util.h" +#include "errno-util.h" #include "fd-util.h" #include "macro.h" +#include "string-util.h" + +int chattr_full(const char *path, + int fd, + unsigned value, + unsigned mask, + unsigned *ret_previous, + unsigned *ret_final, + ChattrApplyFlags flags) { -int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, bool fallback) { _cleanup_close_ int fd_will_close = -1; unsigned old_attr, new_attr; struct stat st; @@ -57,12 +66,16 @@ int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigne return 1; } - if (errno != EINVAL || !fallback) + if ((errno != EINVAL && !ERRNO_IS_NOT_SUPPORTED(errno)) || + !FLAGS_SET(flags, CHATTR_FALLBACK_BITWISE)) return -errno; /* When -EINVAL is returned, we assume that incompatible attributes are simultaneously * specified. E.g., compress(c) and nocow(C) attributes cannot be set to files on btrfs. - * As a fallback, let's try to set attributes one by one. */ + * As a fallback, let's try to set attributes one by one. + * + * Also, when we get EOPNOTSUPP (or a similar error code) we assume a flag might just not be + * supported, and we can ignore it too */ unsigned current_attr = old_attr; for (unsigned i = 0; i < sizeof(unsigned) * 8; i++) { @@ -76,8 +89,12 @@ int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigne continue; if (ioctl(fd, FS_IOC_SETFLAGS, &new_one) < 0) { - if (errno != EINVAL) + if (errno != EINVAL && !ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; + + log_full_errno(FLAGS_SET(flags, CHATTR_WARN_UNSUPPORTED_FLAGS) ? LOG_WARNING : LOG_DEBUG, + errno, + "Unable to set file attribute 0x%x on %s, ignoring: %m", mask_one, strna(path)); continue; } diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h index 3f46367c82a..82f91c66d9e 100644 --- a/src/basic/chattr-util.h +++ b/src/basic/chattr-util.h @@ -34,13 +34,28 @@ FS_NOCOW_FL | \ FS_PROJINHERIT_FL) -int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, bool fallback); +typedef enum ChattrApplyFlags { + CHATTR_FALLBACK_BITWISE = 1 << 0, + CHATTR_WARN_UNSUPPORTED_FLAGS = 1 << 1, +} ChattrApplyFlags; + +int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, ChattrApplyFlags flags); + static inline int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) { - return chattr_full(NULL, fd, value, mask, previous, NULL, false); + return chattr_full(NULL, fd, value, mask, previous, NULL, 0); } static inline int chattr_path(const char *path, unsigned value, unsigned mask, unsigned *previous) { - return chattr_full(path, -1, value, mask, previous, NULL, false); + return chattr_full(path, -1, value, mask, previous, NULL, 0); } int read_attr_fd(int fd, unsigned *ret); int read_attr_path(const char *p, unsigned *ret); + +/* Combination of chattr flags, that should be appropriate for secrets stored on disk: Secure Remove + + * Exclusion from Dumping + Synchronous Writing (i.e. not caching in memory) + In-Place Updating (i.e. not + * spurious copies). */ +#define CHATTR_SECRET_FLAGS (FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL) + +static inline int chattr_secret(int fd, ChattrApplyFlags flags) { + return chattr_full(NULL, fd, CHATTR_SECRET_FLAGS, CHATTR_SECRET_FLAGS, NULL, NULL, flags|CHATTR_FALLBACK_BITWISE); +} diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index c8fb726d420..17fc493b22f 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1902,19 +1902,10 @@ static int setup_keys(void) { if (fd < 0) return log_error_errno(fd, "Failed to open %s: %m", k); - /* Enable secure remove, exclusion from dump, synchronous writing and in-place updating */ - static const unsigned chattr_flags[] = { - FS_SECRM_FL, - FS_NODUMP_FL, - FS_SYNC_FL, - FS_NOCOW_FL, - }; - for (size_t j = 0; j < ELEMENTSOF(chattr_flags); j++) { - r = chattr_fd(fd, chattr_flags[j], chattr_flags[j], NULL); - if (r < 0) - log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set file attribute 0x%x: %m", chattr_flags[j]); - } + r = chattr_secret(fd, CHATTR_WARN_UNSUPPORTED_FLAGS); + if (r < 0) + log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, + r, "Failed to set file attributes on '%s', ignoring: %m", k); struct FSSHeader h = { .signature = { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' }, diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 7e85c506348..b32b709ef5b 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1355,7 +1355,7 @@ static int fd_set_attribute(Item *item, int fd, const char *path, const struct s return log_error_errno(procfs_fd, "Failed to re-open '%s': %m", path); unsigned previous, current; - r = chattr_full(NULL, procfs_fd, f, item->attribute_mask, &previous, ¤t, true); + r = chattr_full(NULL, procfs_fd, f, item->attribute_mask, &previous, ¤t, CHATTR_FALLBACK_BITWISE); if (r == -ENOANO) log_warning("Cannot set file attributes for '%s', maybe due to incompatibility in specified attributes, " "previous=0x%08x, current=0x%08x, expected=0x%08x, ignoring.",