lkml.org 
[lkml]   [2012]   [Mar]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    SubjectRe: [PATCH v3 05/12] ima: add appraise action keywords and default rules
    From
    On Wed, Mar 21, 2012 at 8:54 PM, Mimi Zohar <zohar@linux.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@us.ibm.com>

    Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.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
    >
    \
     
     \ /
      Last update: 2012-03-22 15:29    [W:0.085 / U:29.600 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site