77#include <linux/verification.h>
88
99#include "ipe.h"
10+ #include "eval.h"
11+ #include "fs.h"
1012#include "policy.h"
1113#include "policy_parser.h"
1214
15+ /* lock for synchronizing writers across ipe policy */
16+ DEFINE_MUTEX (ipe_policy_lock );
17+
18+ /**
19+ * ver_to_u64() - Convert an internal ipe_policy_version to a u64.
20+ * @p: Policy to extract the version from.
21+ *
22+ * Bits (LSB is index 0):
23+ * [48,32] -> Major
24+ * [32,16] -> Minor
25+ * [16, 0] -> Revision
26+ *
27+ * Return: u64 version of the embedded version structure.
28+ */
29+ static inline u64 ver_to_u64 (const struct ipe_policy * const p )
30+ {
31+ u64 r ;
32+
33+ r = (((u64 )p -> parsed -> version .major ) << 32 )
34+ | (((u64 )p -> parsed -> version .minor ) << 16 )
35+ | ((u64 )(p -> parsed -> version .rev ));
36+
37+ return r ;
38+ }
39+
1340/**
1441 * ipe_free_policy() - Deallocate a given IPE policy.
1542 * @p: Supplies the policy to free.
@@ -21,6 +48,7 @@ void ipe_free_policy(struct ipe_policy *p)
2148 if (IS_ERR_OR_NULL (p ))
2249 return ;
2350
51+ ipe_del_policyfs_node (p );
2452 ipe_free_parsed_policy (p -> parsed );
2553 /*
2654 * p->text is allocated only when p->pkcs7 is not NULL
@@ -43,6 +71,66 @@ static int set_pkcs7_data(void *ctx, const void *data, size_t len,
4371 return 0 ;
4472}
4573
74+ /**
75+ * ipe_update_policy() - parse a new policy and replace old with it.
76+ * @root: Supplies a pointer to the securityfs inode saved the policy.
77+ * @text: Supplies a pointer to the plain text policy.
78+ * @textlen: Supplies the length of @text.
79+ * @pkcs7: Supplies a pointer to a buffer containing a pkcs7 message.
80+ * @pkcs7len: Supplies the length of @pkcs7len.
81+ *
82+ * @text/@textlen is mutually exclusive with @pkcs7/@pkcs7len - see
83+ * ipe_new_policy.
84+ *
85+ * Context: Requires root->i_rwsem to be held.
86+ * Return: %0 on success. If an error occurs, the function will return
87+ * the -errno.
88+ */
89+ int ipe_update_policy (struct inode * root , const char * text , size_t textlen ,
90+ const char * pkcs7 , size_t pkcs7len )
91+ {
92+ struct ipe_policy * old , * ap , * new = NULL ;
93+ int rc = 0 ;
94+
95+ old = (struct ipe_policy * )root -> i_private ;
96+ if (!old )
97+ return - ENOENT ;
98+
99+ new = ipe_new_policy (text , textlen , pkcs7 , pkcs7len );
100+ if (IS_ERR (new ))
101+ return PTR_ERR (new );
102+
103+ if (strcmp (new -> parsed -> name , old -> parsed -> name )) {
104+ rc = - EINVAL ;
105+ goto err ;
106+ }
107+
108+ if (ver_to_u64 (old ) > ver_to_u64 (new )) {
109+ rc = - EINVAL ;
110+ goto err ;
111+ }
112+
113+ root -> i_private = new ;
114+ swap (new -> policyfs , old -> policyfs );
115+
116+ mutex_lock (& ipe_policy_lock );
117+ ap = rcu_dereference_protected (ipe_active_policy ,
118+ lockdep_is_held (& ipe_policy_lock ));
119+ if (old == ap ) {
120+ rcu_assign_pointer (ipe_active_policy , new );
121+ mutex_unlock (& ipe_policy_lock );
122+ } else {
123+ mutex_unlock (& ipe_policy_lock );
124+ }
125+ synchronize_rcu ();
126+ ipe_free_policy (old );
127+
128+ return 0 ;
129+ err :
130+ ipe_free_policy (new );
131+ return rc ;
132+ }
133+
46134/**
47135 * ipe_new_policy() - Allocate and parse an ipe_policy structure.
48136 *
@@ -101,3 +189,35 @@ struct ipe_policy *ipe_new_policy(const char *text, size_t textlen,
101189 ipe_free_policy (new );
102190 return ERR_PTR (rc );
103191}
192+
193+ /**
194+ * ipe_set_active_pol() - Make @p the active policy.
195+ * @p: Supplies a pointer to the policy to make active.
196+ *
197+ * Context: Requires root->i_rwsem, which i_private has the policy, to be held.
198+ * Return:
199+ * * %0 - Success
200+ * * %-EINVAL - New active policy version is invalid
201+ */
202+ int ipe_set_active_pol (const struct ipe_policy * p )
203+ {
204+ struct ipe_policy * ap = NULL ;
205+
206+ mutex_lock (& ipe_policy_lock );
207+
208+ ap = rcu_dereference_protected (ipe_active_policy ,
209+ lockdep_is_held (& ipe_policy_lock ));
210+ if (ap == p ) {
211+ mutex_unlock (& ipe_policy_lock );
212+ return 0 ;
213+ }
214+ if (ap && ver_to_u64 (ap ) > ver_to_u64 (p )) {
215+ mutex_unlock (& ipe_policy_lock );
216+ return - EINVAL ;
217+ }
218+
219+ rcu_assign_pointer (ipe_active_policy , p );
220+ mutex_unlock (& ipe_policy_lock );
221+
222+ return 0 ;
223+ }
0 commit comments