1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
6 #include <linux/errno.h>
7 #include <linux/verification.h>
13 #include "policy_parser.h"
16 /* lock for synchronizing writers across ipe policy */
17 DEFINE_MUTEX(ipe_policy_lock
);
20 * ver_to_u64() - Convert an internal ipe_policy_version to a u64.
21 * @p: Policy to extract the version from.
23 * Bits (LSB is index 0):
28 * Return: u64 version of the embedded version structure.
30 static inline u64
ver_to_u64(const struct ipe_policy
*const p
)
34 r
= (((u64
)p
->parsed
->version
.major
) << 32)
35 | (((u64
)p
->parsed
->version
.minor
) << 16)
36 | ((u64
)(p
->parsed
->version
.rev
));
42 * ipe_free_policy() - Deallocate a given IPE policy.
43 * @p: Supplies the policy to free.
45 * Safe to call on IS_ERR/NULL.
47 void ipe_free_policy(struct ipe_policy
*p
)
49 if (IS_ERR_OR_NULL(p
))
52 ipe_del_policyfs_node(p
);
53 ipe_free_parsed_policy(p
->parsed
);
55 * p->text is allocated only when p->pkcs7 is not NULL
56 * otherwise it points to the plaintext data inside the pkcs7
64 static int set_pkcs7_data(void *ctx
, const void *data
, size_t len
,
65 size_t asn1hdrlen __always_unused
)
67 struct ipe_policy
*p
= ctx
;
69 p
->text
= (const char *)data
;
76 * ipe_update_policy() - parse a new policy and replace old with it.
77 * @root: Supplies a pointer to the securityfs inode saved the policy.
78 * @text: Supplies a pointer to the plain text policy.
79 * @textlen: Supplies the length of @text.
80 * @pkcs7: Supplies a pointer to a buffer containing a pkcs7 message.
81 * @pkcs7len: Supplies the length of @pkcs7len.
83 * @text/@textlen is mutually exclusive with @pkcs7/@pkcs7len - see
86 * Context: Requires root->i_rwsem to be held.
87 * Return: %0 on success. If an error occurs, the function will return
90 int ipe_update_policy(struct inode
*root
, const char *text
, size_t textlen
,
91 const char *pkcs7
, size_t pkcs7len
)
93 struct ipe_policy
*old
, *ap
, *new = NULL
;
96 old
= (struct ipe_policy
*)root
->i_private
;
100 new = ipe_new_policy(text
, textlen
, pkcs7
, pkcs7len
);
104 if (strcmp(new->parsed
->name
, old
->parsed
->name
)) {
109 if (ver_to_u64(old
) >= ver_to_u64(new)) {
114 root
->i_private
= new;
115 swap(new->policyfs
, old
->policyfs
);
116 ipe_audit_policy_load(new);
118 mutex_lock(&ipe_policy_lock
);
119 ap
= rcu_dereference_protected(ipe_active_policy
,
120 lockdep_is_held(&ipe_policy_lock
));
122 rcu_assign_pointer(ipe_active_policy
, new);
123 mutex_unlock(&ipe_policy_lock
);
124 ipe_audit_policy_activation(old
, new);
126 mutex_unlock(&ipe_policy_lock
);
129 ipe_free_policy(old
);
133 ipe_free_policy(new);
138 * ipe_new_policy() - Allocate and parse an ipe_policy structure.
140 * @text: Supplies a pointer to the plain-text policy to parse.
141 * @textlen: Supplies the length of @text.
142 * @pkcs7: Supplies a pointer to a pkcs7-signed IPE policy.
143 * @pkcs7len: Supplies the length of @pkcs7.
145 * @text/@textlen Should be NULL/0 if @pkcs7/@pkcs7len is set.
148 * * a pointer to the ipe_policy structure - Success
149 * * %-EBADMSG - Policy is invalid
150 * * %-ENOMEM - Out of memory (OOM)
151 * * %-ERANGE - Policy version number overflow
152 * * %-EINVAL - Policy version parsing error
154 struct ipe_policy
*ipe_new_policy(const char *text
, size_t textlen
,
155 const char *pkcs7
, size_t pkcs7len
)
157 struct ipe_policy
*new = NULL
;
160 new = kzalloc(sizeof(*new), GFP_KERNEL
);
162 return ERR_PTR(-ENOMEM
);
165 new->pkcs7len
= pkcs7len
;
166 new->pkcs7
= kmemdup(pkcs7
, pkcs7len
, GFP_KERNEL
);
172 rc
= verify_pkcs7_signature(NULL
, 0, new->pkcs7
, pkcs7len
,
173 #ifdef CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING
174 VERIFY_USE_SECONDARY_KEYRING
,
178 VERIFYING_UNSPECIFIED_SIGNATURE
,
179 set_pkcs7_data
, new);
180 #ifdef CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING
181 if (rc
== -ENOKEY
|| rc
== -EKEYREJECTED
)
182 rc
= verify_pkcs7_signature(NULL
, 0, new->pkcs7
, pkcs7len
,
183 VERIFY_USE_PLATFORM_KEYRING
,
184 VERIFYING_UNSPECIFIED_SIGNATURE
,
185 set_pkcs7_data
, new);
190 new->textlen
= textlen
;
191 new->text
= kstrdup(text
, GFP_KERNEL
);
198 rc
= ipe_parse_policy(new);
204 ipe_free_policy(new);
209 * ipe_set_active_pol() - Make @p the active policy.
210 * @p: Supplies a pointer to the policy to make active.
212 * Context: Requires root->i_rwsem, which i_private has the policy, to be held.
215 * * %-EINVAL - New active policy version is invalid
217 int ipe_set_active_pol(const struct ipe_policy
*p
)
219 struct ipe_policy
*ap
= NULL
;
221 mutex_lock(&ipe_policy_lock
);
223 ap
= rcu_dereference_protected(ipe_active_policy
,
224 lockdep_is_held(&ipe_policy_lock
));
226 mutex_unlock(&ipe_policy_lock
);
229 if (ap
&& ver_to_u64(ap
) > ver_to_u64(p
)) {
230 mutex_unlock(&ipe_policy_lock
);
234 rcu_assign_pointer(ipe_active_policy
, p
);
235 ipe_audit_policy_activation(ap
, p
);
236 mutex_unlock(&ipe_policy_lock
);