Skip to content

Commit a068d93

Browse files
committed
Merge branch 'validate-policy-rules' into next-integrity
From "ima: Fix rule parsing bugs and extend KEXEC_CMDLINE rule support" coverletter. This series ultimately extends the supported IMA rule conditionals for the KEXEC_CMDLINE hook function. As of today, there's an imbalance in IMA language conditional support for KEXEC_CMDLINE rules in comparison to KEXEC_KERNEL_CHECK and KEXEC_INITRAMFS_CHECK rules. The KEXEC_CMDLINE rules do not support *any* conditionals so you cannot have a sequence 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 Instead, KEXEC_CMDLINE rules can only be measured or not measured and there's no additional flexibility in today's implementation of the KEXEC_CMDLINE hook function. With this series, the above sequence of rules becomes valid and any calls to kexec_file_load() with a kernel and initramfs inode type of foo_t will not be measured (that includes the kernel cmdline buffer) while all other objects given to a kexec_file_load() syscall will be measured. There's obviously not an inode directly associated with the kernel cmdline buffer but this patch series ties the inode based decision making for KEXEC_CMDLINE to the kernel's inode. I think this will be intuitive to policy authors. While reading IMA code and preparing to make this change, I realized that the buffer based hook functions (KEXEC_CMDLINE and KEY_CHECK) are quite special in comparison to longer standing hook functions. These buffer based hook functions can only support measure actions and there are some restrictions on the conditionals that they support. However, the rule parser isn't enforcing any of those restrictions and IMA policy authors wouldn't have any immediate way of knowing that the policy that they wrote is invalid. For example, the sequence of rules above parses successfully in today's kernel but the "dont_measure func=KEXEC_CMDLINE ..." rule is incorrectly handled in ima_match_rules(). The dont_measure rule is *always* considered to be a match so, surprisingly, no KEXEC_CMDLINE measurements are made. While making the rule parser more strict, I realized that the parser does not correctly free all of the allocated memory associated with an ima_rule_entry when going down some error paths. Invalid policy loaded by the policy administrator could result in small memory leaks.
2 parents 34e980b + 4834177 commit a068d93

File tree

10 files changed

+184
-94
lines changed

10 files changed

+184
-94
lines changed

include/linux/ima.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
2525
enum kernel_read_file_id id);
2626
extern void ima_post_path_mknod(struct dentry *dentry);
2727
extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
28-
extern void ima_kexec_cmdline(const void *buf, int size);
28+
extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
2929

3030
#ifdef CONFIG_IMA_KEXEC
3131
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)
103103
return -EOPNOTSUPP;
104104
}
105105

106-
static inline void ima_kexec_cmdline(const void *buf, int size) {}
106+
static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
107107
#endif /* CONFIG_IMA */
108108

109109
#ifndef CONFIG_IMA_KEXEC

kernel/kexec_file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
287287
goto out;
288288
}
289289

290-
ima_kexec_cmdline(image->cmdline_buf,
290+
ima_kexec_cmdline(kernel_fd, image->cmdline_buf,
291291
image->cmdline_buf_len - 1);
292292
}
293293

security/integrity/ima/ima.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
265265
struct evm_ima_xattr_data *xattr_value,
266266
int xattr_len, const struct modsig *modsig, int pcr,
267267
struct ima_template_desc *template_desc);
268-
void process_buffer_measurement(const void *buf, int size,
268+
void process_buffer_measurement(struct inode *inode, const void *buf, int size,
269269
const char *eventname, enum ima_hooks func,
270270
int pcr, const char *keyring);
271271
void ima_audit_measurement(struct integrity_iint_cache *iint,
@@ -372,7 +372,6 @@ static inline int ima_read_xattr(struct dentry *dentry,
372372
#endif /* CONFIG_IMA_APPRAISE */
373373

374374
#ifdef CONFIG_IMA_APPRAISE_MODSIG
375-
bool ima_hook_supports_modsig(enum ima_hooks func);
376375
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
377376
struct modsig **modsig);
378377
void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size);
@@ -382,11 +381,6 @@ int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
382381
u32 *data_len);
383382
void ima_free_modsig(struct modsig *modsig);
384383
#else
385-
static inline bool ima_hook_supports_modsig(enum ima_hooks func)
386-
{
387-
return false;
388-
}
389-
390384
static inline int ima_read_modsig(enum ima_hooks func, const void *buf,
391385
loff_t buf_len, struct modsig **modsig)
392386
{
@@ -420,6 +414,7 @@ static inline void ima_free_modsig(struct modsig *modsig)
420414
#ifdef CONFIG_IMA_LSM_RULES
421415

422416
#define security_filter_rule_init security_audit_rule_init
417+
#define security_filter_rule_free security_audit_rule_free
423418
#define security_filter_rule_match security_audit_rule_match
424419

425420
#else
@@ -430,6 +425,10 @@ static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr,
430425
return -EINVAL;
431426
}
432427

