Skip to content

Commit d07eeeb

Browse files
committed
Merge branch 'restrict-digest-alg-v8' into next-integrity
Taken from the cover letter "IMA: restrict the accepted digest algorithms for the security.ima xattr": Provide users the ability to restrict the algorithms accepted by their system, both when writing/updating xattrs, and when appraising files, while retaining a permissive behavior by default to preserve backward compatibility. To provide these features, alter the behavior of setxattr to only accept hashes built in the kernel, instead of any hash listed in the kernel (complete list crypto/hash_info.c). In addition, the user can define in his IMA policy the list of digest algorithms allowed for writing to the security.ima xattr. In that case, only algorithms present in that list are accepted for writing. In addition, users may opt-in to allowlist hash algorithms for appraising thanks to the new 'appraise_algos' IMA policy option. By default IMA will keep accepting any hash algorithm, but specifying that option will make appraisal of files hashed with another algorithm fail. Link: https://lore.kernel.org/linux-integrity/20210816081056.24530-1-Simon.THOBY@viveris.fr/
2 parents e37be53 + 8ecd39c commit d07eeeb

7 files changed

Lines changed: 268 additions & 35 deletions

File tree

Documentation/ABI/testing/ima_policy

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ Description:
2727
lsm: [[subj_user=] [subj_role=] [subj_type=]
2828
[obj_user=] [obj_role=] [obj_type=]]
2929
option: [[appraise_type=]] [template=] [permit_directio]
30-
[appraise_flag=] [keyrings=]
30+
[appraise_flag=] [appraise_algos=] [keyrings=]
3131
base:
3232
func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
33-
[FIRMWARE_CHECK]
33+
[FIRMWARE_CHECK]
3434
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
3535
[KEXEC_CMDLINE] [KEY_CHECK] [CRITICAL_DATA]
36+
[SETXATTR_CHECK]
3637
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
3738
[[^]MAY_EXEC]
3839
fsmagic:= hex value
@@ -55,6 +56,10 @@ Description:
5556
label:= [selinux]|[kernel_info]|[data_label]
5657
data_label:= a unique string used for grouping and limiting critical data.
5758
For example, "selinux" to measure critical data for SELinux.
59+
appraise_algos:= comma-separated list of hash algorithms
60+
For example, "sha256,sha512" to only accept to appraise
61+
files where the security.ima xattr was hashed with one
62+
of these two algorithms.
5863

5964
default policy:
6065
# PROC_SUPER_MAGIC
@@ -134,3 +139,9 @@ Description:
134139
keys added to .builtin_trusted_keys or .ima keyring:
135140

136141
measure func=KEY_CHECK keyrings=.builtin_trusted_keys|.ima
142+
143+
Example of the special SETXATTR_CHECK appraise rule, that
144+
restricts the hash algorithms allowed when writing to the
145+
security.ima xattr of a file:
146+
147+
appraise func=SETXATTR_CHECK appraise_algos=sha256,sha384,sha512

security/integrity/ima/Kconfig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ config IMA
66
select SECURITYFS
77
select CRYPTO
88
select CRYPTO_HMAC
9-
select CRYPTO_MD5
109
select CRYPTO_SHA1
1110
select CRYPTO_HASH_INFO
1211
select TCG_TPM if HAS_IOMEM && !UML

security/integrity/ima/ima.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
4646
/* current content of the policy */
4747
extern int ima_policy_flag;
4848

49+
/* bitset of digests algorithms allowed in the setxattr hook */
50+
extern atomic_t ima_setxattr_allowed_hash_algorithms;
51+
4952
/* set during initialization */
50-
extern int ima_hash_algo;
53+
extern int ima_hash_algo __ro_after_init;
5154
extern int ima_sha1_idx __ro_after_init;
5255
extern int ima_hash_algo_idx __ro_after_init;
5356
extern int ima_extra_slots __ro_after_init;
@@ -198,6 +201,7 @@ static inline unsigned int ima_hash_key(u8 *digest)
198201
hook(KEXEC_CMDLINE, kexec_cmdline) \
199202
hook(KEY_CHECK, key) \
200203
hook(CRITICAL_DATA, critical_data) \
204+
hook(SETXATTR_CHECK, setxattr_check) \
201205
hook(MAX_CHECK, none)
202206

