Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorri...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 7 Apr 2018 23:53:59 +0000 (16:53 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 7 Apr 2018 23:53:59 +0000 (16:53 -0700)
Pull integrity updates from James Morris:
 "A mixture of bug fixes, code cleanup, and continues to close
  IMA-measurement, IMA-appraisal, and IMA-audit gaps.

  Also note the addition of a new cred_getsecid LSM hook by Matthew
  Garrett:

     For IMA purposes, we want to be able to obtain the prepared secid
     in the bprm structure before the credentials are committed. Add a
     cred_getsecid hook that makes this possible.

  which is used by a new CREDS_CHECK target in IMA:

     In ima_bprm_check(), check with both the existing process
     credentials and the credentials that will be committed when the new
     process is started. This will not change behaviour unless the
     system policy is extended to include CREDS_CHECK targets -
     BPRM_CHECK will continue to check the same credentials that it did
     previously"

* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  ima: Fallback to the builtin hash algorithm
  ima: Add smackfs to the default appraise/measure list
  evm: check for remount ro in progress before writing
  ima: Improvements in ima_appraise_measurement()
  ima: Simplify ima_eventsig_init()
  integrity: Remove unused macro IMA_ACTION_RULE_FLAGS
  ima: drop vla in ima_audit_measurement()
  ima: Fix Kconfig to select TPM 2.0 CRB interface
  evm: Constify *integrity_status_msg[]
  evm: Move evm_hmac and evm_hash from evm_main.c to evm_crypto.c
  fuse: define the filesystem as untrusted
  ima: fail signature verification based on policy
  ima: clear IMA_HASH
  ima: re-evaluate files on privileged mounted filesystems
  ima: fail file signature verification on non-init mounted filesystems
  IMA: Support using new creds in appraisal policy
  security: Add a cred_getsecid hook

22 files changed:
Documentation/ABI/testing/ima_policy
Documentation/admin-guide/kernel-parameters.txt
fs/fuse/inode.c
include/linux/fs.h
include/linux/lsm_hooks.h
include/linux/security.h
security/integrity/evm/evm.h
security/integrity/evm/evm_crypto.c
security/integrity/evm/evm_main.c
security/integrity/iint.c
security/integrity/ima/Kconfig
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template_lib.c
security/integrity/integrity.h
security/security.c
security/selinux/hooks.c
security/smack/smack_lsm.c

index 2028f2d093b2049ca0a75b265d80dd14446d397a..b8465e00ba5fb7d06e434e9508302b71b1809f5b 100644 (file)
@@ -26,7 +26,7 @@ Description:
                                 [obj_user=] [obj_role=] [obj_type=]]
                        option: [[appraise_type=]] [permit_directio]
 