428+
static inline void security_filter_rule_free(void *lsmrule)
429+
{
430+
}
431+
433432
static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
434433
void *lsmrule)
435434
{

security/integrity/ima/ima_api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
162162

163163
/**
164164
* ima_get_action - appraise & measure decision based on policy.
165-
* @inode: pointer to inode to measure
165+
* @inode: pointer to the inode associated with the object being validated
166166
* @cred: pointer to credentials structure to validate
167167
* @secid: secid of the task being validated
168168
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,

security/integrity/ima/ima_appraise.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
328328

329329
rc = is_binary_blacklisted(digest, digestsize);
330330
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
331-
process_buffer_measurement(digest, digestsize,
331+
process_buffer_measurement(NULL, digest, digestsize,
332332
"blacklisted-hash", NONE,
333333
pcr, NULL);
334334
}

security/integrity/ima/ima_asymmetric_keys.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
5858
* if the IMA policy is configured to measure a key linked
5959
* to the given keyring.
6060
*/
61-
process_buffer_measurement(payload, payload_len,
61+
process_buffer_measurement(NULL, payload, payload_len,
6262
keyring->description, KEY_CHECK, 0,
6363
keyring->description);
6464
}

security/integrity/ima/ima_main.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,7 @@ int ima_load_data(enum kernel_load_data_id id)
726726

727727
/*
728728
* process_buffer_measurement - Measure the buffer to ima log.
729+
* @inode: inode associated with the object being measured (NULL for KEY_CHECK)
729730
* @buf: pointer to the buffer that needs to be added to the log.
730731
* @size: size of buffer(in bytes).
731732
* @eventname: event name to be used for the buffer entry.
@@ -735,7 +736,7 @@ int ima_load_data(enum kernel_load_data_id id)
735736
*
736737
* Based on policy, the buffer is measured into the ima log.
737738
*/
738-
void process_buffer_measurement(const void *buf, int size,
739+
void process_buffer_measurement(struct inode *inode, const void *buf, int size,
739740
const char *eventname, enum ima_hooks func,
740741
int pcr, const char *keyring)
741742
{
@@ -768,7 +769,7 @@ void process_buffer_measurement(const void *buf, int size,
768769
*/
769770
if (func) {
770771
security_task_getsecid(current, &secid);
771-
action = ima_get_action(NULL, current_cred(), secid, 0, func,
772+
action = ima_get_action(inode, current_cred(), secid, 0, func,
772773
&pcr, &template, keyring);
773774
if (!(action & IMA_MEASURE))
774775
return;
@@ -823,16 +824,26 @@ void process_buffer_measurement(const void *buf, int size,
823824

824825
/**
825826
* ima_kexec_cmdline - measure kexec cmdline boot args
827+
* @kernel_fd: file descriptor of the kexec kernel being loaded
826828
* @buf: pointer to buffer
827829
* @size: size of buffer
828830
*
829831
* Buffers can only be measured, not appraised.
830832
*/
831-
void ima_kexec_cmdline(const void *buf, int size)
833+
void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
832834
{
833-
if (buf && size != 0)
834-
process_buffer_measurement(buf, size, "kexec-cmdline",
835-
KEXEC_CMDLINE, 0, NULL);
835+
struct fd f;
836+
837+
if (!buf || !size)
838+
return;
839+
840+
f = fdget(kernel_fd);
841+
if (!f.file)
842+
return;
843+
844+
process_buffer_measurement(file_inode(f.file), buf, size,
845+
"kexec-cmdline", KEXEC_CMDLINE, 0, NULL);
846+
fdput(f);
836847
}
837848

838849
static int __init init_ima(void)

security/integrity/ima/ima_modsig.c

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,6 @@ struct modsig {
3232
u8 raw_pkcs7[];
3333
};
3434

35-
/**
36-
* ima_hook_supports_modsig - can the policy allow modsig for this hook?
37-
*
38-
* modsig is only supported by hooks using ima_post_read_file(), because only
39-
* they preload the contents of the file in a buffer. FILE_CHECK does that in
40-
* some cases, but not when reached from vfs_open(). POLICY_CHECK can support
41-
* it, but it's not useful in practice because it's a text file so deny.
42-
*/
43-
bool ima_hook_supports_modsig(enum ima_hooks func)
44-
{
45-
switch (func) {
46-
case KEXEC_KERNEL_CHECK:
47-
case KEXEC_INITRAMFS_CHECK:
48-
case MODULE_CHECK:
49-
return true;
50-
default:
51-
return false;
52-
}
53-
}
54-
5535
/*
5636
* ima_read_modsig - Read modsig from buf.
5737
*

0 commit comments

Comments
 (0)