Re: [PATCH v3 4/5] LSM: Define SELinux function to measure security state

From: Lakshmi Ramasubramanian
Date: Mon Jul 20 2020 - 11:17:33 EST


On 7/20/20 7:31 AM, Stephen Smalley wrote:

+void __init selinux_init_measurement(void)
+{
+ int i;
+
+ /*
+ * enabled
+ * enforcing
+ * checkreqport

checkreqprot (spelling)
:( - will fix that.


What about initialized? Or do you consider that to be implicitly
true/1 else we wouldn't be taking a measurement? Only caveat there is
that it provides one more means of disabling measurements (at the same
time as disabling enforcement) by setting it to false/0 via kernel
write flaw.
Yes - I was thinking measuring SELinux state would be meaningful only when initialized is set to true/1.

I can include "initialized" as well in the measurement.


+ * All policy capability flags
+ */
+ selinux_state_count = 3 + __POLICYDB_CAPABILITY_MAX;
+
+ selinux_state_string_len = snprintf(NULL, 0, str_format,
+ "enabled", 0);
+ selinux_state_string_len += snprintf(NULL, 0, str_format,
+ "enforcing", 0);
+ selinux_state_string_len += snprintf(NULL, 0, str_format,
+ "checkreqprot", 0);
+ for (i = 3; i < selinux_state_count; i++) {
+ selinux_state_string_len +=
+ snprintf(NULL, 0, str_format,
+ selinux_policycap_names[i-3], 0);
+ }

What's the benefit of this pattern versus just making the loop go from
0 to __POLICYDB_CAPABILITY_MAX and using selinux_policycap_names[i]?

No real benefit - I was just trying to use selinux_state_count.
I'll change the loop to go from 0 to POLICY_CAP_MAX


+void selinux_measure_state(struct selinux_state *selinux_state)
+{
+ void *policy = NULL;
+ void *policy_hash = NULL;
+ size_t curr, buflen;
+ int i, policy_hash_len, rc = 0;
+
+ if (!selinux_initialized(selinux_state)) {
+ pr_warn("%s: SELinux not yet initialized.\n", __func__);
+ return;
+ }

We could measure the global state variables before full SELinux
initialization (i.e. policy load).
Only the policy hash depends on having loaded the policy.

Thanks for the information. I'll measure the state variables always and measure policy only if "initialized" is true/1.


+
+ if (!selinux_state_string) {
+ pr_warn("%s: Buffer for state not allocated.\n", __func__);
+ return;
+ }
+
+ curr = snprintf(selinux_state_string, selinux_state_string_len,
+ str_format, "enabled",
+ !selinux_disabled(selinux_state));
+ curr += snprintf((selinux_state_string + curr),
+ (selinux_state_string_len - curr),
+ str_format, "enforcing",
+ enforcing_enabled(selinux_state));
+ curr += snprintf((selinux_state_string + curr),
+ (selinux_state_string_len - curr),
+ str_format, "checkreqprot",
+ selinux_checkreqprot(selinux_state));
+
+ for (i = 3; i < selinux_state_count; i++) {
+ curr += snprintf((selinux_state_string + curr),
+ (selinux_state_string_len - curr),
+ str_format,
+ selinux_policycap_names[i - 3],
+ selinux_state->policycap[i - 3]);
+ }

Same question here as for the previous loop; seems cleaner to go from
0 to __POLICYDB_CAPABILITY_MAX and use [i].
Will change it.


What public git tree / branch would you recommend trying to use your
patches against? Didn't seem to apply to any of the obvious ones.


Please try it on Mimi's next-integrity branch

https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git/log/?h=next-integrity

You can try it on Linus's mainline as well if you apply the following patch first (have mentioned that in the Cover letter as well)


https://patchwork.kernel.org/patch/11612989/

Thanks for trying out the changes. Please let me know the defects you find.

Just to let you know - I am making the following change (will update in the next patch):

=> Save the last policy hash and state string in selinux_state struct.
=> Measure policy and hash only if it has changed since the last measurement.
=> Also, suffix the IMA event name used with time stamp. For example,

10 e32e...5ac3 ima-buf sha256:86e8...4594
selinux-state-1595257807:874963248 656e61626c65643d313b656e666f7263696e673d303b636865636b72657170726f743d313b6e6574706565723d313b6f70656e7065726d3d313b657874736f636b636c6173733d313b616c776179736e6574776f726b3d303b6367726f75707365636c6162656c3d313b6e6e706e6f737569647472616e736974696f6e3d313b67656e66737365636c6162656c73796d6c696e6b3d303b

10 f4a7...9408 ima-buf sha256:4941...68fc
selinux-policy-hash-1595257807:874963248
8d1d...1834

The above will ensure the following sequence will be measured:
#1 State A - Measured
#2 Change from State A to State B - Measured
#3 Change from State B back to State A - Since the measured data is same as in #1, the change will be measured only if the event name is different between #1 and #3

thanks,
-lakshmi