Commit c867d07e authored by James Morris's avatar James Morris

Merge branch 'next' of...

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next
parents 858f61c4 1b68bdf9
...@@ -1292,7 +1292,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1292,7 +1292,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Set number of hash buckets for inode cache. Set number of hash buckets for inode cache.
ima_appraise= [IMA] appraise integrity measurements ima_appraise= [IMA] appraise integrity measurements
Format: { "off" | "enforce" | "fix" } Format: { "off" | "enforce" | "fix" | "log" }
default: "enforce" default: "enforce"
ima_appraise_tcb [IMA] ima_appraise_tcb [IMA]
......
...@@ -43,6 +43,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; ...@@ -43,6 +43,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
#define IMA_TEMPLATE_IMA_NAME "ima" #define IMA_TEMPLATE_IMA_NAME "ima"
#define IMA_TEMPLATE_IMA_FMT "d|n" #define IMA_TEMPLATE_IMA_FMT "d|n"
/* current content of the policy */
extern int ima_policy_flag;
/* set during initialization */ /* set during initialization */
extern int ima_initialized; extern int ima_initialized;
extern int ima_used_chip; extern int ima_used_chip;
...@@ -153,14 +156,16 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, ...@@ -153,14 +156,16 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags); int flags);
void ima_init_policy(void); void ima_init_policy(void);
void ima_update_policy(void); void ima_update_policy(void);
void ima_update_policy_flag(void);
ssize_t ima_parse_add_rule(char *); ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void); void ima_delete_rules(void);
/* Appraise integrity measurements */ /* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01 #define IMA_APPRAISE_ENFORCE 0x01
#define IMA_APPRAISE_FIX 0x02 #define IMA_APPRAISE_FIX 0x02
#define IMA_APPRAISE_MODULES 0x04 #define IMA_APPRAISE_LOG 0x04
#define IMA_APPRAISE_FIRMWARE 0x08 #define IMA_APPRAISE_MODULES 0x08
#define IMA_APPRAISE_FIRMWARE 0x10
#ifdef CONFIG_IMA_APPRAISE #ifdef CONFIG_IMA_APPRAISE
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
......
...@@ -179,11 +179,6 @@ int ima_get_action(struct inode *inode, int mask, int function) ...@@ -179,11 +179,6 @@ int ima_get_action(struct inode *inode, int mask, int function)
return ima_match_policy(inode, function, mask, flags); 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 * ima_collect_measurement - collect file measurement
* *
......
...@@ -23,6 +23,8 @@ static int __init default_appraise_setup(char *str) ...@@ -23,6 +23,8 @@ static int __init default_appraise_setup(char *str)
{ {
if (strncmp(str, "off", 3) == 0) if (strncmp(str, "off", 3) == 0)
ima_appraise = 0; ima_appraise = 0;
else if (strncmp(str, "log", 3) == 0)
ima_appraise = IMA_APPRAISE_LOG;
else if (strncmp(str, "fix", 3) == 0) else if (strncmp(str, "fix", 3) == 0)
ima_appraise = IMA_APPRAISE_FIX; ima_appraise = IMA_APPRAISE_FIX;
return 1; return 1;
...@@ -316,7 +318,7 @@ void ima_inode_post_setattr(struct dentry *dentry) ...@@ -316,7 +318,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
struct integrity_iint_cache *iint; struct integrity_iint_cache *iint;
int must_appraise, rc; 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) || !inode->i_op->removexattr)
return; return;
...@@ -354,7 +356,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig) ...@@ -354,7 +356,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
{ {
struct integrity_iint_cache *iint; 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; return;
iint = integrity_iint_find(inode); iint = integrity_iint_find(inode);
......
...@@ -43,7 +43,7 @@ int ima_used_chip; ...@@ -43,7 +43,7 @@ int ima_used_chip;
* a different value.) Violations add a zero entry to the measurement * a different value.) Violations add a zero entry to the measurement
* list and extend the aggregate PCR value with ff...ff's. * 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"; static const char op[] = "add_boot_aggregate";
const char *audit_cause = "ENOMEM"; const char *audit_cause = "ENOMEM";
...@@ -72,17 +72,23 @@ static void __init ima_add_boot_aggregate(void) ...@@ -72,17 +72,23 @@ static void __init ima_add_boot_aggregate(void)
result = ima_alloc_init_template(iint, NULL, boot_aggregate_name, result = ima_alloc_init_template(iint, NULL, boot_aggregate_name,
NULL, 0, &entry); NULL, 0, &entry);
if (result < 0) if (result < 0) {
return; audit_cause = "alloc_entry";
goto err_out;
}
result = ima_store_template(entry, violation, NULL, result = ima_store_template(entry, violation, NULL,
boot_aggregate_name); boot_aggregate_name);
if (result < 0) if (result < 0) {
ima_free_template_entry(entry); ima_free_template_entry(entry);
return; audit_cause = "store_entry";
goto err_out;
}
return 0;
err_out: err_out:
integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
audit_cause, result, 0); audit_cause, result, 0);
return result;
} }
int __init ima_init(void) int __init ima_init(void)
...@@ -98,6 +104,10 @@ int __init ima_init(void) ...@@ -98,6 +104,10 @@ int __init ima_init(void)
if (!ima_used_chip) if (!ima_used_chip)
pr_info("No TPM chip found, activating TPM-bypass!\n"); 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(); rc = ima_init_crypto();
if (rc) if (rc)
return rc; return rc;
...@@ -105,7 +115,10 @@ int __init ima_init(void) ...@@ -105,7 +115,10 @@ int __init ima_init(void)
if (rc != 0) if (rc != 0)
return rc; 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(); ima_init_policy();
return ima_fs_init(); return ima_fs_init();
......
...@@ -77,42 +77,39 @@ __setup("ima_hash=", hash_setup); ...@@ -77,42 +77,39 @@ __setup("ima_hash=", hash_setup);
* could result in a file measurement error. * 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); struct inode *inode = file_inode(file);
fmode_t mode = file->f_mode; fmode_t mode = file->f_mode;
bool send_tomtou = false, send_writers = false; 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 (mode & FMODE_WRITE) {
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
struct integrity_iint_cache *iint; if (!iint)
iint = integrity_iint_find(inode); iint = integrity_iint_find(inode);
/* IMA_MEASURE is set from reader side */ /* IMA_MEASURE is set from reader side */
if (iint && (iint->flags & IMA_MEASURE)) if (iint && (iint->flags & IMA_MEASURE))
send_tomtou = true; send_tomtou = true;
} }
} else { } else {
if ((atomic_read(&inode->i_writecount) > 0) && if ((atomic_read(&inode->i_writecount) > 0) && must_measure)
ima_must_measure(inode, MAY_READ, FILE_CHECK))
send_writers = true; send_writers = true;
} }
if (!send_tomtou && !send_writers) if (!send_tomtou && !send_writers)
return; return;
pathname = ima_d_path(&file->f_path, &pathbuf); *pathname = ima_d_path(&file->f_path, pathbuf);
if (send_tomtou) if (send_tomtou)
ima_add_violation(file, pathname, "invalid_pcr", "ToMToU"); ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU");
if (send_writers) if (send_writers)
ima_add_violation(file, pathname, ima_add_violation(file, *pathname,
"invalid_pcr", "open_writers"); "invalid_pcr", "open_writers");
kfree(pathbuf);
} }
static void ima_check_last_writer(struct integrity_iint_cache *iint, 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, ...@@ -160,15 +157,16 @@ static int process_measurement(struct file *file, int mask, int function,
int opened) int opened)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint; struct integrity_iint_cache *iint = NULL;
struct ima_template_desc *template_desc; struct ima_template_desc *template_desc;
char *pathbuf = NULL; char *pathbuf = NULL;
const char *pathname = NULL; const char *pathname = NULL;
int rc = -ENOMEM, action, must_appraise; int rc = -ENOMEM, action, must_appraise;
struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
int xattr_len = 0; 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 0;
/* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action
...@@ -176,7 +174,9 @@ static int process_measurement(struct file *file, int mask, int function, ...@@ -176,7 +174,9 @@ static int process_measurement(struct file *file, int mask, int function,
* Included is the appraise submask. * Included is the appraise submask.
*/ */
action = ima_get_action(inode, mask, function); 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; return 0;
must_appraise = action & IMA_APPRAISE; must_appraise = action & IMA_APPRAISE;
...@@ -187,9 +187,20 @@ static int process_measurement(struct file *file, int mask, int function, ...@@ -187,9 +187,20 @@ static int process_measurement(struct file *file, int mask, int function,
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
iint = integrity_inode_get(inode); if (action) {
if (!iint) iint = integrity_inode_get(inode);
goto out; 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 /* Determine if already appraised/measured based on bitmask
* (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, * (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, ...@@ -218,7 +229,8 @@ static int process_measurement(struct file *file, int mask, int function,
goto out_digsig; 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) if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname, ima_store_measurement(iint, file, pathname,
...@@ -228,13 +240,15 @@ static int process_measurement(struct file *file, int mask, int function, ...@@ -228,13 +240,15 @@ static int process_measurement(struct file *file, int mask, int function,
xattr_value, xattr_len, opened); xattr_value, xattr_len, opened);
if (action & IMA_AUDIT) if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname); ima_audit_measurement(iint, pathname);
kfree(pathbuf);
out_digsig: out_digsig:
if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG))
rc = -EACCES; rc = -EACCES;
kfree(xattr_value);
out_free:
kfree(pathbuf);
out: out:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
kfree(xattr_value);
if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
return -EACCES; return -EACCES;
return 0; return 0;
...@@ -288,7 +302,6 @@ int ima_bprm_check(struct linux_binprm *bprm) ...@@ -288,7 +302,6 @@ int ima_bprm_check(struct linux_binprm *bprm)
*/ */
int ima_file_check(struct file *file, int mask, int opened) int ima_file_check(struct file *file, int mask, int opened)
{ {
ima_rdwr_violation_check(file);
return process_measurement(file, return process_measurement(file,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC), mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
FILE_CHECK, opened); FILE_CHECK, opened);
...@@ -334,14 +347,10 @@ static int __init init_ima(void) ...@@ -334,14 +347,10 @@ static int __init init_ima(void)
hash_setup(CONFIG_IMA_DEFAULT_HASH); hash_setup(CONFIG_IMA_DEFAULT_HASH);
error = ima_init(); error = ima_init();
if (error) if (!error) {
goto out; ima_initialized = 1;
ima_update_policy_flag();
error = ima_init_keyring(INTEGRITY_KEYRING_IMA); }
if (error)
goto out;
ima_initialized = 1;
out:
return error; return error;
} }
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#define DONT_APPRAISE 0x0008 #define DONT_APPRAISE 0x0008
#define AUDIT 0x0040 #define AUDIT 0x0040
int ima_policy_flag;
#define MAX_LSM_RULES 6 #define MAX_LSM_RULES 6
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_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, ...@@ -295,6 +297,26 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
return action; 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. * ima_init_policy - initialize the default measure rules.
* *
...@@ -341,6 +363,7 @@ void ima_update_policy(void) ...@@ -341,6 +363,7 @@ void ima_update_policy(void)
if (ima_rules == &ima_default_rules) { if (ima_rules == &ima_default_rules) {
ima_rules = &ima_policy_rules; ima_rules = &ima_policy_rules;
ima_update_policy_flag();
cause = "complete"; cause = "complete";
result = 0; result = 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment