diff --git a/include/linux/ima.h b/include/linux/ima.h index f5683756f2b50a88049ddb0413710fd6fce20b76..d7b2864d7d7c2cbd611f095c818c2cefedac8ee6 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -37,6 +37,8 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size, extern void ima_post_path_mknod(struct dentry *dentry); extern int ima_file_hash(struct file *file, char *buf, size_t buf_size); extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size); +extern void ima_inode_free(struct inode *inode); +extern bool ima_is_root_namespace(void); #ifdef CONFIG_IMA_KEXEC extern void ima_add_kexec_buffer(struct kimage *image); @@ -128,6 +130,15 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size) } static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {} + +static inline void ima_inode_free(struct inode *inode) +{ +} + +static inline bool ima_is_root_namespace(void) +{ + return true; +} #endif /* CONFIG_IMA */ #ifndef CONFIG_IMA_KEXEC diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 33400ff051a848b05989b82753358451bfb4c53b..d407f798302001d807eec1c1527a949590567e05 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -362,6 +362,13 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) return -EPERM; + /* Allow only from the initial IMA namespace, so that the user can't + * spawn a new IMA namespace with the empty policy and circumvent the + * appraisal protection. + */ + if (!ima_is_root_namespace()) + return -EPERM; + /* Make sure we have a legal set of flags */ if (flags != (flags & KEXEC_FILE_FLAGS)) return -EINVAL; diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 8e181863565b29344320314e2ea01e32fc664b5f..1a1c1eebc01c0bff5bafe10f66fc821892c93693 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -44,15 +44,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 }; #define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0) -/* current content of the policy */ -extern int ima_policy_flag; - /* set during initialization */ extern int ima_hash_algo; extern int ima_sha1_idx __ro_after_init; extern int ima_hash_algo_idx __ro_after_init; extern int ima_extra_slots __ro_after_init; -extern int ima_appraise; extern struct tpm_chip *ima_tpm_chip; extern int ima_digest_list_pcr; extern bool ima_plus_standard_pcr; @@ -69,6 +65,8 @@ struct ima_policy_setup_data { int ima_appraise; bool ima_use_secure_boot; bool ima_use_appraise_tcb; + bool ima_use_appraise_exec_tcb; + bool ima_use_appraise_exec_immutable; }; /* IMA event related data */ @@ -402,6 +400,9 @@ struct ima_policy_data { int temp_ima_appraise; }; +extern struct list_head ima_ns_list; +extern struct rw_semaphore ima_ns_list_lock; + extern struct ima_policy_data init_policy_data; extern struct ima_policy_setup_data init_policy_setup_data; @@ -415,6 +416,9 @@ static inline struct ima_namespace *get_current_ns(void) { return current->nsproxy->ima_ns; } + +void ima_delete_ns_rules(struct ima_policy_data *policy_data, + bool is_root_ns); #else static inline int __init ima_init_namespace(void) { diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index b4347eac9c85eeba3a6ba70fa6fe281c2472cdf1..743b9337d9e573f9db8d2b69432e09d5b0ff93a9 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -212,7 +212,7 @@ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; - flags &= ima_policy_flag; + flags &= ima_ns->policy_data->ima_policy_flag; return ima_match_policy(inode, cred, secid, func, mask, flags, pcr, template_desc, keyring, ima_ns); diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 9213c012cbe45a3d1440a8c01d518a6c4459e88d..9d041e3deef2d1f572d201d8bc7620a368536b73 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -21,18 +21,10 @@ static bool ima_appraise_req_evm __ro_after_init; int ima_default_appraise_setup(const char *str, struct ima_policy_setup_data *setup_data) -{ - /* Currently unused. It will be implemented after namespacing ima - * policy, when global variables are removed. - */ - return 1; -} - -static int __init default_appraise_setup(char *str) { #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM bool sb_state = arch_ima_get_secureboot(); - int appraisal_state = ima_appraise; + int appraisal_state = setup_data->ima_appraise; if (strncmp(str, "off", 3) == 0) appraisal_state = 0; @@ -52,7 +44,7 @@ static int __init default_appraise_setup(char *str) pr_info("Secure boot enabled: ignoring ima_appraise=%s option", str); } else { - ima_appraise = appraisal_state; + setup_data->ima_appraise = appraisal_state; } #endif if (strcmp(str, "enforce-evm") == 0 || @@ -61,6 +53,11 @@ static int __init default_appraise_setup(char *str) return 1; } +static int __init default_appraise_setup(char *str) +{ + return ima_default_appraise_setup(str, &init_policy_setup_data); +} + __setup("ima_appraise=", default_appraise_setup); static bool ima_appraise_no_metadata __ro_after_init; @@ -87,7 +84,10 @@ __setup("ima_appraise_digest_list=", appraise_digest_list_setup); */ bool is_ima_appraise_enabled(const struct ima_namespace *ima_ns) { - return ima_appraise & IMA_APPRAISE_ENFORCE; + if (!ima_ns) + return false; + + return ima_ns->policy_data->ima_appraise & IMA_APPRAISE_ENFORCE; } /* @@ -95,18 +95,18 @@ bool is_ima_appraise_enabled(const struct ima_namespace *ima_ns) * * Return 1 to appraise or hash */ -int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func, - struct ima_namespace *ima_ns) +int ima_must_appraise(struct inode *inode, int mask, + enum ima_hooks func, struct ima_namespace *ima_ns) { u32 secid; - if (!ima_appraise) + if (!ima_ns->policy_data->ima_appraise) return 0; security_task_getsecid(current, &secid); return ima_match_policy(inode, current_cred(), secid, func, mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL, - NULL); + ima_ns); } static int ima_fix_xattr(struct dentry *dentry, @@ -352,7 +352,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, if ((rc == -EPERM) && (iint->flags & IMA_MEASURE)) process_buffer_measurement(NULL, digest, digestsize, "blacklisted-hash", NONE, - pcr, NULL, NULL); + pcr, NULL, ima_ns); } return rc; @@ -381,6 +381,7 @@ int ima_appraise_measurement(enum ima_hooks func, int rc = xattr_len, rc_evm; char _buf[sizeof(struct evm_ima_xattr_data) + 1 + SHA512_DIGEST_SIZE]; bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig; + struct ima_namespace *ima_ns = get_current_ns(); /* If not appraising a modsig, we need an xattr. */ if (!(inode->i_opflags & IOP_XATTR) && !try_modsig) @@ -509,7 +510,8 @@ int ima_appraise_measurement(enum ima_hooks func, op, cause, rc, 0); } else if (status != INTEGRITY_PASS) { /* Fix mode, but don't replace file signatures. */ - if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig && + if ((ima_ns->policy_data->ima_appraise & IMA_APPRAISE_FIX) && + !try_modsig && (!xattr_value || xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { if (!ima_fix_xattr(dentry, iint)) @@ -574,18 +576,30 @@ void ima_inode_post_setattr(struct dentry *dentry) struct inode *inode = d_backing_inode(dentry); struct integrity_iint_cache *iint; int action; + struct ima_namespace *ima_ns; - if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) - || !(inode->i_opflags & IOP_XATTR)) + if (!S_ISREG(inode->i_mode) || + !(inode->i_opflags & IOP_XATTR)) return; - action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR, NULL); - iint = integrity_iint_find(inode); - if (iint) { - set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); - if (!action) - clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); + down_read(&ima_ns_list_lock); + list_for_each_entry(ima_ns, &ima_ns_list, list) { + if (atomic_read(&ima_ns->inactive)) + continue; + if (!(ima_ns->policy_data->ima_policy_flag & IMA_APPRAISE)) + continue; + + action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR, + ima_ns); + iint = integrity_iint_rb_find(ima_ns->iint_tree, inode); + if (iint) { + set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); + if (!action) + clear_bit(IMA_UPDATE_XATTR, + &iint->atomic_flags); + } } + up_read(&ima_ns_list_lock); } /* @@ -607,19 +621,30 @@ 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_namespace *ima_ns; - if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)) + if (!S_ISREG(inode->i_mode)) return; - iint = integrity_iint_find(inode); - if (!iint) - return; - iint->measured_pcrs = 0; - set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags); - if (digsig) - set_bit(IMA_DIGSIG, &iint->atomic_flags); - else - clear_bit(IMA_DIGSIG, &iint->atomic_flags); + down_read(&ima_ns_list_lock); + list_for_each_entry(ima_ns, &ima_ns_list, list) { + if (atomic_read(&ima_ns->inactive)) + continue; + if (!(ima_ns->policy_data->ima_policy_flag & IMA_APPRAISE)) + continue; + + iint = integrity_iint_rb_find(ima_ns->iint_tree, inode); + if (!iint) + continue; + + iint->measured_pcrs = 0; + set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags); + if (digsig) + set_bit(IMA_DIGSIG, &iint->atomic_flags); + else + clear_bit(IMA_DIGSIG, &iint->atomic_flags); + } + up_read(&ima_ns_list_lock); } int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c index 58aa56b0422d3e537732a42e590ba11ae16fc859..b3330a0a1481487df24a5d2cbc3bca05b4bcd2dc 100644 --- a/security/integrity/ima/ima_asymmetric_keys.c +++ b/security/integrity/ima/ima_asymmetric_keys.c @@ -29,6 +29,16 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, unsigned long flags, bool create) { bool queued = false; + /* Measure the keys according to the current ima namespace's policy + * rules. If the new ima namespace with empty policy is created to hide + * the log, parent can join it to inspect the log until the child + * namespace exists. After its destruction, log can be accessed only + * by the processes from the initial ima namespace that see all + * measurement list entries. If this is a problem, maybe the solution + * is to track in which namespaces the key was measured and re-measure + * it when necessary. + */ + struct ima_namespace *ima_ns = get_current_ns(); /* Only asymmetric keys are handled by this hook. */ if (key->type != &key_type_asymmetric) @@ -60,6 +70,5 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, */ process_buffer_measurement(NULL, payload, payload_len, keyring->description, KEY_CHECK, 0, - keyring->description, - NULL); + keyring->description, ima_ns); } diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c index 4759f0435b29d197a9940c6ac7f20a44fd33bee5..74b08c3a3c815b430651f2c761e3d57cdbfbb2ea 100644 --- a/security/integrity/ima/ima_digest_list.c +++ b/security/integrity/ima/ima_digest_list.c @@ -167,7 +167,7 @@ int ima_parse_compact_list(loff_t size, void *buf, int op) size_t digest_len; int ret = 0, i; - if (!(ima_digest_list_actions & ima_policy_flag)) + if (!(ima_digest_list_actions & init_policy_data.ima_policy_flag)) return -EACCES; while (bufp < bufendp) { @@ -383,7 +383,7 @@ void __init ima_load_digest_lists(void) .ctx.actor = load_digest_list, }; - if (!(ima_digest_list_actions & ima_policy_flag)) + if (!(ima_digest_list_actions & init_policy_data.ima_policy_flag)) return; ret = kern_path(CONFIG_IMA_DIGEST_LISTS_DIR, 0, &path); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 8c45e404351e2b6d9faf7ff37c9930968644cc97..2ae4adfbaa8246dca9d5185952233be8d43cfbf0 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -365,6 +365,7 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf, ssize_t result; struct dentry *dentry = file_dentry(file); int i; + struct ima_namespace *ima_ns = get_current_ns(); /* No partial writes. */ result = -EINVAL; @@ -400,7 +401,7 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf, if (data[0] == '/') { result = ima_read_sfs_file(data, dentry); } else if (dentry == ima_policy) { - if (ima_appraise & IMA_APPRAISE_POLICY) { + if (ima_ns->policy_data->ima_appraise & IMA_APPRAISE_POLICY) { pr_err("signed policy file (specified " "as an absolute pathname) required\n"); integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, @@ -515,6 +516,7 @@ static int ima_release_data_upload(struct inode *inode, struct file *file) struct dentry *dentry = file_dentry(file); const char *cause = valid_policy ? "completed" : "failed"; enum ima_fs_flags flag = ima_get_dentry_flag(dentry); + struct ima_namespace *ima_ns = get_current_ns(); if ((file->f_flags & O_ACCMODE) == O_RDONLY) return seq_release(inode, file); @@ -527,7 +529,7 @@ static int ima_release_data_upload(struct inode *inode, struct file *file) return 0; } - if (valid_policy && ima_check_policy(NULL) < 0) { + if (valid_policy && ima_check_policy(ima_ns) < 0) { cause = "failed"; valid_policy = 0; } diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 3b8839b97a985dbb52a7e7389c186dfff5d936cc..dea0251142fd5b41c1733378309ca4d50a434aae 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -118,15 +118,16 @@ static int __init ima_add_boot_aggregate(void) #ifdef CONFIG_IMA_LOAD_X509 void __init ima_load_x509(void) { - int unset_flags = ima_policy_flag & IMA_APPRAISE; + int unset_flags = + init_ima_ns.policy_data->ima_policy_flag & IMA_APPRAISE; - ima_policy_flag &= ~unset_flags; + init_ima_ns.policy_data->ima_policy_flag &= ~unset_flags; integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH); /* load also EVM key to avoid appraisal */ evm_load_x509(); - ima_policy_flag |= unset_flags; + init_ima_ns.policy_data->ima_policy_flag |= unset_flags; } #endif diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 422b253006fb7fdd9088054f95e9508fa9cbb9f7..e0460462193d73f8f49f6d3d34f74e3955a9f0c4 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -30,12 +30,6 @@ #include "ima.h" #include "ima_digest_list.h" -#ifdef CONFIG_IMA_APPRAISE -int ima_appraise = IMA_APPRAISE_ENFORCE; -#else -int ima_appraise; -#endif - int ima_hash_algo = HASH_ALGO_SHA1; /* Actions (measure/appraisal) for which digest lists can be used */ @@ -134,7 +128,8 @@ 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 = integrity_iint_rb_find(ima_ns->iint_tree, + inode); /* IMA_MEASURE is set from reader side */ if (iint && test_bit(IMA_MUST_MEASURE, &iint->atomic_flags)) @@ -214,11 +209,38 @@ static int ima_read_xattr(struct dentry *dentry, return ret; } +static void ima_check_active_ns(struct ima_namespace *current_ima_ns, + struct inode *inode) +{ + struct ima_namespace *ima_ns; + struct integrity_iint_cache *iint; + + down_read(&ima_ns_list_lock); + list_for_each_entry(ima_ns, &ima_ns_list, list) { + if (atomic_read(&ima_ns->inactive)) + continue; + if ((ima_ns == current_ima_ns) || + !ima_ns->policy_data->ima_policy_flag) + continue; + + iint = integrity_iint_rb_find(ima_ns->iint_tree, inode); + if (!iint) + continue; + + mutex_lock(&iint->mutex); + iint->flags &= ~IMA_DONE_MASK; + iint->measured_pcrs = 0; + mutex_unlock(&iint->mutex); + } + up_read(&ima_ns_list_lock); +} + static void ima_check_last_writer(struct integrity_iint_cache *iint, struct inode *inode, struct file *file) { fmode_t mode = file->f_mode; bool update; + struct ima_namespace *ima_ns = (struct ima_namespace *)file->f_ima; if (!(mode & FMODE_WRITE)) return; @@ -232,6 +254,9 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint, (iint->flags & IMA_NEW_FILE)) { iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE); iint->measured_pcrs = 0; + + ima_check_active_ns(ima_ns, inode); + if (update) ima_update_xattr(iint, file); } @@ -281,10 +306,10 @@ void ima_file_free(struct file *file) if (unlikely(!(file->f_mode & FMODE_OPENED))) goto out; - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ima_ns->policy_data->ima_policy_flag || !S_ISREG(inode->i_mode)) goto out; - iint = integrity_iint_find(inode); + iint = integrity_iint_rb_find(ima_ns->iint_tree, inode); if (!iint) goto out; @@ -293,10 +318,10 @@ void ima_file_free(struct file *file) put_ima_ns(ima_ns); } -static int process_measurement(struct file *file, const struct cred *cred, - u32 secid, char *buf, loff_t size, int mask, - enum ima_hooks func, - struct ima_namespace *ima_ns) +static int process_ns_measurement(struct file *file, const struct cred *cred, + u32 secid, char *buf, loff_t size, int mask, + enum ima_hooks func, + struct ima_namespace *ima_ns) { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; @@ -312,8 +337,9 @@ static int process_measurement(struct file *file, const struct cred *cred, int xattr_len = 0; bool violation_check; enum hash_algo hash_algo; + struct ima_namespace *current_ima_ns = get_current_ns(); - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ima_ns->policy_data->ima_policy_flag) return 0; /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action @@ -323,7 +349,8 @@ static int process_measurement(struct file *file, const struct cred *cred, action = ima_get_action(inode, cred, secid, mask, func, &pcr, &template_desc, NULL, ima_ns); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) && - (ima_policy_flag & IMA_MEASURE)); + (ima_ns->policy_data->ima_policy_flag & + IMA_MEASURE)); if (!action && !violation_check) return 0; @@ -336,7 +363,7 @@ static int process_measurement(struct file *file, const struct cred *cred, inode_lock(inode); if (action) { - iint = integrity_inode_get(inode); + iint = integrity_inode_rb_get(ima_ns->iint_tree, inode); if (!iint) rc = -ENOMEM; } @@ -351,6 +378,8 @@ static int process_measurement(struct file *file, const struct cred *cred, goto out; if (!action) goto out; + if (ima_ns != current_ima_ns) + goto out; mutex_lock(&iint->mutex); @@ -478,7 +507,8 @@ static int process_measurement(struct file *file, const struct cred *cred, if (pathbuf) __putname(pathbuf); if (must_appraise) { - if (rc && (ima_appraise & IMA_APPRAISE_ENFORCE)) + if (rc && + (ima_ns->policy_data->ima_appraise & IMA_APPRAISE_ENFORCE)) return -EACCES; if (file->f_mode & FMODE_WRITE) set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); @@ -486,6 +516,32 @@ static int process_measurement(struct file *file, const struct cred *cred, return 0; } +static int process_measurement(struct file *file, const struct cred *cred, + u32 secid, char *buf, loff_t size, int mask, + enum ima_hooks func) +{ + int ret; + struct ima_namespace *ima_ns; + struct inode *inode = file_inode(file); + + if (!S_ISREG(inode->i_mode)) + return 0; + + down_read(&ima_ns_list_lock); + list_for_each_entry(ima_ns, &ima_ns_list, list) { + if (atomic_read(&ima_ns->inactive)) + continue; + + ret = process_ns_measurement(file, cred, secid, buf, size, mask, + func, ima_ns); + if (ret != 0) + break; + } + up_read(&ima_ns_list_lock); + + return ret; +} + /** * ima_file_mmap - based on policy, collect/store measurement. * @file: pointer to the file to be measured (May be NULL) @@ -504,7 +560,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) if (file && (prot & PROT_EXEC)) { security_task_getsecid(current, &secid); return process_measurement(file, current_cred(), secid, NULL, - 0, MAY_EXEC, MMAP_CHECK, NULL); + 0, MAY_EXEC, MMAP_CHECK); } return 0; @@ -524,6 +580,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) */ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) { + struct ima_namespace *ima_ns = get_current_ns(); struct ima_template_desc *template; struct file *file = vma->vm_file; char filename[NAME_MAX]; @@ -536,14 +593,15 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) int pcr; /* Is mprotect making an mmap'ed file executable? */ - if (!(ima_policy_flag & IMA_APPRAISE) || !vma->vm_file || - !(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC)) + if (!(ima_ns->policy_data->ima_policy_flag & IMA_APPRAISE) || + !vma->vm_file || !(prot & PROT_EXEC) || + (vma->vm_flags & VM_EXEC)) return 0; security_task_getsecid(current, &secid); inode = file_inode(vma->vm_file); action = ima_get_action(inode, current_cred(), secid, MAY_EXEC, - MMAP_CHECK, &pcr, &template, 0, NULL); + MMAP_CHECK, &pcr, &template, 0, ima_ns); /* Is the mmap'ed file in policy? */ if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK))) @@ -582,13 +640,13 @@ int ima_bprm_check(struct linux_binprm *bprm) security_task_getsecid(current, &secid); ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0, - MAY_EXEC, BPRM_CHECK, NULL); + MAY_EXEC, BPRM_CHECK); if (ret) return ret; security_cred_getsecid(bprm->cred, &secid); return process_measurement(bprm->file, bprm->cred, secid, NULL, 0, - MAY_EXEC, CREDS_CHECK, NULL); + MAY_EXEC, CREDS_CHECK); } /** @@ -609,7 +667,7 @@ int ima_file_check(struct file *file, int mask) security_task_getsecid(current, &secid); rc = process_measurement(file, current_cred(), secid, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | - MAY_APPEND), FILE_CHECK, NULL); + MAY_APPEND), FILE_CHECK); if (ima_current_is_parser() && !rc) ima_check_measured_appraised(file); return rc; @@ -618,7 +676,7 @@ EXPORT_SYMBOL_GPL(ima_file_check); /** * ima_file_hash - return the stored measurement if a file has been hashed and - * is in the iint cache. + * is in the iint cache of the current IMA namespace. * @file: pointer to the file * @buf: buffer in which to store the hash * @buf_size: length of the buffer @@ -636,6 +694,7 @@ EXPORT_SYMBOL_GPL(ima_file_check); */ int ima_file_hash(struct file *file, char *buf, size_t buf_size) { + struct ima_namespace *ima_ns = get_current_ns(); struct inode *inode; struct integrity_iint_cache *iint; int hash_algo; @@ -643,11 +702,11 @@ int ima_file_hash(struct file *file, char *buf, size_t buf_size) if (!file) return -EINVAL; - if (!ima_policy_flag) + if (!ima_ns->policy_data->ima_policy_flag) return -EOPNOTSUPP; inode = file_inode(file); - iint = integrity_iint_find(inode); + iint = integrity_iint_rb_find(ima_ns->iint_tree, inode); if (!iint) return -EOPNOTSUPP; @@ -685,21 +744,30 @@ EXPORT_SYMBOL_GPL(ima_file_hash); */ void ima_post_create_tmpfile(struct inode *inode) { + struct ima_namespace *ima_ns; struct integrity_iint_cache *iint; int must_appraise; - must_appraise = ima_must_appraise(inode, MAY_ACCESS, FILE_CHECK, NULL); - if (!must_appraise) - return; + down_read(&ima_ns_list_lock); + list_for_each_entry(ima_ns, &ima_ns_list, list) { + if (atomic_read(&ima_ns->inactive)) + continue; - /* Nothing to do if we can't allocate memory */ - iint = integrity_inode_get(inode); - if (!iint) - return; + must_appraise = ima_must_appraise(inode, MAY_ACCESS, + FILE_CHECK, ima_ns); + if (!must_appraise) + continue; + + /* Nothing to do if we can't allocate memory */ + iint = integrity_inode_rb_get(ima_ns->iint_tree, inode); + if (!iint) + continue; - /* needed for writing the security xattrs */ - set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); - iint->ima_file_status = INTEGRITY_PASS; + /* needed for writing the security xattrs */ + set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); + iint->ima_file_status = INTEGRITY_PASS; + } + up_read(&ima_ns_list_lock); } /** @@ -711,21 +779,30 @@ void ima_post_create_tmpfile(struct inode *inode) */ void ima_post_path_mknod(struct dentry *dentry) { + struct ima_namespace *ima_ns; struct integrity_iint_cache *iint; struct inode *inode = dentry->d_inode; int must_appraise; - must_appraise = ima_must_appraise(inode, MAY_ACCESS, FILE_CHECK, NULL); - if (!must_appraise) - return; + down_read(&ima_ns_list_lock); + list_for_each_entry(ima_ns, &ima_ns_list, list) { + if (atomic_read(&ima_ns->inactive)) + continue; - /* Nothing to do if we can't allocate memory */ - iint = integrity_inode_get(inode); - if (!iint) - return; + must_appraise = ima_must_appraise(inode, MAY_ACCESS, + FILE_CHECK, ima_ns); + if (!must_appraise) + continue; - /* needed for re-opening empty files */ - iint->flags |= IMA_NEW_FILE; + /* Nothing to do if we can't allocate memory */ + iint = integrity_inode_rb_get(ima_ns->iint_tree, inode); + if (!iint) + continue; + + /* needed for re-opening empty files */ + iint->flags |= IMA_NEW_FILE; + } + up_read(&ima_ns_list_lock); } /** @@ -766,7 +843,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id, func = read_idmap[read_id] ?: FILE_CHECK; security_task_getsecid(current, &secid); return process_measurement(file, current_cred(), secid, NULL, - 0, MAY_READ, func, NULL); + 0, MAY_READ, func); } const int read_idmap[READING_MAX_ID] = { @@ -796,13 +873,14 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, { enum ima_hooks func; u32 secid; + struct ima_namespace *ima_ns = get_current_ns(); /* permit signed certs */ if (!file && read_id == READING_X509_CERTIFICATE) return 0; if (!file || !buf || size == 0) { /* should never happen */ - if (ima_appraise & IMA_APPRAISE_ENFORCE) + if (ima_ns->policy_data->ima_appraise & IMA_APPRAISE_ENFORCE) return -EACCES; return 0; } @@ -810,7 +888,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, func = read_idmap[read_id] ?: FILE_CHECK; security_task_getsecid(current, &secid); return process_measurement(file, current_cred(), secid, buf, size, - MAY_READ, func, NULL); + MAY_READ, func); } /** @@ -828,9 +906,16 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, int ima_load_data(enum kernel_load_data_id id, bool contents) { bool ima_enforce, sig_enforce; + struct ima_namespace *ima_ns = get_current_ns(); + + if (ima_ns != &init_ima_ns) { + pr_err("Prevent data loading in IMA namespaces other than the root\n"); + return -EACCES; + } ima_enforce = - (ima_appraise & IMA_APPRAISE_ENFORCE) == IMA_APPRAISE_ENFORCE; + (ima_ns->policy_data->ima_appraise & IMA_APPRAISE_ENFORCE) == + IMA_APPRAISE_ENFORCE; switch (id) { case LOADING_KEXEC_IMAGE: @@ -840,13 +925,16 @@ int ima_load_data(enum kernel_load_data_id id, bool contents) return -EACCES; } - if (ima_enforce && (ima_appraise & IMA_APPRAISE_KEXEC)) { + if (ima_enforce && + (ima_ns->policy_data->ima_appraise & IMA_APPRAISE_KEXEC)) { pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */ } break; case LOADING_FIRMWARE: - if (ima_enforce && (ima_appraise & IMA_APPRAISE_FIRMWARE) && !contents) { + if (ima_enforce && + (ima_ns->policy_data->ima_appraise & + IMA_APPRAISE_FIRMWARE) && !contents) { pr_err("Prevent firmware sysfs fallback loading.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */ } @@ -854,8 +942,10 @@ int ima_load_data(enum kernel_load_data_id id, bool contents) case LOADING_MODULE: sig_enforce = is_module_sig_enforced(); - if (ima_enforce && (!sig_enforce - && (ima_appraise & IMA_APPRAISE_MODULES))) { + if (ima_enforce && + (!sig_enforce && + (ima_ns->policy_data->ima_appraise & + IMA_APPRAISE_MODULES))) { pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n"); return -EACCES; /* INTEGRITY_UNKNOWN */ } @@ -882,9 +972,14 @@ int ima_post_load_data(char *buf, loff_t size, enum kernel_load_data_id load_id, char *description) { + struct ima_namespace *ima_ns = get_current_ns(); + if (load_id == LOADING_FIRMWARE) { - if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && - (ima_appraise & IMA_APPRAISE_ENFORCE)) { + if (WARN_ON(ima_ns != &init_ima_ns)) + return -EACCES; + + if ((ima_ns->policy_data->ima_appraise & IMA_APPRAISE_FIRMWARE) && + (ima_ns->policy_data->ima_appraise & IMA_APPRAISE_ENFORCE)) { pr_err("Prevent firmware loading_store.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */ } @@ -903,6 +998,7 @@ int ima_post_load_data(char *buf, loff_t size, * @func: IMA hook * @pcr: pcr to extend the measurement * @keyring: keyring name to determine the action to be performed + * @ima_ns: pointer to the IMA namespace in consideration * * Based on policy, the buffer is measured into the ima log. */ @@ -928,7 +1024,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size, int action = 0; u32 secid; - if (!ima_policy_flag) + if (!ima_ns->policy_data->ima_policy_flag) return; /* @@ -941,7 +1037,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size, if (func) { security_task_getsecid(current, &secid); action = ima_get_action(inode, current_cred(), secid, 0, func, - &pcr, &template, keyring, NULL); + &pcr, &template, keyring, ima_ns); if (!(action & IMA_MEASURE)) return; } @@ -1004,6 +1100,11 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size, void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) { struct fd f; + struct ima_namespace *ima_ns = get_current_ns(); + + /* Currently allowed only from the root IMA namespace */ + if (WARN_ON(ima_ns != &init_ima_ns)) + return; if (!buf || !size) return; @@ -1014,10 +1115,31 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) process_buffer_measurement(file_inode(f.file), buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0, NULL, - NULL); + ima_ns); fdput(f); } +void ima_inode_free(struct inode *inode) +{ + struct ima_namespace *ima_ns; + + if (!IS_IMA(inode)) + return; + + down_read(&ima_ns_list_lock); + list_for_each_entry(ima_ns, &ima_ns_list, list) { + if (atomic_read(&ima_ns->inactive)) + continue; + integrity_inode_rb_free(ima_ns->iint_tree, inode); + } + up_read(&ima_ns_list_lock); +} + +bool ima_is_root_namespace(void) +{ + return get_current_ns() == &init_ima_ns; +} + static int __init init_ima(void) { int error; diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c index 226a53279f7195b0276c505ea0a1b312f1cf4af1..04aa50473971ccd9d4ed46f40ff2e8510a3bbe7f 100644 --- a/security/integrity/ima/ima_ns.c +++ b/security/integrity/ima/ima_ns.c @@ -181,11 +181,14 @@ int __init ima_init_namespace(void) static void destroy_ima_ns(struct ima_namespace *ns) { + bool is_init_ns = (ns == &init_ima_ns); + dec_ima_namespaces(ns->ucounts); put_user_ns(ns->user_ns); ns_free_inum(&ns->ns); integrity_iint_tree_free(ns->iint_tree); kfree(ns->iint_tree); + ima_delete_ns_rules(ns->policy_data, is_init_ns); kfree(ns->policy_data); kfree(ns); } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index ebb4721032d41d0369d55c013b9d370a8f4ebf89..0ab91cb31121a4c69a3f525cf260a81b44170c83 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -49,8 +49,6 @@ #define INVALID_PCR(a) (((a) < 0) || \ (a) >= (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8)) -int ima_policy_flag; -static int temp_ima_appraise; static int build_ima_appraise __ro_after_init; #define MAX_LSM_RULES 6 @@ -225,16 +223,11 @@ static struct ima_rule_entry ima_parser_appraise_rule __ro_after_init = { .flags = IMA_PARSER | IMA_DIGSIG_REQUIRED }; +/* Number of architecture specific rules found */ +static int arch_entries_size __ro_after_init; /* An array of architecture specific rules */ static struct ima_rule_entry *arch_policy_entry __ro_after_init; -static LIST_HEAD(ima_default_rules); -static LIST_HEAD(ima_policy_rules); -static LIST_HEAD(ima_temp_rules); -static struct list_head *ima_rules = &ima_default_rules; - -static int ima_policy __initdata; - struct ima_policy_setup_data init_policy_setup_data = { #ifdef CONFIG_IMA_APPRAISE .ima_appraise = IMA_APPRAISE_ENFORCE, @@ -244,31 +237,25 @@ struct ima_policy_data init_policy_data = { .ima_default_rules = LIST_HEAD_INIT(init_policy_data.ima_default_rules), .ima_policy_rules = LIST_HEAD_INIT(init_policy_data.ima_policy_rules), .ima_temp_rules = LIST_HEAD_INIT(init_policy_data.ima_temp_rules), + .ima_rules = &init_policy_data.ima_default_rules, }; int ima_default_measure_policy_setup(const char *str, struct ima_policy_setup_data *setup_data) { - /* Currently unused. It will be implemented after namespacing ima - * policy, when global variables are removed. - */ + if (setup_data->ima_policy) + return 1; + + setup_data->ima_policy = ORIGINAL_TCB; return 1; } static int __init default_measure_policy_setup(char *str) { - if (ima_policy) - return 1; - - ima_policy = ORIGINAL_TCB; - return 1; + return ima_default_measure_policy_setup(str, &init_policy_setup_data); } __setup("ima_tcb", default_measure_policy_setup); -static bool ima_use_appraise_tcb __initdata; -static bool ima_use_appraise_exec_tcb __initdata; -static bool ima_use_appraise_exec_immutable __initdata; -static bool ima_use_secure_boot __initdata; static bool ima_fail_unverifiable_sigs __ro_after_init; /** @@ -276,61 +263,55 @@ static bool ima_fail_unverifiable_sigs __ro_after_init; * @str: string to be parsed * @setup_data: pointer to a structure where parsed data is stored * @fail_unverifiable_sigs: boolean flag treated separately to preserve - * __ro_after_init + * __ro_after_init */ int ima_policy_setup(char *str, struct ima_policy_setup_data *setup_data, bool *fail_unverifiable_sigs) -{ - - /* Currently unused. It will be implemented after namespacing ima - * policy, when global variables are removed. - */ - return 1; -} - -static int __init policy_setup(char *str) { char *p; while ((p = strsep(&str, " |\n")) != NULL) { if (*p == ' ') continue; - if ((strcmp(p, "tcb") == 0) && !ima_policy) - ima_policy = DEFAULT_TCB; - else if ((strcmp(p, "exec_tcb") == 0) && !ima_policy) - ima_policy = EXEC_TCB; + if ((strcmp(p, "tcb") == 0) && !setup_data->ima_policy) + setup_data->ima_policy = DEFAULT_TCB; + else if ((strcmp(p, "exec_tcb") == 0) && !setup_data->ima_policy) + setup_data->ima_policy = EXEC_TCB; else if (strcmp(p, "appraise_tcb") == 0) - ima_use_appraise_tcb = true; + setup_data->ima_use_appraise_tcb = true; else if (strcmp(p, "appraise_exec_tcb") == 0) - ima_use_appraise_exec_tcb = true; + setup_data->ima_use_appraise_exec_tcb = true; else if (strcmp(p, "appraise_exec_immutable") == 0) - ima_use_appraise_exec_immutable = true; + setup_data->ima_use_appraise_exec_immutable = true; else if (strcmp(p, "secure_boot") == 0) - ima_use_secure_boot = true; + setup_data->ima_use_secure_boot = true; else if (strcmp(p, "fail_securely") == 0) - ima_fail_unverifiable_sigs = true; + *fail_unverifiable_sigs = true; else pr_err("policy \"%s\" not found", p); } return 1; } + +static int __init policy_setup(char *str) +{ + return ima_policy_setup(str, &init_policy_setup_data, + &ima_fail_unverifiable_sigs); +} __setup("ima_policy=", policy_setup); int ima_default_appraise_policy_setup(const char *str, struct ima_policy_setup_data *setup_data) { - /* Currently unused. It will be implemented after namespacing ima - * policy, when global variables are removed. - */ + setup_data->ima_use_appraise_tcb = true; return 1; } static int __init default_appraise_policy_setup(char *str) { - ima_use_appraise_tcb = true; - return 1; + return ima_default_appraise_policy_setup(str, &init_policy_setup_data); } __setup("ima_appraise_tcb", default_appraise_policy_setup); @@ -505,9 +486,11 @@ static bool ima_rule_contains_lsm_cond(struct ima_rule_entry *entry) static void ima_lsm_update_rules(void) { struct ima_rule_entry *entry, *e; + struct ima_namespace *ima_ns = get_current_ns(); int result; - list_for_each_entry_safe(entry, e, &ima_policy_rules, list) { + list_for_each_entry_safe(entry, e, + &ima_ns->policy_data->ima_policy_rules, list) { if (!ima_rule_contains_lsm_cond(entry)) continue; @@ -709,12 +692,13 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, { struct ima_rule_entry *entry; int action = 0, actmask = flags | (flags << 1); + bool fail_unverifiable_sigs; if (template_desc) *template_desc = ima_template_desc_current(); rcu_read_lock(); - list_for_each_entry_rcu(entry, ima_rules, list) { + list_for_each_entry_rcu(entry, ima_ns->policy_data->ima_rules, list) { if (!(entry->action & actmask)) continue; @@ -729,7 +713,10 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, if (entry->action & IMA_APPRAISE) { action |= get_subaction(entry, func); action &= ~IMA_HASH; - if (ima_fail_unverifiable_sigs) + fail_unverifiable_sigs = (ima_ns == &init_ima_ns) ? + ima_fail_unverifiable_sigs : + ima_ns->policy_data->ima_fail_unverifiable_sigs; + if (fail_unverifiable_sigs) action |= IMA_FAIL_UNVERIFIABLE_SIGS; } @@ -764,14 +751,15 @@ void ima_update_policy_flag(struct ima_namespace *ima_ns) { struct ima_rule_entry *entry; - list_for_each_entry(entry, ima_rules, list) { + list_for_each_entry(entry, ima_ns->policy_data->ima_rules, list) { if (entry->action & IMA_DO_MASK) - ima_policy_flag |= entry->action; + ima_ns->policy_data->ima_policy_flag |= entry->action; } - ima_appraise |= (build_ima_appraise | temp_ima_appraise); - if (!ima_appraise) - ima_policy_flag &= ~IMA_APPRAISE; + ima_ns->policy_data->ima_appraise |= + (build_ima_appraise | ima_ns->policy_data->temp_ima_appraise); + if (!ima_ns->policy_data->ima_appraise) + ima_ns->policy_data->ima_policy_flag &= ~IMA_APPRAISE; } static int ima_appraise_flag(enum ima_hooks func) @@ -789,16 +777,17 @@ static int ima_appraise_flag(enum ima_hooks func) return 0; } -static void __init add_rules(struct ima_policy_data *policy_data, - struct ima_rule_entry *entries, int count, - enum policy_rule_list policy_rule) +static void add_rules(struct ima_namespace *ima_ns, + struct ima_rule_entry *entries, int count, + enum policy_rule_list policy_rule, + const struct ima_policy_setup_data *setup_data) { int i = 0; for (i = 0; i < count; i++) { struct ima_rule_entry *entry; - if (ima_policy == EXEC_TCB) { + if (setup_data->ima_policy == EXEC_TCB) { if (entries == dont_measure_rules) if ((entries[i].flags & IMA_FSMAGIC) && entries[i].fsmagic == TMPFS_MAGIC) @@ -810,7 +799,7 @@ static void __init add_rules(struct ima_policy_data *policy_data, continue; } - if (ima_use_appraise_exec_tcb) { + if (setup_data->ima_use_appraise_exec_tcb) { if (entries == default_appraise_rules) { if (entries[i].action != DONT_APPRAISE) continue; @@ -820,14 +809,24 @@ static void __init add_rules(struct ima_policy_data *policy_data, } } - if (ima_use_appraise_exec_immutable) + if (setup_data->ima_use_appraise_exec_immutable) if (entries == appraise_exec_rules && (entries[i].flags & IMA_FUNC) && entries[i].func == BPRM_CHECK) entries[i].flags |= IMA_META_IMMUTABLE_REQUIRED; - if (policy_rule & IMA_DEFAULT_POLICY) - list_add_tail(&entries[i].list, &ima_default_rules); + if (policy_rule & IMA_DEFAULT_POLICY) { + entry = &entries[i]; + if (ima_ns != &init_ima_ns) { + entry = kmemdup(&entries[i], sizeof(*entry), + GFP_KERNEL); + if (!entry) + continue; + } + + list_add_tail(&entry->list, + &ima_ns->policy_data->ima_default_rules); + } if (policy_rule & IMA_CUSTOM_POLICY) { entry = kmemdup(&entries[i], sizeof(*entry), @@ -835,11 +834,12 @@ static void __init add_rules(struct ima_policy_data *policy_data, if (!entry) continue; - list_add_tail(&entry->list, &ima_policy_rules); + list_add_tail(&entry->list, + &ima_ns->policy_data->ima_policy_rules); } if (entries[i].action == APPRAISE) { if (entries != build_appraise_rules) - temp_ima_appraise |= + ima_ns->policy_data->temp_ima_appraise |= ima_appraise_flag(entries[i].func); else build_ima_appraise |= @@ -850,7 +850,7 @@ static void __init add_rules(struct ima_policy_data *policy_data, static int ima_parse_rule(char *rule, struct ima_rule_entry *entry); -static int __init ima_init_arch_policy(void) +static int ima_init_arch_policy(void) { const char * const *arch_rules; const char * const *rules; @@ -899,69 +899,71 @@ static int __init ima_init_arch_policy(void) void ima_init_ns_policy(struct ima_namespace *ima_ns, const struct ima_policy_setup_data *setup_data) { - /* Set policy rules to the empty set of default rules. The rest will be - * implemented after namespacing policy. - */ - ima_ns->policy_data->ima_rules = - &ima_ns->policy_data->ima_default_rules; -} + int build_appraise_entries; -/** - * ima_init_policy - initialize the default measure rules. - * - * ima_rules points to either the ima_default_rules or the - * the new ima_policy_rules. - */ -void __init ima_init_policy(void) -{ - int build_appraise_entries, arch_entries; + ima_ns->policy_data->ima_appraise = setup_data->ima_appraise; + + if (ima_ns == &init_ima_ns) { + /* + * Based on runtime secure boot flags, insert arch specific + * measurement and appraise rules requiring file signatures for + * both the initial and custom policies, prior to other + * appraise rules. (Highest priority) + */ + arch_entries_size = ima_init_arch_policy(); + if (!arch_entries_size) + pr_info("No architecture policies found\n"); + + ima_ns->policy_data->ima_fail_unverifiable_sigs = + ima_fail_unverifiable_sigs; + } /* if !ima_policy, we load NO default rules */ - if (ima_policy) - add_rules(NULL, - dont_measure_rules, ARRAY_SIZE(dont_measure_rules), - IMA_DEFAULT_POLICY); + if (setup_data->ima_policy) + add_rules(ima_ns, dont_measure_rules, + ARRAY_SIZE(dont_measure_rules), + IMA_DEFAULT_POLICY, + setup_data); - switch (ima_policy) { + switch (setup_data->ima_policy) { case ORIGINAL_TCB: - add_rules(NULL, original_measurement_rules, + add_rules(ima_ns, original_measurement_rules, ARRAY_SIZE(original_measurement_rules), - IMA_DEFAULT_POLICY); + IMA_DEFAULT_POLICY, + setup_data); break; case EXEC_TCB: fallthrough; case DEFAULT_TCB: - add_rules(NULL, default_measurement_rules, + add_rules(ima_ns, default_measurement_rules, ARRAY_SIZE(default_measurement_rules), - IMA_DEFAULT_POLICY); + IMA_DEFAULT_POLICY, + setup_data); default: break; } - if (ima_policy) - add_rules(NULL, &ima_parser_measure_rule, 1, IMA_DEFAULT_POLICY); + if (setup_data->ima_policy) + add_rules(ima_ns, &ima_parser_measure_rule, 1, IMA_DEFAULT_POLICY, + setup_data); - /* - * Based on runtime secure boot flags, insert arch specific measurement - * and appraise rules requiring file signatures for both the initial - * and custom policies, prior to other appraise rules. - * (Highest priority) - */ - arch_entries = ima_init_arch_policy(); - if (!arch_entries) - pr_info("No architecture policies found\n"); - else - add_rules(NULL, arch_policy_entry, arch_entries, - IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); + if (arch_entries_size) + add_rules(ima_ns, + arch_policy_entry, + arch_entries_size, + IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY, + setup_data); /* * Insert the builtin "secure_boot" policy rules requiring file * signatures, prior to other appraise rules. */ - if (ima_use_secure_boot || ima_use_appraise_exec_tcb) - add_rules(NULL, - secure_boot_rules, ARRAY_SIZE(secure_boot_rules), - IMA_DEFAULT_POLICY); + if (setup_data->ima_use_secure_boot || + setup_data->ima_use_appraise_exec_tcb) + add_rules(ima_ns, secure_boot_rules, + ARRAY_SIZE(secure_boot_rules), + IMA_DEFAULT_POLICY, + setup_data); /* * Insert the build time appraise rules requiring file signatures @@ -970,38 +972,53 @@ void __init ima_init_policy(void) * rules, include either one or the other set of rules, but not both. */ build_appraise_entries = ARRAY_SIZE(build_appraise_rules); - if (build_appraise_entries) { - if (ima_use_secure_boot) - add_rules(NULL, - build_appraise_rules, build_appraise_entries, - IMA_CUSTOM_POLICY); + if (build_appraise_entries && (ima_ns == &init_ima_ns)) { + if (setup_data->ima_use_secure_boot) + add_rules(ima_ns, build_appraise_rules, + build_appraise_entries, + IMA_CUSTOM_POLICY, + setup_data); else - add_rules(NULL, - build_appraise_rules, build_appraise_entries, - IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); + add_rules(ima_ns, build_appraise_rules, + build_appraise_entries, + IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY, + setup_data); } - if (ima_use_appraise_tcb || ima_use_appraise_exec_tcb) - add_rules(NULL, default_appraise_rules, + if (setup_data->ima_use_appraise_tcb || + setup_data->ima_use_appraise_exec_tcb) + add_rules(ima_ns, default_appraise_rules, ARRAY_SIZE(default_appraise_rules), - IMA_DEFAULT_POLICY); + IMA_DEFAULT_POLICY, setup_data); - if (ima_use_appraise_exec_tcb) - add_rules(NULL, appraise_exec_rules, + if (setup_data->ima_use_appraise_exec_tcb) + add_rules(ima_ns, appraise_exec_rules, ARRAY_SIZE(appraise_exec_rules), - IMA_DEFAULT_POLICY); + IMA_DEFAULT_POLICY, setup_data); - if (ima_use_secure_boot || ima_use_appraise_tcb || - ima_use_appraise_exec_tcb) - add_rules(NULL, &ima_parser_appraise_rule, 1, IMA_DEFAULT_POLICY); + if (setup_data->ima_use_secure_boot || + setup_data->ima_use_appraise_tcb || + setup_data->ima_use_appraise_exec_tcb) + add_rules(ima_ns, &ima_parser_appraise_rule, 1, + IMA_DEFAULT_POLICY, setup_data); - ima_update_policy_flag(NULL); + ima_ns->policy_data->ima_rules = + &ima_ns->policy_data->ima_default_rules; + ima_update_policy_flag(ima_ns); +} + +/** + * ima_init_policy - initialize the default measure rules for the initial ima ns + */ +void __init ima_init_policy(void) +{ + ima_init_ns_policy(&init_ima_ns, &init_policy_setup_data); } /* Make sure we have a valid policy, at least containing some rules. */ int ima_check_policy(const struct ima_namespace *ima_ns) { - if (list_empty(&ima_temp_rules)) + if (list_empty(&ima_ns->policy_data->ima_temp_rules)) return -EINVAL; return 0; } @@ -1019,14 +1036,18 @@ int ima_check_policy(const struct ima_namespace *ima_ns) */ void ima_update_policy(void) { - struct list_head *policy = &ima_policy_rules; + /* Update only the current ima namespace */ + struct ima_namespace *ima_ns = get_current_ns(); + struct list_head *policy = &ima_ns->policy_data->ima_policy_rules; - list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu); + list_splice_tail_init_rcu(&ima_ns->policy_data->ima_temp_rules, + policy, synchronize_rcu); - if (ima_rules != policy) { - ima_policy_flag = 0; - ima_rules = policy; + if (ima_ns->policy_data->ima_rules != policy) { + ima_ns->policy_data->ima_policy_flag = 0; + ima_ns->policy_data->ima_rules = policy; +#ifndef CONFIG_IMA_NS /* * IMA architecture specific policy rules are specified * as strings and converted to an array of ima_entry_rules @@ -1034,8 +1055,9 @@ void ima_update_policy(void) * architecture specific rules stored as an array. */ kfree(arch_policy_entry); +#endif } - ima_update_policy_flag(NULL); + ima_update_policy_flag(ima_ns); /* Custom IMA policy has been loaded */ ima_process_queued_keys(); @@ -1099,6 +1121,7 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry, substring_t *args, int lsm_rule, int audit_type) { int result; + struct ima_namespace *ima_ns = get_current_ns(); if (entry->lsm[lsm_rule].rule) return -EINVAL; @@ -1115,7 +1138,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry, pr_warn("rule for LSM \'%s\' is undefined\n", entry->lsm[lsm_rule].args_p); - if (ima_rules == &ima_default_rules) { + if (ima_ns->policy_data->ima_rules == + &ima_ns->policy_data->ima_default_rules) { kfree(entry->lsm[lsm_rule].args_p); entry->lsm[lsm_rule].args_p = NULL; result = -EINVAL; @@ -1279,6 +1303,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) bool uid_token; struct ima_template_desc *template_desc; int result = 0; + struct ima_namespace *ima_ns = get_current_ns(); ab = integrity_audit_log_start(audit_context(), GFP_KERNEL, AUDIT_INTEGRITY_POLICY_RULE); @@ -1640,7 +1665,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) if (!result && !ima_validate_rule(entry)) result = -EINVAL; else if (entry->action == APPRAISE) - temp_ima_appraise |= ima_appraise_flag(entry->func); + ima_ns->policy_data->temp_ima_appraise |= + ima_appraise_flag(entry->func); if (!result && entry->flags & IMA_MODSIG_ALLOWED) { template_desc = entry->template ? entry->template : @@ -1667,6 +1693,8 @@ ssize_t ima_parse_add_rule(char *rule) struct ima_rule_entry *entry; ssize_t result, len; int audit_info = 0; + /* Add rules only to the current ima namespace */ + struct ima_namespace *ima_ns = get_current_ns(); p = strsep(&rule, "\n"); len = strlen(p) + 1; @@ -1693,7 +1721,7 @@ ssize_t ima_parse_add_rule(char *rule) return result; } - list_add_tail(&entry->list, &ima_temp_rules); + list_add_tail(&entry->list, &ima_ns->policy_data->ima_temp_rules); return len; } @@ -1705,15 +1733,51 @@ ssize_t ima_parse_add_rule(char *rule) * ima_delete_rules() at a time. */ void ima_delete_rules(void) +{ + /* Delete rules only from the current ima namespace */ + struct ima_namespace *ima_ns = get_current_ns(); + struct ima_rule_entry *entry, *tmp; + + ima_ns->policy_data->temp_ima_appraise = 0; + list_for_each_entry_safe(entry, tmp, + &ima_ns->policy_data->ima_temp_rules, list) { + list_del(&entry->list); + ima_free_rule(entry); + } +} + +#ifdef CONFIG_IMA_NS +/** + * ima_delete_ns_rules - delete policy rules and free the memory + * @policy_data: a pointer to the policy data of the given namespace + * @is_root_ns: indicates if the namespace being cleaned up is the root + * namespace + * + * This function should be called only for the inactive namespace, when it is + * being destroyed. + */ +void ima_delete_ns_rules(struct ima_policy_data *policy_data, + bool is_root_ns) { struct ima_rule_entry *entry, *tmp; - temp_ima_appraise = 0; - list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) { + /* no locks necessary, namespace is inactive */ + list_for_each_entry_safe(entry, tmp, + &policy_data->ima_policy_rules, list) { list_del(&entry->list); ima_free_rule(entry); } + + if (!is_root_ns) { + list_for_each_entry_safe(entry, tmp, + &policy_data->ima_default_rules, + list) { + list_del(&entry->list); + ima_free_rule(entry); + } + } } +#endif #define __ima_hook_stringify(func, str) (#func), @@ -1737,9 +1801,10 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos) { loff_t l = *pos; struct ima_rule_entry *entry; + struct ima_namespace *ima_ns = get_current_ns(); rcu_read_lock(); - list_for_each_entry_rcu(entry, ima_rules, list) { + list_for_each_entry_rcu(entry, ima_ns->policy_data->ima_rules, list) { if (!l--) { rcu_read_unlock(); return entry; @@ -1751,6 +1816,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos) void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) { + struct ima_namespace *ima_ns = get_current_ns(); struct ima_rule_entry *entry = v; rcu_read_lock(); @@ -1758,7 +1824,7 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) rcu_read_unlock(); (*pos)++; - return (&entry->list == ima_rules) ? NULL : entry; + return (&entry->list == ima_ns->policy_data->ima_rules) ? NULL : entry; } void ima_policy_stop(struct seq_file *m, void *v) @@ -1956,6 +2022,7 @@ int ima_policy_show(struct seq_file *m, void *v) */ bool ima_appraise_signature(enum kernel_read_file_id id) { + struct ima_namespace *ima_ns = get_current_ns(); struct ima_rule_entry *entry; bool found = false; enum ima_hooks func; @@ -1966,7 +2033,7 @@ bool ima_appraise_signature(enum kernel_read_file_id id) func = read_idmap[id] ?: FILE_CHECK; rcu_read_lock(); - list_for_each_entry_rcu(entry, ima_rules, list) { + list_for_each_entry_rcu(entry, ima_ns->policy_data->ima_rules, list) { if (entry->action != APPRAISE) continue; diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c index 34ca54ba52b7e1fd21a3b8e1b64e4a2765b8a603..542cbe894a99ee06eedfcba16033db91993e26a2 100644 --- a/security/integrity/ima/ima_queue_keys.c +++ b/security/integrity/ima/ima_queue_keys.c @@ -110,8 +110,11 @@ bool ima_queue_key(struct key *keyring, const void *payload, if (!entry) return false; + /* Queued keys will be processed according to the root IMA namespace + * policy, therefore allow queueing only for the root namespace. + */ mutex_lock(&ima_keys_lock); - if (!ima_process_keys) { + if (!ima_process_keys && (get_current_ns() == &init_ima_ns)) { list_add_tail(&entry->list, &ima_keys); queued = true; } @@ -158,12 +161,15 @@ void ima_process_queued_keys(void) list_for_each_entry_safe(entry, tmp, &ima_keys, list) { if (!timer_expired) + /* Queued keys are always measured according to the + * initial namespace policy. + */ process_buffer_measurement(NULL, entry->payload, entry->payload_len, entry->keyring_name, KEY_CHECK, 0, entry->keyring_name, - NULL); + &init_ima_ns); list_del(&entry->list); ima_free_key_entry(entry); } diff --git a/security/security.c b/security/security.c index 0c95a714168ceb5cb70e40586a7a5cca25236f21..93db7a266bcdf2f758cf22d916cae9f445cb8cff 100644 --- a/security/security.c +++ b/security/security.c @@ -989,7 +989,7 @@ static void inode_free_by_rcu(struct rcu_head *head) void security_inode_free(struct inode *inode) { - integrity_inode_free(inode); + ima_inode_free(inode); call_void_hook(inode_free_security, inode); /* * The inode may still be referenced in a path walk and