-               base:   func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
+               base:   func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
                                [FIRMWARE_CHECK]
                                [KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
                        mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
index 683145d7b054df49b5994e66bbf94e5a591b40a0..9a3edf7e901ab331e2b005593d15f43d11cae9b3 100644 (file)
 
        ima_policy=     [IMA]
                        The builtin policies to load during IMA setup.
-                       Format: "tcb | appraise_tcb | secure_boot"
+                       Format: "tcb | appraise_tcb | secure_boot |
+                                fail_securely"
 
                        The "tcb" policy measures all programs exec'd, files
                        mmap'd for exec, and all files opened with the read
                        of files (eg. kexec kernel image, kernel modules,
                        firmware, policy, etc) based on file signatures.
 
+                       The "fail_securely" policy forces file signature
+                       verification failure also on privileged mounted
+                       filesystems with the SB_I_UNVERIFIABLE_SIGNATURE
+                       flag.
+
        ima_tcb         [IMA] Deprecated.  Use ima_policy= instead.
                        Load a policy which meets the needs of the Trusted
                        Computing Base.  This means IMA will measure all
index 624f18bbfd2b3430e4a5d67c54cf84af4312a440..ef309958e06073ca0bcc7f8a5b487bf3e42628ba 100644 (file)
@@ -1080,6 +1080,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_maxbytes = MAX_LFS_FILESIZE;
        sb->s_time_gran = 1;
        sb->s_export_op = &fuse_export_operations;
+       sb->s_iflags |= SB_I_IMA_UNVERIFIABLE_SIGNATURE;
+       if (sb->s_user_ns != &init_user_ns)
+               sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER;
 
        file = fget(d.fd);
        err = -EINVAL;
index 0d798052bd8571198aae7f62f6c517862d121b13..1ee7f592e239c3b11587f738b42b06b05291e348 100644 (file)
@@ -1321,6 +1321,8 @@ extern int send_sigurg(struct fown_struct *fown);
 
 /* sb->s_iflags to limit user namespace mounts */
 #define SB_I_USERNS_VISIBLE            0x00000010 /* fstype already mounted */
+#define SB_I_IMA_UNVERIFIABLE_SIGNATURE        0x00000020
+#define SB_I_UNTRUSTED_MOUNTER         0x00000040
 
 /* Possible states of 'frozen' field */
 enum {
index c72c42dbe77b4a1d27bc62df403d62716cbcf25b..9d0b286f3dbaf56c5362327a1bc82ed1a9132a34 100644 (file)
  *     @new points to the new credentials.
  *     @old points to the original credentials.
  *     Transfer data from original creds to new creds
+ * @cred_getsecid:
+ *     Retrieve the security identifier of the cred structure @c
+ *     @c contains the credentials, secid will be placed into @secid.
+ *     In case of failure, @secid will be set to zero.
  * @kernel_act_as:
  *     Set the credentials for a kernel service to act as (subjective context).
  *     @new points to the credentials to be modified.
@@ -1569,6 +1573,7 @@ union security_list_options {
        int (*cred_prepare)(struct cred *new, const struct cred *old,
                                gfp_t gfp);
        void (*cred_transfer)(struct cred *new, const struct cred *old);
+       void (*cred_getsecid)(const struct cred *c, u32 *secid);
        int (*kernel_act_as)(struct cred *new, u32 secid);
        int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
        int (*kernel_module_request)(char *kmod_name);
@@ -1858,6 +1863,7 @@ struct security_hook_heads {
        struct hlist_head cred_free;
        struct hlist_head cred_prepare;
        struct hlist_head cred_transfer;
+       struct hlist_head cred_getsecid;
        struct hlist_head kernel_act_as;
        struct hlist_head kernel_create_files_as;
        struct hlist_head kernel_read_file;
index 4a573c3be93d6a1063eb858f072eecd3c29b0d36..200920f521a1ea03aed601eb5ae69bcdd66aac09 100644 (file)
@@ -322,6 +322,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
 void security_cred_free(struct cred *cred);
 int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
 void security_transfer_creds(struct cred *new, const struct cred *old);
+void security_cred_getsecid(const struct cred *c, u32 *secid);
 int security_kernel_act_as(struct cred *new, u32 secid);
 int security_kernel_create_files_as(struct cred *new, struct inode *inode);
 int security_kernel_module_request(char *kmod_name);
index 04825393facbabe59b8f5aa854bc23975669c3bd..45c4a89c02ffd17bd4a2f920e5c3f4e88c5c0e8f 100644 (file)
@@ -31,8 +31,6 @@
                       EVM_ALLOW_METADATA_WRITES)
 
 extern int evm_initialized;
-extern char *evm_hmac;
-extern char *evm_hash;
 
 #define EVM_ATTR_FSUUID                0x0001
 
index 691f3e09154c752d5d547760a3f9cc554e9465a0..a46fba322340b80fac97fb1c6ca1a5b14e128759 100644 (file)
@@ -37,6 +37,9 @@ static DEFINE_MUTEX(mutex);
 
 static unsigned long evm_set_key_flags;
 
+static char * const evm_hmac = "hmac(sha1)";
+static char * const evm_hash = "sha1";
+
 /**
  * evm_set_key() - set EVM HMAC key from the kernel
  * @key: pointer to a buffer with the key data
index a8d5028272702d59bcce310e97a9765d36c78a98..9ea9c19a545c3abbe0dff5e1ea4e8d32f314d471 100644 (file)
 
 int evm_initialized;
 
-static char *integrity_status_msg[] = {
+static const char * const integrity_status_msg[] = {
        "pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"
 };
-char *evm_hmac = "hmac(sha1)";
-char *evm_hash = "sha1";
 int evm_hmac_attrs;
 
 char *evm_config_xattrnames[] = {
@@ -126,6 +124,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
        struct evm_ima_xattr_data *xattr_data = NULL;
        struct evm_ima_xattr_data calc;
        enum integrity_status evm_status = INTEGRITY_PASS;
+       struct inode *inode;
        int rc, xattr_len;
 
        if (iint && (iint->evm_status == INTEGRITY_PASS ||
@@ -180,12 +179,15 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
                                        (const char *)xattr_data, xattr_len,
                                        calc.digest, sizeof(calc.digest));
                if (!rc) {
+                       inode = d_backing_inode(dentry);
+
                        if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) {
                                if (iint)
                                        iint->flags |= EVM_IMMUTABLE_DIGSIG;
                                evm_status = INTEGRITY_PASS_IMMUTABLE;
-                       } else if (!IS_RDONLY(d_backing_inode(dentry)) &&
-                                  !IS_IMMUTABLE(d_backing_inode(dentry))) {
+                       } else if (!IS_RDONLY(inode) &&
+                                  !(inode->i_sb->s_readonly_remount) &&
+                                  !IS_IMMUTABLE(inode)) {
                                evm_update_evmxattr(dentry, xattr_name,
                                                    xattr_value,
                                                    xattr_value_len);
index 9700e96ab0f05cf27c6dee7bdf3f92fb762d3dab..f266e4b3b7d4614345b8aa6f24806b2f3476b9db 100644 (file)
@@ -79,6 +79,7 @@ static void iint_free(struct integrity_iint_cache *iint)
        iint->ima_mmap_status = INTEGRITY_UNKNOWN;
        iint->ima_bprm_status = INTEGRITY_UNKNOWN;
        iint->ima_read_status = INTEGRITY_UNKNOWN;
+       iint->ima_creds_status = INTEGRITY_UNKNOWN;
        iint->evm_status = INTEGRITY_UNKNOWN;
        iint->measured_pcrs = 0;
        kmem_cache_free(iint_cache, iint);
@@ -158,6 +159,7 @@ static void init_once(void *foo)
        iint->ima_mmap_status = INTEGRITY_UNKNOWN;
        iint->ima_bprm_status = INTEGRITY_UNKNOWN;
        iint->ima_read_status = INTEGRITY_UNKNOWN;
+       iint->ima_creds_status = INTEGRITY_UNKNOWN;
        iint->evm_status = INTEGRITY_UNKNOWN;
        mutex_init(&iint->mutex);
 }
index 35ef69312811377125ff03923c5956ed6ab878af..6a8f67714c831570a674c2bde566191a544906fc 100644 (file)
@@ -10,6 +10,7 @@ config IMA
        select CRYPTO_HASH_INFO
        select TCG_TPM if HAS_IOMEM && !UML
        select TCG_TIS if TCG_TPM && X86
+       select TCG_CRB if TCG_TPM && ACPI
        select TCG_IBMVTPM if TCG_TPM && PPC_PSERIES
        help
          The Trusted Computing Group(TCG) runtime Integrity
index d52b487ad25955fb553813746e0d0c485434221f..35fe91aa1fc95ad6001adccbd85fa3856918879f 100644 (file)
@@ -177,6 +177,7 @@ static inline unsigned long ima_hash_key(u8 *digest)
        hook(FILE_CHECK)                \
        hook(MMAP_CHECK)                \
        hook(BPRM_CHECK)                \
+       hook(CREDS_CHECK)               \
        hook(POST_SETATTR)              \
        hook(MODULE_CHECK)              \
        hook(FIRMWARE_CHECK)            \
@@ -191,8 +192,8 @@ enum ima_hooks {
 };
 
 /* LIM API function definitions */
-int ima_get_action(struct inode *inode, int mask,
-                  enum ima_hooks func, int *pcr);
+int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
+                  int mask, enum ima_hooks func, int *pcr);
 int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
 int ima_collect_measurement(struct integrity_iint_cache *iint,
                            struct file *file, void *buf, loff_t size,
@@ -212,8 +213,8 @@ void ima_free_template_entry(struct ima_template_entry *entry);
 const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
 
 /* IMA policy related functions */
-int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
-                    int flags, int *pcr);
+int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
+                    enum ima_hooks func, int mask, int flags, int *pcr);
 void ima_init_policy(void);
 void ima_update_policy(void);
 void ima_update_policy_flag(void);
index 08fe405338e1fc0443b36ffea07088ece23f8af1..bf88236b7a0bfbb30b550b7e31c35ea1c0ebbaa3 100644 (file)
@@ -158,6 +158,8 @@ err_out:
 /**
  * ima_get_action - appraise & measure decision based on policy.
  * @inode: pointer to inode to measure
+ * @cred: pointer to credentials structure to validate
+ * @secid: secid of the task being validated
  * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
  *        MAY_APPEND)
  * @func: caller identifier
@@ -166,20 +168,21 @@ err_out:
  * The policy is defined in terms of keypairs:
  *             subj=, obj=, type=, func=, mask=, fsmagic=
  *     subj,obj, and type: are LSM specific.
- *     func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK
+ *     func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
  *     mask: contains the permission mask
  *     fsmagic: hex value
  *
  * Returns IMA_MEASURE, IMA_APPRAISE mask.
  *
  */
-int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)
+int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
+                  int mask, enum ima_hooks func, int *pcr)
 {
        int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
 
        flags &= ima_policy_flag;
 
-       return ima_match_policy(inode, func, mask, flags, pcr);
+       return ima_match_policy(inode, cred, secid, func, mask, flags, pcr);
 }
 
 /*
@@ -308,14 +311,17 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
                           const unsigned char *filename)
 {
        struct audit_buffer *ab;
-       char hash[(iint->ima_hash->length * 2) + 1];
+       char *hash;
        const char *algo_name = hash_algo_name[iint->ima_hash->algo];
-       char algo_hash[sizeof(hash) + strlen(algo_name) + 2];
        int i;
 
        if (iint->flags & IMA_AUDITED)
                return;
 
+       hash = kzalloc((iint->ima_hash->length * 2) + 1, GFP_KERNEL);
+       if (!hash)
+               return;
+
        for (i = 0; i < iint->ima_hash->length; i++)
                hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
        hash[i * 2] = '\0';
@@ -323,18 +329,19 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
        ab = audit_log_start(current->audit_context, GFP_KERNEL,
                             AUDIT_INTEGRITY_RULE);
        if (!ab)
-               return;
+               goto out;
 
        audit_log_format(ab, "file=");
        audit_log_untrustedstring(ab, filename);
-       audit_log_format(ab, " hash=");
-       snprintf(algo_hash, sizeof(algo_hash), "%s:%s", algo_name, hash);
-       audit_log_untrustedstring(ab, algo_hash);
+       audit_log_format(ab, " hash=\"%s:%s\"", algo_name, hash);
 
        audit_log_task_info(ab, current);
        audit_log_end(ab);
 
        iint->flags |= IMA_AUDITED;
+out:
+       kfree(hash);
+       return;
 }
 
 /*
index f2803a40ff82ceb81160ca32d01eaf39263c1079..8bd7a0733e5179eca03febd8524a2c08b142cfde 100644 (file)
@@ -50,11 +50,14 @@ bool is_ima_appraise_enabled(void)
  */
 int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
 {
+       u32 secid;
+
        if (!ima_appraise)
                return 0;
 
-       return ima_match_policy(inode, func, mask, IMA_APPRAISE | IMA_HASH,
-                               NULL);
+       security_task_getsecid(current, &secid);
+       return ima_match_policy(inode, current_cred(), secid, func, mask,
+                               IMA_APPRAISE | IMA_HASH, NULL);
 }
 
 static int ima_fix_xattr(struct dentry *dentry,
@@ -87,6 +90,8 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
                return iint->ima_mmap_status;
        case BPRM_CHECK:
                return iint->ima_bprm_status;
+       case CREDS_CHECK:
+               return iint->ima_creds_status;
        case FILE_CHECK:
        case POST_SETATTR:
                return iint->ima_file_status;
@@ -107,6 +112,8 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
        case BPRM_CHECK:
                iint->ima_bprm_status = status;
                break;
+       case CREDS_CHECK:
+               iint->ima_creds_status = status;
        case FILE_CHECK:
        case POST_SETATTR:
                iint->ima_file_status = status;
@@ -128,6 +135,9 @@ static void ima_cache_flags(struct integrity_iint_cache *iint,
        case BPRM_CHECK:
                iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED);
                break;
+       case CREDS_CHECK:
+               iint->flags |= (IMA_CREDS_APPRAISED | IMA_APPRAISED);
+               break;
        case FILE_CHECK:
        case POST_SETATTR:
                iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
@@ -205,7 +215,7 @@ int ima_appraise_measurement(enum ima_hooks func,
                             int xattr_len, int opened)
 {
        static const char op[] = "appraise_data";
-       char *cause = "unknown";
+       const char *cause = "unknown";
        struct dentry *dentry = file_dentry(file);
        struct inode *inode = d_backing_inode(dentry);
        enum integrity_status status = INTEGRITY_UNKNOWN;
@@ -231,16 +241,22 @@ int ima_appraise_measurement(enum ima_hooks func,
        }
 
        status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
-       if ((status != INTEGRITY_PASS) &&
-           (status != INTEGRITY_PASS_IMMUTABLE) &&
-           (status != INTEGRITY_UNKNOWN)) {
-               if ((status == INTEGRITY_NOLABEL)
-                   || (status == INTEGRITY_NOXATTRS))
-                       cause = "missing-HMAC";
-               else if (status == INTEGRITY_FAIL)
-                       cause = "invalid-HMAC";
+       switch (status) {
+       case INTEGRITY_PASS:
+       case INTEGRITY_PASS_IMMUTABLE:
+       case INTEGRITY_UNKNOWN:
+               break;
+       case INTEGRITY_NOXATTRS:        /* No EVM protected xattrs. */
+       case INTEGRITY_NOLABEL:         /* No security.evm xattr. */
+               cause = "missing-HMAC";
                goto out;
+       case INTEGRITY_FAIL:            /* Invalid HMAC/signature. */
+               cause = "invalid-HMAC";
+               goto out;
+       default:
+               WARN_ONCE(true, "Unexpected integrity status %d\n", status);
        }
+
        switch (xattr_value->type) {
        case IMA_XATTR_DIGEST_NG:
                /* first byte contains algorithm id */
@@ -292,23 +308,40 @@ int ima_appraise_measurement(enum ima_hooks func,
        }
 
 out:
-       if (status != INTEGRITY_PASS) {
+       /*
+        * File signatures on some filesystems can not be properly verified.
+        * When such filesystems are mounted by an untrusted mounter or on a
+        * system not willing to accept such a risk, fail the file signature
+        * verification.
+        */
+       if ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
+           ((inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) ||
+            (iint->flags & IMA_FAIL_UNVERIFIABLE_SIGS))) {
+               status = INTEGRITY_FAIL;
+               cause = "unverifiable-signature";
+               integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
+                                   op, cause, rc, 0);
+       } else if (status != INTEGRITY_PASS) {
+               /* Fix mode, but don't replace file signatures. */
                if ((ima_appraise & IMA_APPRAISE_FIX) &&
                    (!xattr_value ||
                     xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
                        if (!ima_fix_xattr(dentry, iint))
                                status = INTEGRITY_PASS;
-               } else if ((inode->i_size == 0) &&
-                          (iint->flags & IMA_NEW_FILE) &&
-                          (xattr_value &&
-                           xattr_value->type == EVM_IMA_XATTR_DIGSIG)) {
+               }
+
+               /* Permit new files with file signatures, but without data. */
+               if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
+                   xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
                        status = INTEGRITY_PASS;
                }
+
                integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
                                    op, cause, rc, 0);
        } else {
                ima_cache_flags(iint, func);
        }
+
        ima_set_cache_status(iint, func, status);
        return status;
 }
index 205bc69361ea6667febadb403c6cede9a7827a52..4e085a17124f1a87154b675d833941e998271c13 100644 (file)
@@ -73,6 +73,8 @@ int __init ima_init_crypto(void)
                       hash_algo_name[ima_hash_algo], rc);
                return rc;
        }
