1
0
mirror of https://github.com/systemd/systemd synced 2026-03-24 07:44:52 +01:00

Compare commits

..

No commits in common. "7d963260a169199b4734c4f68a7319c2f7f7cfe5" and "a4d9c121cc011d3a4feeaa74f54a69de8c9b0b20" have entirely different histories.

17 changed files with 145 additions and 527 deletions

View File

@ -375,9 +375,6 @@ const char *special_glyph(SpecialGlyph code) {
[SPECIAL_GLYPH_DEPRESSED_SMILEY] = ":-[",
[SPECIAL_GLYPH_LOCK_AND_KEY] = "o-,",
[SPECIAL_GLYPH_TOUCH] = "O=", /* Yeah, not very convincing, can you do it better? */
[SPECIAL_GLYPH_RECYCLING] = "~",
[SPECIAL_GLYPH_DOWNLOAD] = "\\",
[SPECIAL_GLYPH_SPARKLES] = "*",
},
/* UTF-8 */
@ -424,12 +421,7 @@ const char *special_glyph(SpecialGlyph code) {
[SPECIAL_GLYPH_LOCK_AND_KEY] = "\360\237\224\220", /* 🔐 (actually called: CLOSED LOCK WITH KEY) */
/* This emoji is a single character cell glyph in Unicode, and two in ASCII */
[SPECIAL_GLYPH_TOUCH] = "\360\237\221\206", /* 👆 (actually called: BACKHAND INDEX POINTING UP) */
/* These three emojis are single character cell glyphs in Unicode and also in ASCII. */
[SPECIAL_GLYPH_RECYCLING] = "\u267B\uFE0F ", /* ♻️ (actually called: UNIVERSAL RECYCLNG SYMBOL) */
[SPECIAL_GLYPH_DOWNLOAD] = "\u2935\uFE0F ", /* ⤵️ (actually called: RIGHT ARROW CURVING DOWN) */
[SPECIAL_GLYPH_SPARKLES] = "\u2728", /* ✨ */
[SPECIAL_GLYPH_TOUCH] = "\360\237\221\206", /* 👆 (actually called: BACKHAND INDEX POINTING UP */
},
};

View File

@ -69,9 +69,6 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_DEPRESSED_SMILEY,
SPECIAL_GLYPH_LOCK_AND_KEY,
SPECIAL_GLYPH_TOUCH,
SPECIAL_GLYPH_RECYCLING,
SPECIAL_GLYPH_DOWNLOAD,
SPECIAL_GLYPH_SPARKLES,
_SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;
@ -98,7 +95,3 @@ static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) {
static inline const char *special_glyph_check_mark(bool b) {
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK);
}
static inline const char *special_glyph_check_mark_space(bool b) {
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " ";
}

View File

