Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next

This commit is contained in:
James Morris 2014-10-02 19:47:23 +10:00
commit c867d07e3c
7 changed files with 95 additions and 48 deletions

View File

@ -1292,7 +1292,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Set number of hash buckets for inode cache.
ima_appraise= [IMA] appraise integrity measurements
Format: { "off" | "enforce" | "fix" }
Format: { "off" | "enforce" | "fix" | "log" }
default: "enforce"
ima_appraise_tcb [IMA]

View File

@ -43,6 +43,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
#define IMA_TEMPLATE_IMA_NAME "ima"
#define IMA_TEMPLATE_IMA_FMT "d|n"
/* current content of the policy */
extern int ima_policy_flag;
/* set during initialization */
extern int ima_initialized;
extern int ima_used_chip;
@ -153,14 +156,16 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags);
void ima_init_policy(void);
void ima_update_policy(void);
void ima_update_policy_flag(void);
ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
#define IMA_APPRAISE_FIX 0x02
#define IMA_APPRAISE_MODULES 0x04
#define IMA_APPRAISE_FIRMWARE 0x08
#define IMA_APPRAISE_LOG 0x04
#define IMA_APPRAISE_MODULES 0x08
#define IMA_APPRAISE_FIRMWARE 0x10
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,

View File

@ -179,11 +179,6 @@ int ima_get_action(struct inode *inode, int mask, int function)
return ima_match_policy(inode, function, mask, flags);
}
int ima_must_measure(struct inode *inode, int mask, int function)
{
return ima_match_policy(inode, function, mask, IMA_MEASURE);
}
/*
* ima_collect_measurement - collect file measurement
*

View File

@ -23,6 +23,8 @@ static int __init default_appraise_setup(char *str)
{
if (strncmp(str, "off", 3) == 0)
ima_appraise = 0;
else if (strncmp(str, "log", 3) == 0)
ima_appraise = IMA_APPRAISE_LOG;
else if (strncmp(str, "fix", 3) == 0)
ima_appraise = IMA_APPRAISE_FIX;
return 1;
@ -316,7 +318,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
struct integrity_iint_cache *iint;
int must_appraise, rc;
if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|| !inode->i_op->removexattr)
return;
@ -354,7 +356,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
{
struct integrity_iint_cache *iint;
if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode))
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
return;
iint = integrity_iint_find(inode);

View File

@ -43,7 +43,7 @@ int ima_used_chip;
* a different value.) Violations add a zero entry to the measurement
* list and extend the aggregate PCR value with ff...ff's.
*/
static void __init ima_add_boot_aggregate(void)
static int __init ima_add_boot_aggregate(void)
{
static const char op[] = "add_boot_aggregate";
const char *audit_cause = "ENOMEM";
@ -72,17 +72,23 @@ static void __init ima_add_boot_aggregate(void)
result = ima_alloc_init_template(iint, NULL, boot_aggregate_name,
NULL, 0, &entry);
if (result < 0)
return;
if (result < 0) {
audit_cause = "alloc_entry";
goto err_out;
}
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name);
if (result < 0)
if (result < 0) {
ima_free_template_entry(entry);
return;
audit_cause = "store_entry";
goto err_out;
}
return 0;
err_out:
integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
audit_cause, result, 0);
return result;
}
int __init ima_init(void)
@ -98,6 +104,10 @@ int __init ima_init(void)
if (!ima_used_chip)
pr_info("No TPM chip found, activating TPM-bypass!\n");
rc = ima_init_keyring(INTEGRITY_KEYRING_IMA);
if (rc)
return rc;
rc = ima_init_crypto();
if (rc)
return rc;
@ -105,7 +115,10 @@ int __init ima_init(void)
if (rc != 0)
return rc;
ima_add_boot_aggregate(); /* boot aggregate must be first entry */
rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */
if (rc != 0)
return rc;
ima_init_policy();
return ima_fs_init();

View File

