Skip to content

Commit

Permalink
ima: Support additional conditionals in the KEXEC_CMDLINE hook function
Browse files Browse the repository at this point in the history
Take the properties of the kexec kernel's inode and the current task
ownership into consideration when matching a KEXEC_CMDLINE operation to
the rules in the IMA policy. This allows for some uniformity when
writing IMA policy rules for KEXEC_KERNEL_CHECK, KEXEC_INITRAMFS_CHECK,
and KEXEC_CMDLINE operations.

Prior to this patch, it was not possible to write a set of rules like
this:

 dont_measure func=KEXEC_KERNEL_CHECK obj_type=foo_t
 dont_measure func=KEXEC_INITRAMFS_CHECK obj_type=foo_t
 dont_measure func=KEXEC_CMDLINE obj_type=foo_t
 measure func=KEXEC_KERNEL_CHECK
 measure func=KEXEC_INITRAMFS_CHECK
 measure func=KEXEC_CMDLINE

The inode information associated with the kernel being loaded by a
kexec_kernel_load(2) syscall can now be included in the decision to
measure or not

Additonally, the uid, euid, and subj_* conditionals can also now be
used in KEXEC_CMDLINE rules. There was no technical reason as to why
those conditionals weren't being considered previously other than
ima_match_rules() didn't have a valid inode to use so it immediately
bailed out for KEXEC_CMDLINE operations rather than going through the
full list of conditional comparisons.

Signed-off-by: Tyler Hicks <[email protected]>
Cc: Eric Biederman <[email protected]>
Cc: [email protected]
Reviewed-by: Lakshmi Ramasubramanian <[email protected]>
Signed-off-by: Mimi Zohar <[email protected]>
  • Loading branch information
tyhicks authored and mimizohar committed Jul 20, 2020
1 parent 592b24c commit 4834177
Show file tree
Hide file tree
Showing 9 changed files with 31 additions and 25 deletions.
4 changes: 2 additions & 2 deletions include/linux/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id id);
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(const void *buf, int size);
extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);

#ifdef CONFIG_IMA_KEXEC
extern void ima_add_kexec_buffer(struct kimage *image);
Expand Down Expand Up @@ -103,7 +103,7 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
return -EOPNOTSUPP;
}

static inline void ima_kexec_cmdline(const void *buf, int size) {}
static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
#endif /* CONFIG_IMA */

#ifndef CONFIG_IMA_KEXEC
Expand Down
2 changes: 1 addition & 1 deletion kernel/kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
goto out;
}

ima_kexec_cmdline(image->cmdline_buf,
ima_kexec_cmdline(kernel_fd, image->cmdline_buf,
image->cmdline_buf_len - 1);
}

Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, const struct modsig *modsig, int pcr,
struct ima_template_desc *template_desc);
void process_buffer_measurement(const void *buf, int size,
void process_buffer_measurement(struct inode *inode, const void *buf, int size,
const char *eventname, enum ima_hooks func,
int pcr, const char *keyring);
void ima_audit_measurement(struct integrity_iint_cache *iint,
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,

/**
* ima_get_action - appraise & measure decision based on policy.
* @inode: pointer to inode to measure
* @inode: pointer to the inode associated with the object being validated
* @cred: pointer to credentials structure to validate
* @secid: secid of the task being validated
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_appraise.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,

rc = is_binary_blacklisted(digest, digestsize);
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
process_buffer_measurement(digest, digestsize,
process_buffer_measurement(NULL, digest, digestsize,
"blacklisted-hash", NONE,
pcr, NULL);
}
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_asymmetric_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
* if the IMA policy is configured to measure a key linked
* to the given keyring.
*/
process_buffer_measurement(payload, payload_len,
process_buffer_measurement(NULL, payload, payload_len,
keyring->description, KEY_CHECK, 0,
keyring->description);
}
23 changes: 17 additions & 6 deletions security/integrity/ima/ima_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ int ima_load_data(enum kernel_load_data_id id)

/*
* process_buffer_measurement - Measure the buffer to ima log.
* @inode: inode associated with the object being measured (NULL for KEY_CHECK)
* @buf: pointer to the buffer that needs to be added to the log.
* @size: size of buffer(in bytes).
* @eventname: event name to be used for the buffer entry.
Expand All @@ -735,7 +736,7 @@ int ima_load_data(enum kernel_load_data_id id)
*
* Based on policy, the buffer is measured into the ima log.
*/
void process_buffer_measurement(const void *buf, int size,
void process_buffer_measurement(struct inode *inode, const void *buf, int size,
const char *eventname, enum ima_hooks func,
int pcr, const char *keyring)
{
Expand Down Expand Up @@ -768,7 +769,7 @@ void process_buffer_measurement(const void *buf, int size,
*/
if (func) {
security_task_getsecid(current, &secid);
action = ima_get_action(NULL, current_cred(), secid, 0, func,
action = ima_get_action(inode, current_cred(), secid, 0, func,
&pcr, &template, keyring);
if (!(action & IMA_MEASURE))
return;
Expand Down Expand Up @@ -823,16 +824,26 @@ void process_buffer_measurement(const void *buf, int size,

/**
* ima_kexec_cmdline - measure kexec cmdline boot args
* @kernel_fd: file descriptor of the kexec kernel being loaded
* @buf: pointer to buffer
* @size: size of buffer
*
* Buffers can only be measured, not appraised.
*/
void ima_kexec_cmdline(const void *buf, int size)
void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
{
if (buf && size != 0)
process_buffer_measurement(buf, size, "kexec-cmdline",
KEXEC_CMDLINE, 0, NULL);
struct fd f;

if (!buf || !size)
return;

f = fdget(kernel_fd);
if (!f.file)
return;

process_buffer_measurement(file_inode(f.file), buf, size,
"kexec-cmdline", KEXEC_CMDLINE, 0, NULL);
fdput(f);
}

static int __init init_ima(void)
Expand Down
17 changes: 6 additions & 11 deletions security/integrity/ima/ima_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,13 +443,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
{
int i;

if ((func == KEXEC_CMDLINE) || (func == KEY_CHECK)) {
if ((rule->flags & IMA_FUNC) && (rule->func == func)) {
if (func == KEY_CHECK)
return ima_match_keyring(rule, keyring, cred);
return true;
}
return false;
if (func == KEY_CHECK) {
return (rule->flags & IMA_FUNC) && (rule->func == func) &&
ima_match_keyring(rule, keyring, cred);
}
if ((rule->flags & IMA_FUNC) &&
(rule->func != func && func != POST_SETATTR))
Expand Down Expand Up @@ -1035,10 +1031,9 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
if (entry->action & ~(MEASURE | DONT_MEASURE))
return false;

if (entry->flags & ~(IMA_FUNC | IMA_PCR))
return false;

if (ima_rule_contains_lsm_cond(entry))
if (entry->flags & ~(IMA_FUNC | IMA_FSMAGIC | IMA_UID |
IMA_FOWNER | IMA_FSUUID | IMA_EUID |
IMA_PCR | IMA_FSNAME))
return false;

break;
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_queue_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ void ima_process_queued_keys(void)

list_for_each_entry_safe(entry, tmp, &ima_keys, list) {
if (!timer_expired)
process_buffer_measurement(entry->payload,
process_buffer_measurement(NULL, entry->payload,
entry->payload_len,
entry->keyring_name,
KEY_CHECK, 0,
Expand Down

0 comments on commit 4834177

Please sign in to comment.