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: Tyler Hicks <tyhicks@linux.microsoft.com> Cc: Eric Biederman <ebiederm@xmission.com> Cc: kexec@lists.infradead.org Reviewed-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
This commit is contained in:
parent
592b24cbdc
commit
4834177e63
@ -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);
|
||||
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -162,7 +162,7 @@ err_out:
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
@ -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)
|
||||
{
|
||||
@ -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;
|
||||
@ -823,16 +824,26 @@ out:
|
||||
|
||||
/**
|
||||
* 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)
|
||||
|
@ -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))
|
||||
@ -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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user