@ -65,7 +65,6 @@ int enroll_tpm2(struct crypt_device *cd,
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
size_t secret_size, secret2_size, blob_size, hash_size;
_cleanup_free_ void *blob = NULL, *hash = NULL;
uint16_t pcr_bank;
const char *node;
int r, keyslot;
@ -76,7 +75,7 @@ int enroll_tpm2(struct crypt_device *cd,
assert_se(node = crypt_get_device_name(cd));
r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank);
r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size);
if (r < 0)
return r;
@ -93,7 +92,7 @@ int enroll_tpm2(struct crypt_device *cd,
/* Quick verification that everything is in order, we are not in a hurry after all. */
log_debug("Unsealing for verification...");
r = tpm2_unseal(device, pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
r = tpm2_unseal(device, pcr_mask, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
if (r < 0)
return r;
@ -119,7 +118,7 @@ int enroll_tpm2(struct crypt_device *cd,
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &v);
r = tpm2_make_luks2_json(keyslot, pcr_mask, blob, blob_size, hash, hash_size, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");

View File

@ -13,7 +13,6 @@ int acquire_tpm2_key(
const char *volume_name,
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
@ -63,7 +62,7 @@ int acquire_tpm2_key(
blob = loaded_blob;
}
return tpm2_unseal(device, pcr_mask, pcr_bank, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
return tpm2_unseal(device, pcr_mask, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
}
int find_tpm2_auto_data(
@ -71,7 +70,6 @@ int find_tpm2_auto_data(
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
@ -83,7 +81,6 @@ int find_tpm2_auto_data(
size_t blob_size = 0, policy_hash_size = 0;
int r, keyslot = -1, token = -1;
uint32_t pcr_mask = 0;
uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
assert(cd);
@ -122,23 +119,6 @@ int find_tpm2_auto_data(
search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */
continue;
/* The bank field is optional, since it was added in systemd 250 only. Before the bank was hardcoded to SHA256 */
assert(pcr_bank == UINT16_MAX);
w = json_variant_by_key(v, "tpm2-pcr-bank");
if (w) {
/* The PCR bank field is optional */
if (!json_variant_is_string(w))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"TPM2 PCR bank is not a string.");
r = tpm2_pcr_bank_from_string(json_variant_string(w));
if (r < 0)
return log_error_errno(r, "TPM2 PCR bank invalid or not supported: %s", json_variant_string(w));
pcr_bank = r;
}
assert(!blob);
w = json_variant_by_key(v, "tpm2-blob");
if (!w || !json_variant_is_string(w))
@ -183,7 +163,6 @@ int find_tpm2_auto_data(
*ret_policy_hash_size = policy_hash_size;
*ret_keyslot = keyslot;
*ret_token = token;
*ret_pcr_bank = pcr_bank;
return 0;
}

View File

@ -13,7 +13,6 @@ int acquire_tpm2_key(
const char *volume_name,
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
@ -29,7 +28,6 @@ int find_tpm2_auto_data(
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
@ -43,7 +41,6 @@ static inline int acquire_tpm2_key(
const char *volume_name,
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
@ -63,7 +60,6 @@ static inline int find_tpm2_auto_data(
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,

View File

@ -1103,7 +1103,6 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
name,
arg_tpm2_device,
arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask,
UINT16_MAX,
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
NULL, 0, /* we don't know the policy hash */
@ -1140,14 +1139,12 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
for (;;) {
uint32_t pcr_mask;
uint16_t pcr_bank;
r = find_tpm2_auto_data(
cd,
arg_tpm2_pcr_mask, /* if != UINT32_MAX we'll only look for tokens with this PCR mask */
token, /* search for the token with this index, or any later index than this */
&pcr_mask,
&pcr_bank,
&blob, &blob_size,
&policy_hash, &policy_hash_size,
&keyslot,
@ -1169,7 +1166,6 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
name,
arg_tpm2_device,
pcr_mask,
pcr_bank,
NULL, 0, 0, /* no key file */
blob, blob_size,
policy_hash, policy_hash_size,

View File

@ -2624,10 +2624,9 @@ static int partition_encrypt(
_cleanup_(erase_and_freep) void *secret = NULL;
_cleanup_free_ void *blob = NULL, *hash = NULL;
size_t secret_size, blob_size, hash_size;
uint16_t pcr_bank;
int keyslot;
r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank);
r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size);
if (r < 0)
return log_error_errno(r, "Failed to seal to TPM2: %m");
@ -2649,7 +2648,7 @@ static int partition_encrypt(
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &v);
r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, blob, blob_size, hash, hash_size, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");

View File

@ -369,10 +369,7 @@ struct _packed_ encrypted_credential_header {
};
struct _packed_ tpm2_credential_header {
le64_t pcr_mask; /* Note that the spec for PC Clients only mandates 24 PCRs, and that's what systems
* generally have. But keep the door open for more. */
le16_t pcr_bank; /* For now, either TPM2_ALG_SHA256 or TPM2_ALG_SHA1 */
le16_t _zero; /* Filler to maintain 32bit alignment */
le64_t pcr_mask;
le32_t blob_size;
le32_t policy_hash_size;
uint8_t policy_hash_and_blob[];
@ -442,7 +439,6 @@ int encrypt_credential_and_warn(
struct encrypted_credential_header *h;
int ksz, bsz, ivsz, tsz, added, r;
uint8_t md[SHA256_DIGEST_LENGTH];
uint16_t tpm2_pcr_bank = 0;
const EVP_CIPHER *cc;
#if HAVE_TPM2
bool try_tpm2 = false;
@ -509,8 +505,7 @@ int encrypt_credential_and_warn(
&tpm2_blob,
&tpm2_blob_size,
&tpm2_policy_hash,
&tpm2_policy_hash_size,
&tpm2_pcr_bank);
&tpm2_policy_hash_size);
if (r < 0) {
if (!sd_id128_is_null(with_key))
return r;
@ -603,7 +598,6 @@ int encrypt_credential_and_warn(
t = (struct tpm2_credential_header*) ((uint8_t*) output + p);
t->pcr_mask = htole64(tpm2_pcr_mask);
t->pcr_bank = htole16(tpm2_pcr_bank);
t->blob_size = htole32(tpm2_blob_size);
t->policy_hash_size = htole32(tpm2_policy_hash_size);
memcpy(t->policy_hash_and_blob, tpm2_blob, tpm2_blob_size);
@ -745,10 +739,6 @@ int decrypt_credential_and_warn(
if (le64toh(t->pcr_mask) >= (UINT64_C(1) << TPM2_PCRS_MAX))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR mask out of range.");
if (!tpm2_pcr_bank_supported(le16toh(t->pcr_bank)))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR bank invalid or not supported");
if (le16toh(t->_zero) != 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 padding space not zero.");
if (le32toh(t->blob_size) > CREDENTIAL_FIELD_SIZE_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected TPM2 blob size.");
if (le32toh(t->policy_hash_size) > CREDENTIAL_FIELD_SIZE_MAX)
@ -765,7 +755,6 @@ int decrypt_credential_and_warn(
r = tpm2_unseal(tpm2_device,
le64toh(t->pcr_mask),
le16toh(t->pcr_bank),
t->policy_hash_and_blob,
le32toh(t->blob_size),
t->policy_hash_and_blob + le32toh(t->blob_size),

View File

@ -14,114 +14,53 @@
#include "string-table.h"
#include "string-util.h"
static const char *skip_protocol_and_hostname(const char *url) {
const char *d;
size_t n;
int import_url_last_component(const char *url, char **ret) {
const char *e, *p;
char *s;
/* A very very lenient implementation of RFC3986 Section 3.2 */
e = strchrnul(url, '?');
/* Find colon separating protocol and hostname */
d = strchr(url, ':');
if (!d || url == d)
return NULL;
d++;
/* Skip slashes after colon */
d += strspn(d, "/");
/* Skip everything till next slash or end */
n = strcspn(d, "/?#");
if (n == 0)
return NULL;
return d + n;
}
int import_url_last_component(
const char *url,
char **ret) {
const char *e, *p, *h;
/* This extracts the last path component of the specified URI, i.e. the last non-empty substrings
* between two "/" characters. This ignores "Query" and "Fragment" suffixes (as per RFC3986). */
h = skip_protocol_and_hostname(url);
if (!h)
return -EINVAL;
e = h + strcspn(h, "?#"); /* Cut off "Query" and "Fragment" */
while (e > h && e[-1] == '/') /* Eat trailing slashes */
while (e > url && e[-1] == '/')
e--;
p = e;
while (p > h && p[-1] != '/') /* Find component before that */
while (p > url && p[-1] != '/')
p--;
if (e <= p) /* Empty component? */
return -EADDRNOTAVAIL;
if (e <= p)
return -EINVAL;
if (ret) {
char *s;
s = strndup(p, e - p);
if (!s)
return -ENOMEM;
*ret = s;
}
s = strndup(p, e - p);
if (!s)
return -ENOMEM;
*ret = s;
return 0;
}
int import_url_change_suffix(
const char *url,
size_t n_drop_components,
const char *suffix,
char **ret) {
const char *e, *h;
int import_url_change_last_component(const char *url, const char *suffix, char **ret) {
const char *e;
char *s;
assert(url);
assert(ret);
/* This drops the specified number of path components of the specified URI, i.e. the specified number
* of non-empty substring between two "/" characters from the end of the string, and then append the
* specified suffix instead. Before doing all this it chops off the "Query" and "Fragment" suffixes
* (they are *not* readded to the final URL). Note that n_drop_components may be 0 (in which case the
* component are simply added to the end). The suffix may be specified as NULL or empty string in
* which case nothing is appended, only the specified number of components chopped off. Note that the
* function may be called with n_drop_components == 0 and suffix == NULL, in which case the "Query"
* and "Fragment" is chopped off, and ensured the URL ends in a single "/", and that's it. */
e = strchrnul(url, '?');
h = skip_protocol_and_hostname(url);
if (!h)
return -EINVAL;
e = h + strcspn(h, "?#"); /* Cut off "Query" and "Fragment" */
while (e > h && e[-1] == '/') /* Eat trailing slashes */
while (e > url && e[-1] == '/')
e--;
/* Drop the specified number of components from the end. Note that this is pretty lenient: if there
* are less component we silently drop those and then append the suffix to the top. */
while (n_drop_components > 0) {
while (e > h && e[-1] != '/') /* Eat last word (we don't mind if empty) */
e--;
while (e > url && e[-1] != '/')
e--;
while (e > h && e[-1] == '/') /* Eat slashes before the last word */
e--;
if (e <= url)
return -EINVAL;
n_drop_components--;
}
s = new(char, (e - url) + 1 + strlen_ptr(suffix) + 1);
s = new(char, (e - url) + strlen(suffix) + 1);
if (!s)
return -ENOMEM;
strcpy(stpcpy(mempcpy(s, url, e - url), "/"), strempty(suffix));
strcpy(mempcpy(s, url, e - url), suffix);
*ret = s;
return 0;
}

View File

@ -14,16 +14,7 @@ typedef enum ImportVerify {
} ImportVerify;
int import_url_last_component(const char *url, char **ret);
int import_url_change_suffix(const char *url, size_t n_drop_components, const char *suffix, char **ret);
static inline int import_url_change_last_component(const char *url, const char *suffix, char **ret) {
return import_url_change_suffix(url, 1, suffix, ret);
}
static inline int import_url_append_component(const char *url, const char *suffix, char **ret) {
return import_url_change_suffix(url, 0, suffix, ret);
}
int import_url_change_last_component(const char *url, const char *suffix, char **ret);
const char* import_verify_to_string(ImportVerify v) _const_;
ImportVerify import_verify_from_string(const char *s) _pure_;

View File

@ -19,9 +19,6 @@
#include "stat-util.h"
#include "string-util.h"
/* We treat tmpfs/ramfs + cgroupfs as non-physical file sytems. cgroupfs is similar to tmpfs in a way after
* all: we can create arbitrary directory hierarchies in it, and hence can also use rm_rf() on it to remove
* those again. */
static bool is_physical_fs(const struct statfs *sfs) {
return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs);
}
@ -116,145 +113,133 @@ int fstatat_harder(int dfd,
return 0;
}
static int rm_rf_children_inner(
int fd,
const char *fname,
int is_dir,
RemoveFlags flags,
const struct stat *root_dev) {
struct stat st;
int r;
assert(fd >= 0);
assert(fname);
if (is_dir < 0 || (is_dir > 0 && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
r = fstatat_harder(fd, fname, &st, AT_SYMLINK_NOFOLLOW, flags);
if (r < 0)
return r;
is_dir = S_ISDIR(st.st_mode);
}
if (is_dir) {
_cleanup_close_ int subdir_fd = -1;
int q;
/* if root_dev is set, remove subdirectories only if device is same */
if (root_dev && st.st_dev != root_dev->st_dev)
return 0;
/* Stop at mount points */
r = fd_is_mount_point(fd, fname, 0);
if (r < 0)
return r;
if (r > 0)
return 0;
if ((flags & REMOVE_SUBVOLUME) && btrfs_might_be_subvol(&st)) {
/* This could be a subvolume, try to remove it */
r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0) {
if (!IN_SET(r, -ENOTTY, -EINVAL))
return r;
/* ENOTTY, then it wasn't a btrfs subvolume, continue below. */
} else
/* It was a subvolume, done. */
return 1;
}
subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
if (subdir_fd < 0)
return -errno;
/* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type
* again for each directory */
q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
r = unlinkat_harder(fd, fname, AT_REMOVEDIR, flags);
if (r < 0)
return r;
if (q < 0)
return q;
return 1;
} else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
r = unlinkat_harder(fd, fname, 0, flags);
if (r < 0)
return r;
return 1;
}
return 0;
}
int rm_rf_children(
int fd,
RemoveFlags flags,
const struct stat *root_dev) {
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int ret = 0, r;
struct statfs sfs;
assert(fd >= 0);
/* This returns the first error we run into, but nevertheless tries to go on. This closes the passed
* fd, in all cases, including on failure. */
* fd, in all cases, including on failure.. */
if (!(flags & REMOVE_PHYSICAL)) {
r = fstatfs(fd, &sfs);
if (r < 0) {
safe_close(fd);
return -errno;
}
if (is_physical_fs(&sfs)) {
/* We refuse to clean physical file systems with this call,
* unless explicitly requested. This is extra paranoia just
* to be sure we never ever remove non-state data. */
_cleanup_free_ char *path = NULL;
(void) fd_get_path(fd, &path);
log_error("Attempted to remove disk file system under \"%s\", and we can't allow that.",
strna(path));
safe_close(fd);
return -EPERM;
}
}
d = fdopendir(fd);
if (!d) {
safe_close(fd);
return -errno;
}
if (!(flags & REMOVE_PHYSICAL)) {
struct statfs sfs;
if (fstatfs(dirfd(d), &sfs) < 0)
return -errno;
if (is_physical_fs(&sfs)) {
/* We refuse to clean physical file systems with this call, unless explicitly
* requested. This is extra paranoia just to be sure we never ever remove non-state
* data. */
_cleanup_free_ char *path = NULL;
(void) fd_get_path(fd, &path);
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
"Attempted to remove disk file system under \"%s\", and we can't allow that.",
strna(path));
}
return errno == ENOENT ? 0 : -errno;
}
FOREACH_DIRENT_ALL(de, d, return -errno) {
int is_dir;
bool is_dir;
struct stat st;
if (dot_or_dot_dot(de->d_name))
continue;
is_dir =
de->d_type == DT_UNKNOWN ? -1 :
de->d_type == DT_DIR;
if (de->d_type == DT_UNKNOWN ||
(de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
r = fstatat_harder(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW, flags);
if (r < 0) {
if (ret == 0 && r != -ENOENT)
ret = r;
continue;
}
r = rm_rf_children_inner(dirfd(d), de->d_name, is_dir, flags, root_dev);
if (r < 0 && r != -ENOENT && ret == 0)
ret = r;
is_dir = S_ISDIR(st.st_mode);
} else
is_dir = de->d_type == DT_DIR;
if (is_dir) {
_cleanup_close_ int subdir_fd = -1;
/* if root_dev is set, remove subdirectories only if device is same */
if (root_dev && st.st_dev != root_dev->st_dev)
continue;
subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
if (subdir_fd < 0) {
if (ret == 0 && errno != ENOENT)
ret = -errno;
continue;
}
/* Stop at mount points */
r = fd_is_mount_point(fd, de->d_name, 0);
if (r < 0) {
if (ret == 0 && r != -ENOENT)
ret = r;
continue;
}
if (r > 0)
continue;
if ((flags & REMOVE_SUBVOLUME) && btrfs_might_be_subvol(&st)) {
/* This could be a subvolume, try to remove it */
r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0) {
if (!IN_SET(r, -ENOTTY, -EINVAL)) {
if (ret == 0)
ret = r;
continue;
}
/* ENOTTY, then it wasn't a btrfs subvolume, continue below. */
} else
/* It was a subvolume, continue. */
continue;
}
/* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file
* system type again for each directory */
r = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
if (r < 0 && ret == 0)
ret = r;
r = unlinkat_harder(fd, de->d_name, AT_REMOVEDIR, flags);
if (r < 0 && r != -ENOENT && ret == 0)
ret = r;
} else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
r = unlinkat_harder(fd, de->d_name, 0, flags);
if (r < 0 && r != -ENOENT && ret == 0)
ret = r;
}
}
return ret;
}
int rm_rf(const char *path, RemoveFlags flags) {
int fd, r;
struct statfs s;
assert(path);
@ -299,10 +284,9 @@ int rm_rf(const char *path, RemoveFlags flags) {
if (FLAGS_SET(flags, REMOVE_ROOT)) {
if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
struct statfs s;
if (statfs(path, &s) < 0)
return -errno;
if (is_physical_fs(&s))
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
"Attempted to remove files from a disk file system under \"%s\", refusing.",
@ -330,22 +314,3 @@ int rm_rf(const char *path, RemoveFlags flags) {
return r;
}
int rm_rf_child(int fd, const char *name, RemoveFlags flags) {
/* Removes one specific child of the specified directory */
if (fd < 0)
return -EBADF;
if (!filename_is_valid(name))
return -EINVAL;
if ((flags & (REMOVE_ROOT|REMOVE_MISSING_OK)) != 0) /* Doesn't really make sense here, we are not supposed to remove 'fd' anyway */
return -EINVAL;
if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME))
return -EINVAL;
return rm_rf_children_inner(fd, name, -1, flags, NULL);
}

View File

@ -23,8 +23,7 @@ int fstatat_harder(int dfd,
int fstatat_flags,
RemoveFlags remove_flags);
int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev);
int rm_rf_child(int fd, const char *name, RemoveFlags flags);
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
int rm_rf(const char *path, RemoveFlags flags);
/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */

View File

@ -25,7 +25,6 @@ TSS2_RC (*sym_Esys_CreatePrimary)(ESYS_CONTEXT *esysContext, ESYS_TR primaryHand
void (*sym_Esys_Finalize)(ESYS_CONTEXT **context) = NULL;
TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle) = NULL;
void (*sym_Esys_Free)(void *ptr) = NULL;
TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2_CAP capability, UINT32 property, UINT32 propertyCount, TPMI_YES_NO *moreData, TPMS_CAPABILITY_DATA **capabilityData);
TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes) = NULL;
TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion) = NULL;
TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle) = NULL;
@ -52,7 +51,6 @@ int dlopen_tpm2(void) {
DLSYM_ARG(Esys_Finalize),
DLSYM_ARG(Esys_FlushContext),
DLSYM_ARG(Esys_Free),
DLSYM_ARG(Esys_GetCapability),
DLSYM_ARG(Esys_GetRandom),
DLSYM_ARG(Esys_Initialize),
DLSYM_ARG(Esys_Load),
@ -312,93 +310,11 @@ static int tpm2_make_primary(
return 0;
}
static int tpm2_get_best_pcr_bank(
ESYS_CONTEXT *c,
TPMI_ALG_HASH *ret) {
_cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *pcap = NULL;
TPMI_ALG_HASH hash = TPM2_ALG_SHA1;
bool found = false;
TPMI_YES_NO more;
TSS2_RC rc;
rc = sym_Esys_GetCapability(
c,
ESYS_TR_NONE,
ESYS_TR_NONE,
ESYS_TR_NONE,
TPM2_CAP_PCRS,
0,
1,
&more,
&pcap);
if (rc != TSS2_RC_SUCCESS)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to determine TPM2 PCR bank capabilities: %s", sym_Tss2_RC_Decode(rc));
assert(pcap->capability == TPM2_CAP_PCRS);
for (size_t i = 0; i < pcap->data.assignedPCR.count; i++) {
bool valid = true;
/* As per
* https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf a
* TPM2 on a Client PC must have at least 24 PCRs. If this TPM has less, just skip over
* it. */
if (pcap->data.assignedPCR.pcrSelections[i].sizeofSelect < TPM2_PCRS_MAX/8) {
log_debug("Skipping TPM2 PCR bank %s with fewer than 24 PCRs.",
strna(tpm2_pcr_bank_to_string(pcap->data.assignedPCR.pcrSelections[i].hash)));
continue;
}
assert_cc(TPM2_PCRS_MAX % 8 == 0);
/* It's not enought to check how many PCRs there are, we also need to check that the 24 are
* enabled for this bank. Otherwise this TPM doesn't qualify. */
for (size_t j = 0; j < TPM2_PCRS_MAX/8; j++)
if (pcap->data.assignedPCR.pcrSelections[i].pcrSelect[j] != 0xFF) {
valid = false;
break;
}
if (!valid) {
log_debug("TPM2 PCR bank %s has fewer than 24 PCR bits enabled, ignoring.",
strna(tpm2_pcr_bank_to_string(pcap->data.assignedPCR.pcrSelections[i].hash)));
continue;
}
if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA256) {
hash = TPM2_ALG_SHA256;
found = true;
break;
}
if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA1)
found = true;
}
if (!found)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 module supports neither SHA1 nor SHA256 PCR banks, cannot operate.");
if (hash == TPM2_ALG_SHA256)
log_debug("TPM2 device supports SHA256 PCR banks, yay!");
else {
assert(hash == TPM2_ALG_SHA1);
log_debug("TPM2 device lacks support for SHA256 PCR banks, falling back to SHA1 banks.");
}
*ret = hash;
return 0;
}
static int tpm2_make_pcr_session(
ESYS_CONTEXT *c,
uint32_t pcr_mask,
uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
ESYS_TR *ret_session,
TPM2B_DIGEST **ret_policy_digest,
TPMI_ALG_HASH *ret_pcr_bank) {
TPM2B_DIGEST **ret_policy_digest) {
static const TPMT_SYM_DEF symmetric = {
.algorithm = TPM2_ALG_AES,
@ -411,7 +327,7 @@ static int tpm2_make_pcr_session(
};
TPML_PCR_SELECTION pcr_selection = {
.count = 1,
.pcrSelections[0].hash = TPM2_ALG_SHA256, /* overriden below, depending on TPM2 capabilities */
.pcrSelections[0].hash = TPM2_ALG_SHA256,
.pcrSelections[0].sizeofSelect = 3,
.pcrSelections[0].pcrSelect[0] = pcr_mask & 0xFF,
.pcrSelections[0].pcrSelect[1] = (pcr_mask >> 8) & 0xFF,
@ -426,16 +342,6 @@ static int tpm2_make_pcr_session(
log_debug("Starting authentication session.");
if (pcr_bank != UINT16_MAX)
pcr_selection.pcrSelections[0].hash = pcr_bank;
else {
/* No bank configured, pick automatically. Some TPM2 devices only can do SHA1. If we detect
* that use that, but preferably use SHA256 */
r = tpm2_get_best_pcr_bank(c, &pcr_selection.pcrSelections[0].hash);
if (r < 0)
return r;
}
rc = sym_Esys_StartAuthSession(
c,
ESYS_TR_NONE,
@ -506,9 +412,6 @@ static int tpm2_make_pcr_session(
if (ret_policy_digest)
*ret_policy_digest = TAKE_PTR(policy_digest);
if (ret_pcr_bank)
*ret_pcr_bank = pcr_selection.pcrSelections[0].hash;
r = 0;
finish:
@ -524,8 +427,7 @@ int tpm2_seal(
void **ret_blob,
size_t *ret_blob_size,
void **ret_pcr_hash,
size_t *ret_pcr_hash_size,
uint16_t *ret_pcr_bank) {
size_t *ret_pcr_hash_size) {
_cleanup_(tpm2_context_destroy) struct tpm2_context c = {};
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
@ -537,7 +439,6 @@ int tpm2_seal(
TPM2B_SENSITIVE_CREATE hmac_sensitive;
ESYS_TR primary = ESYS_TR_NONE;
TPM2B_PUBLIC hmac_template;
TPMI_ALG_HASH pcr_bank;
size_t k, blob_size;
usec_t start;
TSS2_RC rc;
@ -549,7 +450,6 @@ int tpm2_seal(
assert(ret_blob_size);
assert(ret_pcr_hash);
assert(ret_pcr_hash_size);
assert(ret_pcr_bank);
assert(pcr_mask < (UINT32_C(1) << TPM2_PCRS_MAX)); /* Support 24 PCR banks */
@ -578,7 +478,7 @@ int tpm2_seal(
if (r < 0)
return r;
r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, NULL, &policy_digest, &pcr_bank);
r = tpm2_make_pcr_session(c.esys_context, pcr_mask, NULL, &policy_digest);
if (r < 0)
goto finish;
@ -700,7 +600,6 @@ int tpm2_seal(
*ret_blob_size = blob_size;
*ret_pcr_hash = TAKE_PTR(hash);
*ret_pcr_hash_size = policy_digest->size;
*ret_pcr_bank = pcr_bank;
r = 0;
@ -712,7 +611,6 @@ finish:
int tpm2_unseal(
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
const void *blob,
size_t blob_size,
const void *known_policy_hash,
@ -772,7 +670,7 @@ int tpm2_unseal(
if (r < 0)
return r;
r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, &session, &policy_digest, NULL);
r = tpm2_make_pcr_session(c.esys_context, pcr_mask, &session, &policy_digest);
if (r < 0)
goto finish;
@ -1011,7 +909,6 @@ int tpm2_parse_pcrs(const char *s, uint32_t *ret) {
int tpm2_make_luks2_json(
int keyslot,
uint32_t pcr_mask,
uint16_t pcr_bank,
const void *blob,
size_t blob_size,
const void *policy_hash,
@ -1054,7 +951,6 @@ int tpm2_make_luks2_json(
JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob, blob_size)),
JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a)),
JSON_BUILD_PAIR_CONDITION(!!tpm2_pcr_bank_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_pcr_bank_to_string(pcr_bank))),
JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size))));
if (r < 0)
return r;
@ -1064,36 +960,3 @@ int tpm2_make_luks2_json(
return keyslot;
}
/* We want the helpers below to work also if TPM2 libs are not available, hence define these two defines if
* they are missing. */
#ifndef TPM2_ALG_SHA256
#define TPM2_ALG_SHA256 0xB
#endif
#ifndef TPM2_ALG_SHA1
#define TPM2_ALG_SHA1 0x4
#endif
int tpm2_pcr_bank_supported(uint16_t bank) {
/* For now, let's officially only support these two. We can extend this later on, should the need
* arise. */
return IN_SET(bank, TPM2_ALG_SHA256, TPM2_ALG_SHA1);
}
const char *tpm2_pcr_bank_to_string(uint16_t bank) {
/* Similar here, only support the two for now, we can always extend this later. */
if (bank == TPM2_ALG_SHA256)
return "sha256";
if (bank == TPM2_ALG_SHA1)
return "sha1";
return NULL;
}
int tpm2_pcr_bank_from_string(const char *bank) {
if (streq_ptr(bank, "sha256"))
return TPM2_ALG_SHA256;
if (streq_ptr(bank, "sha1"))
return TPM2_ALG_SHA1;
return -EINVAL;
}

View File

@ -15,7 +15,6 @@ extern TSS2_RC (*sym_Esys_CreatePrimary)(ESYS_CONTEXT *esysContext, ESYS_TR prim
extern void (*sym_Esys_Finalize)(ESYS_CONTEXT **context);
extern TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle);
extern void (*sym_Esys_Free)(void *ptr);
extern TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2_CAP capability, UINT32 property, UINT32 propertyCount, TPMI_YES_NO *moreData, TPMS_CAPABILITY_DATA **capabilityData);
extern TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes);
extern TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion);
extern TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle);
@ -34,8 +33,8 @@ extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], siz
int dlopen_tpm2(void);
int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank);
int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size);
int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size);
int tpm2_unseal(const char *device, uint32_t pcr_mask, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size);
#endif
@ -44,17 +43,13 @@ int tpm2_find_device_auto(int log_level, char **ret);
int tpm2_parse_pcrs(const char *s, uint32_t *ret);
int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret);
int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret);
#define TPM2_PCRS_MAX 24
/* Default to PCR 7 only */
#define TPM2_PCR_MASK_DEFAULT (UINT32_C(1) << 7)
int tpm2_pcr_bank_supported(uint16_t bank);
const char *tpm2_pcr_bank_to_string(uint16_t bank);
int tpm2_pcr_bank_from_string(const char *bank);
typedef struct {
uint32_t search_pcr_mask;
const char *device;

View File

@ -250,8 +250,6 @@ tests += [
[['src/test/test-sysctl-util.c']],
[['src/test/test-import-util.c']],
[['src/test/test-user-record.c']],
[['src/test/test-user-util.c']],

View File

@ -1,72 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "import-util.h"
#include "log.h"
#include "string-util.h"
#include "tests.h"
static void test_import_url_last_component_one(const char *input, const char *output, int ret) {
_cleanup_free_ char *s = NULL;
assert_se(import_url_last_component(input, &s) == ret);
assert_se(streq_ptr(output, s));
}
static void test_import_url_last_component(void) {
test_import_url_last_component_one("https://foobar/waldo/quux", "quux", 0);
test_import_url_last_component_one("https://foobar/waldo/quux/", "quux", 0);
test_import_url_last_component_one("https://foobar/waldo/", "waldo", 0);
test_import_url_last_component_one("https://foobar/", NULL, -EADDRNOTAVAIL);
test_import_url_last_component_one("https://foobar", NULL, -EADDRNOTAVAIL);
test_import_url_last_component_one("https://foobar/waldo/quux?foo=bar", "quux", 0);
test_import_url_last_component_one("https://foobar/waldo/quux/?foo=bar", "quux", 0);
test_import_url_last_component_one("https://foobar/waldo/quux/?foo=bar#piep", "quux", 0);
test_import_url_last_component_one("https://foobar/waldo/quux/#piep", "quux", 0);
test_import_url_last_component_one("https://foobar/waldo/quux#piep", "quux", 0);
test_import_url_last_component_one("https://", NULL, -EINVAL);
test_import_url_last_component_one("", NULL, -EINVAL);
test_import_url_last_component_one(":", NULL, -EINVAL);
test_import_url_last_component_one(":/", NULL, -EINVAL);
test_import_url_last_component_one("x:/", NULL, -EINVAL);
test_import_url_last_component_one("x:y", NULL, -EADDRNOTAVAIL);
test_import_url_last_component_one("x:y/z", "z", 0);
}
static void test_import_url_change_suffix_one(const char *input, size_t n, const char *suffix, const char *output, int ret) {
_cleanup_free_ char *s = NULL;
assert_se(import_url_change_suffix(input, n, suffix, &s) == ret);
assert_se(streq_ptr(output, s));
}
static void test_import_url_change_suffix(void) {
test_import_url_change_suffix_one("https://foobar/waldo/quux", 1, "wuff", "https://foobar/waldo/wuff", 0);
test_import_url_change_suffix_one("https://foobar/waldo/quux/", 1, "wuff", "https://foobar/waldo/wuff", 0);
test_import_url_change_suffix_one("https://foobar/waldo/quux///?mief", 1, "wuff", "https://foobar/waldo/wuff", 0);
test_import_url_change_suffix_one("https://foobar/waldo/quux///?mief#opopo", 1, "wuff", "https://foobar/waldo/wuff", 0);
test_import_url_change_suffix_one("https://foobar/waldo/quux/quff", 2, "wuff", "https://foobar/waldo/wuff", 0);
test_import_url_change_suffix_one("https://foobar/waldo/quux/quff/", 2, "wuff", "https://foobar/waldo/wuff", 0);
test_import_url_change_suffix_one("https://foobar/waldo/quux/quff", 0, "wuff", "https://foobar/waldo/quux/quff/wuff", 0);
test_import_url_change_suffix_one("https://foobar/waldo/quux/quff?aa?bb##4", 0, "wuff", "https://foobar/waldo/quux/quff/wuff", 0);
test_import_url_change_suffix_one("https://", 0, "wuff", NULL, -EINVAL);
test_import_url_change_suffix_one("", 0, "wuff", NULL, -EINVAL);
test_import_url_change_suffix_one(":", 0, "wuff", NULL, -EINVAL);
test_import_url_change_suffix_one(":/", 0, "wuff", NULL, -EINVAL);
test_import_url_change_suffix_one("x:/", 0, "wuff", NULL, -EINVAL);
test_import_url_change_suffix_one("x:y", 0, "wuff", "x:y/wuff", 0);
test_import_url_change_suffix_one("x:y/z", 0, "wuff", "x:y/z/wuff", 0);
test_import_url_change_suffix_one("x:y/z/", 0, "wuff", "x:y/z/wuff", 0);
test_import_url_change_suffix_one("x:y/z/", 1, "wuff", "x:y/wuff", 0);
test_import_url_change_suffix_one("x:y/z/", 2, "wuff", "x:y/wuff", 0);
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_INFO);
test_import_url_last_component();
test_import_url_change_suffix();
return 0;
}

View File

@ -89,7 +89,7 @@ static void test_keymaps(void) {
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
static void dump_special_glyphs(void) {
assert_cc(SPECIAL_GLYPH_SPARKLES + 1 == _SPECIAL_GLYPH_MAX);
assert_cc(SPECIAL_GLYPH_TOUCH + 1 == _SPECIAL_GLYPH_MAX);
log_info("/* %s */", __func__);
@ -120,9 +120,6 @@ static void dump_special_glyphs(void) {
dump_glyph(SPECIAL_GLYPH_DEPRESSED_SMILEY);
dump_glyph(SPECIAL_GLYPH_LOCK_AND_KEY);
dump_glyph(SPECIAL_GLYPH_TOUCH);
dump_glyph(SPECIAL_GLYPH_RECYCLING);
dump_glyph(SPECIAL_GLYPH_DOWNLOAD);
dump_glyph(SPECIAL_GLYPH_SPARKLES);
}
int main(int argc, char *argv[]) {