ima: few policy loading improvements
Subsystems (3)
v2 cover ima: few policy loading improvements
Hi,
Here is few policy loading interface improvements. Refer to the patches descriptions for details.
- Dmitry
Dmitry Kasatkin (4):
ima: report policy load status
ima: no need to allocate entry for comment
ima: ignore empty and with whitespaces policy lines
ima: use atomic bit operations to protect policy update interface
security/integrity/ima/ima_fs.c | 21 ++++++++++++++++----- security/integrity/ima/ima_policy.c | 36 ++++++++---------------------------- 2 files changed, 24 insertions(+), 33 deletions(-)
Signature · 1 line
1.9.1
PATCH v2 1/4 ima: report policy load status
Audit messages are rate limited and often policy update info is not visible. Report policy loading status also using pr_info.
Changes in v2:
* reporting moved to ima_release_policy to notice parsing errors
* reporting both completed and failed status
--- security/integrity/ima/ima_fs.c | 2 ++ 1 file changed, 2 insertions(+)
security/integrity/ima/ima_fs.c +2 -0
@@ -311,6 +311,8 @@ static int ima_open_policy(struct inode *inode, struct file *filp)*/ static int ima_release_policy (struct inode *inode,struct file *file) { +pr_info ("IMA: policy update %s\n" , + valid_policy ?"completed" :"failed" );if (!valid_policy) {ima_delete_rules (); valid_policy =1 ;
Signature · 1 line
1.9.1
PATCH v2 2/4 ima: no need to allocate entry for comment
In reply to Dmitry KasatkinIf rule is a comment, there is no need to allocate entry. Move checking for comment before allocating entry.
--- security/integrity/ima/ima_policy.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
security/integrity/ima/ima_policy.c +6 -8
@@ -694,6 +694,12 @@ ssize_t ima_parse_add_rule(char *rule)return -EACCES ; } + p =strsep (&rule,"\n" ); + len =strlen (p) +1 ; + +if (*p =='#' ) +return len; + entry =kzalloc (sizeof (*entry),GFP_KERNEL );if (!entry) { integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
@@ -703,14 +709,6 @@ ssize_t ima_parse_add_rule(char *rule)INIT_LIST_HEAD (&entry->list); - p =strsep (&rule,"\n" ); - len =strlen (p) +1 ; - -if (*p =='#' ) { -kfree (entry); -return len; - } - result =ima_parse_rule (p, entry);if (result) {kfree (entry);
Signature · 1 line
1.9.1
PATCH v2 3/4 ima: ignore empty and with whitespaces policy lines
In reply to Dmitry KasatkinEmpty policy lines cause parsing failures which is, especially for new users, hard to spot. This patch prevents it.
It is now possible to 'cat policy > <securityfs>/ima/policy'.
Changes in v2:
* strip leading blanks and tabs in rules to prevent parsing failures
--- security/integrity/ima/ima_policy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
security/integrity/ima/ima_policy.c +2 -1
@@ -696,8 +696,9 @@ ssize_t ima_parse_add_rule(char *rule) p =strsep (&rule,"\n" ); len =strlen (p) +1 ; + p +=strspn (p," \t" ); -if (*p =='#' ) +if (*p =='#' || *p =='\0' )return len; entry =kzalloc (sizeof (*entry),GFP_KERNEL );
Signature · 1 line
1.9.1
Re: [PATCH v2 3/4] ima: ignore empty and with whitespaces policy lines
Quoted 4 lines · Dmitry Kasatkin
Empty policy lines cause parsing failures which is, especially for new users, hard to spot. This patch prevents it.
It is now possible to 'cat policy > <securityfs>/ima/policy'.
The patch itself is fine, but dropping this comment as commit "6ccd045
ima: handle multiple rules per write" already added support to 'cat' the policy.
Mimi
Quoted 23 lines
Changes in v2:
* strip leading blanks and tabs in rules to prevent parsing failuresSigned-off-by Dmitry Kasatkin <[email protected]>--- security/integrity/ima/ima_policy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)security/integrity/ima/ima_policy.c +2
-1@@ -696,8 +696,9 @@ ssize_t ima_parse_add_rule(char *rule) p =strsep (&rule,"\n" ); len =strlen (p) +1 ; + p +=strspn (p," \t" ); -if (*p =='#' ) +if (*p =='#' || *p =='\0' )return len; entry =kzalloc (sizeof (*entry),GFP_KERNEL );
PATCH v2 4/4 ima: use atomic bit operations to protect policy update interface
In reply to Dmitry KasatkinCurrent implementation uses atomic counter to provide exclusive access to the sysfs 'policy' entry to update the IMA policy. While practically it is almost unlikely, usage of counter might potentially allow another process to overflow the counter, open the interface and insert additional rules into the policy being loaded.
This patch replace atomic counter with atomic bit operations which is more reliable and widely used to provide exclusive access.
As bit operation keeps interface locked after successful update, it makes it unnecessary to verify if default policy was set or not during parsing and interface closing. This patch also removes it.
Changes in v3:
* move audit log message to ima_relead_policy() to report successful and unsuccessful result
* unnecessary comment removed
Changes in v2:
* keep interface locked after successful policy load as in original design
* remove sysfs entry as in original design
--- security/integrity/ima/ima_fs.c | 23 ++++++++++++++++------- security/integrity/ima/ima_policy.c | 23 ++--------------------- 2 files changed, 18 insertions(+), 28 deletions(-)
security/integrity/ima/ima_fs.c +16 -7
@@ -288,7 +288,12 @@ static struct dentry *runtime_measurements_count;static struct dentry *violations;static struct dentry *ima_policy; -static atomic_t policy_opencount =ATOMIC_INIT (1 ); +enum ima_fs_flags { +IMA_FS_BUSY , +}; + +static unsigned long ima_fs_flags; +/* * ima_open_policy: sequentialize access to the policy file */
@@ -297,9 +302,9 @@ static int ima_open_policy(struct inode *inode, struct file *filp)/* No point in being allowed to open it if you aren't going to write */ if (!(filp->f_flags &O_WRONLY ))return -EACCES ; -if (atomic_dec_and_test (&policy_opencount)) -return 0 ; -return -EBUSY ; +if (test_and_set_bit (IMA_FS_BUSY , &ima_fs_flags)) +return -EBUSY ; +return 0 ; }/*
@@ -311,12 +316,16 @@ static int ima_open_policy(struct inode *inode, struct file *filp)*/ static int ima_release_policy (struct inode *inode,struct file *file) { -pr_info ("IMA: policy update %s\n" , - valid_policy ?"completed" :"failed" ); +const char *cause = valid_policy ?"completed" :"failed" ; + +pr_info ("IMA: policy update %s\n" , cause); +integrity_audit_msg (AUDIT_INTEGRITY_STATUS ,NULL ,NULL , +"policy_update" , cause, !valid_policy,0 ); +if (!valid_policy) {ima_delete_rules (); valid_policy =1 ; -atomic_set (&policy_opencount,1 ); +clear_bit (IMA_FS_BUSY , &ima_fs_flags);return 0 ; }ima_update_policy ();
security/integrity/ima/ima_policy.c +2 -21
@@ -356,19 +356,8 @@ void __init ima_init_policy(void)*/ void ima_update_policy (void ) { -static const char op[] ="policy_update" ; -const char *cause ="already-exists" ; -int result =1 ; -int audit_info =0 ; - -if (ima_rules == &ima_default_rules) { - ima_rules = &ima_policy_rules; -ima_update_policy_flag (); - cause ="complete" ; - result =0 ; - } -integrity_audit_msg (AUDIT_INTEGRITY_STATUS ,NULL , -NULL , op, cause, result, audit_info); + ima_rules = &ima_policy_rules; +ima_update_policy_flag (); }enum {
@@ -686,14 +675,6 @@ ssize_t ima_parse_add_rule(char *rule)ssize_t result, len;int audit_info =0 ; -/* Prevent installed policy from changing */ -if (ima_rules != &ima_default_rules) { -integrity_audit_msg (AUDIT_INTEGRITY_STATUS ,NULL , -NULL , op,"already-exists" , - -EACCES , audit_info); -return -EACCES ; - } - p =strsep (&rule,"\n" ); len =strlen (p) +1 ; p +=strspn (p," \t" );
Signature · 1 line
1.9.1