mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #29644 from poettering/json-iovec
add iovec/base64 json helpers and other iovec tweaks
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "macro.h"
|
||||
|
||||
size_t iovec_total_size(const struct iovec *i, size_t n);
|
||||
@@ -20,6 +21,27 @@ bool iovec_increment(struct iovec *i, size_t n, size_t k);
|
||||
IOVEC_MAKE((char*) _s, strlen(_s)); \
|
||||
})
|
||||
|
||||
#define TAKE_IOVEC(p) TAKE_GENERIC((p), struct iovec, IOVEC_NULL)
|
||||
|
||||
static inline void iovec_done(struct iovec *iovec) {
|
||||
/* A _cleanup_() helper that frees the iov_base in the iovec */
|
||||
assert(iovec);
|
||||
|
||||
iovec->iov_base = mfree(iovec->iov_base);
|
||||
iovec->iov_len = 0;
|
||||
}
|
||||
|
||||
static inline void iovec_done_erase(struct iovec *iovec) {
|
||||
assert(iovec);
|
||||
|
||||
iovec->iov_base = erase_and_free(iovec->iov_base);
|
||||
iovec->iov_len = 0;
|
||||
}
|
||||
|
||||
static inline bool iovec_is_set(const struct iovec *iov) {
|
||||
return iov && iov->iov_len > 0 && iov->iov_base;
|
||||
}
|
||||
|
||||
char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
|
||||
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
|
||||
|
||||
|
||||
@@ -268,8 +268,7 @@ typedef struct Partition {
|
||||
int read_only;
|
||||
int growfs;
|
||||
|
||||
uint8_t *roothash;
|
||||
size_t roothash_size;
|
||||
struct iovec roothash;
|
||||
|
||||
char *split_name_format;
|
||||
char *split_path;
|
||||
@@ -418,7 +417,7 @@ static Partition* partition_free(Partition *p) {
|
||||
strv_free(p->subvolumes);
|
||||
free(p->verity_match_key);
|
||||
|
||||
free(p->roothash);
|
||||
iovec_done(&p->roothash);
|
||||
|
||||
free(p->split_name_format);
|
||||
unlink_and_free(p->split_path);
|
||||
@@ -2824,7 +2823,7 @@ static int context_dump_partitions(Context *context) {
|
||||
if (p->verity != VERITY_OFF) {
|
||||
Partition *hp = p->verity == VERITY_HASH ? p : p->siblings[VERITY_HASH];
|
||||
|
||||
rh = hp->roothash ? hexmem(hp->roothash, hp->roothash_size) : strdup("TBD");
|
||||
rh = iovec_is_set(&hp->roothash) ? hexmem(hp->roothash.iov_base, hp->roothash.iov_len) : strdup("TBD");
|
||||
if (!rh)
|
||||
return log_oom();
|
||||
}
|
||||
@@ -3101,7 +3100,7 @@ static int context_dump_partition_bar(Context *context) {
|
||||
|
||||
static bool context_has_roothash(Context *context) {
|
||||
LIST_FOREACH(partitions, p, context->partitions)
|
||||
if (p->roothash)
|
||||
if (iovec_is_set(&p->roothash))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -3986,8 +3985,6 @@ static int partition_format_verity_hash(
|
||||
_cleanup_(partition_target_freep) PartitionTarget *t = NULL;
|
||||
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
|
||||
_cleanup_free_ char *hint = NULL;
|
||||
_cleanup_free_ uint8_t *rh = NULL;
|
||||
size_t rhs;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
@@ -4066,30 +4063,31 @@ static int partition_format_verity_hash(
|
||||
r = sym_crypt_get_volume_key_size(cd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine verity root hash size of partition %s: %m", strna(hint));
|
||||
rhs = (size_t) r;
|
||||
|
||||
rh = malloc(rhs);
|
||||
if (!rh)
|
||||
_cleanup_(iovec_done) struct iovec rh = {
|
||||
.iov_base = malloc(r),
|
||||
.iov_len = r,
|
||||
};
|
||||
if (!rh.iov_base)
|
||||
return log_oom();
|
||||
|
||||
r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, (char *) rh, &rhs, NULL, 0);
|
||||
r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, (char *) rh.iov_base, &rh.iov_len, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get verity root hash of partition %s: %m", strna(hint));
|
||||
|
||||
assert(rhs >= sizeof(sd_id128_t) * 2);
|
||||
assert(rh.iov_len >= sizeof(sd_id128_t) * 2);
|
||||
|
||||
if (!dp->new_uuid_is_set) {
|
||||
memcpy_safe(dp->new_uuid.bytes, rh, sizeof(sd_id128_t));
|
||||
memcpy_safe(dp->new_uuid.bytes, rh.iov_base, sizeof(sd_id128_t));
|
||||
dp->new_uuid_is_set = true;
|
||||
}
|
||||
|
||||
if (!p->new_uuid_is_set) {
|
||||
memcpy_safe(p->new_uuid.bytes, rh + rhs - sizeof(sd_id128_t), sizeof(sd_id128_t));
|
||||
memcpy_safe(p->new_uuid.bytes, (uint8_t*) rh.iov_base + (rh.iov_len - sizeof(sd_id128_t)), sizeof(sd_id128_t));
|
||||
p->new_uuid_is_set = true;
|
||||
}
|
||||
|
||||
p->roothash = TAKE_PTR(rh);
|
||||
p->roothash_size = rhs;
|
||||
p->roothash = TAKE_IOVEC(rh);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
@@ -4098,10 +4096,8 @@ static int partition_format_verity_hash(
|
||||
}
|
||||
|
||||
static int sign_verity_roothash(
|
||||
const uint8_t *roothash,
|
||||
size_t roothash_size,
|
||||
uint8_t **ret_signature,
|
||||
size_t *ret_signature_size) {
|
||||
const struct iovec *roothash,
|
||||
struct iovec *ret_signature) {
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
_cleanup_(BIO_freep) BIO *rb = NULL;
|
||||
@@ -4111,11 +4107,10 @@ static int sign_verity_roothash(
|
||||
int sigsz;
|
||||
|
||||
assert(roothash);
|
||||
assert(roothash_size > 0);
|
||||
assert(iovec_is_set(roothash));
|
||||
assert(ret_signature);
|
||||
assert(ret_signature_size);
|
||||
|
||||
hex = hexmem(roothash, roothash_size);
|
||||
hex = hexmem(roothash->iov_base, roothash->iov_len);
|
||||
if (!hex)
|
||||
return log_oom();
|
||||
|
||||
@@ -4133,8 +4128,8 @@ static int sign_verity_roothash(
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert PKCS7 signature to DER: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
|
||||
*ret_signature = TAKE_PTR(sig);
|
||||
*ret_signature_size = sigsz;
|
||||
ret_signature->iov_base = TAKE_PTR(sig);
|
||||
ret_signature->iov_len = sigsz;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
@@ -4144,11 +4139,10 @@ static int sign_verity_roothash(
|
||||
|
||||
static int partition_format_verity_sig(Context *context, Partition *p) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
_cleanup_free_ uint8_t *sig = NULL;
|
||||
_cleanup_(iovec_done) struct iovec sig = IOVEC_NULL;
|
||||
_cleanup_free_ char *text = NULL, *hint = NULL;
|
||||
Partition *hp;
|
||||
uint8_t fp[X509_FINGERPRINT_SIZE];
|
||||
size_t sigsz = 0; /* avoid false maybe-uninitialized warning */
|
||||
int whole_fd, r;
|
||||
|
||||
assert(p->verity == VERITY_SIG);
|
||||
@@ -4168,7 +4162,7 @@ static int partition_format_verity_sig(Context *context, Partition *p) {
|
||||
|
||||
assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
|
||||
|
||||
r = sign_verity_roothash(hp->roothash, hp->roothash_size, &sig, &sigsz);
|
||||
r = sign_verity_roothash(&hp->roothash, &sig);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -4178,12 +4172,12 @@ static int partition_format_verity_sig(Context *context, Partition *p) {
|
||||
|
||||
r = json_build(&v,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("rootHash", JSON_BUILD_HEX(hp->roothash, hp->roothash_size)),
|
||||
JSON_BUILD_PAIR("rootHash", JSON_BUILD_HEX(hp->roothash.iov_base, hp->roothash.iov_len)),
|
||||
JSON_BUILD_PAIR(
|
||||
"certificateFingerprint",
|
||||
JSON_BUILD_HEX(fp, sizeof(fp))
|
||||
),
|
||||
JSON_BUILD_PAIR("signature", JSON_BUILD_BASE64(sig, sigsz))
|
||||
JSON_BUILD_PAIR("signature", JSON_BUILD_IOVEC_BASE64(&sig))
|
||||
)
|
||||
);
|
||||
if (r < 0)
|
||||
|
||||
@@ -3790,6 +3790,34 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
||||
break;
|
||||
}
|
||||
|
||||
case _JSON_BUILD_IOVEC_BASE64: {
|
||||
const struct iovec *iov;
|
||||
|
||||
if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
iov = ASSERT_PTR(va_arg(ap, const struct iovec*));
|
||||
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_base64(&add, iov->iov_base, iov->iov_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
else if (current->expect == EXPECT_OBJECT_VALUE)
|
||||
current->expect = EXPECT_OBJECT_KEY;
|
||||
else
|
||||
assert(current->expect == EXPECT_ARRAY_ELEMENT);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case _JSON_BUILD_ID128:
|
||||
case _JSON_BUILD_UUID: {
|
||||
const sd_id128_t *id;
|
||||
@@ -4863,6 +4891,24 @@ int json_dispatch_unsupported(const char *name, JsonVariant *variant, JsonDispat
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not allowed in this object.", strna(name));
|
||||
}
|
||||
|
||||
int json_dispatch_unbase64_iovec(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
|
||||
_cleanup_free_ void *buffer = NULL;
|
||||
struct iovec *iov = ASSERT_PTR(userdata);
|
||||
size_t sz;
|
||||
int r;
|
||||
|
||||
if (!json_variant_is_string(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
|
||||
|
||||
r = json_variant_unbase64(variant, &buffer, &sz);
|
||||
if (r < 0)
|
||||
return json_log(variant, flags, r, "JSON field '%s' is not valid Base64 data.", strna(name));
|
||||
|
||||
free_and_replace(iov->iov_base, buffer);
|
||||
iov->iov_len = sz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_cmp_strings(const void *x, const void *y) {
|
||||
JsonVariant *const *a = x, *const *b = y;
|
||||
|
||||
|
||||
@@ -268,6 +268,7 @@ enum {
|
||||
_JSON_BUILD_STRV,
|
||||
_JSON_BUILD_STRV_ENV_PAIR,
|
||||
_JSON_BUILD_BASE64,
|
||||
_JSON_BUILD_IOVEC_BASE64,
|
||||
_JSON_BUILD_BASE32HEX,
|
||||
_JSON_BUILD_HEX,
|
||||
_JSON_BUILD_OCTESCAPE,
|
||||
@@ -311,6 +312,7 @@ typedef int (*JsonBuildCallback)(JsonVariant **ret, const char *name, void *user
|
||||
#define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, (char**) { l }
|
||||
#define JSON_BUILD_STRV_ENV_PAIR(l) _JSON_BUILD_STRV_ENV_PAIR, (char**) { l }
|
||||
#define JSON_BUILD_BASE64(p, n) _JSON_BUILD_BASE64, (const void*) { p }, (size_t) { n }
|
||||
#define JSON_BUILD_IOVEC_BASE64(iov) _JSON_BUILD_IOVEC_BASE64, (const struct iovec*) { iov }
|
||||
#define JSON_BUILD_BASE32HEX(p, n) _JSON_BUILD_BASE32HEX, (const void*) { p }, (size_t) { n }
|
||||
#define JSON_BUILD_HEX(p, n) _JSON_BUILD_HEX, (const void*) { p }, (size_t) { n }
|
||||
#define JSON_BUILD_OCTESCAPE(p, n) _JSON_BUILD_OCTESCAPE, (const void*) { p }, (size_t) { n }
|
||||
@@ -341,6 +343,7 @@ typedef int (*JsonBuildCallback)(JsonVariant **ret, const char *name, void *user
|
||||
#define JSON_BUILD_PAIR_LITERAL(name, l) JSON_BUILD_PAIR(name, JSON_BUILD_LITERAL(l))
|
||||
#define JSON_BUILD_PAIR_STRV(name, l) JSON_BUILD_PAIR(name, JSON_BUILD_STRV(l))
|
||||
#define JSON_BUILD_PAIR_BASE64(name, p, n) JSON_BUILD_PAIR(name, JSON_BUILD_BASE64(p, n))
|
||||
#define JSON_BUILD_PAIR_IOVEC_BASE64(name, iov) JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_BASE64(iov))
|
||||
#define JSON_BUILD_PAIR_HEX(name, p, n) JSON_BUILD_PAIR(name, JSON_BUILD_HEX(p, n))
|
||||
#define JSON_BUILD_PAIR_ID128(name, id) JSON_BUILD_PAIR(name, JSON_BUILD_ID128(id))
|
||||
#define JSON_BUILD_PAIR_UUID(name, id) JSON_BUILD_PAIR(name, JSON_BUILD_UUID(id))
|
||||
@@ -412,6 +415,7 @@ int json_dispatch_uid_gid(const char *name, JsonVariant *variant, JsonDispatchFl
|
||||
int json_dispatch_user_group_name(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_id128(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_unsupported(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_unbase64_iovec(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
|
||||
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
|
||||
#define json_dispatch_uint json_dispatch_uint32
|
||||
|
||||
Reference in New Issue
Block a user