Skip to content

Commit 1624dc0

Browse files
nightmaredmimizohar
authored andcommitted
IMA: add support to restrict the hash algorithms used for file appraisal
The kernel accepts any hash algorithm as a value for the security.ima xattr. Users may wish to restrict the accepted algorithms to only support strong cryptographic ones. Provide the plumbing to restrict the permitted set of hash algorithms used for verifying file hashes and signatures stored in security.ima xattr. Signed-off-by: THOBY Simon <Simon.THOBY@viveris.fr> Reviewed-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
1 parent 50f742d commit 1624dc0

5 files changed

Lines changed: 41 additions & 12 deletions

File tree

security/integrity/ima/ima.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
4747
extern int ima_policy_flag;
4848

4949
/* set during initialization */
50-
extern int ima_hash_algo;
50+
extern int ima_hash_algo __ro_after_init;
5151
extern int ima_sha1_idx __ro_after_init;
5252
extern int ima_hash_algo_idx __ro_after_init;
5353
extern int ima_extra_slots __ro_after_init;
@@ -254,7 +254,7 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
254254
const struct cred *cred, u32 secid, int mask,
255255
enum ima_hooks func, int *pcr,
256256
struct ima_template_desc **template_desc,
257-
const char *func_data);
257+
const char *func_data, unsigned int *allowed_algos);
258258
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
259259
int ima_collect_measurement(struct integrity_iint_cache *iint,
260260
struct file *file, void *buf, loff_t size,
@@ -285,7 +285,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
285285
const struct cred *cred, u32 secid, enum ima_hooks func,
286286
int mask, int flags, int *pcr,
287287
struct ima_template_desc **template_desc,
288-
const char *func_data);
288+
const char *func_data, unsigned int *allowed_algos);
289289
void ima_init_policy(void);
290290
void ima_update_policy(void);
291291
void ima_update_policy_flag(void);

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: 3 additions & 2 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,

security/integrity/ima/ima_main.c

Lines changed: 15 additions & 3 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
}

security/integrity/ima/ima_policy.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#define IMA_FSNAME 0x0200
3636
#define IMA_KEYRINGS 0x0400
3737
#define IMA_LABEL 0x0800
38+
#define IMA_VALIDATE_ALGOS 0x1000
3839

3940
#define UNKNOWN 0
4041
#define MEASURE 0x0001 /* same as IMA_MEASURE */
@@ -79,6 +80,7 @@ struct ima_rule_entry {
7980
bool (*uid_op)(kuid_t, kuid_t); /* Handlers for operators */
8081
bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */
8182
int pcr;
83+
unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
8284
struct {
8385
void *rule; /* LSM file metadata specific */
8486
char *args_p; /* audit value */
@@ -90,6 +92,14 @@ struct ima_rule_entry {
9092
struct ima_template_desc *template;
9193
};
9294

95+
/*
96+
* sanity check in case the kernels gains more hash algorithms that can
97+
* fit in an unsigned int
98+
*/
99+
static_assert(
100+
8 * sizeof(unsigned int) >= HASH_ALGO__LAST,
101+
"The bitfield allowed_algos in ima_rule_entry is too small to contain all the supported hash algorithms, consider using a bigger type");
102+
93103
/*
94104
* Without LSM specific knowledge, the default policy can only be
95105
* written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
@@ -646,6 +656,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
646656
* @pcr: set the pcr to extend
647657
* @template_desc: the template that should be used for this rule
648658
* @func_data: func specific data, may be NULL
659+
* @allowed_algos: allowlist of hash algorithms for the IMA xattr
649660
*
650661
* Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
651662
* conditions.
@@ -658,7 +669,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
658669
const struct cred *cred, u32 secid, enum ima_hooks func,
659670
int mask, int flags, int *pcr,
660671
struct ima_template_desc **template_desc,
661-
const char *func_data)
672+
const char *func_data, unsigned int *allowed_algos)
662673
{
663674
struct ima_rule_entry *entry;
664675
int action = 0, actmask = flags | (flags << 1);
@@ -684,8 +695,11 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
684695
action &= ~IMA_HASH;
685696
if (ima_fail_unverifiable_sigs)
686697
action |= IMA_FAIL_UNVERIFIABLE_SIGS;
687-
}
688698

699+
if (allowed_algos &&
700+
entry->flags & IMA_VALIDATE_ALGOS)
701+
*allowed_algos = entry->allowed_algos;
702+
}
689703

690704
if (entry->action & IMA_DO_MASK)
691705
actmask &= ~(entry->action | entry->action << 1);

0 commit comments

Comments
 (0)