diff options
Diffstat (limited to 'src/shared/image-policy.c')
-rw-r--r-- | src/shared/image-policy.c | 774 |
1 files changed, 774 insertions, 0 deletions
diff --git a/src/shared/image-policy.c b/src/shared/image-policy.c new file mode 100644 index 0000000..3c3de50 --- /dev/null +++ b/src/shared/image-policy.c @@ -0,0 +1,774 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "extract-word.h" +#include "image-policy.h" +#include "logarithm.h" +#include "sort-util.h" +#include "string-util.h" +#include "strv.h" + +/* Rationale for the chosen syntax: + * + * → one line, so that it can be reasonably added to a shell command line, for example via `systemd-dissect + * --image-policy=…` or to the kernel command line via `systemd.image_policy=`. + * + * → no use of "," or ";" as separators, so that it can be included in mount/fstab-style option strings and + * doesn't require escaping. Instead, separators are ":", "=", "+" which should be fine both in shell + * command lines and in mount/fstab style option strings. + */ + +static int partition_policy_compare(const PartitionPolicy *a, const PartitionPolicy *b) { + return CMP(ASSERT_PTR(a)->designator, ASSERT_PTR(b)->designator); +} + +static const PartitionPolicy* image_policy_bsearch(const ImagePolicy *policy, PartitionDesignator designator) { + if (!policy) + return NULL; + + return typesafe_bsearch( + &(const PartitionPolicy) { .designator = designator }, + ASSERT_PTR(policy)->policies, + ASSERT_PTR(policy)->n_policies, + partition_policy_compare); +} + +PartitionPolicyFlags partition_policy_flags_extend(PartitionPolicyFlags flags) { + /* If some parts of a flags field are left unspecified, let's fill in all options. */ + + /* If no protection flag is set, then this means all are set */ + if ((flags & _PARTITION_POLICY_USE_MASK) == 0) + flags |= PARTITION_POLICY_OPEN; + + /* If the gpt flags bits are not specified, set both options for each */ + if ((flags & _PARTITION_POLICY_READ_ONLY_MASK) == 0) + flags |= PARTITION_POLICY_READ_ONLY_ON|PARTITION_POLICY_READ_ONLY_OFF; + + if ((flags & _PARTITION_POLICY_GROWFS_MASK) == 0) + flags |= PARTITION_POLICY_GROWFS_ON|PARTITION_POLICY_GROWFS_OFF; + + return flags; +} + +static PartitionPolicyFlags partition_policy_normalized_flags(const PartitionPolicy *policy) { + PartitionPolicyFlags flags = ASSERT_PTR(policy)->flags; + + /* This normalizes the per-partition policy flags. This means if the user left some things + * unspecified, we'll fill in the appropriate "dontcare" policy instead. We'll also mask out bits + * that do not make any sense for specific partition types. */ + + flags = partition_policy_flags_extend(flags); + + /* If this is a verity or verity signature designator, then mask off all protection bits, this after + * all needs no protection, because it *is* the protection */ + if (partition_verity_to_data(policy->designator) >= 0 || + partition_verity_sig_to_data(policy->designator) >= 0) + flags &= ~(PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED); + + /* if this designator has no verity concept, then mask off verity protection flags */ + if (partition_verity_of(policy->designator) < 0) + flags &= ~(PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED); + + /* If the partition must be absent, then the gpt flags don't matter */ + if ((flags & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_ABSENT) + flags &= ~(_PARTITION_POLICY_READ_ONLY_MASK|_PARTITION_POLICY_GROWFS_MASK); + + return flags; +} + +PartitionPolicyFlags image_policy_get(const ImagePolicy *policy, PartitionDesignator designator) { + PartitionDesignator data_designator = _PARTITION_DESIGNATOR_INVALID; + const PartitionPolicy *pp; + + /* No policy means: everything may be used in any mode */ + if (!policy) + return partition_policy_normalized_flags( + &(const PartitionPolicy) { + .flags = PARTITION_POLICY_OPEN, + .designator = designator, + }); + + pp = image_policy_bsearch(policy, designator); + if (pp) + return partition_policy_normalized_flags(pp); + + /* Hmm, so this didn't work, then let's see if we can derive some policy from the underlying data + * partition in case of verity/signature partitions */ + + data_designator = partition_verity_to_data(designator); + if (data_designator >= 0) { + PartitionPolicyFlags data_flags; + + /* So we are asked for the policy for a verity partition, and there's no explicit policy for + * that case. Let's synthesize a policy from the protection setting for the underlying data + * partition. */ + + data_flags = image_policy_get(policy, data_designator); + if (data_flags < 0) + return data_flags; + + /* We need verity if verity or verity with sig is requested */ + if (!(data_flags & (PARTITION_POLICY_SIGNED|PARTITION_POLICY_VERITY))) + return _PARTITION_POLICY_FLAGS_INVALID; + + /* If the data partition may be unused or absent, then the verity partition may too. Also, inherit the partition flags policy */ + return partition_policy_normalized_flags( + &(const PartitionPolicy) { + .flags = PARTITION_POLICY_UNPROTECTED | (data_flags & (PARTITION_POLICY_UNUSED|PARTITION_POLICY_ABSENT)) | + (data_flags & _PARTITION_POLICY_PFLAGS_MASK), + .designator = designator, + }); + } + + data_designator = partition_verity_sig_to_data(designator); + if (data_designator >= 0) { + PartitionPolicyFlags data_flags; + + /* Similar case as for verity partitions, but slightly more strict rules */ + + data_flags = image_policy_get(policy, data_designator); + if (data_flags < 0) + return data_flags; + + if (!(data_flags & PARTITION_POLICY_SIGNED)) + return _PARTITION_POLICY_FLAGS_INVALID; + + return partition_policy_normalized_flags( + &(const PartitionPolicy) { + .flags = PARTITION_POLICY_UNPROTECTED | (data_flags & (PARTITION_POLICY_UNUSED|PARTITION_POLICY_ABSENT)) | + (data_flags & _PARTITION_POLICY_PFLAGS_MASK), + .designator = designator, + }); + } + + return _PARTITION_POLICY_FLAGS_INVALID; /* got nothing */ +} + +PartitionPolicyFlags image_policy_get_exhaustively(const ImagePolicy *policy, PartitionDesignator designator) { + PartitionPolicyFlags flags; + + /* This is just like image_policy_get() but whenever there is no policy for a specific designator, we + * return the default policy. */ + + flags = image_policy_get(policy, designator); + if (flags < 0) + return partition_policy_normalized_flags( + &(const PartitionPolicy) { + .flags = image_policy_default(policy), + .designator = designator, + }); + + return flags; +} + +static PartitionPolicyFlags policy_flag_from_string_one(const char *s) { + assert(s); + + /* This is a bitmask (i.e. not dense), hence we don't use the "string-table.h" stuff here. */ + + if (streq(s, "verity")) + return PARTITION_POLICY_VERITY; + if (streq(s, "signed")) + return PARTITION_POLICY_SIGNED; + if (streq(s, "encrypted")) + return PARTITION_POLICY_ENCRYPTED; + if (streq(s, "unprotected")) + return PARTITION_POLICY_UNPROTECTED; + if (streq(s, "unused")) + return PARTITION_POLICY_UNUSED; + if (streq(s, "absent")) + return PARTITION_POLICY_ABSENT; + if (streq(s, "open")) /* shortcut alias */ + return PARTITION_POLICY_OPEN; + if (streq(s, "ignore")) /* ditto */ + return PARTITION_POLICY_IGNORE; + if (streq(s, "read-only-on")) + return PARTITION_POLICY_READ_ONLY_ON; + if (streq(s, "read-only-off")) + return PARTITION_POLICY_READ_ONLY_OFF; + if (streq(s, "growfs-on")) + return PARTITION_POLICY_GROWFS_ON; + if (streq(s, "growfs-off")) + return PARTITION_POLICY_GROWFS_OFF; + + return _PARTITION_POLICY_FLAGS_INVALID; +} + +PartitionPolicyFlags partition_policy_flags_from_string(const char *s) { + PartitionPolicyFlags flags = 0; + int r; + + assert(s); + + if (empty_or_dash(s)) + return 0; + + for (;;) { + _cleanup_free_ char *f = NULL; + PartitionPolicyFlags ff; + + r = extract_first_word(&s, &f, "+", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + break; + + ff = policy_flag_from_string_one(strstrip(f)); + if (ff < 0) + return -EBADRQC; /* recognizable error */ + + flags |= ff; + } + + return flags; +} + +static ImagePolicy* image_policy_new(size_t n_policies) { + ImagePolicy *p; + + if (n_policies > (SIZE_MAX - offsetof(ImagePolicy, policies)) / sizeof(PartitionPolicy)) /* overflow check */ + return NULL; + + p = malloc(offsetof(ImagePolicy, policies) + sizeof(PartitionPolicy) * n_policies); + if (!p) + return NULL; + + *p = (ImagePolicy) { + .default_flags = PARTITION_POLICY_IGNORE, + }; + return p; +} + +int image_policy_from_string(const char *s, ImagePolicy **ret) { + _cleanup_free_ ImagePolicy *p = NULL; + uint64_t dmask = 0; + ImagePolicy *t; + PartitionPolicyFlags symbolic_policy; + int r; + + assert(s); + assert_cc(sizeof(dmask) * 8 >= _PARTITION_DESIGNATOR_MAX); + + /* Recognizable errors: + * + * ENOTUNIQ → Two or more rules for the same partition + * EBADSLT → Unknown partition designator + * EBADRQC → Unknown policy flags + */ + + /* First, let's handle "symbolic" policies, i.e. "-", "*", "~" */ + if (empty_or_dash(s)) + /* ignore policy: everything may exist, but nothing used */ + symbolic_policy = PARTITION_POLICY_IGNORE; + else if (streq(s, "*")) + /* allow policy: everything is allowed */ + symbolic_policy = PARTITION_POLICY_OPEN; + else if (streq(s, "~")) + /* deny policy: nothing may exist */ + symbolic_policy = PARTITION_POLICY_ABSENT; + else + symbolic_policy = _PARTITION_POLICY_FLAGS_INVALID; + + if (symbolic_policy >= 0) { + if (!ret) + return 0; + + p = image_policy_new(0); + if (!p) + return -ENOMEM; + + p->default_flags = symbolic_policy; + *ret = TAKE_PTR(p); + return 0; + } + + /* Allocate the policy at maximum size, i.e. for all designators. We might overshoot a bit, but the + * items are cheap, and we can return unused space to libc once we know we don't need it */ + p = image_policy_new(_PARTITION_DESIGNATOR_MAX); + if (!p) + return -ENOMEM; + + const char *q = s; + bool default_specified = false; + for (;;) { + _cleanup_free_ char *e = NULL, *d = NULL; + PartitionDesignator designator; + PartitionPolicyFlags flags; + char *f, *ds, *fs; + + r = extract_first_word(&q, &e, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + break; + + f = e; + r = extract_first_word((const char**) &f, &d, "=", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Expected designator name followed by '='; got instead: %s", e); + if (!f) /* no separator? */ + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing '=' in policy expression: %s", e); + + ds = strstrip(d); + if (isempty(ds)) { + /* Not partition name? then it's the default policy */ + if (default_specified) + return log_debug_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "Default partition policy flags specified more than once."); + + designator = _PARTITION_DESIGNATOR_INVALID; + default_specified = true; + } else { + designator = partition_designator_from_string(ds); + if (designator < 0) + return log_debug_errno(SYNTHETIC_ERRNO(EBADSLT), "Unknown partition designator: %s", ds); /* recognizable error */ + if (dmask & (UINT64_C(1) << designator)) + return log_debug_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "Partition designator specified more than once: %s", ds); + dmask |= UINT64_C(1) << designator; + } + + fs = strstrip(f); + flags = partition_policy_flags_from_string(fs); + if (flags == -EBADRQC) + return log_debug_errno(flags, "Unknown partition policy flag: %s", fs); + if (flags < 0) + return log_debug_errno(flags, "Failed to parse partition policy flags '%s': %m", fs); + + if (designator < 0) + p->default_flags = flags; + else { + p->policies[p->n_policies++] = (PartitionPolicy) { + .designator = designator, + .flags = flags, + }; + } + }; + + assert(p->n_policies <= _PARTITION_DESIGNATOR_MAX); + + /* Return unused space to libc */ + t = realloc(p, offsetof(ImagePolicy, policies) + sizeof(PartitionPolicy) * p->n_policies); + if (t) + p = t; + + typesafe_qsort(p->policies, p->n_policies, partition_policy_compare); + + if (ret) + *ret = TAKE_PTR(p); + + return 0; +} + +int partition_policy_flags_to_string(PartitionPolicyFlags flags, bool simplify, char **ret) { + _cleanup_free_ char *buf = NULL; + const char *l[CONST_LOG2U(_PARTITION_POLICY_MASK) + 1]; /* one string per known flag at most */ + size_t m = 0; + + assert(ret); + + if (flags < 0) + return -EINVAL; + + /* If 'simplify' is false we'll output the precise value of every single flag. + * + * If 'simplify' is true we'll try to make the output shorter, by doing the following: + * + * → we'll spell the long form "verity+signed+encrypted+unprotected+unused+absent" via its + * equivalent shortcut form "open" (which we happily parse btw, see above) + * + * → we'll spell the long form "unused+absent" via its shortcut "ignore" (which we are also happy + * to parse) + * + * → if the read-only/growfs policy flags are both set, we suppress them. this thus removes the + * distinction between "user explicitly declared don't care" and "we implied don't care because + * user didn't say anything". + * + * net result: the resulting string is shorter, but the effective policy declared that way will have + * the same results as the long form. */ + + if (simplify && (flags & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_OPEN) + l[m++] = "open"; + else if (simplify && (flags & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_IGNORE) + l[m++] = "ignore"; + else { + if (flags & PARTITION_POLICY_VERITY) + l[m++] = "verity"; + if (flags & PARTITION_POLICY_SIGNED) + l[m++] = "signed"; + if (flags & PARTITION_POLICY_ENCRYPTED) + l[m++] = "encrypted"; + if (flags & PARTITION_POLICY_UNPROTECTED) + l[m++] = "unprotected"; + if (flags & PARTITION_POLICY_UNUSED) + l[m++] = "unused"; + if (flags & PARTITION_POLICY_ABSENT) + l[m++] = "absent"; + } + + if (!simplify || (!(flags & PARTITION_POLICY_READ_ONLY_ON) != !(flags & PARTITION_POLICY_READ_ONLY_OFF))) { + if (flags & PARTITION_POLICY_READ_ONLY_ON) + l[m++] = "read-only-on"; + if (flags & PARTITION_POLICY_READ_ONLY_OFF) + l[m++] = "read-only-off"; + } + + if (!simplify || (!(flags & PARTITION_POLICY_GROWFS_ON) != !(flags & PARTITION_POLICY_GROWFS_OFF))) { + if (flags & PARTITION_POLICY_GROWFS_OFF) + l[m++] = "growfs-off"; + if (flags & PARTITION_POLICY_GROWFS_ON) + l[m++] = "growfs-on"; + } + + if (m == 0) + buf = strdup("-"); + else { + assert(m+1 < ELEMENTSOF(l)); + l[m] = NULL; + + buf = strv_join((char**) l, "+"); + } + if (!buf) + return -ENOMEM; + + *ret = TAKE_PTR(buf); + return 0; +} + +static bool partition_policy_flags_extended_equal(PartitionPolicyFlags a, PartitionPolicyFlags b) { + return partition_policy_flags_extend(a) == partition_policy_flags_extend(b); +} + +static int image_policy_flags_all_match(const ImagePolicy *policy, PartitionPolicyFlags expected) { + + if (expected < 0) + return -EINVAL; + + if (!partition_policy_flags_extended_equal(image_policy_default(policy), expected)) + return false; + + for (PartitionDesignator d = 0; d < _PARTITION_DESIGNATOR_MAX; d++) { + PartitionPolicyFlags f, w; + + f = image_policy_get_exhaustively(policy, d); + if (f < 0) + return f; + + w = partition_policy_normalized_flags( + &(const PartitionPolicy) { + .flags = expected, + .designator = d, + }); + if (w < 0) + return w; + if (f != w) + return false; + } + + return true; +} + +bool image_policy_equiv_ignore(const ImagePolicy *policy) { + /* Checks if this is the ignore policy (or equivalent to it), i.e. everything is ignored, aka '-', aka '' */ + return image_policy_flags_all_match(policy, PARTITION_POLICY_IGNORE); +} + +bool image_policy_equiv_allow(const ImagePolicy *policy) { + /* Checks if this is the allow policy (or equivalent to it), i.e. everything is allowed, aka '*' */ + return image_policy_flags_all_match(policy, PARTITION_POLICY_OPEN); +} + +bool image_policy_equiv_deny(const ImagePolicy *policy) { + /* Checks if this is the deny policy (or equivalent to it), i.e. everything must be absent, aka '~' */ + return image_policy_flags_all_match(policy, PARTITION_POLICY_ABSENT); +} + +int image_policy_to_string(const ImagePolicy *policy, bool simplify, char **ret) { + _cleanup_free_ char *s = NULL; + int r; + + assert(ret); + + if (simplify) { + const char *fixed; + + if (image_policy_equiv_allow(policy)) + fixed = "*"; + else if (image_policy_equiv_ignore(policy)) + fixed = "-"; + else if (image_policy_equiv_deny(policy)) + fixed = "~"; + else + fixed = NULL; + + if (fixed) { + s = strdup(fixed); + if (!s) + return -ENOMEM; + + *ret = TAKE_PTR(s); + return 0; + } + } + + for (size_t i = 0; i < image_policy_n_entries(policy); i++) { + const PartitionPolicy *p = policy->policies + i; + _cleanup_free_ char *f = NULL; + const char *t; + + assert(i == 0 || p->designator > policy->policies[i-1].designator); /* Validate perfect ordering */ + + assert_se(t = partition_designator_to_string(p->designator)); + + if (simplify) { + /* Skip policy entries that match the default anyway */ + PartitionPolicyFlags df; + + df = partition_policy_normalized_flags( + &(const PartitionPolicy) { + .flags = image_policy_default(policy), + .designator = p->designator, + }); + if (df < 0) + return df; + + if (df == p->flags) + continue; + } + + r = partition_policy_flags_to_string(p->flags, simplify, &f); + if (r < 0) + return r; + + if (!strextend(&s, isempty(s) ? "" : ":", t, "=", f)) + return -ENOMEM; + } + + if (!simplify || !partition_policy_flags_extended_equal(image_policy_default(policy), PARTITION_POLICY_IGNORE)) { + _cleanup_free_ char *df = NULL; + + r = partition_policy_flags_to_string(image_policy_default(policy), simplify, &df); + if (r < 0) + return r; + + if (!strextend(&s, isempty(s) ? "" : ":", "=", df)) + return -ENOMEM; + } + + if (isempty(s)) { /* no rule and default policy? then let's return "-" */ + s = strdup("-"); + if (!s) + return -ENOMEM; + } + + *ret = TAKE_PTR(s); + return 0; +} + +bool image_policy_equal(const ImagePolicy *a, const ImagePolicy *b) { + if (a == b) + return true; + if (image_policy_n_entries(a) != image_policy_n_entries(b)) + return false; + if (image_policy_default(a) != image_policy_default(b)) + return false; + for (size_t i = 0; i < image_policy_n_entries(a); i++) { + if (a->policies[i].designator != b->policies[i].designator) + return false; + if (a->policies[i].flags != b->policies[i].flags) + return false; + } + + return true; +} + +int image_policy_equivalent(const ImagePolicy *a, const ImagePolicy *b) { + + /* The image_policy_equal() function checks if the policy is defined the exact same way. This + * function here instead looks at the outcome of the two policies instead. Where does this come to + * different results you ask? We imply some logic regarding Verity/Encryption: when no rule is + * defined for a verity partition we can synthesize it from the protection level of the data + * partition it protects. Or: any per-partition rule that is identical to the default rule is + * redundant, and will be recognized as such by image_policy_equivalent() but not by + * image_policy_equal()- */ + + if (!partition_policy_flags_extended_equal(image_policy_default(a), image_policy_default(b))) + return false; + + for (PartitionDesignator d = 0; d < _PARTITION_DESIGNATOR_MAX; d++) { + PartitionPolicyFlags f, w; + + f = image_policy_get_exhaustively(a, d); + if (f < 0) + return f; + + w = image_policy_get_exhaustively(b, d); + if (w < 0) + return w; + + if (f != w) + return false; + } + + return true; +} + +int config_parse_image_policy( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_(image_policy_freep) ImagePolicy *np = NULL; + ImagePolicy **p = ASSERT_PTR(data); + int r; + + assert(rvalue); + + if (isempty(rvalue)) { + *p = image_policy_free(*p); + return 0; + } + + r = image_policy_from_string(rvalue, &np); + if (r == -ENOTUNIQ) + return log_syntax(unit, LOG_ERR, filename, line, r, "Duplicate rule in image policy, refusing: %s", rvalue); + if (r == -EBADSLT) + return log_syntax(unit, LOG_ERR, filename, line, r, "Unknown partition type in image policy, refusing: %s", rvalue); + if (r == -EBADRQC) + return log_syntax(unit, LOG_ERR, filename, line, r, "Unknown partition policy flag in image policy, refusing: %s", rvalue); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse image policy, refusing: %s", rvalue); + + return free_and_replace_full(*p, np, image_policy_free); +} + +int parse_image_policy_argument(const char *s, ImagePolicy **policy) { + _cleanup_(image_policy_freep) ImagePolicy *np = NULL; + int r; + + assert(s); + assert(policy); + + /* + * This function is intended to be used in command line parsers. + * + * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON SUCCESS! + * Hence, do not pass in uninitialized pointers. + */ + + r = image_policy_from_string(s, &np); + if (r == -ENOTUNIQ) + return log_error_errno(r, "Duplicate rule in image policy: %s", s); + if (r == -EBADSLT) + return log_error_errno(r, "Unknown partition type in image policy: %s", s); + if (r == -EBADRQC) + return log_error_errno(r, "Unknown partition policy flag in image policy: %s", s); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy: %s", s); + + return free_and_replace_full(*policy, np, image_policy_free); +} + +const ImagePolicy image_policy_allow = { + /* Allow policy */ + .n_policies = 0, + .default_flags = PARTITION_POLICY_OPEN, +}; + +const ImagePolicy image_policy_deny = { + /* Deny policy */ + .n_policies = 0, + .default_flags = PARTITION_POLICY_ABSENT, +}; + +const ImagePolicy image_policy_ignore = { + /* Ignore policy */ + .n_policies = 0, + .default_flags = PARTITION_POLICY_IGNORE, +}; + +const ImagePolicy image_policy_sysext = { + /* For system extensions, honour root file system, and /usr/ and ignore everything else. After all, + * we are only interested in /usr/ + /opt/ trees anyway, and that's really the only place they can + * be. */ + .n_policies = 2, + .policies = { + { PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + }, + .default_flags = PARTITION_POLICY_IGNORE, +}; + +const ImagePolicy image_policy_sysext_strict = { + /* For system extensions, requiring signing */ + .n_policies = 2, + .policies = { + { PARTITION_ROOT, PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT }, + { PARTITION_USR, PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT }, + }, + .default_flags = PARTITION_POLICY_IGNORE, +}; + +const ImagePolicy image_policy_confext = { + /* For configuration extensions, honour root file system, and ignore everything else. After all, we + * are only interested in the /etc/ tree anyway, and that's really the only place it can be. */ + .n_policies = 1, + .policies = { + { PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + }, + .default_flags = PARTITION_POLICY_IGNORE, +}; + +const ImagePolicy image_policy_container = { + /* For systemd-nspawn containers we use all partitions, with the exception of swap */ + .n_policies = 8, + .policies = { + { PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_ESP, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_XBOOTLDR, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + }, + .default_flags = PARTITION_POLICY_IGNORE, +}; + +const ImagePolicy image_policy_host = { + /* For the host policy we basically use everything */ + .n_policies = 9, + .policies = { + { PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_ESP, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_XBOOTLDR, PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_SWAP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + }, + .default_flags = PARTITION_POLICY_IGNORE, +}; + +const ImagePolicy image_policy_service = { + /* For RootImage= in services we skip ESP/XBOOTLDR and swap */ + .n_policies = 6, + .policies = { + { PARTITION_ROOT, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_USR, PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_HOME, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_SRV, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_TMP, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + { PARTITION_VAR, PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ABSENT }, + }, + .default_flags = PARTITION_POLICY_IGNORE, +}; |