@ -77,42 +77,39 @@ __setup("ima_hash=", hash_setup);
* could result in a file measurement error.
*
*/
static void ima_rdwr_violation_check(struct file *file)
static void ima_rdwr_violation_check(struct file *file,
struct integrity_iint_cache *iint,
int must_measure,
char **pathbuf,
const char **pathname)
{
struct inode *inode = file_inode(file);
fmode_t mode = file->f_mode;
bool send_tomtou = false, send_writers = false;
char *pathbuf = NULL;
const char *pathname;
if (!S_ISREG(inode->i_mode) || !ima_initialized)
return;
if (mode & FMODE_WRITE) {
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
struct integrity_iint_cache *iint;
iint = integrity_iint_find(inode);
if (!iint)
iint = integrity_iint_find(inode);
/* IMA_MEASURE is set from reader side */
if (iint && (iint->flags & IMA_MEASURE))
send_tomtou = true;
}
} else {
if ((atomic_read(&inode->i_writecount) > 0) &&
ima_must_measure(inode, MAY_READ, FILE_CHECK))
if ((atomic_read(&inode->i_writecount) > 0) && must_measure)
send_writers = true;
}
if (!send_tomtou && !send_writers)
return;
pathname = ima_d_path(&file->f_path, &pathbuf);
*pathname = ima_d_path(&file->f_path, pathbuf);
if (send_tomtou)
ima_add_violation(file, pathname, "invalid_pcr", "ToMToU");
ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU");
if (send_writers)
ima_add_violation(file, pathname,
ima_add_violation(file, *pathname,
"invalid_pcr", "open_writers");
kfree(pathbuf);
}
static void ima_check_last_writer(struct integrity_iint_cache *iint,
@ -160,15 +157,16 @@ static int process_measurement(struct file *file, int mask, int function,
int opened)
{
struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint;
struct integrity_iint_cache *iint = NULL;
struct ima_template_desc *template_desc;
char *pathbuf = NULL;
const char *pathname = NULL;
int rc = -ENOMEM, action, must_appraise;
struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
int xattr_len = 0;
bool violation_check;
if (!ima_initialized || !S_ISREG(inode->i_mode))
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return 0;
/* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action
@ -176,7 +174,9 @@ static int process_measurement(struct file *file, int mask, int function,
* Included is the appraise submask.
*/
action = ima_get_action(inode, mask, function);
if (!action)
violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check)
return 0;
must_appraise = action & IMA_APPRAISE;
@ -187,9 +187,20 @@ static int process_measurement(struct file *file, int mask, int function,
mutex_lock(&inode->i_mutex);
iint = integrity_inode_get(inode);
if (!iint)
goto out;
if (action) {
iint = integrity_inode_get(inode);
if (!iint)
goto out;
}
if (violation_check) {
ima_rdwr_violation_check(file, iint, action & IMA_MEASURE,
&pathbuf, &pathname);
if (!action) {
rc = 0;
goto out_free;
}
}
/* Determine if already appraised/measured based on bitmask
* (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
@ -218,7 +229,8 @@ static int process_measurement(struct file *file, int mask, int function,
goto out_digsig;
}
pathname = ima_d_path(&file->f_path, &pathbuf);
if (!pathname) /* ima_rdwr_violation possibly pre-fetched */
pathname = ima_d_path(&file->f_path, &pathbuf);
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
@ -228,13 +240,15 @@ static int process_measurement(struct file *file, int mask, int function,
xattr_value, xattr_len, opened);
if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname);
kfree(pathbuf);
out_digsig:
if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG))
rc = -EACCES;
kfree(xattr_value);
out_free:
kfree(pathbuf);
out:
mutex_unlock(&inode->i_mutex);
kfree(xattr_value);
if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
return -EACCES;
return 0;
@ -288,7 +302,6 @@ int ima_bprm_check(struct linux_binprm *bprm)
*/
int ima_file_check(struct file *file, int mask, int opened)
{
ima_rdwr_violation_check(file);
return process_measurement(file,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
FILE_CHECK, opened);
@ -334,14 +347,10 @@ static int __init init_ima(void)
hash_setup(CONFIG_IMA_DEFAULT_HASH);
error = ima_init();
if (error)
goto out;
error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
if (error)
goto out;
ima_initialized = 1;
out:
if (!error) {
ima_initialized = 1;
ima_update_policy_flag();
}
return error;
}

View File

@ -35,6 +35,8 @@
#define DONT_APPRAISE 0x0008
#define AUDIT 0x0040
int ima_policy_flag;
#define MAX_LSM_RULES 6
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
@ -295,6 +297,26 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
return action;
}
/*
* Initialize the ima_policy_flag variable based on the currently
* loaded policy. Based on this flag, the decision to short circuit
* out of a function or not call the function in the first place
* can be made earlier.
*/
void ima_update_policy_flag(void)
{
struct ima_rule_entry *entry;
ima_policy_flag = 0;
list_for_each_entry(entry, ima_rules, list) {
if (entry->action & IMA_DO_MASK)
ima_policy_flag |= entry->action;
}
if (!ima_appraise)
ima_policy_flag &= ~IMA_APPRAISE;
}
/**
* ima_init_policy - initialize the default measure rules.
*
@ -341,6 +363,7 @@ void ima_update_policy(void)
if (ima_rules == &ima_default_rules) {
ima_rules = &ima_policy_rules;
ima_update_policy_flag();
cause = "complete";
result = 0;
}