diff options
| -rw-r--r-- | Documentation/ABI/testing/ima_policy | 12 | ||||
| -rw-r--r-- | fs/befs/linuxvfs.c | 1 | ||||
| -rw-r--r-- | fs/block_dev.c | 7 | ||||
| -rw-r--r-- | fs/file_table.c | 1 | ||||
| -rw-r--r-- | fs/namei.c | 6 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 2 | ||||
| -rw-r--r-- | include/linux/ima.h | 4 | ||||
| -rw-r--r-- | init/main.c | 2 | ||||
| -rw-r--r-- | security/integrity/ima/ima.h | 3 | ||||
| -rw-r--r-- | security/integrity/ima/ima_api.c | 4 | ||||
| -rw-r--r-- | security/integrity/ima/ima_iint.c | 9 | ||||
| -rw-r--r-- | security/integrity/ima/ima_main.c | 239 | ||||
| -rw-r--r-- | security/integrity/ima/ima_policy.c | 9 | ||||
| -rw-r--r-- | security/security.c | 2 |
14 files changed, 123 insertions, 178 deletions
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 6434f0df012e..6cd6daefaaed 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy | |||
| @@ -20,7 +20,7 @@ Description: | |||
| 20 | lsm: [[subj_user=] [subj_role=] [subj_type=] | 20 | lsm: [[subj_user=] [subj_role=] [subj_type=] |
| 21 | [obj_user=] [obj_role=] [obj_type=]] | 21 | [obj_user=] [obj_role=] [obj_type=]] |
| 22 | 22 | ||
| 23 | base: func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION] | 23 | base: func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK] |
| 24 | mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] | 24 | mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] |
| 25 | fsmagic:= hex value | 25 | fsmagic:= hex value |
| 26 | uid:= decimal value | 26 | uid:= decimal value |
| @@ -40,11 +40,11 @@ Description: | |||
| 40 | 40 | ||
| 41 | measure func=BPRM_CHECK | 41 | measure func=BPRM_CHECK |
| 42 | measure func=FILE_MMAP mask=MAY_EXEC | 42 | measure func=FILE_MMAP mask=MAY_EXEC |
| 43 | measure func=INODE_PERM mask=MAY_READ uid=0 | 43 | measure func=FILE_CHECK mask=MAY_READ uid=0 |
| 44 | 44 | ||
| 45 | The default policy measures all executables in bprm_check, | 45 | The default policy measures all executables in bprm_check, |
| 46 | all files mmapped executable in file_mmap, and all files | 46 | all files mmapped executable in file_mmap, and all files |
| 47 | open for read by root in inode_permission. | 47 | open for read by root in do_filp_open. |
| 48 | 48 | ||
| 49 | Examples of LSM specific definitions: | 49 | Examples of LSM specific definitions: |
| 50 | 50 | ||
| @@ -54,8 +54,8 @@ Description: | |||
| 54 | 54 | ||
| 55 | dont_measure obj_type=var_log_t | 55 | dont_measure obj_type=var_log_t |
| 56 | dont_measure obj_type=auditd_log_t | 56 | dont_measure obj_type=auditd_log_t |
| 57 | measure subj_user=system_u func=INODE_PERM mask=MAY_READ | 57 | measure subj_user=system_u func=FILE_CHECK mask=MAY_READ |
| 58 | measure subj_role=system_r func=INODE_PERM mask=MAY_READ | 58 | measure subj_role=system_r func=FILE_CHECK mask=MAY_READ |
| 59 | 59 | ||
| 60 | Smack: | 60 | Smack: |
| 61 | measure subj_user=_ func=INODE_PERM mask=MAY_READ | 61 | measure subj_user=_ func=FILE_CHECK mask=MAY_READ |
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 33baf27fac78..34ddda888e63 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
| @@ -873,6 +873,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 873 | brelse(bh); | 873 | brelse(bh); |
| 874 | 874 | ||
| 875 | unacquire_priv_sbp: | 875 | unacquire_priv_sbp: |
| 876 | kfree(befs_sb->mount_opts.iocharset); | ||
| 876 | kfree(sb->s_fs_info); | 877 | kfree(sb->s_fs_info); |
| 877 | 878 | ||
| 878 | unacquire_none: | 879 | unacquire_none: |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 73d6a735b8f3..d11d0289f3d2 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -246,7 +246,8 @@ struct super_block *freeze_bdev(struct block_device *bdev) | |||
| 246 | if (!sb) | 246 | if (!sb) |
| 247 | goto out; | 247 | goto out; |
| 248 | if (sb->s_flags & MS_RDONLY) { | 248 | if (sb->s_flags & MS_RDONLY) { |
| 249 | deactivate_locked_super(sb); | 249 | sb->s_frozen = SB_FREEZE_TRANS; |
| 250 | up_write(&sb->s_umount); | ||
| 250 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 251 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
| 251 | return sb; | 252 | return sb; |
| 252 | } | 253 | } |
| @@ -307,7 +308,7 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb) | |||
| 307 | BUG_ON(sb->s_bdev != bdev); | 308 | BUG_ON(sb->s_bdev != bdev); |
| 308 | down_write(&sb->s_umount); | 309 | down_write(&sb->s_umount); |
| 309 | if (sb->s_flags & MS_RDONLY) | 310 | if (sb->s_flags & MS_RDONLY) |
| 310 | goto out_deactivate; | 311 | goto out_unfrozen; |
| 311 | 312 | ||
| 312 | if (sb->s_op->unfreeze_fs) { | 313 | if (sb->s_op->unfreeze_fs) { |
| 313 | error = sb->s_op->unfreeze_fs(sb); | 314 | error = sb->s_op->unfreeze_fs(sb); |
| @@ -321,11 +322,11 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb) | |||
| 321 | } | 322 | } |
| 322 | } | 323 | } |
| 323 | 324 | ||
| 325 | out_unfrozen: | ||
| 324 | sb->s_frozen = SB_UNFROZEN; | 326 | sb->s_frozen = SB_UNFROZEN; |
| 325 | smp_wmb(); | 327 | smp_wmb(); |
| 326 | wake_up(&sb->s_wait_unfrozen); | 328 | wake_up(&sb->s_wait_unfrozen); |
| 327 | 329 | ||
| 328 | out_deactivate: | ||
| 329 | if (sb) | 330 | if (sb) |
| 330 | deactivate_locked_super(sb); | 331 | deactivate_locked_super(sb); |
| 331 | out_unlock: | 332 | out_unlock: |
diff --git a/fs/file_table.c b/fs/file_table.c index 69652c5bd5f0..b98404b54383 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
| @@ -253,6 +253,7 @@ void __fput(struct file *file) | |||
| 253 | if (file->f_op && file->f_op->release) | 253 | if (file->f_op && file->f_op->release) |
| 254 | file->f_op->release(inode, file); | 254 | file->f_op->release(inode, file); |
| 255 | security_file_free(file); | 255 | security_file_free(file); |
| 256 | ima_file_free(file); | ||
| 256 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) | 257 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) |
| 257 | cdev_put(inode->i_cdev); | 258 | cdev_put(inode->i_cdev); |
| 258 | fops_put(file->f_op); | 259 | fops_put(file->f_op); |
diff --git a/fs/namei.c b/fs/namei.c index 94a5e60779f9..d62fdc875f22 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1736,8 +1736,7 @@ do_last: | |||
| 1736 | if (nd.root.mnt) | 1736 | if (nd.root.mnt) |
| 1737 | path_put(&nd.root); | 1737 | path_put(&nd.root); |
| 1738 | if (!IS_ERR(filp)) { | 1738 | if (!IS_ERR(filp)) { |
| 1739 | error = ima_path_check(&filp->f_path, filp->f_mode & | 1739 | error = ima_file_check(filp, acc_mode); |
| 1740 | (MAY_READ | MAY_WRITE | MAY_EXEC)); | ||
| 1741 | if (error) { | 1740 | if (error) { |
| 1742 | fput(filp); | 1741 | fput(filp); |
| 1743 | filp = ERR_PTR(error); | 1742 | filp = ERR_PTR(error); |
| @@ -1797,8 +1796,7 @@ ok: | |||
| 1797 | } | 1796 | } |
| 1798 | filp = nameidata_to_filp(&nd); | 1797 | filp = nameidata_to_filp(&nd); |
| 1799 | if (!IS_ERR(filp)) { | 1798 | if (!IS_ERR(filp)) { |
| 1800 | error = ima_path_check(&filp->f_path, filp->f_mode & | 1799 | error = ima_file_check(filp, acc_mode); |
| 1801 | (MAY_READ | MAY_WRITE | MAY_EXEC)); | ||
| 1802 | if (error) { | 1800 | if (error) { |
| 1803 | fput(filp); | 1801 | fput(filp); |
| 1804 | filp = ERR_PTR(error); | 1802 | filp = ERR_PTR(error); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c194793b642b..97d79eff6b7f 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -752,6 +752,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 752 | flags, current_cred()); | 752 | flags, current_cred()); |
| 753 | if (IS_ERR(*filp)) | 753 | if (IS_ERR(*filp)) |
| 754 | host_err = PTR_ERR(*filp); | 754 | host_err = PTR_ERR(*filp); |
| 755 | host_err = ima_file_check(*filp, access); | ||
| 755 | out_nfserr: | 756 | out_nfserr: |
| 756 | err = nfserrno(host_err); | 757 | err = nfserrno(host_err); |
| 757 | out: | 758 | out: |
| @@ -2127,7 +2128,6 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
| 2127 | */ | 2128 | */ |
| 2128 | path.mnt = exp->ex_path.mnt; | 2129 | path.mnt = exp->ex_path.mnt; |
| 2129 | path.dentry = dentry; | 2130 | path.dentry = dentry; |
| 2130 | err = ima_path_check(&path, acc & (MAY_READ | MAY_WRITE | MAY_EXEC)); | ||
| 2131 | nfsd_out: | 2131 | nfsd_out: |
| 2132 | return err? nfserrno(err) : 0; | 2132 | return err? nfserrno(err) : 0; |
| 2133 | } | 2133 | } |
diff --git a/include/linux/ima.h b/include/linux/ima.h index 99dc6d5cf7e5..975837e7d6c0 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h | |||
| @@ -17,7 +17,7 @@ struct linux_binprm; | |||
| 17 | extern int ima_bprm_check(struct linux_binprm *bprm); | 17 | extern int ima_bprm_check(struct linux_binprm *bprm); |
| 18 | extern int ima_inode_alloc(struct inode *inode); | 18 | extern int ima_inode_alloc(struct inode *inode); |
| 19 | extern void ima_inode_free(struct inode *inode); | 19 | extern void ima_inode_free(struct inode *inode); |
| 20 | extern int ima_path_check(struct path *path, int mask); | 20 | extern int ima_file_check(struct file *file, int mask); |
| 21 | extern void ima_file_free(struct file *file); | 21 | extern void ima_file_free(struct file *file); |
| 22 | extern int ima_file_mmap(struct file *file, unsigned long prot); | 22 | extern int ima_file_mmap(struct file *file, unsigned long prot); |
| 23 | extern void ima_counts_get(struct file *file); | 23 | extern void ima_counts_get(struct file *file); |
| @@ -38,7 +38,7 @@ static inline void ima_inode_free(struct inode *inode) | |||
| 38 | return; | 38 | return; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | static inline int ima_path_check(struct path *path, int mask) | 41 | static inline int ima_file_check(struct file *file, int mask) |
| 42 | { | 42 | { |
| 43 | return 0; | 43 | return 0; |
| 44 | } | 44 | } |
diff --git a/init/main.c b/init/main.c index dac44a9356a5..4cb47a159f02 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -657,9 +657,9 @@ asmlinkage void __init start_kernel(void) | |||
| 657 | proc_caches_init(); | 657 | proc_caches_init(); |
| 658 | buffer_init(); | 658 | buffer_init(); |
| 659 | key_init(); | 659 | key_init(); |
| 660 | radix_tree_init(); | ||
| 660 | security_init(); | 661 | security_init(); |
| 661 | vfs_caches_init(totalram_pages); | 662 | vfs_caches_init(totalram_pages); |
| 662 | radix_tree_init(); | ||
| 663 | signals_init(); | 663 | signals_init(); |
| 664 | /* rootfs populating might need page-writeback */ | 664 | /* rootfs populating might need page-writeback */ |
| 665 | page_writeback_init(); | 665 | page_writeback_init(); |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c41afe6639a0..47fb65d1fcbd 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -65,7 +65,6 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, | |||
| 65 | const char *cause, int result, int info); | 65 | const char *cause, int result, int info); |
| 66 | 66 | ||
| 67 | /* Internal IMA function definitions */ | 67 | /* Internal IMA function definitions */ |
| 68 | void ima_iintcache_init(void); | ||
| 69 | int ima_init(void); | 68 | int ima_init(void); |
| 70 | void ima_cleanup(void); | 69 | void ima_cleanup(void); |
| 71 | int ima_fs_init(void); | 70 | int ima_fs_init(void); |
| @@ -131,7 +130,7 @@ void iint_free(struct kref *kref); | |||
| 131 | void iint_rcu_free(struct rcu_head *rcu); | 130 | void iint_rcu_free(struct rcu_head *rcu); |
| 132 | 131 | ||
| 133 | /* IMA policy related functions */ | 132 | /* IMA policy related functions */ |
| 134 | enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | 133 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; |
| 135 | 134 | ||
| 136 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | 135 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); |
| 137 | void ima_init_policy(void); | 136 | void ima_init_policy(void); |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 3cd58b60afd2..2a5e0bcf3887 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
| @@ -95,12 +95,12 @@ err_out: | |||
| 95 | * ima_must_measure - measure decision based on policy. | 95 | * ima_must_measure - measure decision based on policy. |
| 96 | * @inode: pointer to inode to measure | 96 | * @inode: pointer to inode to measure |
| 97 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) | 97 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) |
| 98 | * @function: calling function (PATH_CHECK, BPRM_CHECK, FILE_MMAP) | 98 | * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) |
| 99 | * | 99 | * |
| 100 | * The policy is defined in terms of keypairs: | 100 | * The policy is defined in terms of keypairs: |
| 101 | * subj=, obj=, type=, func=, mask=, fsmagic= | 101 | * subj=, obj=, type=, func=, mask=, fsmagic= |
| 102 | * subj,obj, and type: are LSM specific. | 102 | * subj,obj, and type: are LSM specific. |
| 103 | * func: PATH_CHECK | BPRM_CHECK | FILE_MMAP | 103 | * func: FILE_CHECK | BPRM_CHECK | FILE_MMAP |
| 104 | * mask: contains the permission mask | 104 | * mask: contains the permission mask |
| 105 | * fsmagic: hex value | 105 | * fsmagic: hex value |
| 106 | * | 106 | * |
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index fa592ff1ac1c..0d83edcfc402 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c | |||
| @@ -52,9 +52,6 @@ int ima_inode_alloc(struct inode *inode) | |||
| 52 | struct ima_iint_cache *iint = NULL; | 52 | struct ima_iint_cache *iint = NULL; |
| 53 | int rc = 0; | 53 | int rc = 0; |
| 54 | 54 | ||
| 55 | if (!ima_initialized) | ||
| 56 | return 0; | ||
| 57 | |||
| 58 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | 55 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); |
| 59 | if (!iint) | 56 | if (!iint) |
| 60 | return -ENOMEM; | 57 | return -ENOMEM; |
| @@ -118,8 +115,6 @@ void ima_inode_free(struct inode *inode) | |||
| 118 | { | 115 | { |
| 119 | struct ima_iint_cache *iint; | 116 | struct ima_iint_cache *iint; |
| 120 | 117 | ||
| 121 | if (!ima_initialized) | ||
| 122 | return; | ||
| 123 | spin_lock(&ima_iint_lock); | 118 | spin_lock(&ima_iint_lock); |
| 124 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); | 119 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); |
| 125 | spin_unlock(&ima_iint_lock); | 120 | spin_unlock(&ima_iint_lock); |
| @@ -141,9 +136,11 @@ static void init_once(void *foo) | |||
| 141 | kref_set(&iint->refcount, 1); | 136 | kref_set(&iint->refcount, 1); |
| 142 | } | 137 | } |
| 143 | 138 | ||
| 144 | void __init ima_iintcache_init(void) | 139 | static int __init ima_iintcache_init(void) |
| 145 | { | 140 | { |
| 146 | iint_cache = | 141 | iint_cache = |
| 147 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, | 142 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, |
| 148 | SLAB_PANIC, init_once); | 143 | SLAB_PANIC, init_once); |
| 144 | return 0; | ||
| 149 | } | 145 | } |
| 146 | security_initcall(ima_iintcache_init); | ||
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index a89f44d5e030..294b005d6520 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | * | 14 | * |
| 15 | * File: ima_main.c | 15 | * File: ima_main.c |
| 16 | * implements the IMA hooks: ima_bprm_check, ima_file_mmap, | 16 | * implements the IMA hooks: ima_bprm_check, ima_file_mmap, |
| 17 | * and ima_path_check. | 17 | * and ima_file_check. |
| 18 | */ | 18 | */ |
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/file.h> | 20 | #include <linux/file.h> |
| @@ -84,6 +84,36 @@ out: | |||
| 84 | return found; | 84 | return found; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
| 88 | * | ||
| 89 | * When opening a file for read, if the file is already open for write, | ||
| 90 | * the file could change, resulting in a file measurement error. | ||
| 91 | * | ||
| 92 | * Opening a file for write, if the file is already open for read, results | ||
| 93 | * in a time of measure, time of use (ToMToU) error. | ||
| 94 | * | ||
| 95 | * In either case invalidate the PCR. | ||
| 96 | */ | ||
| 97 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
| 98 | static void ima_read_write_check(enum iint_pcr_error error, | ||
| 99 | struct ima_iint_cache *iint, | ||
| 100 | struct inode *inode, | ||
| 101 | const unsigned char *filename) | ||
| 102 | { | ||
| 103 | switch (error) { | ||
| 104 | case TOMTOU: | ||
| 105 | if (iint->readcount > 0) | ||
| 106 | ima_add_violation(inode, filename, "invalid_pcr", | ||
| 107 | "ToMToU"); | ||
| 108 | break; | ||
| 109 | case OPEN_WRITERS: | ||
| 110 | if (iint->writecount > 0) | ||
| 111 | ima_add_violation(inode, filename, "invalid_pcr", | ||
| 112 | "open_writers"); | ||
| 113 | break; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 87 | /* | 117 | /* |
| 88 | * Update the counts given an fmode_t | 118 | * Update the counts given an fmode_t |
| 89 | */ | 119 | */ |
| @@ -99,6 +129,47 @@ static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | |||
| 99 | } | 129 | } |
| 100 | 130 | ||
| 101 | /* | 131 | /* |
| 132 | * ima_counts_get - increment file counts | ||
| 133 | * | ||
| 134 | * Maintain read/write counters for all files, but only | ||
| 135 | * invalidate the PCR for measured files: | ||
| 136 | * - Opening a file for write when already open for read, | ||
| 137 | * results in a time of measure, time of use (ToMToU) error. | ||
| 138 | * - Opening a file for read when already open for write, | ||
| 139 | * could result in a file measurement error. | ||
| 140 | * | ||
| 141 | */ | ||
| 142 | void ima_counts_get(struct file *file) | ||
| 143 | { | ||
| 144 | struct dentry *dentry = file->f_path.dentry; | ||
| 145 | struct inode *inode = dentry->d_inode; | ||
| 146 | fmode_t mode = file->f_mode; | ||
| 147 | struct ima_iint_cache *iint; | ||
| 148 | int rc; | ||
| 149 | |||
| 150 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
| 151 | return; | ||
| 152 | iint = ima_iint_find_get(inode); | ||
| 153 | if (!iint) | ||
| 154 | return; | ||
| 155 | mutex_lock(&iint->mutex); | ||
| 156 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); | ||
| 157 | if (rc < 0) | ||
| 158 | goto out; | ||
| 159 | |||
| 160 | if (mode & FMODE_WRITE) { | ||
| 161 | ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name); | ||
| 162 | goto out; | ||
| 163 | } | ||
| 164 | ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name); | ||
| 165 | out: | ||
| 166 | ima_inc_counts(iint, file->f_mode); | ||
| 167 | mutex_unlock(&iint->mutex); | ||
| 168 | |||
| 169 | kref_put(&iint->refcount, iint_free); | ||
| 170 | } | ||
| 171 | |||
| 172 | /* | ||
| 102 | * Decrement ima counts | 173 | * Decrement ima counts |
| 103 | */ | 174 | */ |
| 104 | static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | 175 | static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, |
| @@ -153,123 +224,6 @@ void ima_file_free(struct file *file) | |||
| 153 | kref_put(&iint->refcount, iint_free); | 224 | kref_put(&iint->refcount, iint_free); |
| 154 | } | 225 | } |
| 155 | 226 | ||
| 156 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
| 157 | * | ||
| 158 | * When opening a file for read, if the file is already open for write, | ||
| 159 | * the file could change, resulting in a file measurement error. | ||
| 160 | * | ||
| 161 | * Opening a file for write, if the file is already open for read, results | ||
| 162 | * in a time of measure, time of use (ToMToU) error. | ||
| 163 | * | ||
| 164 | * In either case invalidate the PCR. | ||
| 165 | */ | ||
| 166 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
| 167 | static void ima_read_write_check(enum iint_pcr_error error, | ||
| 168 | struct ima_iint_cache *iint, | ||
| 169 | struct inode *inode, | ||
| 170 | const unsigned char *filename) | ||
| 171 | { | ||
| 172 | switch (error) { | ||
| 173 | case TOMTOU: | ||
| 174 | if (iint->readcount > 0) | ||
| 175 | ima_add_violation(inode, filename, "invalid_pcr", | ||
| 176 | "ToMToU"); | ||
| 177 | break; | ||
| 178 | case OPEN_WRITERS: | ||
| 179 | if (iint->writecount > 0) | ||
| 180 | ima_add_violation(inode, filename, "invalid_pcr", | ||
| 181 | "open_writers"); | ||
| 182 | break; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, | ||
| 187 | const unsigned char *filename) | ||
| 188 | { | ||
| 189 | int rc = 0; | ||
| 190 | |||
| 191 | ima_inc_counts(iint, file->f_mode); | ||
| 192 | |||
| 193 | rc = ima_collect_measurement(iint, file); | ||
| 194 | if (!rc) | ||
| 195 | ima_store_measurement(iint, file, filename); | ||
| 196 | return rc; | ||
| 197 | } | ||
| 198 | |||
| 199 | /** | ||
| 200 | * ima_path_check - based on policy, collect/store measurement. | ||
| 201 | * @path: contains a pointer to the path to be measured | ||
| 202 | * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE | ||
| 203 | * | ||
| 204 | * Measure the file being open for readonly, based on the | ||
| 205 | * ima_must_measure() policy decision. | ||
| 206 | * | ||
| 207 | * Keep read/write counters for all files, but only | ||
| 208 | * invalidate the PCR for measured files: | ||
| 209 | * - Opening a file for write when already open for read, | ||
| 210 | * results in a time of measure, time of use (ToMToU) error. | ||
| 211 | * - Opening a file for read when already open for write, | ||
| 212 | * could result in a file measurement error. | ||
| 213 | * | ||
| 214 | * Always return 0 and audit dentry_open failures. | ||
| 215 | * (Return code will be based upon measurement appraisal.) | ||
| 216 | */ | ||
| 217 | int ima_path_check(struct path *path, int mask) | ||
| 218 | { | ||
| 219 | struct inode *inode = path->dentry->d_inode; | ||
| 220 | struct ima_iint_cache *iint; | ||
| 221 | struct file *file = NULL; | ||
| 222 | int rc; | ||
| 223 | |||
| 224 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
| 225 | return 0; | ||
| 226 | iint = ima_iint_find_get(inode); | ||
| 227 | if (!iint) | ||
| 228 | return 0; | ||
| 229 | |||
| 230 | mutex_lock(&iint->mutex); | ||
| 231 | |||
| 232 | rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); | ||
| 233 | if (rc < 0) | ||
| 234 | goto out; | ||
| 235 | |||
| 236 | if ((mask & MAY_WRITE) || (mask == 0)) | ||
| 237 | ima_read_write_check(TOMTOU, iint, inode, | ||
| 238 | path->dentry->d_name.name); | ||
| 239 | |||
| 240 | if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ) | ||
| 241 | goto out; | ||
| 242 | |||
| 243 | ima_read_write_check(OPEN_WRITERS, iint, inode, | ||
| 244 | path->dentry->d_name.name); | ||
| 245 | if (!(iint->flags & IMA_MEASURED)) { | ||
| 246 | struct dentry *dentry = dget(path->dentry); | ||
| 247 | struct vfsmount *mnt = mntget(path->mnt); | ||
| 248 | |||
| 249 | file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE, | ||
| 250 | current_cred()); | ||
| 251 | if (IS_ERR(file)) { | ||
| 252 | int audit_info = 0; | ||
| 253 | |||
| 254 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | ||
| 255 | dentry->d_name.name, | ||
| 256 | "add_measurement", | ||
| 257 | "dentry_open failed", | ||
| 258 | 1, audit_info); | ||
| 259 | file = NULL; | ||
| 260 | goto out; | ||
| 261 | } | ||
| 262 | rc = get_path_measurement(iint, file, dentry->d_name.name); | ||
| 263 | } | ||
| 264 | out: | ||
| 265 | mutex_unlock(&iint->mutex); | ||
| 266 | if (file) | ||
| 267 | fput(file); | ||
| 268 | kref_put(&iint->refcount, iint_free); | ||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | EXPORT_SYMBOL_GPL(ima_path_check); | ||
| 272 | |||
| 273 | static int process_measurement(struct file *file, const unsigned char *filename, | 227 | static int process_measurement(struct file *file, const unsigned char *filename, |
| 274 | int mask, int function) | 228 | int mask, int function) |
| 275 | { | 229 | { |
| @@ -297,33 +251,6 @@ out: | |||
| 297 | return rc; | 251 | return rc; |
| 298 | } | 252 | } |
| 299 | 253 | ||
| 300 | /* | ||
| 301 | * ima_counts_get - increment file counts | ||
| 302 | * | ||
| 303 | * - for IPC shm and shmat file. | ||
| 304 | * - for nfsd exported files. | ||
| 305 | * | ||
| 306 | * Increment the counts for these files to prevent unnecessary | ||
| 307 | * imbalance messages. | ||
| 308 | */ | ||
| 309 | void ima_counts_get(struct file *file) | ||
| 310 | { | ||
| 311 | struct inode *inode = file->f_dentry->d_inode; | ||
| 312 | struct ima_iint_cache *iint; | ||
| 313 | |||
| 314 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
| 315 | return; | ||
| 316 | iint = ima_iint_find_get(inode); | ||
| 317 | if (!iint) | ||
| 318 | return; | ||
| 319 | mutex_lock(&iint->mutex); | ||
| 320 | ima_inc_counts(iint, file->f_mode); | ||
| 321 | mutex_unlock(&iint->mutex); | ||
| 322 | |||
| 323 | kref_put(&iint->refcount, iint_free); | ||
| 324 | } | ||
| 325 | EXPORT_SYMBOL_GPL(ima_counts_get); | ||
| 326 | |||
| 327 | /** | 254 | /** |
| 328 | * ima_file_mmap - based on policy, collect/store measurement. | 255 | * ima_file_mmap - based on policy, collect/store measurement. |
| 329 | * @file: pointer to the file to be measured (May be NULL) | 256 | * @file: pointer to the file to be measured (May be NULL) |
| @@ -369,11 +296,31 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
| 369 | return 0; | 296 | return 0; |
| 370 | } | 297 | } |
| 371 | 298 | ||
| 299 | /** | ||
| 300 | * ima_path_check - based on policy, collect/store measurement. | ||
| 301 | * @file: pointer to the file to be measured | ||
| 302 | * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE | ||
| 303 | * | ||
| 304 | * Measure files based on the ima_must_measure() policy decision. | ||
| 305 | * | ||
| 306 | * Always return 0 and audit dentry_open failures. | ||
| 307 | * (Return code will be based upon measurement appraisal.) | ||
| 308 | */ | ||
| 309 | int ima_file_check(struct file *file, int mask) | ||
| 310 | { | ||
| 311 | int rc; | ||
| 312 | |||
| 313 | rc = process_measurement(file, file->f_dentry->d_name.name, | ||
| 314 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | ||
| 315 | FILE_CHECK); | ||
| 316 | return 0; | ||
| 317 | } | ||
| 318 | EXPORT_SYMBOL_GPL(ima_file_check); | ||
| 319 | |||
| 372 | static int __init init_ima(void) | 320 | static int __init init_ima(void) |
| 373 | { | 321 | { |
| 374 | int error; | 322 | int error; |
| 375 | 323 | ||
| 376 | ima_iintcache_init(); | ||
| 377 | error = ima_init(); | 324 | error = ima_init(); |
| 378 | ima_initialized = 1; | 325 | ima_initialized = 1; |
| 379 | return error; | 326 | return error; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index e1278399b345..4759d0f99335 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
| @@ -67,7 +67,7 @@ static struct ima_measure_rule_entry default_rules[] = { | |||
| 67 | .flags = IMA_FUNC | IMA_MASK}, | 67 | .flags = IMA_FUNC | IMA_MASK}, |
| 68 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, | 68 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, |
| 69 | .flags = IMA_FUNC | IMA_MASK}, | 69 | .flags = IMA_FUNC | IMA_MASK}, |
| 70 | {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, | 70 | {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = 0, |
| 71 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | 71 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| @@ -282,8 +282,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 282 | break; | 282 | break; |
| 283 | case Opt_func: | 283 | case Opt_func: |
| 284 | audit_log_format(ab, "func=%s ", args[0].from); | 284 | audit_log_format(ab, "func=%s ", args[0].from); |
| 285 | if (strcmp(args[0].from, "PATH_CHECK") == 0) | 285 | if (strcmp(args[0].from, "FILE_CHECK") == 0) |
| 286 | entry->func = PATH_CHECK; | 286 | entry->func = FILE_CHECK; |
| 287 | /* PATH_CHECK is for backwards compat */ | ||
| 288 | else if (strcmp(args[0].from, "PATH_CHECK") == 0) | ||
| 289 | entry->func = FILE_CHECK; | ||
| 287 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) | 290 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) |
| 288 | entry->func = FILE_MMAP; | 291 | entry->func = FILE_MMAP; |
| 289 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) | 292 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) |
diff --git a/security/security.c b/security/security.c index 24e060be9fa5..122b748d0f4c 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -666,8 +666,6 @@ int security_file_alloc(struct file *file) | |||
| 666 | void security_file_free(struct file *file) | 666 | void security_file_free(struct file *file) |
| 667 | { | 667 | { |
| 668 | security_ops->file_free_security(file); | 668 | security_ops->file_free_security(file); |
| 669 | if (file->f_dentry) | ||
| 670 | ima_file_free(file); | ||
| 671 | } | 669 | } |
| 672 | 670 | ||
| 673 | int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 671 | int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
