Skip to content

Commit e37be53

Browse files
committed
Merge branch 'ima-buffer-measurement-changes-v4' into next-integrity
Based on cover letter "ima: Provide more info about buffer measurement": Providing more information about buffer measurements requires modification of the existing functions ima_measure_critical_data() and process_buffer_measurement(). Unlike for file measurements, there is no integrity_iint_cache structure for storing and retrieving buffer measurements. With these changes, kernel subsystems relying on IMA to measure critical data don't have to duplicate the function to calculate the buffer digest but, instead, can get directly the one that IMA would insert, depending on the policy, in the new measurement list entry.
2 parents a32ad90 + ca3c9bd commit e37be53

8 files changed

Lines changed: 79 additions & 38 deletions

File tree

include/linux/ima.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
#include <linux/fs.h>
1212
#include <linux/security.h>
1313
#include <linux/kexec.h>
14+
#include <crypto/hash_info.h>
1415
struct linux_binprm;
1516

1617
#ifdef CONFIG_IMA
18+
extern enum hash_algo ima_get_current_hash_algo(void);
1719
extern int ima_bprm_check(struct linux_binprm *bprm);
1820
extern int ima_file_check(struct file *file, int mask);
1921
extern void ima_post_create_tmpfile(struct user_namespace *mnt_userns,
@@ -33,10 +35,10 @@ extern void ima_post_path_mknod(struct user_namespace *mnt_userns,
3335
extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
3436
extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
3537
extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
36-
extern void ima_measure_critical_data(const char *event_label,
37-
const char *event_name,
38-
const void *buf, size_t buf_len,
39-
bool hash);
38+
extern int ima_measure_critical_data(const char *event_label,
39+
const char *event_name,
40+
const void *buf, size_t buf_len,
41+
bool hash, u8 *digest, size_t digest_len);
4042

4143
#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
4244
extern void ima_appraise_parse_cmdline(void);
@@ -64,6 +66,11 @@ static inline const char * const *arch_get_ima_policy(void)
6466
#endif
6567

6668
#else
69+
static inline enum hash_algo ima_get_current_hash_algo(void)
70+
{
71+
return HASH_ALGO__LAST;
72+
}
73+
6774
static inline int ima_bprm_check(struct linux_binprm *bprm)
6875
{
6976
return 0;
@@ -137,10 +144,14 @@ static inline int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size
137144

138145
static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
139146

140-
static inline void ima_measure_critical_data(const char *event_label,
147+
static inline int ima_measure_critical_data(const char *event_label,
141148
const char *event_name,
142149
const void *buf, size_t buf_len,
143-
bool hash) {}
150+
bool hash, u8 *digest,
151+
size_t digest_len)
152+
{
153+
return -ENOENT;
154+
}
144155

145156
#endif /* CONFIG_IMA */
146157

security/integrity/ima/ima.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,11 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
264264
struct evm_ima_xattr_data *xattr_value,
265265
int xattr_len, const struct modsig *modsig, int pcr,
266266
struct ima_template_desc *template_desc);
267-
void process_buffer_measurement(struct user_namespace *mnt_userns,
268-
struct inode *inode, const void *buf, int size,
269-
const char *eventname, enum ima_hooks func,
270-
int pcr, const char *func_data,
271-
bool buf_hash);
267+
int process_buffer_measurement(struct user_namespace *mnt_userns,
268+
struct inode *inode, const void *buf, int size,
269+
const char *eventname, enum ima_hooks func,
270+
int pcr, const char *func_data,
271+
bool buf_hash, u8 *digest, size_t digest_len);
272272
void ima_audit_measurement(struct integrity_iint_cache *iint,
273273
const unsigned char *filename);
274274
int ima_alloc_init_template(struct ima_event_data *event_data,

security/integrity/ima/ima_appraise.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
357357
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
358358
process_buffer_measurement(&init_user_ns, NULL, digest, digestsize,
359359
"blacklisted-hash", NONE,
360-
pcr, NULL, false);
360+
pcr, NULL, false, NULL, 0);
361361
}
362362

363363
return rc;

security/integrity/ima/ima_asymmetric_keys.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,5 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
6262
*/
6363
process_buffer_measurement(&init_user_ns, NULL, payload, payload_len,
6464
keyring->description, KEY_CHECK, 0,
65-
keyring->description, false);
65+
keyring->description, false, NULL, 0);
6666
}