+       pr_info("Allocated hash algorithm: %s\n",
+               hash_algo_name[ima_hash_algo]);
        return 0;
 }
 
index 2cfb0c71496766b3b69f8700f0bf7f07789ca7c6..74d0bd7e76d7159234c036df6c053532f58ab4a4 100644 (file)
@@ -16,6 +16,9 @@
  *     implements the IMA hooks: ima_bprm_check, ima_file_mmap,
  *     and ima_file_check.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/file.h>
 #include <linux/binfmts.h>
@@ -25,6 +28,7 @@
 #include <linux/xattr.h>
 #include <linux/ima.h>
 #include <linux/iversion.h>
+#include <linux/fs.h>
 
 #include "ima.h"
 
@@ -167,8 +171,9 @@ void ima_file_free(struct file *file)
        ima_check_last_writer(iint, inode, file);
 }
 
-static int process_measurement(struct file *file, char *buf, loff_t size,
-                              int mask, enum ima_hooks func, int opened)
+static int process_measurement(struct file *file, const struct cred *cred,
+                              u32 secid, char *buf, loff_t size, int mask,
+                              enum ima_hooks func, int opened)
 {
        struct inode *inode = file_inode(file);
        struct integrity_iint_cache *iint = NULL;
@@ -190,7 +195,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
         * bitmask based on the appraise/audit/measurement policy.
         * Included is the appraise submask.
         */
-       action = ima_get_action(inode, mask, func, &pcr);
+       action = ima_get_action(inode, cred, secid, mask, func, &pcr);
        violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
                           (ima_policy_flag & IMA_MEASURE));
        if (!action && !violation_check)
