Commit 4834177e authored by Tyler Hicks's avatar Tyler Hicks Committed by Mimi Zohar

ima: Support additional conditionals in the KEXEC_CMDLINE hook function

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: default avatarTyler Hicks <tyhicks@linux.microsoft.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: kexec@lists.infradead.org
Reviewed-by: default avatarLakshmi Ramasubramanian <nramas@linux.microsoft.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
parent 592b24cb
...@@ -25,7 +25,7 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size, ...@@ -25,7 +25,7 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id id); enum kernel_read_file_id id);
extern void ima_post_path_mknod(struct dentry *dentry); extern void ima_post_path_mknod(struct dentry *dentry);
extern int ima_file_hash(struct file *file, char *buf, size_t buf_size); 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 #ifdef CONFIG_IMA_KEXEC
extern void ima_add_kexec_buffer(struct kimage *image); extern void ima_add_kexec_buffer(struct kimage *image);
...@@ -103,7 +103,7 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size) ...@@ -103,7 +103,7 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
return -EOPNOTSUPP; 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 */ #endif /* CONFIG_IMA */
#ifndef CONFIG_IMA_KEXEC #ifndef CONFIG_IMA_KEXEC
......
...@@ -287,7 +287,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, ...@@ -287,7 +287,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
goto out; goto out;
} }
ima_kexec_cmdline(image->cmdline_buf, ima_kexec_cmdline(kernel_fd, image->cmdline_buf,
image->cmdline_buf_len - 1); image->cmdline_buf_len - 1);
} }
......
...@@ -265,7 +265,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, ...@@ -265,7 +265,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
struct evm_ima_xattr_data *xattr_value, struct evm_ima_xattr_data *xattr_value,
int xattr_len, const struct modsig *modsig, int pcr, int xattr_len, const struct modsig *modsig, int pcr,
struct ima_template_desc *template_desc); 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, const char *eventname, enum ima_hooks func,
int pcr, const char *keyring); int pcr, const char *keyring);
void ima_audit_measurement(struct integrity_iint_cache *iint, void ima_audit_measurement(struct integrity_iint_cache *iint,
......
...@@ -162,7 +162,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, ...@@ -162,7 +162,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
/** /**
* ima_get_action - appraise & measure decision based on policy. * 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 * @cred: pointer to credentials structure to validate
* @secid: secid of the task being validated * @secid: secid of the task being validated
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC, * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
......
...@@ -328,7 +328,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, ...@@ -328,7 +328,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
rc = is_binary_blacklisted(digest, digestsize); rc = is_binary_blacklisted(digest, digestsize);
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE)) if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
process_buffer_measurement(digest, digestsize, process_buffer_measurement(NULL, digest, digestsize,
"blacklisted-hash", NONE, "blacklisted-hash", NONE,
pcr, NULL); pcr, NULL);
} }
......
...@@ -58,7 +58,7 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, ...@@ -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 * if the IMA policy is configured to measure a key linked
* to the given keyring. * to the given keyring.
*/ */
process_buffer_measurement(payload, payload_len, process_buffer_measurement(NULL, payload, payload_len,
keyring->description, KEY_CHECK, 0, keyring->description, KEY_CHECK, 0,
keyring->description); keyring->description);
} }
...@@ -726,6 +726,7 @@ int ima_load_data(enum kernel_load_data_id id) ...@@ -726,6 +726,7 @@ int ima_load_data(enum kernel_load_data_id id)
/* /*
* process_buffer_measurement - Measure the buffer to ima log. * 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. * @buf: pointer to the buffer that needs to be added to the log.
* @size: size of buffer(in bytes). * @size: size of buffer(in bytes).
* @eventname: event name to be used for the buffer entry. * @eventname: event name to be used for the buffer entry.
...@@ -735,7 +736,7 @@ int ima_load_data(enum kernel_load_data_id id) ...@@ -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. * 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, const char *eventname, enum ima_hooks func,
int pcr, const char *keyring) int pcr, const char *keyring)
{ {
...@@ -768,7 +769,7 @@ void process_buffer_measurement(const void *buf, int size, ...@@ -768,7 +769,7 @@ void process_buffer_measurement(const void *buf, int size,
*/ */
if (func) { if (func) {
security_task_getsecid(current, &secid); 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); &pcr, &template, keyring);
if (!(action & IMA_MEASURE)) if (!(action & IMA_MEASURE))
return; return;
...@@ -823,16 +824,26 @@ void process_buffer_measurement(const void *buf, int size, ...@@ -823,16 +824,26 @@ void process_buffer_measurement(const void *buf, int size,
/** /**
* ima_kexec_cmdline - measure kexec cmdline boot args * ima_kexec_cmdline - measure kexec cmdline boot args
* @kernel_fd: file descriptor of the kexec kernel being loaded
* @buf: pointer to buffer * @buf: pointer to buffer
* @size: size of buffer * @size: size of buffer
* *
* Buffers can only be measured, not appraised. * 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) struct fd f;
process_buffer_measurement(buf, size, "kexec-cmdline",
KEXEC_CMDLINE, 0, NULL); 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) static int __init init_ima(void)
......
...@@ -443,13 +443,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, ...@@ -443,13 +443,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
{ {
int i; int i;
if ((func == KEXEC_CMDLINE) || (func == KEY_CHECK)) { if (func == KEY_CHECK) {
if ((rule->flags & IMA_FUNC) && (rule->func == func)) { return (rule->flags & IMA_FUNC) && (rule->func == func) &&
if (func == KEY_CHECK) ima_match_keyring(rule, keyring, cred);
return ima_match_keyring(rule, keyring, cred);
return true;
}
return false;
} }
if ((rule->flags & IMA_FUNC) && if ((rule->flags & IMA_FUNC) &&
(rule->func != func && func != POST_SETATTR)) (rule->func != func && func != POST_SETATTR))
...@@ -1035,10 +1031,9 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) ...@@ -1035,10 +1031,9 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
if (entry->action & ~(MEASURE | DONT_MEASURE)) if (entry->action & ~(MEASURE | DONT_MEASURE))
return false; return false;
if (entry->flags & ~(IMA_FUNC | IMA_PCR)) if (entry->flags & ~(IMA_FUNC | IMA_FSMAGIC | IMA_UID |
return false; IMA_FOWNER | IMA_FSUUID | IMA_EUID |
IMA_PCR | IMA_FSNAME))
if (ima_rule_contains_lsm_cond(entry))
return false; return false;
break; break;
......
...@@ -158,7 +158,7 @@ void ima_process_queued_keys(void) ...@@ -158,7 +158,7 @@ void ima_process_queued_keys(void)
list_for_each_entry_safe(entry, tmp, &ima_keys, list) { list_for_each_entry_safe(entry, tmp, &ima_keys, list) {
if (!timer_expired) if (!timer_expired)
process_buffer_measurement(entry->payload, process_buffer_measurement(NULL, entry->payload,
entry->payload_len, entry->payload_len,
entry->keyring_name, entry->keyring_name,
KEY_CHECK, 0, KEY_CHECK, 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