On 15-10-19 14:21:42, Mimi Zohar wrote:
> On Fri, 2015-10-16 at 22:31 +0300, Petko Manolov wrote:
> > When in development it is useful to read back the IMA policy.  This patch
> > provides the functionality.  However, this is a potential security hole so
> > it should not be used in production-grade kernels.
>  
> Like the other IMA securityfs files, only root would be able to read it.
> Once we start allowing additional rules to be appended to the policy,
> being able to view the resulting policy is important.  Is there a reason
> for limiting this option to development?

I have not considered allowing non-root users to read the policy - i was merely 
cleaning up the Zbigniew's patch.  I guess it might be useful to be able to 
read 
the policy when in development mode.


                Petko


> > Signed-off-by: Petko Manolov <pet...@mip-labs.com>
> > ---
> >  security/integrity/ima/Kconfig      |  13 +++
> >  security/integrity/ima/ima.h        |  13 ++-
> >  security/integrity/ima/ima_fs.c     |  29 +++++-
> >  security/integrity/ima/ima_policy.c | 190 
> > ++++++++++++++++++++++++++++++++++++
> >  4 files changed, 239 insertions(+), 6 deletions(-)
> > 
> > diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
> > index 235b3c2..040778f 100644
> > --- a/security/integrity/ima/Kconfig
> > +++ b/security/integrity/ima/Kconfig
> > @@ -121,6 +121,19 @@ config IMA_WRITE_POLICY
> > 
> >       If unsure, say N.
> > 
> > +config IMA_READ_POLICY
> > +   bool "Enable reading back the current IMA policy"
> > +   depends on IMA
> > +   default n
> > +   help
> > +      When developing and debugging an IMA enabled system it is often
> > +      useful to be able to read the IMA policy.  This patch allows
> > +      for doing so.  However, being able to read the IMA policy is
> > +      considered insecure and is strongly discouraged for
> > +      production-grade kernels.
> > +
> > +      If unsure, say N.
> > +
> >  config IMA_APPRAISE
> >     bool "Appraise integrity measurements"
> >     depends on IMA
> > diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> > index e2a60c3..ebc3554 100644
> > --- a/security/integrity/ima/ima.h
> > +++ b/security/integrity/ima/ima.h
> > @@ -166,6 +166,10 @@ void ima_update_policy(void);
> >  void ima_update_policy_flag(void);
> >  ssize_t ima_parse_add_rule(char *);
> >  void ima_delete_rules(void);
> > +void *ima_policy_start(struct seq_file *m, loff_t *pos);
> > +void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
> > +void ima_policy_stop(struct seq_file *m, void *v);
> > +int ima_policy_show(struct seq_file *m, void *v);
> > 
> >  /* Appraise integrity measurements */
> >  #define IMA_APPRAISE_ENFORCE       0x01
> > @@ -263,4 +267,11 @@ static inline int ima_init_keyring(const unsigned int 
> > id)
> >     return 0;
> >  }
> >  #endif /* CONFIG_IMA_TRUSTED_KEYRING */
> > -#endif
> > +
> > +#ifdef     CONFIG_IMA_READ_POLICY
> > +#define    POLICY_FILE_FLAGS       (S_IWUSR | S_IRUSR)
> > +#else
> > +#define    POLICY_FILE_FLAGS       S_IWUSR
> > +#endif /* CONFIG_IMA_WRITE_POLICY */
> > +
> > +#endif /* __LINUX_IMA_H */
> > diff --git a/security/integrity/ima/ima_fs.c 
> > b/security/integrity/ima/ima_fs.c
> > index a3cf5c0..85bd129 100644
> > --- a/security/integrity/ima/ima_fs.c
> > +++ b/security/integrity/ima/ima_fs.c
> > @@ -311,14 +311,29 @@ enum ima_fs_flags {
> > 
> >  static unsigned long ima_fs_flags;
> > 
> > +#ifdef     CONFIG_IMA_READ_POLICY
> > +static const struct seq_operations ima_policy_seqops = {
> > +           .start = ima_policy_start,
> > +           .next = ima_policy_next,
> > +           .stop = ima_policy_stop,
> > +           .show = ima_policy_show,
> > +};
> > +#endif
> > +
> >  /*
> >   * ima_open_policy: sequentialize access to the policy file
> >   */
> >  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))
> > +   if (!(filp->f_flags & O_WRONLY)) {
> > +#ifndef    CONFIG_IMA_READ_POLICY
> >             return -EACCES;
> > +#else
> > +           if (!capable(CAP_SYS_ADMIN))
> > +                   return -EPERM;
> > +           return seq_open(filp, &ima_policy_seqops);
> > +#endif
> > +   }
> >     if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
> >             return -EBUSY;
> >     return 0;
> > @@ -334,6 +349,10 @@ static int ima_open_policy(struct inode *inode, struct 
> > file *filp)
> >  static int ima_release_policy(struct inode *inode, struct file *file)
> >  {
> >     const char *cause = valid_policy ? "completed" : "failed";
> > +   int policy_write = (file->f_flags & O_WRONLY);
> > +
> > +   if (!policy_write)
> > +           return 0;
> > 
> >     pr_info("IMA: policy update %s\n", cause);
> >     integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
> > @@ -342,9 +361,9 @@ static int ima_release_policy(struct inode *inode, 
> > struct file *file)
> >     if (!valid_policy) {
> >             ima_delete_rules();
> >             valid_policy = 1;
> > -           clear_bit(IMA_FS_BUSY, &ima_fs_flags);
> >             return 0;
> >     }
> > +
> >     ima_update_policy();
> >  #ifndef    CONFIG_IMA_WRITE_POLICY
> >     securityfs_remove(ima_policy);
> > @@ -358,6 +377,7 @@ static int ima_release_policy(struct inode *inode, 
> > struct file *file)
> >  static const struct file_operations ima_measure_policy_ops = {
> >     .open = ima_open_policy,
> >     .write = ima_write_policy,
> > +   .read = seq_read,
> >     .release = ima_release_policy,
> >     .llseek = generic_file_llseek,
> >  };
> > @@ -395,8 +415,7 @@ int __init ima_fs_init(void)
> >     if (IS_ERR(violations))
> >             goto out;
> > 
> > -   ima_policy = securityfs_create_file("policy",
> > -                                       S_IWUSR,
> > +   ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
> >                                         ima_dir, NULL,
> >                                         &ima_measure_policy_ops);
> >     if (IS_ERR(ima_policy))
> > diff --git a/security/integrity/ima/ima_policy.c 
> > b/security/integrity/ima/ima_policy.c
> > index 7ace4e4..29961d7 100644
> > --- a/security/integrity/ima/ima_policy.c
> > +++ b/security/integrity/ima/ima_policy.c
> > @@ -18,6 +18,7 @@
> >  #include <linux/slab.h>
> >  #include <linux/rculist.h>
> >  #include <linux/genhd.h>
> > +#include <linux/seq_file.h>
> > 
> >  #include "ima.h"
> > 
> > @@ -487,6 +488,35 @@ static match_table_t policy_tokens = {
> >     {Opt_err, NULL}
> >  };
> > 
> > +enum {
> > +   mask_err = -1,
> > +   mask_exec = 1, mask_write, mask_read, mask_append
> > +};
> > +
> > +static match_table_t mask_tokens = {
> > +   {mask_exec, "MAY_EXEC"},
> > +   {mask_write, "MAY_WRITE"},
> > +   {mask_read, "MAY_READ"},
> > +   {mask_append, "MAY_APPEND"},
> > +   {mask_err, NULL}
> > +};
> > +
> > +enum {
> > +   func_err = -1,
> > +   func_file = 1, func_mmap, func_bprm,
> > +   func_module, func_firmware, func_post
> > +};
> > +
> > +static match_table_t func_tokens = {
> > +   {func_file, "FILE_CHECK"},
> > +   {func_mmap, "MMAP_CHECK"},
> > +   {func_bprm, "BPRM_CHECK"},
> > +   {func_module, "MODULE_CHECK"},
> > +   {func_firmware, "FIRMWARE_CHECK"},
> > +   {func_post, "POST_SETATTR"},
> > +   {func_err, NULL}
> > +};
> > +
> >  static int ima_lsm_rule_init(struct ima_rule_entry *entry,
> >                          substring_t *args, int lsm_rule, int audit_type)
> >  {
> > @@ -829,3 +859,163 @@ void ima_delete_rules(void)
> >             kfree(entry);
> >     }
> >  }
> > +
> > +void *ima_policy_start(struct seq_file *m, loff_t *pos)
> > +{
> > +   loff_t l = *pos;
> > +   struct ima_rule_entry *entry;
> > +
> > +   rcu_read_lock();
> > +   list_for_each_entry_rcu(entry, ima_rules, list) {
> > +           if (!l--) {
> > +                   rcu_read_unlock();
> > +                   return entry;
> > +           }
> > +   }
> > +   rcu_read_unlock();
> > +   return NULL;
> > +}
> > +
> > +void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
> > +{
> > +   struct ima_rule_entry *entry = v;
> > +
> > +   rcu_read_lock();
> > +   entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list);
> > +   rcu_read_unlock();
> > +   (*pos)++;
> > +
> > +   return (&entry->list == ima_rules) ? NULL : entry;
> > +}
> > +
> > +void ima_policy_stop(struct seq_file *m, void *v)
> > +{
> > +}
> > +
> > +#define pt(token)  policy_tokens[token-1].pattern
> > +#define mt(token)  mask_tokens[token-1].pattern
> > +#define ft(token)  func_tokens[token-1].pattern
> > +
> > +int ima_policy_show(struct seq_file *m, void *v)
> > +{
> > +   struct ima_rule_entry *entry = v;
> > +   int i = 0;
> > +
> > +   rcu_read_lock();
> > +
> > +   if (entry->action & MEASURE)
> > +           seq_puts(m, pt(Opt_measure));
> > +   if (entry->action & DONT_MEASURE)
> > +           seq_puts(m, pt(Opt_dont_measure));
> > +   if (entry->action & APPRAISE)
> > +           seq_puts(m, pt(Opt_appraise));
> > +   if (entry->action & DONT_APPRAISE)
> > +           seq_puts(m, pt(Opt_dont_appraise));
> > +   if (entry->action & AUDIT)
> > +           seq_puts(m, pt(Opt_audit));
> > +
> > +   seq_puts(m, " ");
> > +
> > +   if (entry->flags & IMA_FUNC) {
> > +           switch (entry->func) {
> > +           case FILE_CHECK:
> > +                   seq_printf(m, pt(Opt_func), ft(func_file));
> > +                   break;
> > +           case MMAP_CHECK:
> > +                   seq_printf(m, pt(Opt_func), ft(func_mmap));
> > +                   break;
> > +           case BPRM_CHECK:
> > +                   seq_printf(m, pt(Opt_func), ft(func_bprm));
> > +                   break;
> > +           case MODULE_CHECK:
> > +                   seq_printf(m, pt(Opt_func), ft(func_module));
> > +                   break;
> > +           case FIRMWARE_CHECK:
> > +                   seq_printf(m, pt(Opt_func), ft(func_firmware));
> > +                   break;
> > +           case POST_SETATTR:
> > +                   seq_printf(m, pt(Opt_func), ft(func_post));
> > +                   break;
> > +           default:
> > +                   seq_printf(m, "func=%d", entry->func);
> > +                   break;
> > +           }
> > +           seq_puts(m, " ");
> > +   }
> > +
> > +   if (entry->flags & IMA_MASK) {
> > +           if (entry->mask & MAY_EXEC)
> > +                   seq_printf(m, pt(Opt_mask), mt(mask_exec));
> > +           if (entry->mask & MAY_WRITE)
> > +                   seq_printf(m, pt(Opt_mask), mt(mask_write));
> > +           if (entry->mask & MAY_READ)
> > +                   seq_printf(m, pt(Opt_mask), mt(mask_read));
> > +           if (entry->mask & MAY_APPEND)
> > +                   seq_printf(m, pt(Opt_mask), mt(mask_append));
> > +           seq_puts(m, " ");
> > +   }
> > +
> > +   if (entry->flags & IMA_FSMAGIC) {
> > +           seq_printf(m, "fsmagic=0x%lx", entry->fsmagic);
> > +           seq_puts(m, " ");
> > +   }
> > +
> > +   if (entry->flags & IMA_FSUUID) {
> > +           seq_puts(m, "fsuuid=");
> > +           for (i = 0; i < ARRAY_SIZE(entry->fsuuid); ++i) {
> > +                   switch (i) {
> > +                   case 4:
> > +                   case 6:
> > +                   case 8:
> > +                   case 10:
> > +                           seq_puts(m, "-");
> > +                   }
> > +                   seq_printf(m, "%x", entry->fsuuid[i]);
> > +           }
> > +           seq_puts(m, " ");
> > +   }
> > +
> > +   if (entry->flags & IMA_UID) {
> > +           seq_printf(m, "uid=%d", __kuid_val(entry->uid));
> > +           seq_puts(m, " ");
> > +   }
> > +
> > +   if (entry->flags & IMA_FOWNER) {
> > +           seq_printf(m, "fowner=%d", __kuid_val(entry->fowner));
> > +           seq_puts(m, " ");
> > +   }
> > +
> > +   for (i = 0; i < MAX_LSM_RULES; i++) {
> > +           if (entry->lsm[i].rule) {
> > +                   switch (i) {
> > +                   case LSM_OBJ_USER:
> > +                           seq_printf(m, pt(Opt_obj_user),
> > +                                      (char *)entry->lsm[i].args_p);
> > +                           break;
> > +                   case LSM_OBJ_ROLE:
> > +                           seq_printf(m, pt(Opt_obj_role),
> > +                                      (char *)entry->lsm[i].args_p);
> > +                           break;
> > +                   case LSM_OBJ_TYPE:
> > +                           seq_printf(m, pt(Opt_obj_type),
> > +                                      (char *)entry->lsm[i].args_p);
> > +                           break;
> > +                   case LSM_SUBJ_USER:
> > +                           seq_printf(m, pt(Opt_subj_user),
> > +                                      (char *)entry->lsm[i].args_p);
> > +                           break;
> > +                   case LSM_SUBJ_ROLE:
> > +                           seq_printf(m, pt(Opt_subj_role),
> > +                                      (char *)entry->lsm[i].args_p);
> > +                           break;
> > +                   case LSM_SUBJ_TYPE:
> > +                           seq_printf(m, pt(Opt_subj_type),
> > +                                      (char *)entry->lsm[i].args_p);
> > +                           break;
> > +                   }
> > +           }
> > +   }
> > +   rcu_read_unlock();
> > +   seq_puts(m, "\n");
> > +   return 0;
> > +}
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe 
> linux-security-module" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to