mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
lsm/stable-6.9 PR 20240312
-----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmXwt3cUHHBhdWxAcGF1 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXObOhAAqldn1nbYS/t1D/k/9ZN/PtSQetK4 S58D8+gB59Sg0daWFaRhCwwShIbXS/6XzhqaVb3iAPptJs0YDFMbWLAW2d+dd69K /7C8diguHbuJdEnCJtFYQIVinavaYVRlyoQcO8uwTz8uvTgXPOhr2P9NcOApJXcR xqttuADVo/9Zn0O9/+GUPCH0ROL0SMnuUjwdVP3bpPHj9zEk8F1/A6chzTeSLJru Y4+cRrN/r0JTkvRqPdnF9LSvxK7mtAEaHkKGeLQbw0O5pv3r3w0EWMJvq+uonGU2 WX0eR5VMfevkFMUdw8FKOTa+OZ0HJ2KKIb4sB4wDMgeGyov7Z6SxgvFeQiSyD3aB QnyfLDzeEuPfousxUd45dUDnsWNnSgFF+JAdi0LSzm5hMuLeQDozTsFmh0orQcX1 L5A6VtAbSPP0ffl+tuPi48q3P3LlSjMP0B8W20NXFYhXukKXCgXVMr/dEvpwpu1m o1glviGIXeLQQSnX3lMWb7Ds2igmCtXPrqkdu2vpRhMp0od6n4R4jH73Aj5MeSQn n3sP73dg5sAaMjtI2NOisMeFUp09MMlOumCCM+AIplPXremm1kwgKRTIp0rKsLW9 VoQPXa43LQc3hAgPrpGuE+4yBfaBUq7Z8I37IFER/2y4K8b9YkduW4kDh7OdRz+d iQ4Nnu2lR/+CCH0= =0mTM -----END PGP SIGNATURE----- Merge tag 'lsm-pr-20240312' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm Pull lsm updates from Paul Moore: - Promote IMA/EVM to a proper LSM This is the bulk of the diffstat, and the source of all the changes in the VFS code. Prior to the start of the LSM stacking work it was important that IMA/EVM were separate from the rest of the LSMs, complete with their own hooks, infrastructure, etc. as it was the only way to enable IMA/EVM at the same time as a LSM. However, now that the bulk of the LSM infrastructure supports multiple simultaneous LSMs, we can simplify things greatly by bringing IMA/EVM into the LSM infrastructure as proper LSMs. This is something I've wanted to see happen for quite some time and Roberto was kind enough to put in the work to make it happen. - Use the LSM hook default values to simplify the call_int_hook() macro Previously the call_int_hook() macro required callers to supply a default return value, despite a default value being specified when the LSM hook was defined. This simplifies the macro by using the defined default return value which makes life easier for callers and should also reduce the number of return value bugs in the future (we've had a few pop up recently, hence this work). - Use the KMEM_CACHE() macro instead of kmem_cache_create() The guidance appears to be to use the KMEM_CACHE() macro when possible and there is no reason why we can't use the macro, so let's use it. - Fix a number of comment typos in the LSM hook comment blocks Not much to say here, we fixed some questionable grammar decisions in the LSM hook comment blocks. * tag 'lsm-pr-20240312' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm: (28 commits) cred: Use KMEM_CACHE() instead of kmem_cache_create() lsm: use default hook return value in call_int_hook() lsm: fix typos in security/security.c comment headers integrity: Remove LSM ima: Make it independent from 'integrity' LSM evm: Make it independent from 'integrity' LSM evm: Move to LSM infrastructure ima: Move IMA-Appraisal to LSM infrastructure ima: Move to LSM infrastructure integrity: Move integrity_kernel_module_request() to IMA security: Introduce key_post_create_or_update hook security: Introduce inode_post_remove_acl hook security: Introduce inode_post_set_acl hook security: Introduce inode_post_create_tmpfile hook security: Introduce path_post_mknod hook security: Introduce file_release hook security: Introduce file_post_open hook security: Introduce inode_post_removexattr hook security: Introduce inode_post_setattr hook security: Align inode_setattr hook definition with EVM ...
This commit is contained in:
commit
cc4a875cf3
@ -16,8 +16,6 @@
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/filelock.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/evm.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@ -502,8 +500,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
|
||||
if (!error) {
|
||||
fsnotify_change(dentry, ia_valid);
|
||||
ima_inode_post_setattr(idmap, dentry);
|
||||
evm_inode_post_setattr(dentry, ia_valid);
|
||||
security_inode_post_setattr(idmap, dentry, ia_valid);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/percpu_counter.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/task_work.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/kmemleak.h>
|
||||
|
||||
@ -414,7 +413,7 @@ static void __fput(struct file *file)
|
||||
eventpoll_release(file);
|
||||
locks_remove_file(file);
|
||||
|
||||
ima_file_free(file);
|
||||
security_file_release(file);
|
||||
if (unlikely(file->f_flags & FASYNC)) {
|
||||
if (file->f_op->fasync)
|
||||
file->f_op->fasync(-1, file, 0);
|
||||
|
12
fs/namei.c
12
fs/namei.c
@ -27,7 +27,6 @@
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/audit.h>
|
||||
@ -3642,7 +3641,7 @@ static int do_open(struct nameidata *nd,
|
||||
if (!error && !(file->f_mode & FMODE_OPENED))
|
||||
error = vfs_open(&nd->path, file);
|
||||
if (!error)
|
||||
error = ima_file_check(file, op->acc_mode);
|
||||
error = security_file_post_open(file, op->acc_mode);
|
||||
if (!error && do_truncate)
|
||||
error = handle_truncate(idmap, file);
|
||||
if (unlikely(error > 0)) {
|
||||
@ -3705,7 +3704,7 @@ static int vfs_tmpfile(struct mnt_idmap *idmap,
|
||||
inode->i_state |= I_LINKABLE;
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
ima_post_create_tmpfile(idmap, inode);
|
||||
security_inode_post_create_tmpfile(idmap, inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4051,8 +4050,6 @@ retry:
|
||||
case 0: case S_IFREG:
|
||||
error = vfs_create(idmap, path.dentry->d_inode,
|
||||
dentry, mode, true);
|
||||
if (!error)
|
||||
ima_post_path_mknod(idmap, dentry);
|
||||
break;
|
||||
case S_IFCHR: case S_IFBLK:
|
||||
error = vfs_mknod(idmap, path.dentry->d_inode,
|
||||
@ -4063,6 +4060,11 @@ retry:
|
||||
dentry, mode, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (error)
|
||||
goto out2;
|
||||
|
||||
security_path_post_mknod(idmap, dentry);
|
||||
out2:
|
||||
done_path_create(&path, dentry);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
@ -895,7 +894,7 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
|
||||
goto out;
|
||||
}
|
||||
|
||||
host_err = ima_file_check(file, may_flags);
|
||||
host_err = security_file_post_open(file, may_flags);
|
||||
if (host_err) {
|
||||
fput(file);
|
||||
goto out;
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include <linux/audit.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fs_struct.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mnt_idmapping.h>
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/mnt_idmapping.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/evm.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/filelock.h>
|
||||
|
||||
@ -1137,7 +1136,7 @@ retry_deleg:
|
||||
error = -EIO;
|
||||
if (!error) {
|
||||
fsnotify_xattr(dentry);
|
||||
evm_inode_post_set_acl(dentry, acl_name, kacl);
|
||||
security_inode_post_set_acl(dentry, acl_name, kacl);
|
||||
}
|
||||
|
||||
out_inode_unlock:
|
||||
@ -1245,7 +1244,7 @@ retry_deleg:
|
||||
error = -EIO;
|
||||
if (!error) {
|
||||
fsnotify_xattr(dentry);
|
||||
evm_inode_post_remove_acl(idmap, dentry, acl_name);
|
||||
security_inode_post_remove_acl(idmap, dentry, acl_name);
|
||||
}
|
||||
|
||||
out_inode_unlock:
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/mount.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/evm.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/fsnotify.h>
|
||||
@ -552,11 +551,11 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
|
||||
goto out;
|
||||
|
||||
error = __vfs_removexattr(idmap, dentry, name);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!error) {
|
||||
fsnotify_xattr(dentry);
|
||||
evm_inode_post_removexattr(dentry, name);
|
||||
}
|
||||
fsnotify_xattr(dentry);
|
||||
security_inode_post_removexattr(dentry, name);
|
||||
|
||||
out:
|
||||
return error;
|
||||
|
@ -12,52 +12,12 @@
|
||||
#include <linux/integrity.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
struct integrity_iint_cache;
|
||||
|
||||
#ifdef CONFIG_EVM
|
||||
extern int evm_set_key(void *key, size_t keylen);
|
||||
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
|
||||
const char *xattr_name,
|
||||
void *xattr_value,
|
||||
size_t xattr_value_len,
|
||||
struct integrity_iint_cache *iint);
|
||||
extern int evm_inode_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct iattr *attr);
|
||||
extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
|
||||
extern int evm_inode_setxattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size);
|
||||
extern void evm_inode_post_setxattr(struct dentry *dentry,
|
||||
const char *xattr_name,
|
||||
const void *xattr_value,
|
||||
size_t xattr_value_len);
|
||||
extern int evm_inode_copy_up_xattr(const char *name);
|
||||
extern int evm_inode_removexattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *xattr_name);
|
||||
extern void evm_inode_post_removexattr(struct dentry *dentry,
|
||||
const char *xattr_name);
|
||||
static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
evm_inode_post_removexattr(dentry, acl_name);
|
||||
}
|
||||
extern int evm_inode_set_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name,
|
||||
struct posix_acl *kacl);
|
||||
static inline int evm_inode_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
|
||||
}
|
||||
static inline void evm_inode_post_set_acl(struct dentry *dentry,
|
||||
const char *acl_name,
|
||||
struct posix_acl *kacl)
|
||||
{
|
||||
return evm_inode_post_setxattr(dentry, acl_name, NULL, 0);
|
||||
}
|
||||
|
||||
size_t xattr_value_len);
|
||||
int evm_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr, struct xattr *xattrs,
|
||||
int *xattr_count);
|
||||
@ -85,85 +45,12 @@ static inline int evm_set_key(void *key, size_t keylen)
|
||||
static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
|
||||
const char *xattr_name,
|
||||
void *xattr_value,
|
||||
size_t xattr_value_len,
|
||||
struct integrity_iint_cache *iint)
|
||||
size_t xattr_value_len)
|
||||
{
|
||||
return INTEGRITY_UNKNOWN;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int evm_inode_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int evm_inode_setxattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void evm_inode_post_setxattr(struct dentry *dentry,
|
||||
const char *xattr_name,
|
||||
const void *xattr_value,
|
||||
size_t xattr_value_len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int evm_inode_copy_up_xattr(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int evm_inode_removexattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *xattr_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void evm_inode_post_removexattr(struct dentry *dentry,
|
||||
const char *xattr_name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int evm_inode_set_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name,
|
||||
struct posix_acl *kacl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int evm_inode_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void evm_inode_post_set_acl(struct dentry *dentry,
|
||||
const char *acl_name,
|
||||
struct posix_acl *kacl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int evm_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr,
|
||||
struct xattr *xattrs,
|
||||
|
@ -16,23 +16,6 @@ struct linux_binprm;
|
||||
|
||||
#ifdef CONFIG_IMA
|
||||
extern enum hash_algo ima_get_current_hash_algo(void);
|
||||
extern int ima_bprm_check(struct linux_binprm *bprm);
|
||||
extern int ima_file_check(struct file *file, int mask);
|
||||
extern void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
struct inode *inode);
|
||||
extern void ima_file_free(struct file *file);
|
||||
extern int ima_file_mmap(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags);
|
||||
extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot);
|
||||
extern int ima_load_data(enum kernel_load_data_id id, bool contents);
|
||||
extern int ima_post_load_data(char *buf, loff_t size,
|
||||
enum kernel_load_data_id id, char *description);
|
||||
extern int ima_read_file(struct file *file, enum kernel_read_file_id id,
|
||||
bool contents);
|
||||
extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
|
||||
enum kernel_read_file_id id);
|
||||
extern void ima_post_path_mknod(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry);
|
||||
extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
|
||||
extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
|
||||
extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
|
||||
@ -57,68 +40,6 @@ static inline enum hash_algo ima_get_current_hash_algo(void)
|
||||
return HASH_ALGO__LAST;
|
||||
}
|
||||
|
||||
static inline int ima_bprm_check(struct linux_binprm *bprm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_file_check(struct file *file, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
struct inode *inode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ima_file_free(struct file *file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int ima_file_mmap(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_file_mprotect(struct vm_area_struct *vma,
|
||||
unsigned long prot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_load_data(enum kernel_load_data_id id, bool contents)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_post_load_data(char *buf, loff_t size,
|
||||
enum kernel_load_data_id id,
|
||||
char *description)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_read_file(struct file *file, enum kernel_read_file_id id,
|
||||
bool contents)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_post_read_file(struct file *file, void *buf, loff_t size,
|
||||
enum kernel_read_file_id id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ima_post_path_mknod(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
@ -169,76 +90,13 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
|
||||
{}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
|
||||
extern void ima_post_key_create_or_update(struct key *keyring,
|
||||
struct key *key,
|
||||
const void *payload, size_t plen,
|
||||
unsigned long flags, bool create);
|
||||
#else
|
||||
static inline void ima_post_key_create_or_update(struct key *keyring,
|
||||
struct key *key,
|
||||
const void *payload,
|
||||
size_t plen,
|
||||
unsigned long flags,
|
||||
bool create) {}
|
||||
#endif /* CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS */
|
||||
|
||||
#ifdef CONFIG_IMA_APPRAISE
|
||||
extern bool is_ima_appraise_enabled(void);
|
||||
extern void ima_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry);
|
||||
extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
const void *xattr_value, size_t xattr_value_len);
|
||||
extern int ima_inode_set_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name,
|
||||
struct posix_acl *kacl);
|
||||
static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
|
||||
}
|
||||
extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name);
|
||||
#else
|
||||
static inline bool is_ima_appraise_enabled(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ima_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int ima_inode_setxattr(struct dentry *dentry,
|
||||
const char *xattr_name,
|
||||
const void *xattr_value,
|
||||
size_t xattr_value_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_inode_set_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name,
|
||||
struct posix_acl *kacl)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_inode_removexattr(struct dentry *dentry,
|
||||
const char *xattr_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_inode_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IMA_APPRAISE */
|
||||
|
||||
#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
|
||||
|
@ -19,40 +19,13 @@ enum integrity_status {
|
||||
INTEGRITY_UNKNOWN,
|
||||
};
|
||||
|
||||
/* List of EVM protected security xattrs */
|
||||
#ifdef CONFIG_INTEGRITY
|
||||
extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
|
||||
extern void integrity_inode_free(struct inode *inode);
|
||||
extern void __init integrity_load_keys(void);
|
||||
|
||||
#else
|
||||
static inline struct integrity_iint_cache *
|
||||
integrity_inode_get(struct inode *inode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void integrity_inode_free(struct inode *inode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void integrity_load_keys(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_INTEGRITY */
|
||||
|
||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||
|
||||
extern int integrity_kernel_module_request(char *kmod_name);
|
||||
|
||||
#else
|
||||
|
||||
static inline int integrity_kernel_module_request(char *kmod_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
|
||||
|
||||
#endif /* _LINUX_INTEGRITY_H */
|
||||
|
@ -94,6 +94,8 @@ LSM_HOOK(int, 0, path_mkdir, const struct path *dir, struct dentry *dentry,
|
||||
LSM_HOOK(int, 0, path_rmdir, const struct path *dir, struct dentry *dentry)
|
||||
LSM_HOOK(int, 0, path_mknod, const struct path *dir, struct dentry *dentry,
|
||||
umode_t mode, unsigned int dev)
|
||||
LSM_HOOK(void, LSM_RET_VOID, path_post_mknod, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry)
|
||||
LSM_HOOK(int, 0, path_truncate, const struct path *path)
|
||||
LSM_HOOK(int, 0, path_symlink, const struct path *dir, struct dentry *dentry,
|
||||
const char *old_name)
|
||||
@ -119,6 +121,8 @@ LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
|
||||
const struct qstr *name, const struct inode *context_inode)
|
||||
LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode)
|
||||
LSM_HOOK(void, LSM_RET_VOID, inode_post_create_tmpfile, struct mnt_idmap *idmap,
|
||||
struct inode *inode)
|
||||
LSM_HOOK(int, 0, inode_link, struct dentry *old_dentry, struct inode *dir,
|
||||
struct dentry *new_dentry)
|
||||
LSM_HOOK(int, 0, inode_unlink, struct inode *dir, struct dentry *dentry)
|
||||
@ -135,7 +139,10 @@ LSM_HOOK(int, 0, inode_readlink, struct dentry *dentry)
|
||||
LSM_HOOK(int, 0, inode_follow_link, struct dentry *dentry, struct inode *inode,
|
||||
bool rcu)
|
||||
LSM_HOOK(int, 0, inode_permission, struct inode *inode, int mask)
|
||||
LSM_HOOK(int, 0, inode_setattr, struct dentry *dentry, struct iattr *attr)
|
||||
LSM_HOOK(int, 0, inode_setattr, struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
LSM_HOOK(void, LSM_RET_VOID, inode_post_setattr, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, int ia_valid)
|
||||
LSM_HOOK(int, 0, inode_getattr, const struct path *path)
|
||||
LSM_HOOK(int, 0, inode_setxattr, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *name, const void *value,
|
||||
@ -146,12 +153,18 @@ LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
|
||||
LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
|
||||
LSM_HOOK(int, 0, inode_removexattr, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *name)
|
||||
LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry,
|
||||
const char *name)
|
||||
LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
|
||||
LSM_HOOK(void, LSM_RET_VOID, inode_post_set_acl, struct dentry *dentry,
|
||||
const char *acl_name, struct posix_acl *kacl)
|
||||
LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name)
|
||||
LSM_HOOK(int, 0, inode_remove_acl, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name)
|
||||
LSM_HOOK(void, LSM_RET_VOID, inode_post_remove_acl, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name)
|
||||
LSM_HOOK(int, 0, inode_need_killpriv, struct dentry *dentry)
|
||||
LSM_HOOK(int, 0, inode_killpriv, struct mnt_idmap *idmap,
|
||||
struct dentry *dentry)
|
||||
@ -168,6 +181,7 @@ LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
|
||||
struct kernfs_node *kn)
|
||||
LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
|
||||
LSM_HOOK(int, 0, file_alloc_security, struct file *file)
|
||||
LSM_HOOK(void, LSM_RET_VOID, file_release, struct file *file)
|
||||
LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
|
||||
LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
@ -186,6 +200,7 @@ LSM_HOOK(int, 0, file_send_sigiotask, struct task_struct *tsk,
|
||||
struct fown_struct *fown, int sig)
|
||||
LSM_HOOK(int, 0, file_receive, struct file *file)
|
||||
LSM_HOOK(int, 0, file_open, struct file *file)
|
||||
LSM_HOOK(int, 0, file_post_open, struct file *file, int mask)
|
||||
LSM_HOOK(int, 0, file_truncate, struct file *file)
|
||||
LSM_HOOK(int, 0, task_alloc, struct task_struct *task,
|
||||
unsigned long clone_flags)
|
||||
@ -390,6 +405,9 @@ LSM_HOOK(void, LSM_RET_VOID, key_free, struct key *key)
|
||||
LSM_HOOK(int, 0, key_permission, key_ref_t key_ref, const struct cred *cred,
|
||||
enum key_need_perm need_perm)
|
||||
LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
|
||||
LSM_HOOK(void, LSM_RET_VOID, key_post_create_or_update, struct key *keyring,
|
||||
struct key *key, const void *payload, size_t payload_len,
|
||||
unsigned long flags, bool create)
|
||||
#endif /* CONFIG_KEYS */
|
||||
|
||||
#ifdef CONFIG_AUDIT
|
||||
|
@ -345,6 +345,8 @@ int security_inode_init_security_anon(struct inode *inode,
|
||||
const struct qstr *name,
|
||||
const struct inode *context_inode);
|
||||
int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode);
|
||||
void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
struct inode *inode);
|
||||
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
|
||||
struct dentry *new_dentry);
|
||||
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
|
||||
@ -362,6 +364,8 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
|
||||
int security_inode_permission(struct inode *inode, int mask);
|
||||
int security_inode_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct iattr *attr);
|
||||
void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
int ia_valid);
|
||||
int security_inode_getattr(const struct path *path);
|
||||
int security_inode_setxattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *name,
|
||||
@ -369,16 +373,22 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
|
||||
int security_inode_set_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name,
|
||||
struct posix_acl *kacl);
|
||||
void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
|
||||
struct posix_acl *kacl);
|
||||
int security_inode_get_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name);
|
||||
int security_inode_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *acl_name);
|
||||
void security_inode_post_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name);
|
||||
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
int security_inode_getxattr(struct dentry *dentry, const char *name);
|
||||
int security_inode_listxattr(struct dentry *dentry);
|
||||
int security_inode_removexattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *name);
|
||||
void security_inode_post_removexattr(struct dentry *dentry, const char *name);
|
||||
int security_inode_need_killpriv(struct dentry *dentry);
|
||||
int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry);
|
||||
int security_inode_getsecurity(struct mnt_idmap *idmap,
|
||||
@ -393,6 +403,7 @@ int security_kernfs_init_security(struct kernfs_node *kn_dir,
|
||||
struct kernfs_node *kn);
|
||||
int security_file_permission(struct file *file, int mask);
|
||||
int security_file_alloc(struct file *file);
|
||||
void security_file_release(struct file *file);
|
||||
void security_file_free(struct file *file);
|
||||
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
int security_file_ioctl_compat(struct file *file, unsigned int cmd,
|
||||
@ -409,6 +420,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,
|
||||
struct fown_struct *fown, int sig);
|
||||
int security_file_receive(struct file *file);
|
||||
int security_file_open(struct file *file);
|
||||
int security_file_post_open(struct file *file, int mask);
|
||||
int security_file_truncate(struct file *file);
|
||||
int security_task_alloc(struct task_struct *task, unsigned long clone_flags);
|
||||
void security_task_free(struct task_struct *task);
|
||||
@ -807,6 +819,10 @@ static inline int security_inode_create(struct inode *dir,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
security_inode_post_create_tmpfile(struct mnt_idmap *idmap, struct inode *inode)
|
||||
{ }
|
||||
|
||||
static inline int security_inode_link(struct dentry *old_dentry,
|
||||
struct inode *dir,
|
||||
struct dentry *new_dentry)
|
||||
@ -880,6 +896,11 @@ static inline int security_inode_setattr(struct mnt_idmap *idmap,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
int ia_valid)
|
||||
{ }
|
||||
|
||||
static inline int security_inode_getattr(const struct path *path)
|
||||
{
|
||||
return 0;
|
||||
@ -900,6 +921,11 @@ static inline int security_inode_set_acl(struct mnt_idmap *idmap,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void security_inode_post_set_acl(struct dentry *dentry,
|
||||
const char *acl_name,
|
||||
struct posix_acl *kacl)
|
||||
{ }
|
||||
|
||||
static inline int security_inode_get_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
@ -914,6 +940,11 @@ static inline int security_inode_remove_acl(struct mnt_idmap *idmap,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void security_inode_post_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{ }
|
||||
|
||||
static inline void security_inode_post_setxattr(struct dentry *dentry,
|
||||
const char *name, const void *value, size_t size, int flags)
|
||||
{ }
|
||||
@ -936,6 +967,10 @@ static inline int security_inode_removexattr(struct mnt_idmap *idmap,
|
||||
return cap_inode_removexattr(idmap, dentry, name);
|
||||
}
|
||||
|
||||
static inline void security_inode_post_removexattr(struct dentry *dentry,
|
||||
const char *name)
|
||||
{ }
|
||||
|
||||
static inline int security_inode_need_killpriv(struct dentry *dentry)
|
||||
{
|
||||
return cap_inode_need_killpriv(dentry);
|
||||
@ -996,6 +1031,9 @@ static inline int security_file_alloc(struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void security_file_release(struct file *file)
|
||||
{ }
|
||||
|
||||
static inline void security_file_free(struct file *file)
|
||||
{ }
|
||||
|
||||
@ -1063,6 +1101,11 @@ static inline int security_file_open(struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_file_post_open(struct file *file, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_file_truncate(struct file *file)
|
||||
{
|
||||
return 0;
|
||||
@ -1872,6 +1915,7 @@ int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t m
|
||||
int security_path_rmdir(const struct path *dir, struct dentry *dentry);
|
||||
int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t mode,
|
||||
unsigned int dev);
|
||||
void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry);
|
||||
int security_path_truncate(const struct path *path);
|
||||
int security_path_symlink(const struct path *dir, struct dentry *dentry,
|
||||
const char *old_name);
|
||||
@ -1906,6 +1950,10 @@ static inline int security_path_mknod(const struct path *dir, struct dentry *den
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void security_path_post_mknod(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry)
|
||||
{ }
|
||||
|
||||
static inline int security_path_truncate(const struct path *path)
|
||||
{
|
||||
return 0;
|
||||
@ -1957,6 +2005,9 @@ void security_key_free(struct key *key);
|
||||
int security_key_permission(key_ref_t key_ref, const struct cred *cred,
|
||||
enum key_need_perm need_perm);
|
||||
int security_key_getsecurity(struct key *key, char **_buffer);
|
||||
void security_key_post_create_or_update(struct key *keyring, struct key *key,
|
||||
const void *payload, size_t payload_len,
|
||||
unsigned long flags, bool create);
|
||||
|
||||
#else
|
||||
|
||||
@ -1984,6 +2035,14 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void security_key_post_create_or_update(struct key *keyring,
|
||||
struct key *key,
|
||||
const void *payload,
|
||||
size_t payload_len,
|
||||
unsigned long flags,
|
||||
bool create)
|
||||
{ }
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_KEYS */
|
||||
|
||||
|
@ -62,6 +62,8 @@ struct lsm_ctx {
|
||||
#define LSM_ID_LOCKDOWN 108
|
||||
#define LSM_ID_BPF 109
|
||||
#define LSM_ID_LANDLOCK 110
|
||||
#define LSM_ID_IMA 111
|
||||
#define LSM_ID_EVM 112
|
||||
|
||||
/*
|
||||
* LSM_ATTR_XXX definitions identify different LSM attributes
|
||||
|
@ -606,8 +606,8 @@ int set_cred_ucounts(struct cred *new)
|
||||
void __init cred_init(void)
|
||||
{
|
||||
/* allocate a slab in which we can store credentials */
|
||||
cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0,
|
||||
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
|
||||
cred_jar = KMEM_CACHE(cred,
|
||||
SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,5 +18,6 @@ integrity-$(CONFIG_LOAD_IPL_KEYS) += platform_certs/load_ipl_s390.o
|
||||
integrity-$(CONFIG_LOAD_PPC_KEYS) += platform_certs/efi_parser.o \
|
||||
platform_certs/load_powerpc.o \
|
||||
platform_certs/keyring_handler.o
|
||||
# The relative order of the 'ima' and 'evm' LSMs depends on the order below.
|
||||
obj-$(CONFIG_IMA) += ima/
|
||||
obj-$(CONFIG_EVM) += evm/
|
||||
|
@ -132,26 +132,3 @@ out:
|
||||
pr_debug("%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests
|
||||
* @kmod_name: kernel module name
|
||||
*
|
||||
* We have situation, when public_key_verify_signature() in case of RSA
|
||||
* algorithm use alg_name to store internal information in order to
|
||||
* construct an algorithm on the fly, but crypto_larval_lookup() will try
|
||||
* to use alg_name in order to load kernel module with same name.
|
||||
* Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
|
||||
* we are safe to fail such module request from crypto_larval_lookup().
|
||||
*
|
||||
* In this way we prevent modprobe execution during digsig verification
|
||||
* and avoid possible deadlock if modprobe and/or it's dependencies
|
||||
* also signed with digsig.
|
||||
*/
|
||||
int integrity_kernel_module_request(char *kmod_name)
|
||||
{
|
||||
if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ config EVM
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA1
|
||||
select CRYPTO_HASH_INFO
|
||||
select SECURITY_PATH
|
||||
default n
|
||||
help
|
||||
EVM protects a file's security extended attributes against
|
||||
|
@ -32,6 +32,25 @@ struct xattr_list {
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
#define EVM_NEW_FILE 0x00000001
|
||||
#define EVM_IMMUTABLE_DIGSIG 0x00000002
|
||||
|
||||
/* EVM integrity metadata associated with an inode */
|
||||
struct evm_iint_cache {
|
||||
unsigned long flags;
|
||||
enum integrity_status evm_status:4;
|
||||
};
|
||||
|
||||
extern struct lsm_blob_sizes evm_blob_sizes;
|
||||
|
||||
static inline struct evm_iint_cache *evm_iint_inode(const struct inode *inode)
|
||||
{
|
||||
if (unlikely(!inode->i_security))
|
||||
return NULL;
|
||||
|
||||
return inode->i_security + evm_blob_sizes.lbs_inode;
|
||||
}
|
||||
|
||||
extern int evm_initialized;
|
||||
|
||||
#define EVM_ATTR_FSUUID 0x0001
|
||||
|
@ -322,10 +322,10 @@ int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
|
||||
static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
const struct evm_ima_xattr_data *xattr_data = NULL;
|
||||
struct integrity_iint_cache *iint;
|
||||
struct evm_iint_cache *iint;
|
||||
int rc = 0;
|
||||
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = evm_iint_inode(inode);
|
||||
if (iint && (iint->flags & EVM_IMMUTABLE_DIGSIG))
|
||||
return 1;
|
||||
|
||||
|
@ -178,14 +178,14 @@ static int is_unsupported_fs(struct dentry *dentry)
|
||||
static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
const char *xattr_name,
|
||||
char *xattr_value,
|
||||
size_t xattr_value_len,
|
||||
struct integrity_iint_cache *iint)
|
||||
size_t xattr_value_len)
|
||||
{
|
||||
struct evm_ima_xattr_data *xattr_data = NULL;
|
||||
struct signature_v2_hdr *hdr;
|
||||
enum integrity_status evm_status = INTEGRITY_PASS;
|
||||
struct evm_digest digest;
|
||||
struct inode *inode;
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
struct evm_iint_cache *iint = evm_iint_inode(inode);
|
||||
int rc, xattr_len, evm_immutable = 0;
|
||||
|
||||
if (iint && (iint->evm_status == INTEGRITY_PASS ||
|
||||
@ -254,8 +254,6 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
(const char *)xattr_data, xattr_len,
|
||||
digest.digest, digest.hdr.length);
|
||||
if (!rc) {
|
||||
inode = d_backing_inode(dentry);
|
||||
|
||||
if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) {
|
||||
if (iint)
|
||||
iint->flags |= EVM_IMMUTABLE_DIGSIG;
|
||||
@ -403,7 +401,6 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
|
||||
* @xattr_name: requested xattr
|
||||
* @xattr_value: requested xattr value
|
||||
* @xattr_value_len: requested xattr value length
|
||||
* @iint: inode integrity metadata
|
||||
*
|
||||
* Calculate the HMAC for the given dentry and verify it against the stored
|
||||
* security.evm xattr. For performance, use the xattr value and length
|
||||
@ -416,8 +413,7 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
|
||||
*/
|
||||
enum integrity_status evm_verifyxattr(struct dentry *dentry,
|
||||
const char *xattr_name,
|
||||
void *xattr_value, size_t xattr_value_len,
|
||||
struct integrity_iint_cache *iint)
|
||||
void *xattr_value, size_t xattr_value_len)
|
||||
{
|
||||
if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
|
||||
return INTEGRITY_UNKNOWN;
|
||||
@ -425,13 +421,8 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
|
||||
if (is_unsupported_fs(dentry))
|
||||
return INTEGRITY_UNKNOWN;
|
||||
|
||||
if (!iint) {
|
||||
iint = integrity_iint_find(d_backing_inode(dentry));
|
||||
if (!iint)
|
||||
return INTEGRITY_UNKNOWN;
|
||||
}
|
||||
return evm_verify_hmac(dentry, xattr_name, xattr_value,
|
||||
xattr_value_len, iint);
|
||||
xattr_value_len);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(evm_verifyxattr);
|
||||
|
||||
@ -448,7 +439,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
|
||||
|
||||
if (!evm_key_loaded() || !S_ISREG(inode->i_mode) || evm_fixmode)
|
||||
return INTEGRITY_PASS;
|
||||
return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
|
||||
return evm_verify_hmac(dentry, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -526,14 +517,14 @@ static int evm_protect_xattr(struct mnt_idmap *idmap,
|
||||
|
||||
evm_status = evm_verify_current_integrity(dentry);
|
||||
if (evm_status == INTEGRITY_NOXATTRS) {
|
||||
struct integrity_iint_cache *iint;
|
||||
struct evm_iint_cache *iint;
|
||||
|
||||
/* Exception if the HMAC is not going to be calculated. */
|
||||
if (evm_hmac_disabled())
|
||||
return 0;
|
||||
|
||||
iint = integrity_iint_find(d_backing_inode(dentry));
|
||||
if (iint && (iint->flags & IMA_NEW_FILE))
|
||||
iint = evm_iint_inode(d_backing_inode(dentry));
|
||||
if (iint && (iint->flags & EVM_NEW_FILE))
|
||||
return 0;
|
||||
|
||||
/* exception for pseudo filesystems */
|
||||
@ -581,6 +572,7 @@ out:
|
||||
* @xattr_name: pointer to the affected extended attribute name
|
||||
* @xattr_value: pointer to the new extended attribute value
|
||||
* @xattr_value_len: pointer to the new extended attribute value length
|
||||
* @flags: flags to pass into filesystem operations
|
||||
*
|
||||
* Before allowing the 'security.evm' protected xattr to be updated,
|
||||
* verify the existing value is valid. As only the kernel should have
|
||||
@ -588,9 +580,9 @@ out:
|
||||
* userspace from writing HMAC value. Writing 'security.evm' requires
|
||||
* requires CAP_SYS_ADMIN privileges.
|
||||
*/
|
||||
int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *xattr_name, const void *xattr_value,
|
||||
size_t xattr_value_len)
|
||||
static int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *xattr_name, const void *xattr_value,
|
||||
size_t xattr_value_len, int flags)
|
||||
{
|
||||
const struct evm_ima_xattr_data *xattr_data = xattr_value;
|
||||
|
||||
@ -620,8 +612,8 @@ int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
* Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
|
||||
* the current value is valid.
|
||||
*/
|
||||
int evm_inode_removexattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *xattr_name)
|
||||
static int evm_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *xattr_name)
|
||||
{
|
||||
/* Policy permits modification of the protected xattrs even though
|
||||
* there's no HMAC key loaded
|
||||
@ -671,9 +663,11 @@ static inline int evm_inode_set_acl_change(struct mnt_idmap *idmap,
|
||||
* Prevent modifying posix acls causing the EVM HMAC to be re-calculated
|
||||
* and 'security.evm' xattr updated, unless the existing 'security.evm' is
|
||||
* valid.
|
||||
*
|
||||
* Return: zero on success, -EPERM on failure.
|
||||
*/
|
||||
int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *acl_name, struct posix_acl *kacl)
|
||||
static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *acl_name, struct posix_acl *kacl)
|
||||
{
|
||||
enum integrity_status evm_status;
|
||||
|
||||
@ -712,11 +706,29 @@ int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_inode_remove_acl - Protect the EVM extended attribute from posix acls
|
||||
* @idmap: idmap of the mount
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @acl_name: name of the posix acl
|
||||
*
|
||||
* Prevent removing posix acls causing the EVM HMAC to be re-calculated
|
||||
* and 'security.evm' xattr updated, unless the existing 'security.evm' is
|
||||
* valid.
|
||||
*
|
||||
* Return: zero on success, -EPERM on failure.
|
||||
*/
|
||||
static int evm_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
|
||||
}
|
||||
|
||||
static void evm_reset_status(struct inode *inode)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
struct evm_iint_cache *iint;
|
||||
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = evm_iint_inode(inode);
|
||||
if (iint)
|
||||
iint->evm_status = INTEGRITY_UNKNOWN;
|
||||
}
|
||||
@ -752,6 +764,7 @@ bool evm_revalidate_status(const char *xattr_name)
|
||||
* @xattr_name: pointer to the affected extended attribute name
|
||||
* @xattr_value: pointer to the new extended attribute value
|
||||
* @xattr_value_len: pointer to the new extended attribute value length
|
||||
* @flags: flags to pass into filesystem operations
|
||||
*
|
||||
* Update the HMAC stored in 'security.evm' to reflect the change.
|
||||
*
|
||||
@ -759,8 +772,11 @@ bool evm_revalidate_status(const char *xattr_name)
|
||||
* __vfs_setxattr_noperm(). The caller of which has taken the inode's
|
||||
* i_mutex lock.
|
||||
*/
|
||||
void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
const void *xattr_value, size_t xattr_value_len)
|
||||
static void evm_inode_post_setxattr(struct dentry *dentry,
|
||||
const char *xattr_name,
|
||||
const void *xattr_value,
|
||||
size_t xattr_value_len,
|
||||
int flags)
|
||||
{
|
||||
if (!evm_revalidate_status(xattr_name))
|
||||
return;
|
||||
@ -779,6 +795,21 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_inode_post_set_acl - Update the EVM extended attribute from posix acls
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @acl_name: name of the posix acl
|
||||
* @kacl: pointer to the posix acls
|
||||
*
|
||||
* Update the 'security.evm' xattr with the EVM HMAC re-calculated after setting
|
||||
* posix acls.
|
||||
*/
|
||||
static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
|
||||
struct posix_acl *kacl)
|
||||
{
|
||||
return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_inode_post_removexattr - update 'security.evm' after removing the xattr
|
||||
* @dentry: pointer to the affected dentry
|
||||
@ -789,7 +820,8 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
* No need to take the i_mutex lock here, as this function is called from
|
||||
* vfs_removexattr() which takes the i_mutex.
|
||||
*/
|
||||
void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
|
||||
static void evm_inode_post_removexattr(struct dentry *dentry,
|
||||
const char *xattr_name)
|
||||
{
|
||||
if (!evm_revalidate_status(xattr_name))
|
||||
return;
|
||||
@ -805,6 +837,22 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
|
||||
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_inode_post_remove_acl - Update the EVM extended attribute from posix acls
|
||||
* @idmap: idmap of the mount
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @acl_name: name of the posix acl
|
||||
*
|
||||
* Update the 'security.evm' xattr with the EVM HMAC re-calculated after
|
||||
* removing posix acls.
|
||||
*/
|
||||
static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
evm_inode_post_removexattr(dentry, acl_name);
|
||||
}
|
||||
|
||||
static int evm_attr_change(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
@ -828,8 +876,8 @@ static int evm_attr_change(struct mnt_idmap *idmap,
|
||||
* Permit update of file attributes when files have a valid EVM signature,
|
||||
* except in the case of them having an immutable portable signature.
|
||||
*/
|
||||
int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
enum integrity_status evm_status;
|
||||
@ -870,6 +918,7 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
|
||||
/**
|
||||
* evm_inode_post_setattr - update 'security.evm' after modifying metadata
|
||||
* @idmap: idmap of the idmapped mount
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @ia_valid: for the UID and GID status
|
||||
*
|
||||
@ -879,7 +928,8 @@ int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
* This function is called from notify_change(), which expects the caller
|
||||
* to lock the inode's i_mutex.
|
||||
*/
|
||||
void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
|
||||
static void evm_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, int ia_valid)
|
||||
{
|
||||
if (!evm_revalidate_status(NULL))
|
||||
return;
|
||||
@ -896,7 +946,7 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
|
||||
evm_update_evmxattr(dentry, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
int evm_inode_copy_up_xattr(const char *name)
|
||||
static int evm_inode_copy_up_xattr(const char *name)
|
||||
{
|
||||
if (strcmp(name, XATTR_NAME_EVM) == 0)
|
||||
return 1; /* Discard */
|
||||
@ -960,6 +1010,42 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(evm_inode_init_security);
|
||||
|
||||
static int evm_inode_alloc_security(struct inode *inode)
|
||||
{
|
||||
struct evm_iint_cache *iint = evm_iint_inode(inode);
|
||||
|
||||
/* Called by security_inode_alloc(), it cannot be NULL. */
|
||||
iint->flags = 0UL;
|
||||
iint->evm_status = INTEGRITY_UNKNOWN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void evm_file_release(struct file *file)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct evm_iint_cache *iint = evm_iint_inode(inode);
|
||||
fmode_t mode = file->f_mode;
|
||||
|
||||
if (!S_ISREG(inode->i_mode) || !(mode & FMODE_WRITE))
|
||||
return;
|
||||
|
||||
if (iint && atomic_read(&inode->i_writecount) == 1)
|
||||
iint->flags &= ~EVM_NEW_FILE;
|
||||
}
|
||||
|
||||
static void evm_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
struct evm_iint_cache *iint = evm_iint_inode(inode);
|
||||
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return;
|
||||
|
||||
if (iint)
|
||||
iint->flags |= EVM_NEW_FILE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EVM_LOAD_X509
|
||||
void __init evm_load_x509(void)
|
||||
{
|
||||
@ -999,4 +1085,45 @@ error:
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct security_hook_list evm_hooks[] __ro_after_init = {
|
||||
LSM_HOOK_INIT(inode_setattr, evm_inode_setattr),
|
||||
LSM_HOOK_INIT(inode_post_setattr, evm_inode_post_setattr),
|
||||
LSM_HOOK_INIT(inode_copy_up_xattr, evm_inode_copy_up_xattr),
|
||||
LSM_HOOK_INIT(inode_setxattr, evm_inode_setxattr),
|
||||
LSM_HOOK_INIT(inode_post_setxattr, evm_inode_post_setxattr),
|
||||
LSM_HOOK_INIT(inode_set_acl, evm_inode_set_acl),
|
||||
LSM_HOOK_INIT(inode_post_set_acl, evm_inode_post_set_acl),
|
||||
LSM_HOOK_INIT(inode_remove_acl, evm_inode_remove_acl),
|
||||
LSM_HOOK_INIT(inode_post_remove_acl, evm_inode_post_remove_acl),
|
||||
LSM_HOOK_INIT(inode_removexattr, evm_inode_removexattr),
|
||||
LSM_HOOK_INIT(inode_post_removexattr, evm_inode_post_removexattr),
|
||||
LSM_HOOK_INIT(inode_init_security, evm_inode_init_security),
|
||||
LSM_HOOK_INIT(inode_alloc_security, evm_inode_alloc_security),
|
||||
LSM_HOOK_INIT(file_release, evm_file_release),
|
||||
LSM_HOOK_INIT(path_post_mknod, evm_post_path_mknod),
|
||||
};
|
||||
|
||||
static const struct lsm_id evm_lsmid = {
|
||||
.name = "evm",
|
||||
.id = LSM_ID_EVM,
|
||||
};
|
||||
|
||||
static int __init init_evm_lsm(void)
|
||||
{
|
||||
security_add_hooks(evm_hooks, ARRAY_SIZE(evm_hooks), &evm_lsmid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
|
||||
.lbs_inode = sizeof(struct evm_iint_cache),
|
||||
.lbs_xattr_count = 1,
|
||||
};
|
||||
|
||||
DEFINE_LSM(evm) = {
|
||||
.name = "evm",
|
||||
.init = init_evm_lsm,
|
||||
.order = LSM_ORDER_LAST,
|
||||
.blobs = &evm_blob_sizes,
|
||||
};
|
||||
|
||||
late_initcall(init_evm);
|
||||
|
@ -6,207 +6,14 @@
|
||||
* Mimi Zohar <zohar@us.ibm.com>
|
||||
*
|
||||
* File: integrity_iint.c
|
||||
* - implements the integrity hooks: integrity_inode_alloc,
|
||||
* integrity_inode_free
|
||||
* - cache integrity information associated with an inode
|
||||
* using a rbtree tree.
|
||||
* - initialize the integrity directory in securityfs
|
||||
* - load IMA and EVM keys
|
||||
*/
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/lsm_hooks.h>
|
||||
#include "integrity.h"
|
||||
|
||||
static struct rb_root integrity_iint_tree = RB_ROOT;
|
||||
static DEFINE_RWLOCK(integrity_iint_lock);
|
||||
static struct kmem_cache *iint_cache __ro_after_init;
|
||||
|
||||
struct dentry *integrity_dir;
|
||||
|
||||
/*
|
||||
* __integrity_iint_find - return the iint associated with an inode
|
||||
*/
|
||||
static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
struct rb_node *n = integrity_iint_tree.rb_node;
|
||||
|
||||
while (n) {
|
||||
iint = rb_entry(n, struct integrity_iint_cache, rb_node);
|
||||
|
||||
if (inode < iint->inode)
|
||||
n = n->rb_left;
|
||||
else if (inode > iint->inode)
|
||||
n = n->rb_right;
|
||||
else
|
||||
return iint;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* integrity_iint_find - return the iint associated with an inode
|
||||
*/
|
||||
struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
|
||||
if (!IS_IMA(inode))
|
||||
return NULL;
|
||||
|
||||
read_lock(&integrity_iint_lock);
|
||||
iint = __integrity_iint_find(inode);
|
||||
read_unlock(&integrity_iint_lock);
|
||||
|
||||
return iint;
|
||||
}
|
||||
|
||||
#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH+1)
|
||||
|
||||
/*
|
||||
* It is not clear that IMA should be nested at all, but as long is it measures
|
||||
* files both on overlayfs and on underlying fs, we need to annotate the iint
|
||||
* mutex to avoid lockdep false positives related to IMA + overlayfs.
|
||||
* See ovl_lockdep_annotate_inode_mutex_key() for more details.
|
||||
*/
|
||||
static inline void iint_lockdep_annotate(struct integrity_iint_cache *iint,
|
||||
struct inode *inode)
|
||||
{
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
static struct lock_class_key iint_mutex_key[IMA_MAX_NESTING];
|
||||
|
||||
int depth = inode->i_sb->s_stack_depth;
|
||||
|
||||
if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING))
|
||||
depth = 0;
|
||||
|
||||
lockdep_set_class(&iint->mutex, &iint_mutex_key[depth]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void iint_init_always(struct integrity_iint_cache *iint,
|
||||
struct inode *inode)
|
||||
{
|
||||
iint->ima_hash = NULL;
|
||||
iint->version = 0;
|
||||
iint->flags = 0UL;
|
||||
iint->atomic_flags = 0UL;
|
||||
iint->ima_file_status = INTEGRITY_UNKNOWN;
|
||||
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;
|
||||
mutex_init(&iint->mutex);
|
||||
iint_lockdep_annotate(iint, inode);
|
||||
}
|
||||
|
||||
static void iint_free(struct integrity_iint_cache *iint)
|
||||
{
|
||||
kfree(iint->ima_hash);
|
||||
mutex_destroy(&iint->mutex);
|
||||
kmem_cache_free(iint_cache, iint);
|
||||
}
|
||||
|
||||
/**
|
||||
* integrity_inode_get - find or allocate an iint associated with an inode
|
||||
* @inode: pointer to the inode
|
||||
* @return: allocated iint
|
||||
*
|
||||
* Caller must lock i_mutex
|
||||
*/
|
||||
struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
|
||||
{
|
||||
struct rb_node **p;
|
||||
struct rb_node *node, *parent = NULL;
|
||||
struct integrity_iint_cache *iint, *test_iint;
|
||||
|
||||
iint = integrity_iint_find(inode);
|
||||
if (iint)
|
||||
return iint;
|
||||
|
||||
iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
|
||||
if (!iint)
|
||||
return NULL;
|
||||
|
||||
iint_init_always(iint, inode);
|
||||
|
||||
write_lock(&integrity_iint_lock);
|
||||
|
||||
p = &integrity_iint_tree.rb_node;
|
||||
while (*p) {
|
||||
parent = *p;
|
||||
test_iint = rb_entry(parent, struct integrity_iint_cache,
|
||||
rb_node);
|
||||
if (inode < test_iint->inode) {
|
||||
p = &(*p)->rb_left;
|
||||
} else if (inode > test_iint->inode) {
|
||||
p = &(*p)->rb_right;
|
||||
} else {
|
||||
write_unlock(&integrity_iint_lock);
|
||||
kmem_cache_free(iint_cache, iint);
|
||||
return test_iint;
|
||||
}
|
||||
}
|
||||
|
||||
iint->inode = inode;
|
||||
node = &iint->rb_node;
|
||||
inode->i_flags |= S_IMA;
|
||||
rb_link_node(node, parent, p);
|
||||
rb_insert_color(node, &integrity_iint_tree);
|
||||
|
||||
write_unlock(&integrity_iint_lock);
|
||||
return iint;
|
||||
}
|
||||
|
||||
/**
|
||||
* integrity_inode_free - called on security_inode_free
|
||||
* @inode: pointer to the inode
|
||||
*
|
||||
* Free the integrity information(iint) associated with an inode.
|
||||
*/
|
||||
void integrity_inode_free(struct inode *inode)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
|
||||
if (!IS_IMA(inode))
|
||||
return;
|
||||
|
||||
write_lock(&integrity_iint_lock);
|
||||
iint = __integrity_iint_find(inode);
|
||||
rb_erase(&iint->rb_node, &integrity_iint_tree);
|
||||
write_unlock(&integrity_iint_lock);
|
||||
|
||||
iint_free(iint);
|
||||
}
|
||||
|
||||
static void iint_init_once(void *foo)
|
||||
{
|
||||
struct integrity_iint_cache *iint = (struct integrity_iint_cache *) foo;
|
||||
|
||||
memset(iint, 0, sizeof(*iint));
|
||||
}
|
||||
|
||||
static int __init integrity_iintcache_init(void)
|
||||
{
|
||||
iint_cache =
|
||||
kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
|
||||
0, SLAB_PANIC, iint_init_once);
|
||||
return 0;
|
||||
}
|
||||
DEFINE_LSM(integrity) = {
|
||||
.name = "integrity",
|
||||
.init = integrity_iintcache_init,
|
||||
.order = LSM_ORDER_LAST,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* integrity_kernel_read - read data from the file
|
||||
*
|
||||
|
@ -8,6 +8,7 @@ config IMA
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA1
|
||||
select CRYPTO_HASH_INFO
|
||||
select SECURITY_PATH
|
||||
select TCG_TPM if HAS_IOMEM
|
||||
select TCG_TIS if TCG_TPM && X86
|
||||
select TCG_CRB if TCG_TPM && ACPI
|
||||
|
@ -4,7 +4,7 @@
|
||||
# Measurement Architecture(IMA).
|
||||
#
|
||||
|
||||
obj-$(CONFIG_IMA) += ima.o
|
||||
obj-$(CONFIG_IMA) += ima.o ima_iint.o
|
||||
|
||||
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
|
||||
ima_policy.o ima_template.o ima_template_lib.o
|
||||
|
@ -60,7 +60,7 @@ extern const char boot_aggregate_name[];
|
||||
|
||||
/* IMA event related data */
|
||||
struct ima_event_data {
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
struct file *file;
|
||||
const unsigned char *filename;
|
||||
struct evm_ima_xattr_data *xattr_value;
|
||||
@ -119,6 +119,107 @@ struct ima_kexec_hdr {
|
||||
u64 count;
|
||||
};
|
||||
|
||||
/* IMA iint action cache flags */
|
||||
#define IMA_MEASURE 0x00000001
|
||||
#define IMA_MEASURED 0x00000002
|
||||
#define IMA_APPRAISE 0x00000004
|
||||
#define IMA_APPRAISED 0x00000008
|
||||
/*#define IMA_COLLECT 0x00000010 do not use this flag */
|
||||
#define IMA_COLLECTED 0x00000020
|
||||
#define IMA_AUDIT 0x00000040
|
||||
#define IMA_AUDITED 0x00000080
|
||||
#define IMA_HASH 0x00000100
|
||||
#define IMA_HASHED 0x00000200
|
||||
|
||||
/* IMA iint policy rule cache flags */
|
||||
#define IMA_NONACTION_FLAGS 0xff000000
|
||||
#define IMA_DIGSIG_REQUIRED 0x01000000
|
||||
#define IMA_PERMIT_DIRECTIO 0x02000000
|
||||
#define IMA_NEW_FILE 0x04000000
|
||||
#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000
|
||||
#define IMA_MODSIG_ALLOWED 0x20000000
|
||||
#define IMA_CHECK_BLACKLIST 0x40000000
|
||||
#define IMA_VERITY_REQUIRED 0x80000000
|
||||
|
||||
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
||||
IMA_HASH | IMA_APPRAISE_SUBMASK)
|
||||
#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \
|
||||
IMA_HASHED | IMA_COLLECTED | \
|
||||
IMA_APPRAISED_SUBMASK)
|
||||
|
||||
/* IMA iint subaction appraise cache flags */
|
||||
#define IMA_FILE_APPRAISE 0x00001000
|
||||
#define IMA_FILE_APPRAISED 0x00002000
|
||||
#define IMA_MMAP_APPRAISE 0x00004000
|
||||
#define IMA_MMAP_APPRAISED 0x00008000
|
||||
#define IMA_BPRM_APPRAISE 0x00010000
|
||||
#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_CREDS_APPRAISE)
|
||||
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
|
||||
IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \
|
||||
IMA_CREDS_APPRAISED)
|
||||
|
||||
/* IMA iint cache atomic_flags */
|
||||
#define IMA_CHANGE_XATTR 0
|
||||
#define IMA_UPDATE_XATTR 1
|
||||
#define IMA_CHANGE_ATTR 2
|
||||
#define IMA_DIGSIG 3
|
||||
#define IMA_MUST_MEASURE 4
|
||||
|
||||
/* IMA integrity metadata associated with an inode */
|
||||
struct ima_iint_cache {
|
||||
struct mutex mutex; /* protects: version, flags, digest */
|
||||
u64 version; /* track inode changes */
|
||||
unsigned long flags;
|
||||
unsigned long measured_pcrs;
|
||||
unsigned long atomic_flags;
|
||||
unsigned long real_ino;
|
||||
dev_t real_dev;
|
||||
enum integrity_status ima_file_status:4;
|
||||
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;
|
||||
struct ima_digest_data *ima_hash;
|
||||
};
|
||||
|
||||
extern struct lsm_blob_sizes ima_blob_sizes;
|
||||
|
||||
static inline struct ima_iint_cache *
|
||||
ima_inode_get_iint(const struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache **iint_sec;
|
||||
|
||||
if (unlikely(!inode->i_security))
|
||||
return NULL;
|
||||
|
||||
iint_sec = inode->i_security + ima_blob_sizes.lbs_inode;
|
||||
return *iint_sec;
|
||||
}
|
||||
|
||||
static inline void ima_inode_set_iint(const struct inode *inode,
|
||||
struct ima_iint_cache *iint)
|
||||
{
|
||||
struct ima_iint_cache **iint_sec;
|
||||
|
||||
if (unlikely(!inode->i_security))
|
||||
return;
|
||||
|
||||
iint_sec = inode->i_security + ima_blob_sizes.lbs_inode;
|
||||
*iint_sec = iint;
|
||||
}
|
||||
|
||||
struct ima_iint_cache *ima_iint_find(struct inode *inode);
|
||||
struct ima_iint_cache *ima_inode_get(struct inode *inode);
|
||||
void ima_inode_free(struct inode *inode);
|
||||
void __init ima_iintcache_init(void);
|
||||
|
||||
extern const int read_idmap[];
|
||||
|
||||
#ifdef CONFIG_HAVE_IMA_KEXEC
|
||||
@ -127,6 +228,12 @@ void ima_load_kexec_buffer(void);
|
||||
static inline void ima_load_kexec_buffer(void) {}
|
||||
#endif /* CONFIG_HAVE_IMA_KEXEC */
|
||||
|
||||
#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
|
||||
void ima_post_key_create_or_update(struct key *keyring, struct key *key,
|
||||
const void *payload, size_t plen,
|
||||
unsigned long flags, bool create);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The default binary_runtime_measurements list format is defined as the
|
||||
* platform native format. The canonical format is defined as little-endian.
|
||||
@ -146,8 +253,8 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data,
|
||||
struct ima_template_entry *entry);
|
||||
int ima_calc_boot_aggregate(struct ima_digest_data *hash);
|
||||
void ima_add_violation(struct file *file, const unsigned char *filename,
|
||||
struct integrity_iint_cache *iint,
|
||||
const char *op, const char *cause);
|
||||
struct ima_iint_cache *iint, const char *op,
|
||||
const char *cause);
|
||||
int ima_init_crypto(void);
|
||||
void ima_putc(struct seq_file *m, void *data, int datalen);
|
||||
void ima_print_digest(struct seq_file *m, u8 *digest, u32 size);
|
||||
@ -261,10 +368,10 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
|
||||
struct ima_template_desc **template_desc,
|
||||
const char *func_data, unsigned int *allowed_algos);
|
||||
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,
|
||||
enum hash_algo algo, struct modsig *modsig);
|
||||
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
|
||||
int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
void *buf, loff_t size, enum hash_algo algo,
|
||||
struct modsig *modsig);
|
||||
void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, const struct modsig *modsig, int pcr,
|
||||
@ -274,7 +381,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
||||
const char *eventname, enum ima_hooks func,
|
||||
int pcr, const char *func_data,
|
||||
bool buf_hash, u8 *digest, size_t digest_len);
|
||||
void ima_audit_measurement(struct integrity_iint_cache *iint,
|
||||
void ima_audit_measurement(struct ima_iint_cache *iint,
|
||||
const unsigned char *filename);
|
||||
int ima_alloc_init_template(struct ima_event_data *event_data,
|
||||
struct ima_template_entry **entry,
|
||||
@ -312,32 +419,32 @@ int ima_policy_show(struct seq_file *m, void *v);
|
||||
#define IMA_APPRAISE_KEXEC 0x40
|
||||
|
||||
#ifdef CONFIG_IMA_APPRAISE
|
||||
int ima_check_blacklist(struct integrity_iint_cache *iint,
|
||||
int ima_check_blacklist(struct ima_iint_cache *iint,
|
||||
const struct modsig *modsig, int pcr);
|
||||
int ima_appraise_measurement(enum ima_hooks func,
|
||||
struct integrity_iint_cache *iint,
|
||||
int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, const struct modsig *modsig);
|
||||
int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
|
||||
int mask, enum ima_hooks func);
|
||||
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
|
||||
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
|
||||
void ima_update_xattr(struct ima_iint_cache *iint, struct file *file);
|
||||
enum integrity_status ima_get_cache_status(struct ima_iint_cache *iint,
|
||||
enum ima_hooks func);
|
||||
enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len);
|
||||
int ima_read_xattr(struct dentry *dentry,
|
||||
struct evm_ima_xattr_data **xattr_value, int xattr_len);
|
||||
void __init init_ima_appraise_lsm(const struct lsm_id *lsmid);
|
||||
|
||||
#else
|
||||
static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
|
||||
static inline int ima_check_blacklist(struct ima_iint_cache *iint,
|
||||
const struct modsig *modsig, int pcr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_appraise_measurement(enum ima_hooks func,
|
||||
struct integrity_iint_cache *iint,
|
||||
struct ima_iint_cache *iint,
|
||||
struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
@ -354,14 +461,13 @@ static inline int ima_must_appraise(struct mnt_idmap *idmap,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ima_update_xattr(struct integrity_iint_cache *iint,
|
||||
static inline void ima_update_xattr(struct ima_iint_cache *iint,
|
||||
struct file *file)
|
||||
{
|
||||
}
|
||||
|
||||
static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache
|
||||
*iint,
|
||||
enum ima_hooks func)
|
||||
static inline enum integrity_status
|
||||
ima_get_cache_status(struct ima_iint_cache *iint, enum ima_hooks func)
|
||||
{
|
||||
return INTEGRITY_UNKNOWN;
|
||||
}
|
||||
@ -379,6 +485,10 @@ static inline int ima_read_xattr(struct dentry *dentry,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IMA_APPRAISE */
|
||||
|
||||
#ifdef CONFIG_IMA_APPRAISE_MODSIG
|
||||
|
@ -131,8 +131,8 @@ int ima_store_template(struct ima_template_entry *entry,
|
||||
* value is invalidated.
|
||||
*/
|
||||
void ima_add_violation(struct file *file, const unsigned char *filename,
|
||||
struct integrity_iint_cache *iint,
|
||||
const char *op, const char *cause)
|
||||
struct ima_iint_cache *iint, const char *op,
|
||||
const char *cause)
|
||||
{
|
||||
struct ima_template_entry *entry;
|
||||
struct inode *inode = file_inode(file);
|
||||
@ -201,7 +201,8 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
|
||||
allowed_algos);
|
||||
}
|
||||
|
||||
static bool ima_get_verity_digest(struct integrity_iint_cache *iint,
|
||||
static bool ima_get_verity_digest(struct ima_iint_cache *iint,
|
||||
struct inode *inode,
|
||||
struct ima_max_digest_data *hash)
|
||||
{
|
||||
enum hash_algo alg;
|
||||
@ -211,7 +212,7 @@ static bool ima_get_verity_digest(struct integrity_iint_cache *iint,
|
||||
* On failure, 'measure' policy rules will result in a file data
|
||||
* hash containing 0's.
|
||||
*/
|
||||
digest_len = fsverity_get_digest(iint->inode, hash->digest, NULL, &alg);
|
||||
digest_len = fsverity_get_digest(inode, hash->digest, NULL, &alg);
|
||||
if (digest_len == 0)
|
||||
return false;
|
||||
|
||||
@ -237,9 +238,9 @@ static bool ima_get_verity_digest(struct integrity_iint_cache *iint,
|
||||
*
|
||||
* Return 0 on success, error code otherwise
|
||||
*/
|
||||
int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, void *buf, loff_t size,
|
||||
enum hash_algo algo, struct modsig *modsig)
|
||||
int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
void *buf, loff_t size, enum hash_algo algo,
|
||||
struct modsig *modsig)
|
||||
{
|
||||
const char *audit_cause = "failed";
|
||||
struct inode *inode = file_inode(file);
|
||||
@ -280,7 +281,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
memset(&hash.digest, 0, sizeof(hash.digest));
|
||||
|
||||
if (iint->flags & IMA_VERITY_REQUIRED) {
|
||||
if (!ima_get_verity_digest(iint, &hash)) {
|
||||
if (!ima_get_verity_digest(iint, inode, &hash)) {
|
||||
audit_cause = "no-verity-digest";
|
||||
result = -ENODATA;
|
||||
}
|
||||
@ -338,8 +339,8 @@ out:
|
||||
*
|
||||
* Must be called with iint->mutex held.
|
||||
*/
|
||||
void ima_store_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, const struct modsig *modsig, int pcr,
|
||||
struct ima_template_desc *template_desc)
|
||||
@ -382,7 +383,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
|
||||
ima_free_template_entry(entry);
|
||||
}
|
||||
|
||||
void ima_audit_measurement(struct integrity_iint_cache *iint,
|
||||
void ima_audit_measurement(struct ima_iint_cache *iint,
|
||||
const unsigned char *filename)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
|
@ -84,8 +84,7 @@ int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int ima_fix_xattr(struct dentry *dentry,
|
||||
struct integrity_iint_cache *iint)
|
||||
static int ima_fix_xattr(struct dentry *dentry, struct ima_iint_cache *iint)
|
||||
{
|
||||
int rc, offset;
|
||||
u8 algo = iint->ima_hash->algo;
|
||||
@ -106,7 +105,7 @@ static int ima_fix_xattr(struct dentry *dentry,
|
||||
}
|
||||
|
||||
/* Return specific func appraised cached result */
|
||||
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
|
||||
enum integrity_status ima_get_cache_status(struct ima_iint_cache *iint,
|
||||
enum ima_hooks func)
|
||||
{
|
||||
switch (func) {
|
||||
@ -126,7 +125,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
|
||||
}
|
||||
}
|
||||
|
||||
static void ima_set_cache_status(struct integrity_iint_cache *iint,
|
||||
static void ima_set_cache_status(struct ima_iint_cache *iint,
|
||||
enum ima_hooks func,
|
||||
enum integrity_status status)
|
||||
{
|
||||
@ -152,8 +151,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
|
||||
}
|
||||
}
|
||||
|
||||
static void ima_cache_flags(struct integrity_iint_cache *iint,
|
||||
enum ima_hooks func)
|
||||
static void ima_cache_flags(struct ima_iint_cache *iint, enum ima_hooks func)
|
||||
{
|
||||
switch (func) {
|
||||
case MMAP_CHECK:
|
||||
@ -276,7 +274,7 @@ static int calc_file_id_hash(enum evm_ima_xattr_type type,
|
||||
*
|
||||
* Return 0 on success, error code otherwise.
|
||||
*/
|
||||
static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
|
||||
static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint,
|
||||
struct evm_ima_xattr_data *xattr_value, int xattr_len,
|
||||
enum integrity_status *status, const char **cause)
|
||||
{
|
||||
@ -443,7 +441,7 @@ static int modsig_verify(enum ima_hooks func, const struct modsig *modsig,
|
||||
*
|
||||
* Returns -EPERM if the hash is blacklisted.
|
||||
*/
|
||||
int ima_check_blacklist(struct integrity_iint_cache *iint,
|
||||
int ima_check_blacklist(struct ima_iint_cache *iint,
|
||||
const struct modsig *modsig, int pcr)
|
||||
{
|
||||
enum hash_algo hash_algo;
|
||||
@ -477,8 +475,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
|
||||
*
|
||||
* Return 0 on success, error code otherwise
|
||||
*/
|
||||
int ima_appraise_measurement(enum ima_hooks func,
|
||||
struct integrity_iint_cache *iint,
|
||||
int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, const struct modsig *modsig)
|
||||
@ -520,7 +517,7 @@ int ima_appraise_measurement(enum ima_hooks func,
|
||||
}
|
||||
|
||||
status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
|
||||
rc < 0 ? 0 : rc, iint);
|
||||
rc < 0 ? 0 : rc);
|
||||
switch (status) {
|
||||
case INTEGRITY_PASS:
|
||||
case INTEGRITY_PASS_IMMUTABLE:
|
||||
@ -603,7 +600,7 @@ out:
|
||||
/*
|
||||
* ima_update_xattr - update 'security.ima' hash value
|
||||
*/
|
||||
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
|
||||
void ima_update_xattr(struct ima_iint_cache *iint, struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file_dentry(file);
|
||||
int rc = 0;
|
||||
@ -629,17 +626,18 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
|
||||
* ima_inode_post_setattr - reflect file metadata changes
|
||||
* @idmap: idmap of the mount the inode was found from
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @ia_valid: for the UID and GID status
|
||||
*
|
||||
* Changes to a dentry's metadata might result in needing to appraise.
|
||||
*
|
||||
* This function is called from notify_change(), which expects the caller
|
||||
* to lock the inode's i_mutex.
|
||||
*/
|
||||
void ima_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry)
|
||||
static void ima_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, int ia_valid)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
int action;
|
||||
|
||||
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|
||||
@ -647,7 +645,7 @@ void ima_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
return;
|
||||
|
||||
action = ima_must_appraise(idmap, inode, MAY_ACCESS, POST_SETATTR);
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
if (iint) {
|
||||
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
|
||||
if (!action)
|
||||
@ -673,12 +671,12 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
||||
|
||||
static void ima_reset_appraise_flags(struct inode *inode, int digsig)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
|
||||
return;
|
||||
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
iint->measured_pcrs = 0;
|
||||
@ -749,8 +747,9 @@ static int validate_hash_algo(struct dentry *dentry,
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
const void *xattr_value, size_t xattr_value_len)
|
||||
static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *xattr_name, const void *xattr_value,
|
||||
size_t xattr_value_len, int flags)
|
||||
{
|
||||
const struct evm_ima_xattr_data *xvalue = xattr_value;
|
||||
int digsig = 0;
|
||||
@ -779,8 +778,8 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
return result;
|
||||
}
|
||||
|
||||
int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *acl_name, struct posix_acl *kacl)
|
||||
static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *acl_name, struct posix_acl *kacl)
|
||||
{
|
||||
if (evm_revalidate_status(acl_name))
|
||||
ima_reset_appraise_flags(d_backing_inode(dentry), 0);
|
||||
@ -788,7 +787,8 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
|
||||
static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *xattr_name)
|
||||
{
|
||||
int result;
|
||||
|
||||
@ -800,3 +800,23 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ima_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
|
||||
}
|
||||
|
||||
static struct security_hook_list ima_appraise_hooks[] __ro_after_init = {
|
||||
LSM_HOOK_INIT(inode_post_setattr, ima_inode_post_setattr),
|
||||
LSM_HOOK_INIT(inode_setxattr, ima_inode_setxattr),
|
||||
LSM_HOOK_INIT(inode_set_acl, ima_inode_set_acl),
|
||||
LSM_HOOK_INIT(inode_removexattr, ima_inode_removexattr),
|
||||
LSM_HOOK_INIT(inode_remove_acl, ima_inode_remove_acl),
|
||||
};
|
||||
|
||||
void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
|
||||
{
|
||||
security_add_hooks(ima_appraise_hooks, ARRAY_SIZE(ima_appraise_hooks),
|
||||
lsmid);
|
||||
}
|
||||
|
142
security/integrity/ima/ima_iint.c
Normal file
142
security/integrity/ima/ima_iint.c
Normal file
@ -0,0 +1,142 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2008 IBM Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Mimi Zohar <zohar@us.ibm.com>
|
||||
*
|
||||
* File: ima_iint.c
|
||||
* - implements the IMA hook: ima_inode_free
|
||||
* - cache integrity information in the inode security blob
|
||||
*/
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "ima.h"
|
||||
|
||||
static struct kmem_cache *ima_iint_cache __ro_after_init;
|
||||
|
||||
/**
|
||||
* ima_iint_find - Return the iint associated with an inode
|
||||
* @inode: Pointer to the inode
|
||||
*
|
||||
* Return the IMA integrity information (iint) associated with an inode, if the
|
||||
* inode was processed by IMA.
|
||||
*
|
||||
* Return: Found iint or NULL.
|
||||
*/
|
||||
struct ima_iint_cache *ima_iint_find(struct inode *inode)
|
||||
{
|
||||
if (!IS_IMA(inode))
|
||||
return NULL;
|
||||
|
||||
return ima_inode_get_iint(inode);
|
||||
}
|
||||
|
||||
#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH + 1)
|
||||
|
||||
/*
|
||||
* It is not clear that IMA should be nested at all, but as long is it measures
|
||||
* files both on overlayfs and on underlying fs, we need to annotate the iint
|
||||
* mutex to avoid lockdep false positives related to IMA + overlayfs.
|
||||
* See ovl_lockdep_annotate_inode_mutex_key() for more details.
|
||||
*/
|
||||
static inline void ima_iint_lockdep_annotate(struct ima_iint_cache *iint,
|
||||
struct inode *inode)
|
||||
{
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
static struct lock_class_key ima_iint_mutex_key[IMA_MAX_NESTING];
|
||||
|
||||
int depth = inode->i_sb->s_stack_depth;
|
||||
|
||||
if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING))
|
||||
depth = 0;
|
||||
|
||||
lockdep_set_class(&iint->mutex, &ima_iint_mutex_key[depth]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ima_iint_init_always(struct ima_iint_cache *iint,
|
||||
struct inode *inode)
|
||||
{
|
||||
iint->ima_hash = NULL;
|
||||
iint->version = 0;
|
||||
iint->flags = 0UL;
|
||||
iint->atomic_flags = 0UL;
|
||||
iint->ima_file_status = INTEGRITY_UNKNOWN;
|
||||
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->measured_pcrs = 0;
|
||||
mutex_init(&iint->mutex);
|
||||
ima_iint_lockdep_annotate(iint, inode);
|
||||
}
|
||||
|
||||
static void ima_iint_free(struct ima_iint_cache *iint)
|
||||
{
|
||||
kfree(iint->ima_hash);
|
||||
mutex_destroy(&iint->mutex);
|
||||
kmem_cache_free(ima_iint_cache, iint);
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_inode_get - Find or allocate an iint associated with an inode
|
||||
* @inode: Pointer to the inode
|
||||
*
|
||||
* Find an iint associated with an inode, and allocate a new one if not found.
|
||||
* Caller must lock i_mutex.
|
||||
*
|
||||
* Return: An iint on success, NULL on error.
|
||||
*/
|
||||
struct ima_iint_cache *ima_inode_get(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
iint = ima_iint_find(inode);
|
||||
if (iint)
|
||||
return iint;
|
||||
|
||||
iint = kmem_cache_alloc(ima_iint_cache, GFP_NOFS);
|
||||
if (!iint)
|
||||
return NULL;
|
||||
|
||||
ima_iint_init_always(iint, inode);
|
||||
|
||||
inode->i_flags |= S_IMA;
|
||||
ima_inode_set_iint(inode, iint);
|
||||
|
||||
return iint;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_inode_free - Called on inode free
|
||||
* @inode: Pointer to the inode
|
||||
*
|
||||
* Free the iint associated with an inode.
|
||||
*/
|
||||
void ima_inode_free(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
if (!IS_IMA(inode))
|
||||
return;
|
||||
|
||||
iint = ima_iint_find(inode);
|
||||
ima_inode_set_iint(inode, NULL);
|
||||
|
||||
ima_iint_free(iint);
|
||||
}
|
||||
|
||||
static void ima_iint_init_once(void *foo)
|
||||
{
|
||||
struct ima_iint_cache *iint = (struct ima_iint_cache *)foo;
|
||||
|
||||
memset(iint, 0, sizeof(*iint));
|
||||
}
|
||||
|
||||
void __init ima_iintcache_init(void)
|
||||
{
|
||||
ima_iint_cache =
|
||||
kmem_cache_create("ima_iint_cache", sizeof(struct ima_iint_cache),
|
||||
0, SLAB_PANIC, ima_iint_init_once);
|
||||
}
|
@ -44,7 +44,7 @@ static int __init ima_add_boot_aggregate(void)
|
||||
static const char op[] = "add_boot_aggregate";
|
||||
const char *audit_cause = "ENOMEM";
|
||||
struct ima_template_entry *entry;
|
||||
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
|
||||
struct ima_iint_cache tmp_iint, *iint = &tmp_iint;
|
||||
struct ima_event_data event_data = { .iint = iint,
|
||||
.filename = boot_aggregate_name };
|
||||
struct ima_max_digest_data hash;
|
||||
|
@ -114,7 +114,7 @@ static int mmap_violation_check(enum ima_hooks func, struct file *file,
|
||||
*
|
||||
*/
|
||||
static void ima_rdwr_violation_check(struct file *file,
|
||||
struct integrity_iint_cache *iint,
|
||||
struct ima_iint_cache *iint,
|
||||
int must_measure,
|
||||
char **pathbuf,
|
||||
const char **pathname,
|
||||
@ -127,7 +127,7 @@ static void ima_rdwr_violation_check(struct file *file,
|
||||
if (mode & FMODE_WRITE) {
|
||||
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
|
||||
if (!iint)
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
/* IMA_MEASURE is set from reader side */
|
||||
if (iint && test_bit(IMA_MUST_MEASURE,
|
||||
&iint->atomic_flags))
|
||||
@ -153,7 +153,7 @@ static void ima_rdwr_violation_check(struct file *file,
|
||||
"invalid_pcr", "open_writers");
|
||||
}
|
||||
|
||||
static void ima_check_last_writer(struct integrity_iint_cache *iint,
|
||||
static void ima_check_last_writer(struct ima_iint_cache *iint,
|
||||
struct inode *inode, struct file *file)
|
||||
{
|
||||
fmode_t mode = file->f_mode;
|
||||
@ -189,15 +189,15 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
|
||||
*
|
||||
* Flag files that changed, based on i_version
|
||||
*/
|
||||
void ima_file_free(struct file *file)
|
||||
static void ima_file_free(struct file *file)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
|
||||
return;
|
||||
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
|
||||
@ -209,7 +209,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
|
||||
enum ima_hooks func)
|
||||
{
|
||||
struct inode *backing_inode, *inode = file_inode(file);
|
||||
struct integrity_iint_cache *iint = NULL;
|
||||
struct ima_iint_cache *iint = NULL;
|
||||
struct ima_template_desc *template_desc = NULL;
|
||||
char *pathbuf = NULL;
|
||||
char filename[NAME_MAX];
|
||||
@ -248,7 +248,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
|
||||
inode_lock(inode);
|
||||
|
||||
if (action) {
|
||||
iint = integrity_inode_get(inode);
|
||||
iint = ima_inode_get(inode);
|
||||
if (!iint)
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
@ -427,8 +427,8 @@ out:
|
||||
* On success return 0. On integrity appraisal error, assuming the file
|
||||
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
|
||||
*/
|
||||
int ima_file_mmap(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags)
|
||||
static int ima_file_mmap(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags)
|
||||
{
|
||||
u32 secid;
|
||||
int ret;
|
||||
@ -455,7 +455,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
|
||||
/**
|
||||
* ima_file_mprotect - based on policy, limit mprotect change
|
||||
* @vma: vm_area_struct protection is set to
|
||||
* @prot: contains the protection that will be applied by the kernel.
|
||||
* @reqprot: protection requested by the application
|
||||
* @prot: protection that will be applied by the kernel
|
||||
*
|
||||
* Files can be mmap'ed read/write and later changed to execute to circumvent
|
||||
* IMA's mmap appraisal policy rules. Due to locking issues (mmap semaphore
|
||||
@ -465,7 +466,8 @@ int ima_file_mmap(struct file *file, unsigned long reqprot,
|
||||
*
|
||||
* On mprotect change success, return 0. On failure, return -EACESS.
|
||||
*/
|
||||
int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
|
||||
static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
|
||||
unsigned long prot)
|
||||
{
|
||||
struct ima_template_desc *template = NULL;
|
||||
struct file *file;
|
||||
@ -523,7 +525,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
|
||||
* On success return 0. On integrity appraisal error, assuming the file
|
||||
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
|
||||
*/
|
||||
int ima_bprm_check(struct linux_binprm *bprm)
|
||||
static int ima_bprm_check(struct linux_binprm *bprm)
|
||||
{
|
||||
int ret;
|
||||
u32 secid;
|
||||
@ -549,7 +551,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
|
||||
* On success return 0. On integrity appraisal error, assuming the file
|
||||
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
|
||||
*/
|
||||
int ima_file_check(struct file *file, int mask)
|
||||
static int ima_file_check(struct file *file, int mask)
|
||||
{
|
||||
u32 secid;
|
||||
|
||||
@ -558,16 +560,15 @@ int ima_file_check(struct file *file, int mask)
|
||||
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
|
||||
MAY_APPEND), FILE_CHECK);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ima_file_check);
|
||||
|
||||
static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
struct integrity_iint_cache *iint = NULL, tmp_iint;
|
||||
struct ima_iint_cache *iint = NULL, tmp_iint;
|
||||
int rc, hash_algo;
|
||||
|
||||
if (ima_policy_flag) {
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
if (iint)
|
||||
mutex_lock(&iint->mutex);
|
||||
}
|
||||
@ -577,7 +578,6 @@ static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
|
||||
mutex_unlock(&iint->mutex);
|
||||
|
||||
memset(&tmp_iint, 0, sizeof(tmp_iint));
|
||||
tmp_iint.inode = inode;
|
||||
mutex_init(&tmp_iint.mutex);
|
||||
|
||||
rc = ima_collect_measurement(&tmp_iint, file, NULL, 0,
|
||||
@ -683,10 +683,11 @@ EXPORT_SYMBOL_GPL(ima_inode_hash);
|
||||
* Skip calling process_measurement(), but indicate which newly, created
|
||||
* tmpfiles are in policy.
|
||||
*/
|
||||
void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
struct inode *inode)
|
||||
static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
struct inode *inode)
|
||||
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
int must_appraise;
|
||||
|
||||
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
|
||||
@ -698,7 +699,7 @@ void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
return;
|
||||
|
||||
/* Nothing to do if we can't allocate memory */
|
||||
iint = integrity_inode_get(inode);
|
||||
iint = ima_inode_get(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
|
||||
@ -715,10 +716,9 @@ void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
* Mark files created via the mknodat syscall as new, so that the
|
||||
* file data can be written later.
|
||||
*/
|
||||
void ima_post_path_mknod(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry)
|
||||
static void ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int must_appraise;
|
||||
|
||||
@ -731,7 +731,7 @@ void ima_post_path_mknod(struct mnt_idmap *idmap,
|
||||
return;
|
||||
|
||||
/* Nothing to do if we can't allocate memory */
|
||||
iint = integrity_inode_get(inode);
|
||||
iint = ima_inode_get(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
|
||||
@ -751,8 +751,8 @@ void ima_post_path_mknod(struct mnt_idmap *idmap,
|
||||
*
|
||||
* For permission return 0, otherwise return -EACCES.
|
||||
*/
|
||||
int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
|
||||
bool contents)
|
||||
static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
|
||||
bool contents)
|
||||
{
|
||||
enum ima_hooks func;
|
||||
u32 secid;
|
||||
@ -801,8 +801,8 @@ const int read_idmap[READING_MAX_ID] = {
|
||||
* On success return 0. On integrity appraisal error, assuming the file
|
||||
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
|
||||
*/
|
||||
int ima_post_read_file(struct file *file, void *buf, loff_t size,
|
||||
enum kernel_read_file_id read_id)
|
||||
static int ima_post_read_file(struct file *file, char *buf, loff_t size,
|
||||
enum kernel_read_file_id read_id)
|
||||
{
|
||||
enum ima_hooks func;
|
||||
u32 secid;
|
||||
@ -835,7 +835,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
|
||||
*
|
||||
* For permission return 0, otherwise return -EACCES.
|
||||
*/
|
||||
int ima_load_data(enum kernel_load_data_id id, bool contents)
|
||||
static int ima_load_data(enum kernel_load_data_id id, bool contents)
|
||||
{
|
||||
bool ima_enforce, sig_enforce;
|
||||
|
||||
@ -889,9 +889,9 @@ int ima_load_data(enum kernel_load_data_id id, bool contents)
|
||||
* On success return 0. On integrity appraisal error, assuming the file
|
||||
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
|
||||
*/
|
||||
int ima_post_load_data(char *buf, loff_t size,
|
||||
enum kernel_load_data_id load_id,
|
||||
char *description)
|
||||
static int ima_post_load_data(char *buf, loff_t size,
|
||||
enum kernel_load_data_id load_id,
|
||||
char *description)
|
||||
{
|
||||
if (load_id == LOADING_FIRMWARE) {
|
||||
if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
|
||||
@ -934,7 +934,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
||||
int ret = 0;
|
||||
const char *audit_cause = "ENOMEM";
|
||||
struct ima_template_entry *entry = NULL;
|
||||
struct integrity_iint_cache iint = {};
|
||||
struct ima_iint_cache iint = {};
|
||||
struct ima_event_data event_data = {.iint = &iint,
|
||||
.filename = eventname,
|
||||
.buf = buf,
|
||||
@ -1089,6 +1089,39 @@ int ima_measure_critical_data(const char *event_label,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ima_measure_critical_data);
|
||||
|
||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||
|
||||
/**
|
||||
* ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
|
||||
* @kmod_name: kernel module name
|
||||
*
|
||||
* Avoid a verification loop where verifying the signature of the modprobe
|
||||
* binary requires executing modprobe itself. Since the modprobe iint->mutex
|
||||
* is already held when the signature verification is performed, a deadlock
|
||||
* occurs as soon as modprobe is executed within the critical region, since
|
||||
* the same lock cannot be taken again.
|
||||
*
|
||||
* This happens when public_key_verify_signature(), in case of RSA algorithm,
|
||||
* use alg_name to store internal information in order to construct an
|
||||
* algorithm on the fly, but crypto_larval_lookup() will try to use alg_name
|
||||
* in order to load a kernel module with same name.
|
||||
*
|
||||
* Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
|
||||
* we are safe to fail such module request from crypto_larval_lookup(), and
|
||||
* avoid the verification loop.
|
||||
*
|
||||
* Return: Zero if it is safe to load the kernel module, -EINVAL otherwise.
|
||||
*/
|
||||
static int ima_kernel_module_request(char *kmod_name)
|
||||
{
|
||||
if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
|
||||
|
||||
static int __init init_ima(void)
|
||||
{
|
||||
int error;
|
||||
@ -1120,4 +1153,49 @@ static int __init init_ima(void)
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct security_hook_list ima_hooks[] __ro_after_init = {
|
||||
LSM_HOOK_INIT(bprm_check_security, ima_bprm_check),
|
||||
LSM_HOOK_INIT(file_post_open, ima_file_check),
|
||||
LSM_HOOK_INIT(inode_post_create_tmpfile, ima_post_create_tmpfile),
|
||||
LSM_HOOK_INIT(file_release, ima_file_free),
|
||||
LSM_HOOK_INIT(mmap_file, ima_file_mmap),
|
||||
LSM_HOOK_INIT(file_mprotect, ima_file_mprotect),
|
||||
LSM_HOOK_INIT(kernel_load_data, ima_load_data),
|
||||
LSM_HOOK_INIT(kernel_post_load_data, ima_post_load_data),
|
||||
LSM_HOOK_INIT(kernel_read_file, ima_read_file),
|
||||
LSM_HOOK_INIT(kernel_post_read_file, ima_post_read_file),
|
||||
LSM_HOOK_INIT(path_post_mknod, ima_post_path_mknod),
|
||||
#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
|
||||
LSM_HOOK_INIT(key_post_create_or_update, ima_post_key_create_or_update),
|
||||
#endif
|
||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||
LSM_HOOK_INIT(kernel_module_request, ima_kernel_module_request),
|
||||
#endif
|
||||
LSM_HOOK_INIT(inode_free_security, ima_inode_free),
|
||||
};
|
||||
|
||||
static const struct lsm_id ima_lsmid = {
|
||||
.name = "ima",
|
||||
.id = LSM_ID_IMA,
|
||||
};
|
||||
|
||||
static int __init init_ima_lsm(void)
|
||||
{
|
||||
ima_iintcache_init();
|
||||
security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
|
||||
init_ima_appraise_lsm(&ima_lsmid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
|
||||
.lbs_inode = sizeof(struct ima_iint_cache *),
|
||||
};
|
||||
|
||||
DEFINE_LSM(ima) = {
|
||||
.name = "ima",
|
||||
.init = init_ima_lsm,
|
||||
.order = LSM_ORDER_LAST,
|
||||
.blobs = &ima_blob_sizes,
|
||||
};
|
||||
|
||||
late_initcall(init_ima); /* Start IMA after the TPM is available */
|
||||
|
@ -49,7 +49,7 @@
|
||||
#define DONT_HASH 0x0200
|
||||
|
||||
#define INVALID_PCR(a) (((a) < 0) || \
|
||||
(a) >= (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8))
|
||||
(a) >= (sizeof_field(struct ima_iint_cache, measured_pcrs) * 8))
|
||||
|
||||
int ima_policy_flag;
|
||||
static int temp_ima_appraise;
|
||||
|
@ -18,60 +18,7 @@
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/key.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
/* iint action cache flags */
|
||||
#define IMA_MEASURE 0x00000001
|
||||
#define IMA_MEASURED 0x00000002
|
||||
#define IMA_APPRAISE 0x00000004
|
||||
#define IMA_APPRAISED 0x00000008
|
||||
/*#define IMA_COLLECT 0x00000010 do not use this flag */
|
||||
#define IMA_COLLECTED 0x00000020
|
||||
#define IMA_AUDIT 0x00000040
|
||||
#define IMA_AUDITED 0x00000080
|
||||
#define IMA_HASH 0x00000100
|
||||
#define IMA_HASHED 0x00000200
|
||||
|
||||
/* iint policy rule cache flags */
|
||||
#define IMA_NONACTION_FLAGS 0xff000000
|
||||
#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_MODSIG_ALLOWED 0x20000000
|
||||
#define IMA_CHECK_BLACKLIST 0x40000000
|
||||
#define IMA_VERITY_REQUIRED 0x80000000
|
||||
|
||||
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
||||
IMA_HASH | IMA_APPRAISE_SUBMASK)
|
||||
#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \
|
||||
IMA_HASHED | IMA_COLLECTED | \
|
||||
IMA_APPRAISED_SUBMASK)
|
||||
|
||||
/* iint subaction appraise cache flags */
|
||||
#define IMA_FILE_APPRAISE 0x00001000
|
||||
#define IMA_FILE_APPRAISED 0x00002000
|
||||
#define IMA_MMAP_APPRAISE 0x00004000
|
||||
#define IMA_MMAP_APPRAISED 0x00008000
|
||||
#define IMA_BPRM_APPRAISE 0x00010000
|
||||
#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_CREDS_APPRAISE)
|
||||
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
|
||||
IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \
|
||||
IMA_CREDS_APPRAISED)
|
||||
|
||||
/* iint cache atomic_flags */
|
||||
#define IMA_CHANGE_XATTR 0
|
||||
#define IMA_UPDATE_XATTR 1
|
||||
#define IMA_CHANGE_ATTR 2
|
||||
#define IMA_DIGSIG 3
|
||||
#define IMA_MUST_MEASURE 4
|
||||
#include <linux/lsm_hooks.h>
|
||||
|
||||
enum evm_ima_xattr_type {
|
||||
IMA_XATTR_DIGEST = 0x01,
|
||||
@ -155,31 +102,6 @@ struct ima_file_id {
|
||||
__u8 hash[HASH_MAX_DIGESTSIZE];
|
||||
} __packed;
|
||||
|
||||
/* integrity data associated with an inode */
|
||||
struct integrity_iint_cache {
|
||||
struct rb_node rb_node; /* rooted in integrity_iint_tree */
|
||||
struct mutex mutex; /* protects: version, flags, digest */
|
||||
struct inode *inode; /* back pointer to inode in question */
|
||||
u64 version; /* track inode changes */
|
||||
unsigned long flags;
|
||||
unsigned long measured_pcrs;
|
||||
unsigned long atomic_flags;
|
||||
unsigned long real_ino;
|
||||
dev_t real_dev;
|
||||
enum integrity_status ima_file_status:4;
|
||||
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;
|
||||
};
|
||||
|
||||
/* rbtree tree calls to lookup, insert, delete
|
||||
* integrity data associated with an inode.
|
||||
*/
|
||||
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
|
||||
|
||||
int integrity_kernel_read(struct file *file, loff_t offset,
|
||||
void *addr, unsigned long count);
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <linux/security.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/err.h>
|
||||
#include "internal.h"
|
||||
|
||||
@ -930,8 +929,8 @@ static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
|
||||
goto error_link_end;
|
||||
}
|
||||
|
||||
ima_post_key_create_or_update(keyring, key, payload, plen,
|
||||
flags, true);
|
||||
security_key_post_create_or_update(keyring, key, payload, plen, flags,
|
||||
true);
|
||||
|
||||
key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
|
||||
|
||||
@ -964,9 +963,8 @@ error:
|
||||
key_ref = __key_update(key_ref, &prep);
|
||||
|
||||
if (!IS_ERR(key_ref))
|
||||
ima_post_key_create_or_update(keyring, key,
|
||||
payload, plen,
|
||||
flags, false);
|
||||
security_key_post_create_or_update(keyring, key, payload, plen,
|
||||
flags, false);
|
||||
|
||||
goto error_free_prep;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3135,7 +3135,8 @@ static int selinux_inode_permission(struct inode *inode, int mask)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *iattr)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
|
@ -1238,12 +1238,14 @@ static int smack_inode_permission(struct inode *inode, int mask)
|
||||
|
||||
/**
|
||||
* smack_inode_setattr - Smack check for setting attributes
|
||||
* @idmap: idmap of the mount
|
||||
* @dentry: the object
|
||||
* @iattr: for the force flag
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
static int smack_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *iattr)
|
||||
{
|
||||
struct smk_audit_info ad;
|
||||
int rc;
|
||||
|
@ -122,6 +122,12 @@ TEST(correct_lsm_list_modules)
|
||||
case LSM_ID_LANDLOCK:
|
||||
name = "landlock";
|
||||
break;
|
||||
case LSM_ID_IMA:
|
||||
name = "ima";
|
||||
break;
|
||||
case LSM_ID_EVM:
|
||||
name = "evm";
|
||||
break;
|
||||
default:
|
||||
name = "INVALID";
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user