security/integrity/ima/ima_init.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ int __init ima_init(void)
154154
ima_init_key_queue();
155155

156156
ima_measure_critical_data("kernel_info", "kernel_version",
157-
UTS_RELEASE, strlen(UTS_RELEASE), false);
157+
UTS_RELEASE, strlen(UTS_RELEASE), false,
158+
NULL, 0);
158159

159160
return rc;
160161
}

security/integrity/ima/ima_main.c

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ int ima_appraise = IMA_APPRAISE_ENFORCE;
3535
int ima_appraise;
3636
#endif
3737

38-
int ima_hash_algo = HASH_ALGO_SHA1;
38+
int __ro_after_init ima_hash_algo = HASH_ALGO_SHA1;
3939
static int hash_setup_done;
4040

4141
static struct notifier_block ima_lsm_policy_notifier = {
@@ -76,6 +76,11 @@ static int __init hash_setup(char *str)
7676
}
7777
__setup("ima_hash=", hash_setup);
7878

79+
enum hash_algo ima_get_current_hash_algo(void)
80+
{
81+
return ima_hash_algo;
82+
}
83+
7984
/* Prevent mmap'ing a file execute that is already mmap'ed write */
8085
static int mmap_violation_check(enum ima_hooks func, struct file *file,
8186
char **pathbuf, const char **pathname,
@@ -822,7 +827,7 @@ int ima_post_load_data(char *buf, loff_t size,
822827
return 0;
823828
}
824829

825-
/*
830+
/**
826831
* process_buffer_measurement - Measure the buffer or the buffer data hash
827832
* @mnt_userns: user namespace of the mount the inode was found from
828833
* @inode: inode associated with the object being measured (NULL for KEY_CHECK)
@@ -833,14 +838,20 @@ int ima_post_load_data(char *buf, loff_t size,
833838
* @pcr: pcr to extend the measurement
834839
* @func_data: func specific data, may be NULL
835840
* @buf_hash: measure buffer data hash
841+
* @digest: buffer digest will be written to
842+
* @digest_len: buffer length
836843
*
837844
* Based on policy, either the buffer data or buffer data hash is measured
845+
*
846+
* Return: 0 if the buffer has been successfully measured, 1 if the digest
847+
* has been written to the passed location but not added to a measurement entry,
848+
* a negative value otherwise.
838849
*/
839-
void process_buffer_measurement(struct user_namespace *mnt_userns,
840-
struct inode *inode, const void *buf, int size,
841-
const char *eventname, enum ima_hooks func,
842-
int pcr, const char *func_data,
843-
bool buf_hash)
850+
int process_buffer_measurement(struct user_namespace *mnt_userns,
851+
struct inode *inode, const void *buf, int size,
852+
const char *eventname, enum ima_hooks func,
853+
int pcr, const char *func_data,
854+
bool buf_hash, u8 *digest, size_t digest_len)
844855
{
845856
int ret = 0;
846857
const char *audit_cause = "ENOMEM";
@@ -861,8 +872,11 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
861872
int action = 0;
862873
u32 secid;
863874

864-
if (!ima_policy_flag)
865-
return;
875+
if (digest && digest_len < digest_hash_len)
876+
return -EINVAL;
877+
878+
if (!ima_policy_flag && !digest)
879+
return -ENOENT;
866880

867881
template = ima_template_desc_buf();
868882
if (!template) {
@@ -883,8 +897,8 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
883897
action = ima_get_action(mnt_userns, inode, current_cred(),
884898
secid, 0, func, &pcr, &template,
885899
func_data);
886-
if (!(action & IMA_MEASURE))
887-
return;
900+
if (!(action & IMA_MEASURE) && !digest)
901+
return -ENOENT;
888902
}
889903

890904
if (!pcr)
@@ -914,6 +928,12 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
914928
event_data.buf_len = digest_hash_len;
915929
}
916930

931+
if (digest)
932+
memcpy(digest, iint.ima_hash->digest, digest_hash_len);
933+
934+
if (!ima_policy_flag || (func && !(action & IMA_MEASURE)))
935+
return 1;
936+
917937
ret = ima_alloc_init_template(&event_data, &entry, template);
918938
if (ret < 0) {
919939
audit_cause = "alloc_entry";
@@ -932,7 +952,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
932952
func_measure_str(func),
933953
audit_cause, ret, 0, ret);
934954

935-
return;
955+
return ret;
936956
}
937957