@@ -229,9 +234,18 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
                                 IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
                                 IMA_ACTION_FLAGS);
 
-       if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags))
-               /* reset all flags if ima_inode_setxattr was called */
+       /*
+        * Re-evaulate the file if either the xattr has changed or the
+        * kernel has no way of detecting file change on the filesystem.
+        * (Limited to privileged mounted filesystems.)
+        */
+       if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags) ||
+           ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
+            !(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) &&
+            !(action & IMA_FAIL_UNVERIFIABLE_SIGS))) {
                iint->flags &= ~IMA_DONE_MASK;
+               iint->measured_pcrs = 0;
+       }
 
        /* Determine if already appraised/measured based on bitmask
         * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
@@ -324,9 +338,14 @@ out:
  */
 int ima_file_mmap(struct file *file, unsigned long prot)
 {
-       if (file && (prot & PROT_EXEC))
-               return process_measurement(file, NULL, 0, MAY_EXEC,
-                                          MMAP_CHECK, 0);
+       u32 secid;
+
+       if (file && (prot & PROT_EXEC)) {
+               security_task_getsecid(current, &secid);
+               return process_measurement(file, current_cred(), secid, NULL,
+                                          0, MAY_EXEC, MMAP_CHECK, 0);
+       }
+
        return 0;
 }
 
