mirror of https://gitee.com/openkylin/linux.git
integrity-v5.10
-----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEEjSMCCC7+cjo3nszSa3kkZrA+cVoFAl+GX1oUHHpvaGFyQGxp bnV4LmlibS5jb20ACgkQa3kkZrA+cVpACRAAqkLjZZioCl8SB2PgtOvfNGmK8b70 j4RIWKVFnzZVq6cjzc6OY/ujjOg1Psuyr48g//5fLAZVpqD7RLv0s12npZ/Q+Pim 8uInUh4G4TKZlcPmsMA2uC31NmK6xwVz2+rQjQUB8XP0ZWq392M+nrcjg2nPU1r0 ozXg0zefY/NAJwpgJlZfjxCs2YhLYe6ooqBF5Hw6kiBgWEW7O3cgBCeW3zXv9CDA TTh7bL8Y3tLiB9DYat6alfT/IU9tb9GLCgWMxmzb+MeAiSjKLWG/9wMvsAW/7M69 ECARmf28zBNjRU8OZaf615q6hXp3JghYJNpirob3B8MX6galA5oux6sOecrXxduR yEexPR2HWiCgazcN/a1NkE9nGxICsrOmLoiYdAs4pz7Csqlj4hY0HQkL8HLQzD7U MTXvdZMAd35cFDb2zMGWSnOvJrX7RlvulkgAkFpM5y3WjddY1R0hdf4fs5dYrfxb CVi+40ZCO/Xt4c689Jnga/nwFABgMhU3XCYHgZz5tBv/3YW41xgM7HwK0WskunFM xQ3zNHnj9ZmjVfwuVH+yQU16FgSjJ7rdrMj1NucH8xColPnfr8erSBIc3UWoMGPb zq0E9y8LXebI8HVmymDiWLSjH0CQ86VtSGfmtJWB0oE3ad8DZ0HW9rydoYFzgc6+ VZISjEfZN5t7xws= =qyUG -----END PGP SIGNATURE----- Merge tag 'integrity-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity Pull integrity updates from Mimi Zohar: "Continuing IMA policy rule cleanup and validation in particular for measuring keys, adding/removing/updating informational and error messages (e.g. "ima_appraise" boot command line option), and other bug fixes (e.g. minimal data size validation before use, return code and NULL pointer checking)" * tag 'integrity-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity: ima: Fix NULL pointer dereference in ima_file_hash evm: Check size of security.evm before using it ima: Remove semicolon at the end of ima_get_binary_runtime_size() ima: Don't ignore errors from crypto_shash_update() ima: Use kmemdup rather than kmalloc+memcpy integrity: include keyring name for unknown key request ima: limit secure boot feedback scope for appraise integrity: invalid kernel parameters feedback ima: add check for enforced appraise option integrity: Use current_uid() in integrity_audit_message() ima: Fail rule parsing when asymmetric key measurement isn't supportable ima: Pre-parse the list of keyrings in a KEY_CHECK rule
This commit is contained in:
commit
840e5bb326
|
@ -55,8 +55,14 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
|
|||
}
|
||||
|
||||
if (IS_ERR(key)) {
|
||||
pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
|
||||
name, PTR_ERR(key));
|
||||
if (keyring)
|
||||
pr_err_ratelimited("Request for unknown key '%s' in '%s' keyring. err %ld\n",
|
||||
name, keyring->description,
|
||||
PTR_ERR(key));
|
||||
else
|
||||
pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
|
||||
name, PTR_ERR(key));
|
||||
|
||||
switch (PTR_ERR(key)) {
|
||||
/* Hide some search errors */
|
||||
case -EACCES:
|
||||
|
|
|
@ -59,6 +59,9 @@ static int __init evm_set_fixmode(char *str)
|
|||
{
|
||||
if (strncmp(str, "fix", 3) == 0)
|
||||
evm_fixmode = 1;
|
||||
else
|
||||
pr_err("invalid \"%s\" mode", str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__setup("evm=", evm_set_fixmode);
|
||||
|
@ -181,6 +184,12 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
|||
break;
|
||||
case EVM_IMA_XATTR_DIGSIG:
|
||||
case EVM_XATTR_PORTABLE_DIGSIG:
|
||||
/* accept xattr with non-empty signature field */
|
||||
if (xattr_len <= sizeof(struct signature_v2_hdr)) {
|
||||
evm_status = INTEGRITY_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdr = (struct signature_v2_hdr *)xattr_data;
|
||||
digest.hdr.algo = hdr->hash_algo;
|
||||
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
|
||||
|
|
|
@ -19,18 +19,29 @@
|
|||
static int __init default_appraise_setup(char *str)
|
||||
{
|
||||
#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
|
||||
if (arch_ima_get_secureboot()) {
|
||||
pr_info("Secure boot enabled: ignoring ima_appraise=%s boot parameter option",
|
||||
str);
|
||||
return 1;
|
||||
}
|
||||
bool sb_state = arch_ima_get_secureboot();
|
||||
int appraisal_state = ima_appraise;
|
||||
|
||||
if (strncmp(str, "off", 3) == 0)
|
||||
ima_appraise = 0;
|
||||
appraisal_state = 0;
|
||||
else if (strncmp(str, "log", 3) == 0)
|
||||
ima_appraise = IMA_APPRAISE_LOG;
|
||||
appraisal_state = IMA_APPRAISE_LOG;
|
||||
else if (strncmp(str, "fix", 3) == 0)
|
||||
ima_appraise = IMA_APPRAISE_FIX;
|
||||
appraisal_state = IMA_APPRAISE_FIX;
|
||||
else if (strncmp(str, "enforce", 7) == 0)
|
||||
appraisal_state = IMA_APPRAISE_ENFORCE;
|
||||
else
|
||||
pr_err("invalid \"%s\" appraise option", str);
|
||||
|
||||
/* If appraisal state was changed, but secure boot is enabled,
|
||||
* keep its default */
|
||||
if (sb_state) {
|
||||
if (!(appraisal_state & IMA_APPRAISE_ENFORCE))
|
||||
pr_info("Secure boot enabled: ignoring ima_appraise=%s option",
|
||||
str);
|
||||
} else {
|
||||
ima_appraise = appraisal_state;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -829,6 +829,8 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
|
|||
/* now accumulate with current aggregate */
|
||||
rc = crypto_shash_update(shash, d.digest,
|
||||
crypto_shash_digestsize(tfm));
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
/*
|
||||
* Extend cumulative digest over TPM registers 8-9, which contain
|
||||
|
|
|
@ -51,18 +51,23 @@ static int __init hash_setup(char *str)
|
|||
return 1;
|
||||
|
||||
if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
|
||||
if (strncmp(str, "sha1", 4) == 0)
|
||||
if (strncmp(str, "sha1", 4) == 0) {
|
||||
ima_hash_algo = HASH_ALGO_SHA1;
|
||||
else if (strncmp(str, "md5", 3) == 0)
|
||||
} else if (strncmp(str, "md5", 3) == 0) {
|
||||
ima_hash_algo = HASH_ALGO_MD5;
|
||||
else
|
||||
} else {
|
||||
pr_err("invalid hash algorithm \"%s\" for template \"%s\"",
|
||||
str, IMA_TEMPLATE_IMA_NAME);
|
||||
return 1;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = match_string(hash_algo_name, HASH_ALGO__LAST, str);
|
||||
if (i < 0)
|
||||
if (i < 0) {
|
||||
pr_err("invalid hash algorithm \"%s\"", str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ima_hash_algo = i;
|
||||
out:
|
||||
|
@ -532,6 +537,16 @@ int ima_file_hash(struct file *file, char *buf, size_t buf_size)
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&iint->mutex);
|
||||
|
||||
/*
|
||||
* ima_file_hash can be called when ima_collect_measurement has still
|
||||
* not been called, we might not always have a hash.
|
||||
*/
|
||||
if (!iint->ima_hash) {
|
||||
mutex_unlock(&iint->mutex);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
size_t copied_size;
|
||||
|
||||
|
|
|
@ -60,6 +60,11 @@ enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB };
|
|||
|
||||
enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY };
|
||||
|
||||
struct ima_rule_opt_list {
|
||||
size_t count;
|
||||
char *items[];
|
||||
};
|
||||
|
||||
struct ima_rule_entry {
|
||||
struct list_head list;
|
||||
int action;
|
||||
|
@ -79,7 +84,7 @@ struct ima_rule_entry {
|
|||
int type; /* audit type */
|
||||
} lsm[MAX_LSM_RULES];
|
||||
char *fsname;
|
||||
char *keyrings; /* Measure keys added to these keyrings */
|
||||
struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */
|
||||
struct ima_template_desc *template;
|
||||
};
|
||||
|
||||
|
@ -207,10 +212,6 @@ static LIST_HEAD(ima_policy_rules);
|
|||
static LIST_HEAD(ima_temp_rules);
|
||||
static struct list_head *ima_rules = &ima_default_rules;
|
||||
|
||||
/* Pre-allocated buffer used for matching keyrings. */
|
||||
static char *ima_keyrings;
|
||||
static size_t ima_keyrings_len;
|
||||
|
||||
static int ima_policy __initdata;
|
||||
|
||||
static int __init default_measure_policy_setup(char *str)
|
||||
|
@ -241,6 +242,8 @@ static int __init policy_setup(char *str)
|
|||
ima_use_secure_boot = true;
|
||||
else if (strcmp(p, "fail_securely") == 0)
|
||||
ima_fail_unverifiable_sigs = true;
|
||||
else
|
||||
pr_err("policy \"%s\" not found", p);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -254,6 +257,72 @@ static int __init default_appraise_policy_setup(char *str)
|
|||
}
|
||||
__setup("ima_appraise_tcb", default_appraise_policy_setup);
|
||||
|
||||
static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
|
||||
{
|
||||
struct ima_rule_opt_list *opt_list;
|
||||
size_t count = 0;
|
||||
char *src_copy;
|
||||
char *cur, *next;
|
||||
size_t i;
|
||||
|
||||
src_copy = match_strdup(src);
|
||||
if (!src_copy)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
next = src_copy;
|
||||
while ((cur = strsep(&next, "|"))) {
|
||||
/* Don't accept an empty list item */
|
||||
if (!(*cur)) {
|
||||
kfree(src_copy);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Don't accept an empty list */
|
||||
if (!count) {
|
||||
kfree(src_copy);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
opt_list = kzalloc(struct_size(opt_list, items, count), GFP_KERNEL);
|
||||
if (!opt_list) {
|
||||
kfree(src_copy);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* strsep() has already replaced all instances of '|' with '\0',
|
||||
* leaving a byte sequence of NUL-terminated strings. Reference each
|
||||
* string with the array of items.
|
||||
*
|
||||
* IMPORTANT: Ownership of the allocated buffer is transferred from
|
||||
* src_copy to the first element in the items array. To free the
|
||||
* buffer, kfree() must only be called on the first element of the
|
||||
* array.
|
||||
*/
|
||||
for (i = 0, cur = src_copy; i < count; i++) {
|
||||
opt_list->items[i] = cur;
|
||||
cur = strchr(cur, '\0') + 1;
|
||||
}
|
||||
opt_list->count = count;
|
||||
|
||||
return opt_list;
|
||||
}
|
||||
|
||||
static void ima_free_rule_opt_list(struct ima_rule_opt_list *opt_list)
|
||||
{
|
||||
if (!opt_list)
|
||||
return;
|
||||
|
||||
if (opt_list->count) {
|
||||
kfree(opt_list->items[0]);
|
||||
opt_list->count = 0;
|
||||
}
|
||||
|
||||
kfree(opt_list);
|
||||
}
|
||||
|
||||
static void ima_lsm_free_rule(struct ima_rule_entry *entry)
|
||||
{
|
||||
int i;
|
||||
|
@ -275,7 +344,7 @@ static void ima_free_rule(struct ima_rule_entry *entry)
|
|||
* the defined_templates list and cannot be freed here
|
||||
*/
|
||||
kfree(entry->fsname);
|
||||
kfree(entry->keyrings);
|
||||
ima_free_rule_opt_list(entry->keyrings);
|
||||
ima_lsm_free_rule(entry);
|
||||
kfree(entry);
|
||||
}
|
||||
|
@ -285,15 +354,14 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
|
|||
struct ima_rule_entry *nentry;
|
||||
int i;
|
||||
|
||||
nentry = kmalloc(sizeof(*nentry), GFP_KERNEL);
|
||||
if (!nentry)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Immutable elements are copied over as pointers and data; only
|
||||
* lsm rules can change
|
||||
*/
|
||||
memcpy(nentry, entry, sizeof(*nentry));
|
||||
nentry = kmemdup(entry, sizeof(*nentry), GFP_KERNEL);
|
||||
if (!nentry)
|
||||
return NULL;
|
||||
|
||||
memset(nentry->lsm, 0, sizeof_field(struct ima_rule_entry, lsm));
|
||||
|
||||
for (i = 0; i < MAX_LSM_RULES; i++) {
|
||||
|
@ -395,8 +463,8 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
|
|||
static bool ima_match_keyring(struct ima_rule_entry *rule,
|
||||
const char *keyring, const struct cred *cred)
|
||||
{
|
||||
char *next_keyring, *keyrings_ptr;
|
||||
bool matched = false;
|
||||
size_t i;
|
||||
|
||||
if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid))
|
||||
return false;
|
||||
|
@ -407,15 +475,8 @@ static bool ima_match_keyring(struct ima_rule_entry *rule,
|
|||
if (!keyring)
|
||||
return false;
|
||||
|
||||
strcpy(ima_keyrings, rule->keyrings);
|
||||
|
||||
/*
|
||||
* "keyrings=" is specified in the policy in the format below:
|
||||
* keyrings=.builtin_trusted_keys|.ima|.evm
|
||||
*/
|
||||
keyrings_ptr = ima_keyrings;
|
||||
while ((next_keyring = strsep(&keyrings_ptr, "|")) != NULL) {
|
||||
if (!strcmp(next_keyring, keyring)) {
|
||||
for (i = 0; i < rule->keyrings->count; i++) {
|
||||
if (!strcmp(rule->keyrings->items[i], keyring)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1066,7 +1127,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|||
bool uid_token;
|
||||
struct ima_template_desc *template_desc;
|
||||
int result = 0;
|
||||
size_t keyrings_len;
|
||||
|
||||
ab = integrity_audit_log_start(audit_context(), GFP_KERNEL,
|
||||
AUDIT_INTEGRITY_POLICY_RULE);
|
||||
|
@ -1175,7 +1235,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|||
entry->func = POLICY_CHECK;
|
||||
else if (strcmp(args[0].from, "KEXEC_CMDLINE") == 0)
|
||||
entry->func = KEXEC_CMDLINE;
|
||||
else if (strcmp(args[0].from, "KEY_CHECK") == 0)
|
||||
else if (IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) &&
|
||||
strcmp(args[0].from, "KEY_CHECK") == 0)
|
||||
entry->func = KEY_CHECK;
|
||||
else
|
||||
result = -EINVAL;
|
||||
|
@ -1232,37 +1293,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|||
case Opt_keyrings:
|
||||
ima_log_string(ab, "keyrings", args[0].from);
|
||||
|
||||
keyrings_len = strlen(args[0].from) + 1;
|
||||
|
||||
if ((entry->keyrings) ||
|
||||
(keyrings_len < 2)) {
|
||||
if (!IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) ||
|
||||
entry->keyrings) {
|
||||
result = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (keyrings_len > ima_keyrings_len) {
|
||||
char *tmpbuf;
|
||||
|
||||
tmpbuf = krealloc(ima_keyrings, keyrings_len,
|
||||
GFP_KERNEL);
|
||||
if (!tmpbuf) {
|
||||
result = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
ima_keyrings = tmpbuf;
|
||||
ima_keyrings_len = keyrings_len;
|
||||
}
|
||||
|
||||
entry->keyrings = kstrdup(args[0].from, GFP_KERNEL);
|
||||
if (!entry->keyrings) {
|
||||
kfree(ima_keyrings);
|
||||
ima_keyrings = NULL;
|
||||
ima_keyrings_len = 0;
|
||||
result = -ENOMEM;
|
||||
entry->keyrings = ima_alloc_rule_opt_list(args);
|
||||
if (IS_ERR(entry->keyrings)) {
|
||||
result = PTR_ERR(entry->keyrings);
|
||||
entry->keyrings = NULL;
|
||||
break;
|
||||
}
|
||||
result = 0;
|
||||
|
||||
entry->flags |= IMA_KEYRINGS;
|
||||
break;
|
||||
case Opt_fsuuid:
|
||||
|
@ -1575,6 +1618,15 @@ static void policy_func_show(struct seq_file *m, enum ima_hooks func)
|
|||
seq_printf(m, "func=%d ", func);
|
||||
}
|
||||
|
||||
static void ima_show_rule_opt_list(struct seq_file *m,
|
||||
const struct ima_rule_opt_list *opt_list)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < opt_list->count; i++)
|
||||
seq_printf(m, "%s%s", i ? "|" : "", opt_list->items[i]);
|
||||
}
|
||||
|
||||
int ima_policy_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct ima_rule_entry *entry = v;
|
||||
|
@ -1631,9 +1683,8 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|||
}
|
||||
|
||||
if (entry->flags & IMA_KEYRINGS) {
|
||||
if (entry->keyrings != NULL)
|
||||
snprintf(tbuf, sizeof(tbuf), "%s", entry->keyrings);
|
||||
seq_printf(m, pt(Opt_keyrings), tbuf);
|
||||
seq_puts(m, "keyrings=");
|
||||
ima_show_rule_opt_list(m, entry->keyrings);
|
||||
seq_puts(m, " ");
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ unsigned long ima_get_binary_runtime_size(void)
|
|||
return ULONG_MAX;
|
||||
else
|
||||
return binary_runtime_size + sizeof(struct ima_kexec_hdr);
|
||||
};
|
||||
}
|
||||
|
||||
static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr)
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ void integrity_audit_message(int audit_msgno, struct inode *inode,
|
|||
ab = audit_log_start(audit_context(), GFP_KERNEL, audit_msgno);
|
||||
audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u",
|
||||
task_pid_nr(current),
|
||||
from_kuid(&init_user_ns, current_cred()->uid),
|
||||
from_kuid(&init_user_ns, current_uid()),
|
||||
from_kuid(&init_user_ns, audit_get_loginuid(current)),
|
||||
audit_get_sessionid(current));
|
||||
audit_log_task_context(ab);
|
||||
|
|
Loading…
Reference in New Issue