summaryrefslogtreecommitdiff
path: root/security/integrity/ima/ima_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima/ima_main.c')
-rw-r--r--security/integrity/ima/ima_main.c141
1 files changed, 90 insertions, 51 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index f04f43af651c..f99ab1a3b0f0 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -129,16 +129,22 @@ static void ima_rdwr_violation_check(struct file *file,
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
if (!iint)
iint = ima_iint_find(inode);
+
/* IMA_MEASURE is set from reader side */
- if (iint && test_bit(IMA_MUST_MEASURE,
- &iint->atomic_flags))
+ if (iint && test_and_clear_bit(IMA_MAY_EMIT_TOMTOU,
+ &iint->atomic_flags))
send_tomtou = true;
}
} else {
if (must_measure)
- set_bit(IMA_MUST_MEASURE, &iint->atomic_flags);
- if (inode_is_open_for_write(inode) && must_measure)
- send_writers = true;
+ set_bit(IMA_MAY_EMIT_TOMTOU, &iint->atomic_flags);
+
+ /* Limit number of open_writers violations */
+ if (inode_is_open_for_write(inode) && must_measure) {
+ if (!test_and_set_bit(IMA_EMITTED_OPENWRITERS,
+ &iint->atomic_flags))
+ send_writers = true;
+ }
}
if (!send_tomtou && !send_writers)
@@ -167,6 +173,8 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
if (atomic_read(&inode->i_writecount) == 1) {
struct kstat stat;
+ clear_bit(IMA_EMITTED_OPENWRITERS, &iint->atomic_flags);
+
update = test_and_clear_bit(IMA_UPDATE_XATTR,
&iint->atomic_flags);
if ((iint->flags & IMA_NEW_FILE) ||
@@ -206,8 +214,8 @@ static void ima_file_free(struct file *file)
}
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 lsm_prop *prop, char *buf, loff_t size,
+ int mask, enum ima_hooks func)
{
struct inode *real_inode, *inode = file_inode(file);
struct ima_iint_cache *iint = NULL;
@@ -232,12 +240,14 @@ static int process_measurement(struct file *file, const struct cred *cred,
* bitmask based on the appraise/audit/measurement policy.
* Included is the appraise submask.
*/
- action = ima_get_action(file_mnt_idmap(file), inode, cred, secid,
+ action = ima_get_action(file_mnt_idmap(file), inode, cred, prop,
mask, func, &pcr, &template_desc, NULL,
&allowed_algos);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK ||
func == MMAP_CHECK_REQPROT) &&
- (ima_policy_flag & IMA_MEASURE));
+ (ima_policy_flag & IMA_MEASURE) &&
+ ((action & IMA_MEASURE) ||
+ (file->f_mode & FMODE_WRITE)));
if (!action && !violation_check)
return 0;
@@ -269,10 +279,13 @@ static int process_measurement(struct file *file, const struct cred *cred,
mutex_lock(&iint->mutex);
if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags))
- /* reset appraisal flags if ima_inode_post_setattr was called */
+ /*
+ * Reset appraisal flags (action and non-action rule-specific)
+ * if ima_inode_post_setattr was called.
+ */
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
- IMA_NONACTION_FLAGS);
+ IMA_NONACTION_RULE_FLAGS);
/*
* Re-evaulate the file if either the xattr has changed or the
@@ -443,23 +456,23 @@ out:
static int ima_file_mmap(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags)
{
- u32 secid;
+ struct lsm_prop prop;
int ret;
if (!file)
return 0;
- security_current_getsecid_subj(&secid);
+ security_current_getlsmprop_subj(&prop);
if (reqprot & PROT_EXEC) {
- ret = process_measurement(file, current_cred(), secid, NULL,
+ ret = process_measurement(file, current_cred(), &prop, NULL,
0, MAY_EXEC, MMAP_CHECK_REQPROT);
if (ret)
return ret;
}
if (prot & PROT_EXEC)
- return process_measurement(file, current_cred(), secid, NULL,
+ return process_measurement(file, current_cred(), &prop, NULL,
0, MAY_EXEC, MMAP_CHECK);
return 0;
@@ -488,9 +501,9 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
char *pathbuf = NULL;
const char *pathname = NULL;
struct inode *inode;
+ struct lsm_prop prop;
int result = 0;
int action;
- u32 secid;
int pcr;
/* Is mprotect making an mmap'ed file executable? */
@@ -498,13 +511,13 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
!(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC))
return 0;
- security_current_getsecid_subj(&secid);
+ security_current_getlsmprop_subj(&prop);
inode = file_inode(vma->vm_file);
action = ima_get_action(file_mnt_idmap(vma->vm_file), inode,
- current_cred(), secid, MAY_EXEC, MMAP_CHECK,
+ current_cred(), &prop, MAY_EXEC, MMAP_CHECK,
&pcr, &template, NULL, NULL);
action |= ima_get_action(file_mnt_idmap(vma->vm_file), inode,
- current_cred(), secid, MAY_EXEC,
+ current_cred(), &prop, MAY_EXEC,
MMAP_CHECK_REQPROT, &pcr, &template, NULL,
NULL);
@@ -541,20 +554,48 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
static int ima_bprm_check(struct linux_binprm *bprm)
{
int ret;
- u32 secid;
+ struct lsm_prop prop;
- security_current_getsecid_subj(&secid);
- ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0,
- MAY_EXEC, BPRM_CHECK);
+ security_current_getlsmprop_subj(&prop);
+ ret = process_measurement(bprm->file, current_cred(),
+ &prop, NULL, 0, MAY_EXEC, BPRM_CHECK);
if (ret)
return ret;
- security_cred_getsecid(bprm->cred, &secid);
- return process_measurement(bprm->file, bprm->cred, secid, NULL, 0,
+ security_cred_getlsmprop(bprm->cred, &prop);
+ return process_measurement(bprm->file, bprm->cred, &prop, NULL, 0,
MAY_EXEC, CREDS_CHECK);
}
/**
+ * ima_bprm_creds_for_exec - collect/store/appraise measurement.
+ * @bprm: contains the linux_binprm structure
+ *
+ * Based on the IMA policy and the execveat(2) AT_EXECVE_CHECK flag, measure
+ * and appraise the integrity of a file to be executed by script interpreters.
+ * Unlike any of the other LSM hooks where the kernel enforces file integrity,
+ * enforcing file integrity is left up to the discretion of the script
+ * interpreter (userspace).
+ *
+ * On success return 0. On integrity appraisal error, assuming the file
+ * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
+ */
+static int ima_bprm_creds_for_exec(struct linux_binprm *bprm)
+{
+ /*
+ * As security_bprm_check() is called multiple times, both
+ * the script and the shebang interpreter are measured, appraised,
+ * and audited. Limit usage of this LSM hook to just measuring,
+ * appraising, and auditing the indirect script execution
+ * (e.g. ./sh example.sh).
+ */
+ if (!bprm->is_check)
+ return 0;
+
+ return ima_bprm_check(bprm);
+}
+
+/**
* ima_file_check - based on policy, collect/store measurement.
* @file: pointer to the file to be measured
* @mask: contains MAY_READ, MAY_WRITE, MAY_EXEC or MAY_APPEND
@@ -566,10 +607,10 @@ static int ima_bprm_check(struct linux_binprm *bprm)
*/
static int ima_file_check(struct file *file, int mask)
{
- u32 secid;
+ struct lsm_prop prop;
- security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, NULL, 0,
+ security_current_getlsmprop_subj(&prop);
+ return process_measurement(file, current_cred(), &prop, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
MAY_APPEND), FILE_CHECK);
}
@@ -768,7 +809,7 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
bool contents)
{
enum ima_hooks func;
- u32 secid;
+ struct lsm_prop prop;
/*
* Do devices using pre-allocated memory run the risk of the
@@ -788,9 +829,9 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
/* Read entire file for all partial reads. */
func = read_idmap[read_id] ?: FILE_CHECK;
- security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, NULL,
- 0, MAY_READ, func);
+ security_current_getlsmprop_subj(&prop);
+ return process_measurement(file, current_cred(), &prop, NULL, 0,
+ MAY_READ, func);
}
const int read_idmap[READING_MAX_ID] = {
@@ -818,7 +859,7 @@ 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;
+ struct lsm_prop prop;
/* permit signed certs */
if (!file && read_id == READING_X509_CERTIFICATE)
@@ -831,8 +872,8 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size,
}
func = read_idmap[read_id] ?: FILE_CHECK;
- security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, buf, size,
+ security_current_getlsmprop_subj(&prop);
+ return process_measurement(file, current_cred(), &prop, buf, size,
MAY_READ, func);
}
@@ -967,7 +1008,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
int digest_hash_len = hash_digest_size[ima_hash_algo];
int violation = 0;
int action = 0;
- u32 secid;
+ struct lsm_prop prop;
if (digest && digest_len < digest_hash_len)
return -EINVAL;
@@ -983,16 +1024,16 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
}
/*
- * Both LSM hooks and auxilary based buffer measurements are
- * based on policy. To avoid code duplication, differentiate
- * between the LSM hooks and auxilary buffer measurements,
+ * Both LSM hooks and auxiliary based buffer measurements are
+ * based on policy. To avoid code duplication, differentiate
+ * between the LSM hooks and auxiliary buffer measurements,
* retrieving the policy rule information only for the LSM hook
* buffer measurements.
*/
if (func) {
- security_current_getsecid_subj(&secid);
+ security_current_getlsmprop_subj(&prop);
action = ima_get_action(idmap, inode, current_cred(),
- secid, 0, func, &pcr, &template,
+ &prop, 0, func, &pcr, &template,
func_data, NULL);
if (!(action & IMA_MEASURE) && !digest)
return -ENOENT;
@@ -1062,19 +1103,16 @@ out:
*/
void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
{
- struct fd f;
-
if (!buf || !size)
return;
- f = fdget(kernel_fd);
- if (!f.file)
+ CLASS(fd, f)(kernel_fd);
+ if (fd_empty(f))
return;
- process_buffer_measurement(file_mnt_idmap(f.file), file_inode(f.file),
+ process_buffer_measurement(file_mnt_idmap(fd_file(f)), file_inode(fd_file(f)),
buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0,
NULL, false, NULL, 0);
- fdput(f);
}
/**
@@ -1114,7 +1152,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
/**
- * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
+ * ima_kernel_module_request - Prevent crypto-pkcs1(rsa,*) requests
* @kmod_name: kernel module name
*
* Avoid a verification loop where verifying the signature of the modprobe
@@ -1128,7 +1166,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
* 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,
+ * Since we don't have any real "crypto-pkcs1(rsa,*)" kernel modules,
* we are safe to fail such module request from crypto_larval_lookup(), and
* avoid the verification loop.
*
@@ -1136,7 +1174,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
*/
static int ima_kernel_module_request(char *kmod_name)
{
- if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
+ if (strncmp(kmod_name, "crypto-pkcs1(rsa,", 17) == 0)
return -EINVAL;
return 0;
@@ -1177,6 +1215,7 @@ static int __init init_ima(void)
static struct security_hook_list ima_hooks[] __ro_after_init = {
LSM_HOOK_INIT(bprm_check_security, ima_bprm_check),
+ LSM_HOOK_INIT(bprm_creds_for_exec, ima_bprm_creds_for_exec),
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),
@@ -1193,7 +1232,7 @@ static struct security_hook_list ima_hooks[] __ro_after_init = {
#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),
+ LSM_HOOK_INIT(inode_free_security_rcu, ima_inode_free_rcu),
};
static const struct lsm_id ima_lsmid = {