@@ -345,8 +364,18 @@ int ima_file_mmap(struct file *file, unsigned long prot)
  */
 int ima_bprm_check(struct linux_binprm *bprm)
 {
-       return process_measurement(bprm->file, NULL, 0, MAY_EXEC,
-                                  BPRM_CHECK, 0);
+       int ret;
+       u32 secid;
+
+       security_task_getsecid(current, &secid);
+       ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0,
+                                 MAY_EXEC, BPRM_CHECK, 0);
+       if (ret)
+               return ret;
+
+       security_cred_getsecid(bprm->cred, &secid);
+       return process_measurement(bprm->file, bprm->cred, secid, NULL, 0,
+                                  MAY_EXEC, CREDS_CHECK, 0);
 }
 
 /**
@@ -361,7 +390,10 @@ int ima_bprm_check(struct linux_binprm *bprm)
  */
 int ima_file_check(struct file *file, int mask, int opened)
 {
-       return process_measurement(file, NULL, 0,
+       u32 secid;
+
+       security_task_getsecid(current, &secid);
+       return process_measurement(file, current_cred(), secid, NULL, 0,
                                   mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
                                           MAY_APPEND), FILE_CHECK, opened);
 }
@@ -440,6 +472,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
                       enum kernel_read_file_id read_id)
 {
        enum ima_hooks func;
+       u32 secid;
 
        if (!file && read_id == READING_FIRMWARE) {
                if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
@@ -462,7 +495,9 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
        }
 
        func = read_idmap[read_id] ?: FILE_CHECK;
-       return process_measurement(file, buf, size, MAY_READ, func, 0);
+       security_task_getsecid(current, &secid);
+       return process_measurement(file, current_cred(), secid, buf, size,
+                                  MAY_READ, func, 0);
 }
 
 static int __init init_ima(void)
