[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CALLzPKa2-mxMv-j850jALxDC=gdeDf1Vnd1Y2DxJF4BzfaWiAg@mail.gmail.com>
Date: Thu, 22 Mar 2012 16:27:17 +0200
From: "Kasatkin, Dmitry" <dmitry.kasatkin@...el.com>
To: Mimi Zohar <zohar@...ux.vnet.ibm.com>
Cc: linux-security-module@...r.kernel.org,
linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org,
Al Viro <viro@...iv.linux.org.uk>,
David Safford <safford@...ux.vnet.ibm.com>,
Mimi Zohar <zohar@...ibm.com>
Subject: Re: [PATCH v3 05/12] ima: add appraise action keywords and default rules
On Wed, Mar 21, 2012 at 8:54 PM, Mimi Zohar <zohar@...ux.vnet.ibm.com> wrote:
> Unlike the IMA measurement policy, the appraise policy can not be dependent
> on runtime process information, such as the task uid, as the 'security.ima'
> xattr is written on file close and must be updated each time the file changes,
> regardless of the current task uid.
>
> This patch extends the policy language with 'fowner', defines an appraise
> policy, which appraises all files owned by root, and defines 'ima_appraise_tcb',
> a new boot command line option, to enable the appraise policy.
>
> Changelog v3:
> - separate the measure from the appraise rules in order to support measuring
> without appraising and appraising without measuring.
> - change appraisal default for filesystems without xattr support to fail
> - update default appraise policy for cgroups
>
> Changelog v1:
> - don't appraise RAMFS (Dmitry Kasatkin)
> - merged rest of "ima: ima_must_appraise_or_measure API change" commit
> (Dmtiry Kasatkin)
>
> ima_must_appraise_or_measure() called ima_match_policy twice, which
> searched the policy for a matching rule. Once for a matching measurement
> rule and subsequently for an appraisal rule. Searching the policy twice
> is unnecessary overhead, which could be noticeable with a large policy.
>
> The new version of ima_must_appraise_or_measure() does everything in a
> single iteration using a new version of ima_match_policy(). It returns
> IMA_MEASURE, IMA_APPRAISE mask.
>
> With the use of action mask only one efficient matching function
> is enough. Removed other specific versions of matching functions.
>
> Changelog:
> - change 'owner' to 'fowner' to conform to the new LSM conditions posted by
> Roberto Sassu.
> - fix calls to ima_log_string()
>
> Signed-off-by: Mimi Zohar <zohar@...ibm.com>
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@...el.com>
> ---
> Documentation/ABI/testing/ima_policy | 25 +++++-
> Documentation/kernel-parameters.txt | 4 +
> security/integrity/ima/ima_appraise.c | 5 +-
> security/integrity/ima/ima_policy.c | 149 ++++++++++++++++++++++++---------
> 4 files changed, 139 insertions(+), 44 deletions(-)
>
> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
> index 6cd6dae..dcff822 100644
> --- a/Documentation/ABI/testing/ima_policy
> +++ b/Documentation/ABI/testing/ima_policy
> @@ -12,11 +12,14 @@ Description:
> then closing the file. The new policy takes effect after
> the file ima/policy is closed.
>
> + IMA appraisal, if configured, uses these file measurements
> + for local measurement appraisal.
> +
> rule format: action [condition ...]
>
> - action: measure | dont_measure
> + action: measure | dont_measure | appraise | dont_appraise
> condition:= base | lsm
> - base: [[func=] [mask=] [fsmagic=] [uid=]]
> + base: [[func=] [mask=] [fsmagic=] [uid=] [fowner]]
> lsm: [[subj_user=] [subj_role=] [subj_type=]
> [obj_user=] [obj_role=] [obj_type=]]
>
> @@ -24,36 +27,50 @@ Description:
> mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
> fsmagic:= hex value
> uid:= decimal value
> + fowner:=decimal value
> lsm: are LSM specific
>
> default policy:
> # PROC_SUPER_MAGIC
> dont_measure fsmagic=0x9fa0
> + dont_appraise fsmagic=0x9fa0
> # SYSFS_MAGIC
> dont_measure fsmagic=0x62656572
> + dont_appraise fsmagic=0x62656572
> # DEBUGFS_MAGIC
> dont_measure fsmagic=0x64626720
> + dont_appraise fsmagic=0x64626720
> # TMPFS_MAGIC
> dont_measure fsmagic=0x01021994
> + dont_appraise fsmagic=0x01021994
> + # RAMFS_MAGIC
> + dont_measure fsmagic=0x858458f6
> + dont_appraise fsmagic=0x858458f6
> # SECURITYFS_MAGIC
> dont_measure fsmagic=0x73636673
> + dont_appraise fsmagic=0x73636673
>
> measure func=BPRM_CHECK
> measure func=FILE_MMAP mask=MAY_EXEC
> measure func=FILE_CHECK mask=MAY_READ uid=0
> + appraise fowner=0
>
> The default policy measures all executables in bprm_check,
> all files mmapped executable in file_mmap, and all files
> - open for read by root in do_filp_open.
> + open for read by root in do_filp_open. The default appraisal
> + policy appraises all files owned by root.
>
> Examples of LSM specific definitions:
>
> SELinux:
> # SELINUX_MAGIC
> - dont_measure fsmagic=0xF97CFF8C
> + dont_measure fsmagic=0xf97cff8c
> + dont_appraise fsmagic=0xf97cff8c
>
> dont_measure obj_type=var_log_t
> + dont_appraise obj_type=var_log_t
> dont_measure obj_type=auditd_log_t
> + dont_appraise obj_type=auditd_log_t
> measure subj_user=system_u func=FILE_CHECK mask=MAY_READ
> measure subj_role=system_r func=FILE_CHECK mask=MAY_READ
>
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index a86765d..6c00491 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1008,6 +1008,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
> Format: { "off" | "enforce" | "fix" }
> default: "enforce"
>
> + ima_appraise_tcb [IMA]
> + The builtin appraise policy appraises all files
> + owned by uid=0.
> +
> ima_audit= [IMA]
> Format: { "0" | "1" }
> 0 -- integrity auditing messages. (Default)
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index 4865f61..681cb6e 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -36,7 +36,10 @@ __setup("ima_appraise=", default_appraise_setup);
> */
> int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask)
> {
> - return 0;
> + if (!ima_appraise)
> + return 0;
> +
> + return ima_match_policy(inode, func, mask, IMA_APPRAISE);
> }
>
> static void ima_fix_xattr(struct dentry *dentry,
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index 8ee301c..238aa2b 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -24,6 +24,7 @@
> #define IMA_MASK 0x0002
> #define IMA_FSMAGIC 0x0004
> #define IMA_UID 0x0008
> +#define IMA_FOWNER 0x0010
>
> #define UNKNOWN 0
> #define MEASURE 1 /* same as IMA_MEASURE */
> @@ -38,7 +39,7 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
> LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
> };
>
> -struct ima_measure_rule_entry {
> +struct ima_rule_entry {
> struct list_head list;
> int action;
> unsigned int flags;
> @@ -46,6 +47,7 @@ struct ima_measure_rule_entry {
> int mask;
> unsigned long fsmagic;
> uid_t uid;
> + uid_t fowner;
> struct {
> void *rule; /* LSM file metadata specific */
> int type; /* audit type */
> @@ -54,7 +56,7 @@ struct ima_measure_rule_entry {
>
> /*
> * Without LSM specific knowledge, the default policy can only be
> - * written in terms of .action, .func, .mask, .fsmagic, and .uid
> + * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
> */
>
> /*
> @@ -63,7 +65,7 @@ struct ima_measure_rule_entry {
> * normal users can easily run the machine out of memory simply building
> * and running executables.
> */
> -static struct ima_measure_rule_entry default_rules[] = {
> +static struct ima_rule_entry default_rules[] = {
> {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC},
> {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
> {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
> @@ -79,19 +81,39 @@ static struct ima_measure_rule_entry default_rules[] = {
> .flags = IMA_FUNC | IMA_MASK | IMA_UID},
> };
>
> -static LIST_HEAD(measure_default_rules);
> -static LIST_HEAD(measure_policy_rules);
> -static struct list_head *ima_measure;
> +static struct ima_rule_entry default_appraise_rules[] = {
> + {.action = DONT_APPRAISE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC},
> + {.action = DONT_APPRAISE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
> + {.action = DONT_APPRAISE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
> + {.action = DONT_APPRAISE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
> + {.action = DONT_APPRAISE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC},
> + {.action = DONT_APPRAISE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
> + {.action = DONT_APPRAISE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
> + {.action = DONT_APPRAISE,.fsmagic = CGROUP_SUPER_MAGIC,.flags = IMA_FSMAGIC},
> + {.action = APPRAISE,.fowner = 0,.flags = IMA_FOWNER},
> +};
> +
> +static LIST_HEAD(ima_default_rules);
> +static LIST_HEAD(ima_policy_rules);
> +static struct list_head *ima_rules;
>
> -static DEFINE_MUTEX(ima_measure_mutex);
> +static DEFINE_MUTEX(ima_rules_mutex);
>
> static bool ima_use_tcb __initdata;
> -static int __init default_policy_setup(char *str)
> +static int __init default_measure_policy_setup(char *str)
> {
> ima_use_tcb = 1;
> return 1;
> }
> -__setup("ima_tcb", default_policy_setup);
> +__setup("ima_tcb", default_measure_policy_setup);
> +
> +static bool ima_use_appraise_tcb __initdata;
> +static int __init default_appraise_policy_setup(char *str)
> +{
> + ima_use_appraise_tcb = 1;
> + return 1;
> +}
> +__setup("ima_appraise_tcb", default_appraise_policy_setup);
>
> /**
> * ima_match_rules - determine whether an inode matches the measure rule.
> @@ -102,7 +124,7 @@ __setup("ima_tcb", default_policy_setup);
> *
> * Returns true on rule match, false on failure.
> */
> -static bool ima_match_rules(struct ima_measure_rule_entry *rule,
> +static bool ima_match_rules(struct ima_rule_entry *rule,
> struct inode *inode, enum ima_hooks func, int mask)
> {
> struct task_struct *tsk = current;
> @@ -118,6 +140,8 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
> return false;
> if ((rule->flags & IMA_UID) && rule->uid != cred->uid)
> return false;
> + if ((rule->flags & IMA_FOWNER) && rule->fowner != inode->i_uid)
> + return false;
> for (i = 0; i < MAX_LSM_RULES; i++) {
> int rc = 0;
> u32 osid, sid;
> @@ -170,10 +194,10 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
> int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
> int flags)
> {
> - struct ima_measure_rule_entry *entry;
> + struct ima_rule_entry *entry;
> int action = 0, actmask = flags | (flags << 1);
>
> - list_for_each_entry(entry, ima_measure, list) {
> + list_for_each_entry(entry, ima_rules, list) {
>
> if (!(entry->action & actmask))
> continue;
> @@ -194,22 +218,31 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
> /**
> * ima_init_policy - initialize the default measure rules.
> *
> - * ima_measure points to either the measure_default_rules or the
> - * the new measure_policy_rules.
> + * ima_rules points to either the ima_default_rules or the
> + * the new ima_policy_rules.
> */
> void __init ima_init_policy(void)
> {
> - int i, entries;
> + int i, measure_entries, appraise_entries;
>
> /* if !ima_use_tcb set entries = 0 so we load NO default rules */
> - if (ima_use_tcb)
> - entries = ARRAY_SIZE(default_rules);
> - else
> - entries = 0;
> -
> - for (i = 0; i < entries; i++)
> - list_add_tail(&default_rules[i].list, &measure_default_rules);
> - ima_measure = &measure_default_rules;
> + measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0;
> + appraise_entries = ima_use_appraise_tcb ?
> + ARRAY_SIZE(default_appraise_rules) : 0;
> +
> + for (i = 0; i < measure_entries + appraise_entries; i++) {
> + if (i < measure_entries)
> + list_add_tail(&default_rules[i].list,
> + &ima_default_rules);
> + else {
> + int j = i - measure_entries;
> +
> + list_add_tail(&default_appraise_rules[j].list,
> + &ima_default_rules);
> + }
> + }
> +
> + ima_rules = &ima_default_rules;
> }
>
> /**
> @@ -226,8 +259,8 @@ void ima_update_policy(void)
> int result = 1;
> int audit_info = 0;
>
> - if (ima_measure == &measure_default_rules) {
> - ima_measure = &measure_policy_rules;
> + if (ima_rules == &ima_default_rules) {
> + ima_rules = &ima_policy_rules;
> cause = "complete";
> result = 0;
> }
> @@ -238,14 +271,17 @@ void ima_update_policy(void)
> enum {
> Opt_err = -1,
> Opt_measure = 1, Opt_dont_measure,
> + Opt_appraise, Opt_dont_appraise,
> Opt_obj_user, Opt_obj_role, Opt_obj_type,
> Opt_subj_user, Opt_subj_role, Opt_subj_type,
> - Opt_func, Opt_mask, Opt_fsmagic, Opt_uid
> + Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner
> };
>
> static match_table_t policy_tokens = {
> {Opt_measure, "measure"},
> {Opt_dont_measure, "dont_measure"},
> + {Opt_appraise, "appraise"},
> + {Opt_dont_appraise, "dont_appraise"},
> {Opt_obj_user, "obj_user=%s"},
> {Opt_obj_role, "obj_role=%s"},
> {Opt_obj_type, "obj_type=%s"},
> @@ -256,10 +292,11 @@ static match_table_t policy_tokens = {
> {Opt_mask, "mask=%s"},
> {Opt_fsmagic, "fsmagic=%s"},
> {Opt_uid, "uid=%s"},
> + {Opt_fowner, "fowner=%s"},
> {Opt_err, NULL}
> };
>
> -static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
> +static int ima_lsm_rule_init(struct ima_rule_entry *entry,
> char *args, int lsm_rule, int audit_type)
> {
> int result;
> @@ -283,7 +320,7 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
> audit_log_format(ab, " ");
> }
>
> -static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
> +static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
> {
> struct audit_buffer *ab;
> char *p;
> @@ -292,6 +329,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
> ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
>
> entry->uid = -1;
> + entry->fowner = -1;
> entry->action = UNKNOWN;
> while ((p = strsep(&rule, " \t")) != NULL) {
> substring_t args[MAX_OPT_ARGS];
> @@ -320,11 +358,27 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
>
> entry->action = DONT_MEASURE;
> break;
> + case Opt_appraise:
> + ima_log_string(ab, "action", "appraise");
> +
> + if (entry->action != UNKNOWN)
> + result = -EINVAL;
> +
> + entry->action = APPRAISE;
> + break;
> + case Opt_dont_appraise:
> + ima_log_string(ab, "action", "dont_appraise");
> +
> + if (entry->action != UNKNOWN)
> + result = -EINVAL;
> +
> + entry->action = DONT_APPRAISE;
> + break;
> case Opt_func:
> ima_log_string(ab, "func", args[0].from);
>
> if (entry->func)
> - result = -EINVAL;
> + result = -EINVAL;
>
> if (strcmp(args[0].from, "FILE_CHECK") == 0)
> entry->func = FILE_CHECK;
> @@ -389,6 +443,23 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
> entry->flags |= IMA_UID;
> }
> break;
> + case Opt_fowner:
> + ima_log_string(ab, "fowner", args[0].from);
> +
> + if (entry->fowner != -1) {
> + result = -EINVAL;
> + break;
> + }
> +
> + result = strict_strtoul(args[0].from, 10, &lnum);
> + if (!result) {
> + entry->fowner = (uid_t) lnum;
> + if (entry->fowner != lnum)
> + result = -EINVAL;
> + else
> + entry->flags |= IMA_FOWNER;
> + }
> + break;
> case Opt_obj_user:
> ima_log_string(ab, "obj_user", args[0].from);
> result = ima_lsm_rule_init(entry, args[0].from,
> @@ -440,7 +511,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
> }
>
> /**
> - * ima_parse_add_rule - add a rule to measure_policy_rules
> + * ima_parse_add_rule - add a rule to ima_policy_rules
> * @rule - ima measurement policy rule
> *
> * Uses a mutex to protect the policy list from multiple concurrent writers.
> @@ -450,12 +521,12 @@ ssize_t ima_parse_add_rule(char *rule)
> {
> const char *op = "update_policy";
> char *p;
> - struct ima_measure_rule_entry *entry;
> + struct ima_rule_entry *entry;
> ssize_t result, len;
> int audit_info = 0;
>
> /* Prevent installed policy from changing */
> - if (ima_measure != &measure_default_rules) {
> + if (ima_rules != &ima_default_rules) {
> integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
> NULL, op, "already exists",
> -EACCES, audit_info);
> @@ -488,9 +559,9 @@ ssize_t ima_parse_add_rule(char *rule)
> return result;
> }
>
> - mutex_lock(&ima_measure_mutex);
> - list_add_tail(&entry->list, &measure_policy_rules);
> - mutex_unlock(&ima_measure_mutex);
> + mutex_lock(&ima_rules_mutex);
> + list_add_tail(&entry->list, &ima_policy_rules);
> + mutex_unlock(&ima_rules_mutex);
>
> return len;
> }
> @@ -498,12 +569,12 @@ ssize_t ima_parse_add_rule(char *rule)
> /* ima_delete_rules called to cleanup invalid policy */
> void ima_delete_rules(void)
> {
> - struct ima_measure_rule_entry *entry, *tmp;
> + struct ima_rule_entry *entry, *tmp;
>
> - mutex_lock(&ima_measure_mutex);
> - list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) {
> + mutex_lock(&ima_rules_mutex);
> + list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
> list_del(&entry->list);
> kfree(entry);
> }
> - mutex_unlock(&ima_measure_mutex);
> + mutex_unlock(&ima_rules_mutex);
> }
> --
> 1.7.6.5
>
Powered by blists - more mailing lists