ima: support new "hash" and "dont_hash" policy actions
The builtin ima_appraise_tcb policy, which is specified on the boot command line, can be replaced with a custom policy, normally early in the boot process. Custom policies can be more restrictive in some ways, like requiring file signatures, but can be less restrictive in other ways, like not appraising mutable files. With a less restrictive policy in place, files in the builtin policy might not be hashed and labeled with a security.ima hash. On reboot, files which should be labeled in the ima_appraise_tcb are not labeled, possibly preventing the system from booting properly. To resolve this problem, this patch extends the existing IMA policy actions "measure", "dont_measure", "appraise", "dont_appraise", and "audit" with "hash" and "dont_hash". The new "hash" action will write the file hash as security.ima, but without requiring the file to be appraised as well. For example, the builtin ima_appraise_tcb policy includes the rule, "appraise fowner=0". Adding the "hash fowner=0" rule to a custom policy, will cause the needed file hashes to be calculated and written as security.ima xattrs. Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
parent
0d73a55208
commit
da1b0029f5
|
@ -17,7 +17,8 @@ Description:
|
||||||
|
|
||||||
rule format: action [condition ...]
|
rule format: action [condition ...]
|
||||||
|
|
||||||
action: measure | dont_measure | appraise | dont_appraise | audit
|
action: measure | dont_measure | appraise | dont_appraise |
|
||||||
|
audit | hash | dont_hash
|
||||||
condition:= base | lsm [option]
|
condition:= base | lsm [option]
|
||||||
base: [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
|
base: [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
|
||||||
[euid=] [fowner=]]
|
[euid=] [fowner=]]
|
||||||
|
|
|
@ -174,7 +174,7 @@ err_out:
|
||||||
*/
|
*/
|
||||||
int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)
|
int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)
|
||||||
{
|
{
|
||||||
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
|
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
|
||||||
|
|
||||||
flags &= ima_policy_flag;
|
flags &= ima_policy_flag;
|
||||||
|
|
||||||
|
|
|
@ -46,14 +46,15 @@ bool is_ima_appraise_enabled(void)
|
||||||
/*
|
/*
|
||||||
* ima_must_appraise - set appraise flag
|
* ima_must_appraise - set appraise flag
|
||||||
*
|
*
|
||||||
* Return 1 to appraise
|
* Return 1 to appraise or hash
|
||||||
*/
|
*/
|
||||||
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
|
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
|
||||||
{
|
{
|
||||||
if (!ima_appraise)
|
if (!ima_appraise)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return ima_match_policy(inode, func, mask, IMA_APPRAISE, NULL);
|
return ima_match_policy(inode, func, mask, IMA_APPRAISE | IMA_HASH,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ima_fix_xattr(struct dentry *dentry,
|
static int ima_fix_xattr(struct dentry *dentry,
|
||||||
|
@ -324,7 +325,8 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
|
||||||
if (test_bit(IMA_DIGSIG, &iint->atomic_flags))
|
if (test_bit(IMA_DIGSIG, &iint->atomic_flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (iint->ima_file_status != INTEGRITY_PASS)
|
if ((iint->ima_file_status != INTEGRITY_PASS) &&
|
||||||
|
!(iint->flags & IMA_HASH))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);
|
rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);
|
||||||
|
@ -349,19 +351,19 @@ void ima_inode_post_setattr(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct inode *inode = d_backing_inode(dentry);
|
struct inode *inode = d_backing_inode(dentry);
|
||||||
struct integrity_iint_cache *iint;
|
struct integrity_iint_cache *iint;
|
||||||
int must_appraise;
|
int action;
|
||||||
|
|
||||||
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|
||||||
|| !(inode->i_opflags & IOP_XATTR))
|
|| !(inode->i_opflags & IOP_XATTR))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
|
action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
|
||||||
if (!must_appraise)
|
if (!action)
|
||||||
__vfs_removexattr(dentry, XATTR_NAME_IMA);
|
__vfs_removexattr(dentry, XATTR_NAME_IMA);
|
||||||
iint = integrity_iint_find(inode);
|
iint = integrity_iint_find(inode);
|
||||||
if (iint) {
|
if (iint) {
|
||||||
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
|
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
|
||||||
if (!must_appraise)
|
if (!action)
|
||||||
clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
|
clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,6 +243,18 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
|
||||||
if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr)))
|
if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr)))
|
||||||
action ^= IMA_MEASURE;
|
action ^= IMA_MEASURE;
|
||||||
|
|
||||||
|
/* HASH sets the digital signature and update flags, nothing else */
|
||||||
|
if ((action & IMA_HASH) &&
|
||||||
|
!(test_bit(IMA_DIGSIG, &iint->atomic_flags))) {
|
||||||
|
xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
|
||||||
|
if ((xattr_value && xattr_len > 2) &&
|
||||||
|
(xattr_value->type == EVM_IMA_XATTR_DIGSIG))
|
||||||
|
set_bit(IMA_DIGSIG, &iint->atomic_flags);
|
||||||
|
iint->flags |= IMA_HASHED;
|
||||||
|
action ^= IMA_HASH;
|
||||||
|
set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* Nothing to do, just return existing appraised status */
|
/* Nothing to do, just return existing appraised status */
|
||||||
if (!action) {
|
if (!action) {
|
||||||
if (must_appraise)
|
if (must_appraise)
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
#define APPRAISE 0x0004 /* same as IMA_APPRAISE */
|
#define APPRAISE 0x0004 /* same as IMA_APPRAISE */
|
||||||
#define DONT_APPRAISE 0x0008
|
#define DONT_APPRAISE 0x0008
|
||||||
#define AUDIT 0x0040
|
#define AUDIT 0x0040
|
||||||
|
#define HASH 0x0100
|
||||||
|
#define DONT_HASH 0x0200
|
||||||
|
|
||||||
#define INVALID_PCR(a) (((a) < 0) || \
|
#define INVALID_PCR(a) (((a) < 0) || \
|
||||||
(a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
|
(a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
|
||||||
|
@ -380,8 +382,10 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
||||||
action |= entry->flags & IMA_ACTION_FLAGS;
|
action |= entry->flags & IMA_ACTION_FLAGS;
|
||||||
|
|
||||||
action |= entry->action & IMA_DO_MASK;
|
action |= entry->action & IMA_DO_MASK;
|
||||||
if (entry->action & IMA_APPRAISE)
|
if (entry->action & IMA_APPRAISE) {
|
||||||
action |= get_subaction(entry, func);
|
action |= get_subaction(entry, func);
|
||||||
|
action ^= IMA_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
if (entry->action & IMA_DO_MASK)
|
if (entry->action & IMA_DO_MASK)
|
||||||
actmask &= ~(entry->action | entry->action << 1);
|
actmask &= ~(entry->action | entry->action << 1);
|
||||||
|
@ -521,7 +525,7 @@ enum {
|
||||||
Opt_err = -1,
|
Opt_err = -1,
|
||||||
Opt_measure = 1, Opt_dont_measure,
|
Opt_measure = 1, Opt_dont_measure,
|
||||||
Opt_appraise, Opt_dont_appraise,
|
Opt_appraise, Opt_dont_appraise,
|
||||||
Opt_audit,
|
Opt_audit, Opt_hash, Opt_dont_hash,
|
||||||
Opt_obj_user, Opt_obj_role, Opt_obj_type,
|
Opt_obj_user, Opt_obj_role, Opt_obj_type,
|
||||||
Opt_subj_user, Opt_subj_role, Opt_subj_type,
|
Opt_subj_user, Opt_subj_role, Opt_subj_type,
|
||||||
Opt_func, Opt_mask, Opt_fsmagic,
|
Opt_func, Opt_mask, Opt_fsmagic,
|
||||||
|
@ -538,6 +542,8 @@ static match_table_t policy_tokens = {
|
||||||
{Opt_appraise, "appraise"},
|
{Opt_appraise, "appraise"},
|
||||||
{Opt_dont_appraise, "dont_appraise"},
|
{Opt_dont_appraise, "dont_appraise"},
|
||||||
{Opt_audit, "audit"},
|
{Opt_audit, "audit"},
|
||||||
|
{Opt_hash, "hash"},
|
||||||
|
{Opt_dont_hash, "dont_hash"},
|
||||||
{Opt_obj_user, "obj_user=%s"},
|
{Opt_obj_user, "obj_user=%s"},
|
||||||
{Opt_obj_role, "obj_role=%s"},
|
{Opt_obj_role, "obj_role=%s"},
|
||||||
{Opt_obj_type, "obj_type=%s"},
|
{Opt_obj_type, "obj_type=%s"},
|
||||||
|
@ -671,6 +677,22 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||||
|
|
||||||
entry->action = AUDIT;
|
entry->action = AUDIT;
|
||||||
break;
|
break;
|
||||||
|
case Opt_hash:
|
||||||
|
ima_log_string(ab, "action", "hash");
|
||||||
|
|
||||||
|
if (entry->action != UNKNOWN)
|
||||||
|
result = -EINVAL;
|
||||||
|
|
||||||
|
entry->action = HASH;
|
||||||
|
break;
|
||||||
|
case Opt_dont_hash:
|
||||||
|
ima_log_string(ab, "action", "dont_hash");
|
||||||
|
|
||||||
|
if (entry->action != UNKNOWN)
|
||||||
|
result = -EINVAL;
|
||||||
|
|
||||||
|
entry->action = DONT_HASH;
|
||||||
|
break;
|
||||||
case Opt_func:
|
case Opt_func:
|
||||||
ima_log_string(ab, "func", args[0].from);
|
ima_log_string(ab, "func", args[0].from);
|
||||||
|
|
||||||
|
@ -1040,6 +1062,10 @@ int ima_policy_show(struct seq_file *m, void *v)
|
||||||
seq_puts(m, pt(Opt_dont_appraise));
|
seq_puts(m, pt(Opt_dont_appraise));
|
||||||
if (entry->action & AUDIT)
|
if (entry->action & AUDIT)
|
||||||
seq_puts(m, pt(Opt_audit));
|
seq_puts(m, pt(Opt_audit));
|
||||||
|
if (entry->action & HASH)
|
||||||
|
seq_puts(m, pt(Opt_hash));
|
||||||
|
if (entry->action & DONT_HASH)
|
||||||
|
seq_puts(m, pt(Opt_dont_hash));
|
||||||
|
|
||||||
seq_puts(m, " ");
|
seq_puts(m, " ");
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#define IMA_COLLECTED 0x00000020
|
#define IMA_COLLECTED 0x00000020
|
||||||
#define IMA_AUDIT 0x00000040
|
#define IMA_AUDIT 0x00000040
|
||||||
#define IMA_AUDITED 0x00000080
|
#define IMA_AUDITED 0x00000080
|
||||||
|
#define IMA_HASH 0x00000100
|
||||||
|
#define IMA_HASHED 0x00000200
|
||||||
|
|
||||||
/* iint cache flags */
|
/* iint cache flags */
|
||||||
#define IMA_ACTION_FLAGS 0xff000000
|
#define IMA_ACTION_FLAGS 0xff000000
|
||||||
|
@ -35,19 +37,20 @@
|
||||||
#define EVM_IMMUTABLE_DIGSIG 0x08000000
|
#define EVM_IMMUTABLE_DIGSIG 0x08000000
|
||||||
|
|
||||||
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
||||||
IMA_APPRAISE_SUBMASK)
|
IMA_HASH | IMA_APPRAISE_SUBMASK)
|
||||||
#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \
|
#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \
|
||||||
IMA_COLLECTED | IMA_APPRAISED_SUBMASK)
|
IMA_HASHED | IMA_COLLECTED | \
|
||||||
|
IMA_APPRAISED_SUBMASK)
|
||||||
|
|
||||||
/* iint subaction appraise cache flags */
|
/* iint subaction appraise cache flags */
|
||||||
#define IMA_FILE_APPRAISE 0x00000100
|
#define IMA_FILE_APPRAISE 0x00001000
|
||||||
#define IMA_FILE_APPRAISED 0x00000200
|
#define IMA_FILE_APPRAISED 0x00002000
|
||||||
#define IMA_MMAP_APPRAISE 0x00000400
|
#define IMA_MMAP_APPRAISE 0x00004000
|
||||||
#define IMA_MMAP_APPRAISED 0x00000800
|
#define IMA_MMAP_APPRAISED 0x00008000
|
||||||
#define IMA_BPRM_APPRAISE 0x00001000
|
#define IMA_BPRM_APPRAISE 0x00010000
|
||||||
#define IMA_BPRM_APPRAISED 0x00002000
|
#define IMA_BPRM_APPRAISED 0x00020000
|
||||||
#define IMA_READ_APPRAISE 0x00004000
|
#define IMA_READ_APPRAISE 0x00040000
|
||||||
#define IMA_READ_APPRAISED 0x00008000
|
#define IMA_READ_APPRAISED 0x00080000
|
||||||
#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
|
#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
|
||||||
IMA_BPRM_APPRAISE | IMA_READ_APPRAISE)
|
IMA_BPRM_APPRAISE | IMA_READ_APPRAISE)
|
||||||
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
|
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
|
||||||
|
|
Loading…
Reference in New Issue