938958
/**
@@ -956,7 +976,7 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
956976

957977
process_buffer_measurement(file_mnt_user_ns(f.file), file_inode(f.file),
958978
buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0,
959-
NULL, false);
979+
NULL, false, NULL, 0);
960980
fdput(f);
961981
}
962982

@@ -967,23 +987,30 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
967987
* @buf: pointer to buffer data
968988
* @buf_len: length of buffer data (in bytes)
969989
* @hash: measure buffer data hash
990+
* @digest: buffer digest will be written to
991+
* @digest_len: buffer length
970992
*
971993
* Measure data critical to the integrity of the kernel into the IMA log
972994
* and extend the pcr. Examples of critical data could be various data
973995
* structures, policies, and states stored in kernel memory that can
974996
* impact the integrity of the system.
997+
*
998+
* Return: 0 if the buffer has been successfully measured, 1 if the digest
999+
* has been written to the passed location but not added to a measurement entry,
1000+
* a negative value otherwise.
9751001
*/
976-
void ima_measure_critical_data(const char *event_label,
977-
const char *event_name,
978-
const void *buf, size_t buf_len,
979-
bool hash)
1002+
int ima_measure_critical_data(const char *event_label,
1003+
const char *event_name,
1004+
const void *buf, size_t buf_len,
1005+
bool hash, u8 *digest, size_t digest_len)
9801006
{
9811007
if (!event_name || !event_label || !buf || !buf_len)
982-
return;
1008+
return -ENOPARAM;
9831009

984-
process_buffer_measurement(&init_user_ns, NULL, buf, buf_len, event_name,
985-
CRITICAL_DATA, 0, event_label,
986-
hash);
1010+
return process_buffer_measurement(&init_user_ns, NULL, buf, buf_len,
1011+
event_name, CRITICAL_DATA, 0,
1012+
event_label, hash, digest,
1013+
digest_len);
9871014
}
9881015

9891016
static int __init init_ima(void)

security/integrity/ima/ima_queue_keys.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ void ima_process_queued_keys(void)
165165
entry->keyring_name,
166166
KEY_CHECK, 0,
167167
entry->keyring_name,
168-
false);
168+
false, NULL, 0);
169169
list_del(&entry->list);
170170
ima_free_key_entry(entry);
171171
}

security/selinux/ima.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
8686
}
8787

8888
ima_measure_critical_data("selinux", "selinux-state",
89-
state_str, strlen(state_str), false);
89+
state_str, strlen(state_str), false,
90+
NULL, 0);
9091

9192
kfree(state_str);
9293

@@ -103,7 +104,8 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
103104
}
104105

105106
ima_measure_critical_data("selinux", "selinux-policy-hash",
106-
policy, policy_len, true);
107+
policy, policy_len, true,
108+
NULL, 0);
107109

108110
vfree(policy);
109111
}

0 commit comments

Comments
 (0)