aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/ima_policy15
-rw-r--r--security/integrity/ima/Kconfig1
-rw-r--r--security/integrity/ima/ima.h14
-rw-r--r--security/integrity/ima/ima_api.c6
-rw-r--r--security/integrity/ima/ima_appraise.c73
-rw-r--r--security/integrity/ima/ima_main.c20
-rw-r--r--security/integrity/ima/ima_policy.c174
7 files changed, 268 insertions, 35 deletions
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index 070779e8d836..5c2798534950 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -27,12 +27,13 @@ Description:
lsm: [[subj_user=] [subj_role=] [subj_type=]
[obj_user=] [obj_role=] [obj_type=]]
option: [[appraise_type=]] [template=] [permit_directio]
- [appraise_flag=] [keyrings=]
+ [appraise_flag=] [appraise_algos=] [keyrings=]
base:
func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
- [FIRMWARE_CHECK]
+ [FIRMWARE_CHECK]
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
[KEXEC_CMDLINE] [KEY_CHECK] [CRITICAL_DATA]
+ [SETXATTR_CHECK]
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
[[^]MAY_EXEC]
fsmagic:= hex value
@@ -55,6 +56,10 @@ Description:
label:= [selinux]|[kernel_info]|[data_label]
data_label:= a unique string used for grouping and limiting critical data.
For example, "selinux" to measure critical data for SELinux.
+ appraise_algos:= comma-separated list of hash algorithms
+ For example, "sha256,sha512" to only accept to appraise
+ files where the security.ima xattr was hashed with one
+ of these two algorithms.
default policy:
# PROC_SUPER_MAGIC
@@ -134,3 +139,9 @@ Description:
keys added to .builtin_trusted_keys or .ima keyring:
measure func=KEY_CHECK keyrings=.builtin_trusted_keys|.ima
+
+ Example of the special SETXATTR_CHECK appraise rule, that
+ restricts the hash algorithms allowed when writing to the
+ security.ima xattr of a file:
+
+ appraise func=SETXATTR_CHECK appraise_algos=sha256,sha384,sha512
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index d0ceada99243..f3a9cc201c8c 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -6,7 +6,6 @@ config IMA
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
- select CRYPTO_MD5
select CRYPTO_SHA1
select CRYPTO_HASH_INFO
select TCG_TPM if HAS_IOMEM && !UML
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 2f4c20b16ad7..be965a8715e4 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -46,8 +46,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
/* current content of the policy */
extern int ima_policy_flag;
+/* bitset of digests algorithms allowed in the setxattr hook */
+extern atomic_t ima_setxattr_allowed_hash_algorithms;
+
/* set during initialization */
-extern int ima_hash_algo;
+extern int ima_hash_algo __ro_after_init;
extern int ima_sha1_idx __ro_after_init;
extern int ima_hash_algo_idx __ro_after_init;
extern int ima_extra_slots __ro_after_init;
@@ -198,6 +201,7 @@ static inline unsigned int ima_hash_key(u8 *digest)
hook(KEXEC_CMDLINE, kexec_cmdline) \
hook(KEY_CHECK, key) \
hook(CRITICAL_DATA, critical_data) \
+ hook(SETXATTR_CHECK, setxattr_check) \
hook(MAX_CHECK, none)
#define __ima_hook_enumify(ENUM, str) ENUM,
@@ -254,7 +258,7 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
- const char *func_data);
+ const char *func_data, unsigned int *allowed_algos);
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file, void *buf, loff_t size,
@@ -285,10 +289,10 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, enum ima_hooks func,
int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
- const char *func_data);
+ const char *func_data, unsigned int *allowed_algos);
void ima_init_policy(void);
void ima_update_policy(void);
-void ima_update_policy_flag(void);
+void ima_update_policy_flags(void);
ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);
int ima_check_policy(void);
@@ -319,7 +323,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
enum ima_hooks func);
-enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
+enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
int xattr_len);
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index d8e321cc6936..2c6c3a5228b5 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -172,6 +172,7 @@ err_out:
* @pcr: pointer filled in if matched measure policy sets pcr=
* @template_desc: pointer filled in if matched measure policy sets template=
* @func_data: func specific data, may be NULL
+ * @allowed_algos: allowlist of hash algorithms for the IMA xattr
*
* The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic=
@@ -188,14 +189,15 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
- const char *func_data)
+ const char *func_data, unsigned int *allowed_algos)
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
flags &= ima_policy_flag;
return ima_match_policy(mnt_userns, inode, cred, secid, func, mask,
- flags, pcr, template_desc, func_data);
+ flags, pcr, template_desc, func_data,
+ allowed_algos);
}
/*
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 63bec42c353f..8f1eb7ef041e 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -77,8 +77,9 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
return 0;
security_task_getsecid_subj(current, &secid);
- return ima_match_policy(mnt_userns, inode, current_cred(), secid, func,
- mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL);
+ return ima_match_policy(mnt_userns, inode, current_cred(), secid,
+ func, mask, IMA_APPRAISE | IMA_HASH, NULL,
+ NULL, NULL, NULL);
}
static int ima_fix_xattr(struct dentry *dentry,
@@ -171,7 +172,7 @@ static void ima_cache_flags(struct integrity_iint_cache *iint,
}
}
-enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
+enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
int xattr_len)
{
struct signature_v2_hdr *sig;
@@ -575,6 +576,66 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
}
+/**
+ * validate_hash_algo() - Block setxattr with unsupported hash algorithms
+ * @dentry: object of the setxattr()
+ * @xattr_value: userland supplied xattr value
+ * @xattr_value_len: length of xattr_value
+ *
+ * The xattr value is mapped to its hash algorithm, and this algorithm
+ * must be built in the kernel for the setxattr to be allowed.
+ *
+ * Emit an audit message when the algorithm is invalid.
+ *
+ * Return: 0 on success, else an error.
+ */
+static int validate_hash_algo(struct dentry *dentry,
+ const struct evm_ima_xattr_data *xattr_value,
+ size_t xattr_value_len)
+{
+ char *path = NULL, *pathbuf = NULL;
+ enum hash_algo xattr_hash_algo;
+ const char *errmsg = "unavailable-hash-algorithm";
+ unsigned int allowed_hashes;
+
+ xattr_hash_algo = ima_get_hash_algo(xattr_value, xattr_value_len);
+
+ allowed_hashes = atomic_read(&ima_setxattr_allowed_hash_algorithms);
+
+ if (allowed_hashes) {
+ /* success if the algorithm is allowed in the ima policy */
+ if (allowed_hashes & (1U << xattr_hash_algo))
+ return 0;
+
+ /*
+ * We use a different audit message when the hash algorithm
+ * is denied by a policy rule, instead of not being built
+ * in the kernel image
+ */
+ errmsg = "denied-hash-algorithm";
+ } else {
+ if (likely(xattr_hash_algo == ima_hash_algo))
+ return 0;
+
+ /* allow any xattr using an algorithm built in the kernel */
+ if (crypto_has_alg(hash_algo_name[xattr_hash_algo], 0, 0))
+ return 0;
+ }
+
+ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+ if (!pathbuf)
+ return -EACCES;
+
+ path = dentry_path(dentry, pathbuf, PATH_MAX);
+
+ integrity_audit_msg(AUDIT_INTEGRITY_DATA, d_inode(dentry), path,
+ "set_data", errmsg, -EACCES, 0);
+
+ kfree(pathbuf);
+
+ return -EACCES;
+}
+
int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len)
{
@@ -592,9 +653,11 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
}
if (result == 1 || evm_revalidate_status(xattr_name)) {
+ result = validate_hash_algo(dentry, xvalue, xattr_value_len);
+ if (result)
+ return result;
+
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
- if (result == 1)
- result = 0;
}
return result;
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 1cba6beb5a60..a734f7d5292c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -215,6 +215,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
int xattr_len = 0;
bool violation_check;
enum hash_algo hash_algo;
+ unsigned int allowed_algos = 0;
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return 0;
@@ -224,7 +225,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
* Included is the appraise submask.
*/
action = ima_get_action(file_mnt_user_ns(file), inode, cred, secid,
- mask, func, &pcr, &template_desc, NULL);
+ mask, func, &pcr, &template_desc, NULL,
+ &allowed_algos);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check)
@@ -361,6 +363,16 @@ static int process_measurement(struct file *file, const struct cred *cred,
if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO))
rc = 0;
+
+ /* Ensure the digest was generated using an allowed algorithm */
+ if (rc == 0 && must_appraise && allowed_algos != 0 &&
+ (allowed_algos & (1U << hash_algo)) == 0) {
+ rc = -EACCES;
+
+ integrity_audit_msg(AUDIT_INTEGRITY_DATA, file_inode(file),
+ pathname, "collect_data",
+ "denied-hash-algorithm", rc, 0);
+ }
out_locked:
if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) &&
!(iint->flags & IMA_NEW_FILE))
@@ -438,7 +450,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
inode = file_inode(vma->vm_file);
action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
- &pcr, &template, NULL);
+ &pcr, &template, NULL, NULL);
/* Is the mmap'ed file in policy? */
if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
@@ -896,7 +908,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
security_task_getsecid_subj(current, &secid);
action = ima_get_action(mnt_userns, inode, current_cred(),
secid, 0, func, &pcr, &template,
- func_data);
+ func_data, NULL);
if (!(action & IMA_MEASURE) && !digest)
return -ENOENT;
}
@@ -1039,7 +1051,7 @@ static int __init init_ima(void)
pr_warn("Couldn't register LSM notifier, error %d\n", error);
if (!error)
- ima_update_policy_flag();
+ ima_update_policy_flags();
return error;
}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index fd5d46e511f1..87b9b71cb820 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -35,6 +35,7 @@
#define IMA_FSNAME 0x0200
#define IMA_KEYRINGS 0x0400
#define IMA_LABEL 0x0800
+#define IMA_VALIDATE_ALGOS 0x1000
#define UNKNOWN 0
#define MEASURE 0x0001 /* same as IMA_MEASURE */
@@ -52,6 +53,8 @@ int ima_policy_flag;
static int temp_ima_appraise;
static int build_ima_appraise __ro_after_init;
+atomic_t ima_setxattr_allowed_hash_algorithms;
+
#define MAX_LSM_RULES 6
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
@@ -79,6 +82,7 @@ struct ima_rule_entry {
bool (*uid_op)(kuid_t, kuid_t); /* Handlers for operators */
bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */
int pcr;
+ unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
struct {
void *rule; /* LSM file metadata specific */
char *args_p; /* audit value */
@@ -91,6 +95,14 @@ struct ima_rule_entry {
};
/*
+ * sanity check in case the kernels gains more hash algorithms that can
+ * fit in an unsigned int
+ */
+static_assert(
+ 8 * sizeof(unsigned int) >= HASH_ALGO__LAST,
+ "The bitfield allowed_algos in ima_rule_entry is too small to contain all the supported hash algorithms, consider using a bigger type");
+
+/*
* Without LSM specific knowledge, the default policy can only be
* written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
*/
@@ -646,6 +658,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @pcr: set the pcr to extend
* @template_desc: the template that should be used for this rule
* @func_data: func specific data, may be NULL
+ * @allowed_algos: allowlist of hash algorithms for the IMA xattr
*
* Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
* conditions.
@@ -658,7 +671,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, enum ima_hooks func,
int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
- const char *func_data)
+ const char *func_data, unsigned int *allowed_algos)
{
struct ima_rule_entry *entry;
int action = 0, actmask = flags | (flags << 1);
@@ -684,8 +697,11 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
action &= ~IMA_HASH;
if (ima_fail_unverifiable_sigs)
action |= IMA_FAIL_UNVERIFIABLE_SIGS;
- }
+ if (allowed_algos &&
+ entry->flags & IMA_VALIDATE_ALGOS)
+ *allowed_algos = entry->allowed_algos;
+ }
if (entry->action & IMA_DO_MASK)
actmask &= ~(entry->action | entry->action << 1);
@@ -706,24 +722,57 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
return action;
}
-/*
- * Initialize the ima_policy_flag variable based on the currently
- * loaded policy. Based on this flag, the decision to short circuit
- * out of a function or not call the function in the first place
- * can be made earlier.
+/**
+ * ima_update_policy_flags() - Update global IMA variables
+ *
+ * Update ima_policy_flag and ima_setxattr_allowed_hash_algorithms
+ * based on the currently loaded policy.
+ *
+ * With ima_policy_flag, the decision to short circuit out of a function
+ * or not call the function in the first place can be made earlier.
+ *
+ * With ima_setxattr_allowed_hash_algorithms, the policy can restrict the
+ * set of hash algorithms accepted when updating the security.ima xattr of
+ * a file.
+ *
+ * Context: called after a policy update and at system initialization.
*/
-void ima_update_policy_flag(void)
+void ima_update_policy_flags(void)
{
struct ima_rule_entry *entry;
+ int new_policy_flag = 0;
+ rcu_read_lock();
list_for_each_entry(entry, ima_rules, list) {
+ /*
+ * SETXATTR_CHECK rules do not implement a full policy check
+ * because rule checking would probably have an important
+ * performance impact on setxattr(). As a consequence, only one
+ * SETXATTR_CHECK can be active at a given time.
+ * Because we want to preserve that property, we set out to use
+ * atomic_cmpxchg. Either:
+ * - the atomic was non-zero: a setxattr hash policy is
+ * already enforced, we do nothing
+ * - the atomic was zero: no setxattr policy was set, enable
+ * the setxattr hash policy
+ */
+ if (entry->func == SETXATTR_CHECK) {
+ atomic_cmpxchg(&ima_setxattr_allowed_hash_algorithms,
+ 0, entry->allowed_algos);
+ /* SETXATTR_CHECK doesn't impact ima_policy_flag */
+ continue;
+ }
+
if (entry->action & IMA_DO_MASK)
- ima_policy_flag |= entry->action;
+ new_policy_flag |= entry->action;
}
+ rcu_read_unlock();
ima_appraise |= (build_ima_appraise | temp_ima_appraise);
if (!ima_appraise)
- ima_policy_flag &= ~IMA_APPRAISE;
+ new_policy_flag &= ~IMA_APPRAISE;
+
+ ima_policy_flag = new_policy_flag;
}
static int ima_appraise_flag(enum ima_hooks func)
@@ -889,7 +938,9 @@ void __init ima_init_policy(void)
ARRAY_SIZE(critical_data_rules),
IMA_DEFAULT_POLICY);
- ima_update_policy_flag();
+ atomic_set(&ima_setxattr_allowed_hash_algorithms, 0);
+
+ ima_update_policy_flags();
}
/* Make sure we have a valid policy, at least containing some rules. */
@@ -929,7 +980,7 @@ void ima_update_policy(void)
*/
kfree(arch_policy_entry);
}
- ima_update_policy_flag();
+ ima_update_policy_flags();
/* Custom IMA policy has been loaded */
ima_process_queued_keys();
@@ -946,7 +997,7 @@ enum {
Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
- Opt_appraise_type, Opt_appraise_flag,
+ Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
Opt_label, Opt_err
};
@@ -981,6 +1032,7 @@ static const match_table_t policy_tokens = {
{Opt_fowner_lt, "fowner<%s"},
{Opt_appraise_type, "appraise_type=%s"},
{Opt_appraise_flag, "appraise_flag=%s"},
+ {Opt_appraise_algos, "appraise_algos=%s"},
{Opt_permit_directio, "permit_directio"},
{Opt_pcr, "pcr=%s"},
{Opt_template, "template=%s"},
@@ -1081,7 +1133,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
return false;
if (entry->action != APPRAISE &&
- entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST))
+ entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
+ IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
return false;
/*
@@ -1111,7 +1164,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
IMA_UID | IMA_FOWNER | IMA_FSUUID |
IMA_INMASK | IMA_EUID | IMA_PCR |
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
- IMA_PERMIT_DIRECTIO))
+ IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS))
return false;
break;
@@ -1123,7 +1176,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
IMA_INMASK | IMA_EUID | IMA_PCR |
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED |
- IMA_CHECK_BLACKLIST))
+ IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
return false;
break;
@@ -1161,6 +1214,23 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
return false;
break;
+ case SETXATTR_CHECK:
+ /* any action other than APPRAISE is unsupported */
+ if (entry->action != APPRAISE)
+ return false;
+
+ /* SETXATTR_CHECK requires an appraise_algos parameter */
+ if (!(entry->flags & IMA_VALIDATE_ALGOS))
+ return false;
+
+ /*
+ * full policies are not supported, they would have too
+ * much of a performance impact
+ */
+ if (entry->flags & ~(IMA_FUNC | IMA_VALIDATE_ALGOS))
+ return false;
+
+ break;
default:
return false;
}
@@ -1173,6 +1243,34 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
return true;
}
+static unsigned int ima_parse_appraise_algos(char *arg)
+{
+ unsigned int res = 0;
+ int idx;
+ char *token;
+
+ while ((token = strsep(&arg, ",")) != NULL) {
+ idx = match_string(hash_algo_name, HASH_ALGO__LAST, token);
+
+ if (idx < 0) {
+ pr_err("unknown hash algorithm \"%s\"",
+ token);
+ return 0;
+ }
+
+ if (!crypto_has_alg(hash_algo_name[idx], 0, 0)) {
+ pr_err("unavailable hash algorithm \"%s\", check your kernel configuration",
+ token);
+ return 0;
+ }
+
+ /* Add the hash algorithm to the 'allowed' bitfield */
+ res |= (1U << idx);
+ }
+
+ return res;
+}
+
static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
{
struct audit_buffer *ab;
@@ -1294,6 +1392,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
entry->func = KEY_CHECK;
else if (strcmp(args[0].from, "CRITICAL_DATA") == 0)
entry->func = CRITICAL_DATA;
+ else if (strcmp(args[0].from, "SETXATTR_CHECK") == 0)
+ entry->func = SETXATTR_CHECK;
else
result = -EINVAL;
if (!result)
@@ -1508,6 +1608,25 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
else
result = -EINVAL;
break;
+ case Opt_appraise_algos:
+ ima_log_string(ab, "appraise_algos", args[0].from);
+
+ if (entry->allowed_algos) {
+ result = -EINVAL;
+ break;
+ }
+
+ entry->allowed_algos =
+ ima_parse_appraise_algos(args[0].from);
+ /* invalid or empty list of algorithms */
+ if (!entry->allowed_algos) {
+ result = -EINVAL;
+ break;
+ }
+
+ entry->flags |= IMA_VALIDATE_ALGOS;
+
+ break;
case Opt_permit_directio:
entry->flags |= IMA_PERMIT_DIRECTIO;
break;
@@ -1700,6 +1819,23 @@ static void ima_show_rule_opt_list(struct seq_file *m,
seq_printf(m, "%s%s", i ? "|" : "", opt_list->items[i]);
}
+static void ima_policy_show_appraise_algos(struct seq_file *m,
+ unsigned int allowed_hashes)
+{
+ int idx, list_size = 0;
+
+ for (idx = 0; idx < HASH_ALGO__LAST; idx++) {
+ if (!(allowed_hashes & (1U << idx)))
+ continue;
+
+ /* only add commas if the list contains multiple entries */
+ if (list_size++)
+ seq_puts(m, ",");
+
+ seq_puts(m, hash_algo_name[idx]);
+ }
+}
+
int ima_policy_show(struct seq_file *m, void *v)
{
struct ima_rule_entry *entry = v;
@@ -1811,6 +1947,12 @@ int ima_policy_show(struct seq_file *m, void *v)
seq_puts(m, " ");
}
+ if (entry->flags & IMA_VALIDATE_ALGOS) {
+ seq_puts(m, "appraise_algos=");
+ ima_policy_show_appraise_algos(m, entry->allowed_algos);
+ seq_puts(m, " ");
+ }
+
for (i = 0; i < MAX_LSM_RULES; i++) {
if (entry->lsm[i].rule) {
switch (i) {