203207
#define __ima_hook_enumify(ENUM, str) ENUM,
@@ -254,7 +258,7 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
254258
const struct cred *cred, u32 secid, int mask,
255259
enum ima_hooks func, int *pcr,
256260
struct ima_template_desc **template_desc,
257-
const char *func_data);
261+
const char *func_data, unsigned int *allowed_algos);
258262
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
259263
int ima_collect_measurement(struct integrity_iint_cache *iint,
260264
struct file *file, void *buf, loff_t size,
@@ -285,10 +289,10 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
285289
const struct cred *cred, u32 secid, enum ima_hooks func,
286290
int mask, int flags, int *pcr,
287291
struct ima_template_desc **template_desc,
288-
const char *func_data);
292+
const char *func_data, unsigned int *allowed_algos);
289293
void ima_init_policy(void);
290294
void ima_update_policy(void);
291-
void ima_update_policy_flag(void);
295+
void ima_update_policy_flags(void);
292296
ssize_t ima_parse_add_rule(char *);
293297
void ima_delete_rules(void);
294298
int ima_check_policy(void);
@@ -319,7 +323,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
319323
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
320324
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
321325
enum ima_hooks func);
322-
enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
326+
enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
323327
int xattr_len);
324328
int ima_read_xattr(struct dentry *dentry,
325329
struct evm_ima_xattr_data **xattr_value);

security/integrity/ima/ima_api.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
172172
* @pcr: pointer filled in if matched measure policy sets pcr=
173173
* @template_desc: pointer filled in if matched measure policy sets template=
174174
* @func_data: func specific data, may be NULL
175+
* @allowed_algos: allowlist of hash algorithms for the IMA xattr
175176
*
176177
* The policy is defined in terms of keypairs:
177178
* subj=, obj=, type=, func=, mask=, fsmagic=
@@ -188,14 +189,15 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
188189
const struct cred *cred, u32 secid, int mask,
189190
enum ima_hooks func, int *pcr,
190191
struct ima_template_desc **template_desc,
191-
const char *func_data)
192+
const char *func_data, unsigned int *allowed_algos)
192193
{
193194
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
194195

195196
flags &= ima_policy_flag;
196197

197198
return ima_match_policy(mnt_userns, inode, cred, secid, func, mask,
198-
flags, pcr, template_desc, func_data);
199+
flags, pcr, template_desc, func_data,
200+
allowed_algos);
199201
}
200202