@@ -472,6 +507,16 @@ static int __init init_ima(void)
        ima_init_template_list();
        hash_setup(CONFIG_IMA_DEFAULT_HASH);
        error = ima_init();
+
+       if (error && strcmp(hash_algo_name[ima_hash_algo],
+                           CONFIG_IMA_DEFAULT_HASH) != 0) {
+               pr_info("Allocating %s failed, going to use default hash algorithm %s\n",
+                       hash_algo_name[ima_hash_algo], CONFIG_IMA_DEFAULT_HASH);
+               hash_setup_done = 0;
+               hash_setup(CONFIG_IMA_DEFAULT_HASH);
+               error = ima_init();
+       }
+
        if (!error) {
                ima_initialized = 1;
                ima_update_policy_flag();
index 915f5572c6ffac5cc9703fab6127cc1757092582..d89bebf85421e7134aff233a52545218efabf512 100644 (file)
@@ -96,6 +96,7 @@ static struct ima_rule_entry dont_measure_rules[] __ro_after_init = {
        {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC,
         .flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC,
@@ -141,6 +142,7 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
        {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_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 = SMACK_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC},
@@ -188,6 +190,7 @@ __setup("ima_tcb", default_measure_policy_setup);
 
 static bool ima_use_appraise_tcb __initdata;
 static bool ima_use_secure_boot __initdata;
+static bool ima_fail_unverifiable_sigs __ro_after_init;
 static int __init policy_setup(char *str)
 {
        char *p;
@@ -201,6 +204,8 @@ static int __init policy_setup(char *str)
                        ima_use_appraise_tcb = true;
                else if (strcmp(p, "secure_boot") == 0)
                        ima_use_secure_boot = true;
+               else if (strcmp(p, "fail_securely") == 0)
+                       ima_fail_unverifiable_sigs = true;
        }
 
        return 1;
@@ -243,16 +248,17 @@ static void ima_lsm_update_rules(void)
  * ima_match_rules - determine whether an inode matches the measure rule.
  * @rule: a pointer to a rule
  * @inode: a pointer to an inode
+ * @cred: a pointer to a credentials structure for user validation
+ * @secid: the secid of the task to be validated
  * @func: LIM hook identifier
  * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
  *
  * Returns true on rule match, false on failure.
  */
 static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
+                           const struct cred *cred, u32 secid,
                            enum ima_hooks func, int mask)
 {
-       struct task_struct *tsk = current;
-       const struct cred *cred = current_cred();
        int i;
 
        if ((rule->flags & IMA_FUNC) &&
@@ -287,7 +293,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
                return false;
        for (i = 0; i < MAX_LSM_RULES; i++) {
                int rc = 0;
-               u32 osid, sid;
+               u32 osid;
                int retried = 0;
 
                if (!rule->lsm[i].rule)
@@ -307,8 +313,7 @@ retry:
                case LSM_SUBJ_USER:
                case LSM_SUBJ_ROLE:
                case LSM_SUBJ_TYPE:
-                       security_task_getsecid(tsk, &sid);
-                       rc = security_filter_rule_match(sid,
+                       rc = security_filter_rule_match(secid,
                                                        rule->lsm[i].type,
                                                        Audit_equal,
                                                        rule->lsm[i].rule,
@@ -341,6 +346,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
                return IMA_MMAP_APPRAISE;
        case BPRM_CHECK:
                return IMA_BPRM_APPRAISE;
+       case CREDS_CHECK:
+               return IMA_CREDS_APPRAISE;
        case FILE_CHECK:
        case POST_SETATTR:
                return IMA_FILE_APPRAISE;
@@ -353,6 +360,9 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
 /**
  * ima_match_policy - decision based on LSM and other conditions
  * @inode: pointer to an inode for which the policy decision is being made
+ * @cred: pointer to a credentials structure for which the policy decision is
+ *        being made
+ * @secid: LSM secid of the task to be validated
  * @func: IMA hook identifier
  * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
  * @pcr: set the pcr to extend
@@ -364,8 +374,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
  * list when walking it.  Reads are many orders of magnitude more numerous
  * than writes so ima_match_policy() is classical RCU candidate.
  */
-int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
-                    int flags, int *pcr)
+int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
+                    enum ima_hooks func, int mask, int flags, int *pcr)
 {
        struct ima_rule_entry *entry;
        int action = 0, actmask = flags | (flags << 1);
@@ -376,7 +386,7 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                if (!(entry->action & actmask))
                        continue;
 
-               if (!ima_match_rules(entry, inode, func, mask))
+               if (!ima_match_rules(entry, inode, cred, secid, func, mask))
                        continue;
 
                action |= entry->flags & IMA_ACTION_FLAGS;
@@ -384,7 +394,9 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                action |= entry->action & IMA_DO_MASK;
                if (entry->action & IMA_APPRAISE) {
                        action |= get_subaction(entry, func);
-                       action ^= IMA_HASH;
+                       action &= ~IMA_HASH;
+                       if (ima_fail_unverifiable_sigs)
+                               action |= IMA_FAIL_UNVERIFIABLE_SIGS;
                }
 
                if (entry->action & IMA_DO_MASK)
@@ -713,6 +725,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                                entry->func = MMAP_CHECK;
                        else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
                                entry->func = BPRM_CHECK;
+                       else if (strcmp(args[0].from, "CREDS_CHECK") == 0)
+                               entry->func = CREDS_CHECK;
                        else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") ==
                                 0)
                                entry->func = KEXEC_KERNEL_CHECK;
index 28af43f63572a7df9ea435656aa924552bbac8a6..5afaa53decc50416ad5963a82ddecb47f4c2f9c5 100644 (file)
@@ -378,16 +378,11 @@ int ima_eventname_ng_init(struct ima_event_data *event_data,
 int ima_eventsig_init(struct ima_event_data *event_data,
                      struct ima_field_data *field_data)
 {
-       enum data_formats fmt = DATA_FMT_HEX;
        struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
-       int xattr_len = event_data->xattr_len;
-       int rc = 0;
 
        if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
-               goto out;
+               return 0;
 
-       rc = ima_write_template_field_data(xattr_value, xattr_len, fmt,
-                                          field_data);
-out:
-       return rc;
+       return ima_write_template_field_data(xattr_value, event_data->xattr_len,
+                                            DATA_FMT_HEX, field_data);
 }
index 50a8e3365df7387cb62ee03ad605af1905c1ad97..5e58e02ba8dc97ff1c4a88f5722109f4783d3f62 100644 (file)
 
 /* iint cache flags */
 #define IMA_ACTION_FLAGS       0xff000000
-#define IMA_ACTION_RULE_FLAGS  0x06000000
 #define IMA_DIGSIG_REQUIRED    0x01000000
 #define IMA_PERMIT_DIRECTIO    0x02000000
 #define IMA_NEW_FILE           0x04000000
 #define EVM_IMMUTABLE_DIGSIG   0x08000000
+#define IMA_FAIL_UNVERIFIABLE_SIGS     0x10000000
 
 #define IMA_DO_MASK            (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
                                 IMA_HASH | IMA_APPRAISE_SUBMASK)
 #define IMA_BPRM_APPRAISED     0x00020000
 #define IMA_READ_APPRAISE      0x00040000
 #define IMA_READ_APPRAISED     0x00080000
+#define IMA_CREDS_APPRAISE     0x00100000
+#define IMA_CREDS_APPRAISED    0x00200000
 #define IMA_APPRAISE_SUBMASK   (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
-                                IMA_BPRM_APPRAISE | IMA_READ_APPRAISE)
+                                IMA_BPRM_APPRAISE | IMA_READ_APPRAISE | \
+                                IMA_CREDS_APPRAISE)
 #define IMA_APPRAISED_SUBMASK  (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
-                                IMA_BPRM_APPRAISED | IMA_READ_APPRAISED)
+                                IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \
+                                IMA_CREDS_APPRAISED)
 
 /* iint cache atomic_flags */
 #define IMA_CHANGE_XATTR       0
@@ -121,6 +125,7 @@ struct integrity_iint_cache {
        enum integrity_status ima_mmap_status:4;
        enum integrity_status ima_bprm_status:4;
        enum integrity_status ima_read_status:4;
+       enum integrity_status ima_creds_status:4;
        enum integrity_status evm_status:4;
        struct ima_digest_data *ima_hash;
 };
index 7301902a872171e028749771f6c599a0b39f103c..d2a84cda7e8d4de1d650a5da1d899a5f5caf0960 100644 (file)
@@ -1005,6 +1005,13 @@ void security_transfer_creds(struct cred *new, const struct cred *old)
        call_void_hook(cred_transfer, new, old);
 }
 
+void security_cred_getsecid(const struct cred *c, u32 *secid)
+{
+       *secid = 0;
+       call_void_hook(cred_getsecid, c, secid);
+}
+EXPORT_SYMBOL(security_cred_getsecid);
+
 int security_kernel_act_as(struct cred *new, u32 secid)
 {
        return call_int_hook(kernel_act_as, 0, new, secid);
index 2b8c55e181aea5815327fa637873513ba885f7ed..1eeb70e439d7999646d3fab9c38da5ea60cf1b60 100644 (file)
@@ -3947,6 +3947,11 @@ static void selinux_cred_transfer(struct cred *new, const struct cred *old)
        *tsec = *old_tsec;
 }
 
+static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
+{
+       *secid = cred_sid(c);
+}
+
 /*
  * set the security data for a kernel service
  * - all the creation contexts are set to unlabelled
@@ -6926,6 +6931,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(cred_free, selinux_cred_free),
        LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
        LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
+       LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
        LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
        LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
        LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
index 34e1e649f17515ca151cde820e9fac75f220e095..73549007bf9e63d75920376b71671d5bd55ca3f0 100644 (file)
@@ -2049,6 +2049,23 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
        /* cbs copy rule list */
 }
 
+/**
+ * smack_cred_getsecid - get the secid corresponding to a creds structure
+ * @c: the object creds
+ * @secid: where to put the result
+ *
+ * Sets the secid to contain a u32 version of the smack label.
+ */
+static void smack_cred_getsecid(const struct cred *c, u32 *secid)
+{
+       struct smack_known *skp;
+
+       rcu_read_lock();
+       skp = smk_of_task(c->security);
+       *secid = skp->smk_secid;
+       rcu_read_unlock();
+}
+
 /**
  * smack_kernel_act_as - Set the subjective context in a set of credentials
  * @new: points to the set of credentials to be modified.
@@ -4654,6 +4671,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(cred_free, smack_cred_free),
        LSM_HOOK_INIT(cred_prepare, smack_cred_prepare),
        LSM_HOOK_INIT(cred_transfer, smack_cred_transfer),
+       LSM_HOOK_INIT(cred_getsecid, smack_cred_getsecid),
        LSM_HOOK_INIT(kernel_act_as, smack_kernel_act_as),
        LSM_HOOK_INIT(kernel_create_files_as, smack_kernel_create_files_as),
        LSM_HOOK_INIT(task_setpgid, smack_task_setpgid),