201203
/*

security/integrity/ima/ima_appraise.c

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
7777
return 0;
7878

7979
security_task_getsecid_subj(current, &secid);
80-
return ima_match_policy(mnt_userns, inode, current_cred(), secid, func,
81-
mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL);
80+
return ima_match_policy(mnt_userns, inode, current_cred(), secid,
81+
func, mask, IMA_APPRAISE | IMA_HASH, NULL,
82+
NULL, NULL, NULL);
8283
}
8384

8485
static int ima_fix_xattr(struct dentry *dentry,
@@ -171,7 +172,7 @@ static void ima_cache_flags(struct integrity_iint_cache *iint,
171172
}
172173
}
173174

174-
enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
175+
enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
175176
int xattr_len)
176177
{
177178
struct signature_v2_hdr *sig;
@@ -575,6 +576,66 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
575576
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
576577
}
577578

579+
/**
580+
* validate_hash_algo() - Block setxattr with unsupported hash algorithms
581+
* @dentry: object of the setxattr()
582+
* @xattr_value: userland supplied xattr value
583+
* @xattr_value_len: length of xattr_value
584+
*
585+
* The xattr value is mapped to its hash algorithm, and this algorithm
586+
* must be built in the kernel for the setxattr to be allowed.
587+
*
588+
* Emit an audit message when the algorithm is invalid.
589+
*
590+
* Return: 0 on success, else an error.
591+
*/
592+
static int validate_hash_algo(struct dentry *dentry,
593+
const struct evm_ima_xattr_data *xattr_value,
594+
size_t xattr_value_len)
595+
{
596+
char *path = NULL, *pathbuf = NULL;
597+
enum hash_algo xattr_hash_algo;
598+
const char *errmsg = "unavailable-hash-algorithm";
599+
unsigned int allowed_hashes;
600+
601+
xattr_hash_algo = ima_get_hash_algo(xattr_value, xattr_value_len);
602+
603+
allowed_hashes = atomic_read(&ima_setxattr_allowed_hash_algorithms);
604+
605+
if (allowed_hashes) {
606+
/* success if the algorithm is allowed in the ima policy */
607+
if (allowed_hashes & (1U << xattr_hash_algo))
608+
return 0;
609+
610+
/*
611+
* We use a different audit message when the hash algorithm
612+
* is denied by a policy rule, instead of not being built
613+
* in the kernel image
614+
*/
615+
errmsg = "denied-hash-algorithm";
616+
} else {
617+
if (likely(xattr_hash_algo == ima_hash_algo))
618+
return 0;
619+
620+
/* allow any xattr using an algorithm built in the kernel */
621+
if (crypto_has_alg(hash_algo_name[xattr_hash_algo], 0, 0))
622+
return 0;
623+
}
624+
625+
pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
626+
if (!pathbuf)
627+
return -EACCES;
628+
629+
path = dentry_path(dentry, pathbuf, PATH_MAX);
630+
631+
integrity_audit_msg(AUDIT_INTEGRITY_DATA, d_inode(dentry), path,
632+
"set_data", errmsg, -EACCES, 0);
633+
634+
kfree(pathbuf);
635+
636+
return -EACCES;
637+
}
638+
578639
int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
579640
const void *xattr_value, size_t xattr_value_len)
580641
{
@@ -592,9 +653,11 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
592653
digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
593654
}
594655
if (result == 1 || evm_revalidate_status(xattr_name)) {
656+
result = validate_hash_algo(dentry, xvalue, xattr_value_len);
657+
if (result)
658+
return result;
659+
595660
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
596-
if (result == 1)
597-
result = 0;
598661
}
599662
return result;
600663
}

security/integrity/ima/ima_main.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
215215
int xattr_len = 0;
216216
bool violation_check;
217217
enum hash_algo hash_algo;
218+
unsigned int allowed_algos = 0;
218219

219220
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
220221
return 0;
@@ -224,7 +225,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
224225
* Included is the appraise submask.
225226
*/
226227
action = ima_get_action(file_mnt_user_ns(file), inode, cred, secid,
227-
mask, func, &pcr, &template_desc, NULL);
228+
mask, func, &pcr, &template_desc, NULL,
229+
&allowed_algos);
228230
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
229231
(ima_policy_flag & IMA_MEASURE));
230232
if (!action && !violation_check)
@@ -361,6 +363,16 @@ static int process_measurement(struct file *file, const struct cred *cred,
361363

362364
if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO))
363365
rc = 0;
366+
367+
/* Ensure the digest was generated using an allowed algorithm */
368+
if (rc == 0 && must_appraise && allowed_algos != 0 &&
369+
(allowed_algos & (1U << hash_algo)) == 0) {
370+
rc = -EACCES;
371+
372+
integrity_audit_msg(AUDIT_INTEGRITY_DATA, file_inode(file),
373+
pathname, "collect_data",
374+
"denied-hash-algorithm", rc, 0);
375+
}
364376
out_locked:
365377
if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) &&
366378
!(iint->flags & IMA_NEW_FILE))
@@ -438,7 +450,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
438450
inode = file_inode(vma->vm_file);
439451
action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
440452
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
441-
&pcr, &template, NULL);
453+
&pcr, &template, NULL, NULL);
442454

443455
/* Is the mmap'ed file in policy? */
444456
if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
@@ -896,7 +908,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
896908
security_task_getsecid_subj(current, &secid);
897909
action = ima_get_action(mnt_userns, inode, current_cred(),
898910
secid, 0, func, &pcr, &template,
899-
func_data);
911+
func_data, NULL);
900912
if (!(action & IMA_MEASURE) && !digest)
901913
return -ENOENT;
902914
}
@@ -1039,7 +1051,7 @@ static int __init init_ima(void)
10391051
pr_warn("Couldn't register LSM notifier, error %d\n", error);
10401052

10411053
if (!error)
1042-
ima_update_policy_flag();
1054+
ima_update_policy_flags();
10431055

10441056
return error;
10451057
}

0 commit comments

Comments
 (0)