forked from luck/tmp_suning_uos_patched
integrity-v5.8
-----BEGIN PGP SIGNATURE-----
iQIcBAABAgAGBQJe2nHRAAoJEGt5JGawPnFagTMP/jMdo7DzOJYxALQ+HQPZ1cO+
tyZdEoVeO/I6LeKWR3emf53ingH/KAL0PdxPAGfo/DBwSpdlkmd/WmKXYQWQbOk+
s8MtRfAV1Fra4ON6KsuI2frBMtQrPNIzjRVDU4dQr/Ogo7ZUQnWK+36s0yT8vvfg
jZ40UKpy3Om78OYSlH55KncVFxUOZrLpjFC9yPvrdo7hrhLsS+lp4qvpuoY9vPHf
2r9/T7OBbUlavzGwRmJO0Rphimm9ZvgBmcyB2Y4H00m0KqN3uxPRMRvs2lRX1SyQ
C8k5qg18HsdHVomQ7J/wx6w7vxy4bOThbBLWDL2OgnHFt5ZXMDj7pwkO+fmOFFIh
bdAFXb5SiZu/Y5gHOamthr0ylfyGFhmRjJXvznLbTy3/PrJE0giuOEOEV+1qpYVf
Ds0j6uYV5ZVbPpSzRay7aWispxQ6EBPwN+qp74x/moM5gctBdNm6HskRxOyy8IH3
ZWmd3y902rwLl0Eaz9rETU5Wf7NyWtdQwateLzeVBcLRd+bqaqfdQXi1MFEzx23/
V87FMmdQ8aoEjO9jgRSilYTs2VVHkcprw/uqr6ooQHTer8fLs292z/Rh8McncqpF
/ptJZ6blRERlaKqEcefXYjP8xYTnGiLDA5LZM5Ko5NB71RyEDeDYUxaJLBPlYuP7
oO5Gj38zD2VGjz1xDKgA
=G3xj
-----END PGP SIGNATURE-----
Merge tag 'integrity-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity
Pull integrity updates from Mimi Zohar:
"The main changes are extending the TPM 2.0 PCR banks with bank
specific file hashes, calculating the "boot_aggregate" based on other
TPM PCR banks, using the default IMA hash algorithm, instead of SHA1,
as the basis for the cache hash table key, and preventing the mprotect
syscall to circumvent an IMA mmap appraise policy rule.
- In preparation for extending TPM 2.0 PCR banks with bank specific
digests, commit 0b6cf6b97b
("tpm: pass an array of
tpm_extend_digest structures to tpm_pcr_extend()") modified
tpm_pcr_extend(). The original SHA1 file digests were
padded/truncated, before being extended into the other TPM PCR
banks. This pull request calculates and extends the TPM PCR banks
with bank specific file hashes completing the above change.
- The "boot_aggregate", the first IMA measurement list record, is the
"trusted boot" link between the pre-boot environment and the
running OS. With TPM 2.0, the "boot_aggregate" record is not
limited to being based on the SHA1 TPM PCR bank, but can be
calculated based on any enabled bank, assuming the hash algorithm
is also enabled in the kernel.
Other changes include the following and five other bug fixes/code
clean up:
- supporting both a SHA1 and a larger "boot_aggregate" digest in a
custom template format containing both the the SHA1 ('d') and
larger digests ('d-ng') fields.
- Initial hash table key fix, but additional changes would be good"
* tag 'integrity-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
ima: Directly free *entry in ima_alloc_init_template() if digests is NULL
ima: Call ima_calc_boot_aggregate() in ima_eventdigest_init()
ima: Directly assign the ima_default_policy pointer to ima_rules
ima: verify mprotect change is consistent with mmap policy
evm: Fix possible memory leak in evm_calc_hmac_or_hash()
ima: Set again build_ima_appraise variable
ima: Remove redundant policy rule set in add_rules()
ima: Fix ima digest hash table key calculation
ima: Use ima_hash_algo for collision detection in the measurement list
ima: Calculate and extend PCR with digests in ima_template_entry
ima: Allocate and initialize tfm for each PCR bank
ima: Switch to dynamically allocated buffer for template digests
ima: Store template digest directly in ima_template_entry
ima: Evaluate error in init_ima()
ima: Switch to ima_hash_algo for boot aggregate
This commit is contained in:
commit
3c0ad98c2e
|
@ -18,6 +18,7 @@ extern int ima_file_check(struct file *file, int mask);
|
|||
extern void ima_post_create_tmpfile(struct inode *inode);
|
||||
extern void ima_file_free(struct file *file);
|
||||
extern int ima_file_mmap(struct file *file, unsigned long prot);
|
||||
extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot);
|
||||
extern int ima_load_data(enum kernel_load_data_id id);
|
||||
extern int ima_read_file(struct file *file, enum kernel_read_file_id id);
|
||||
extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
|
||||
|
@ -70,6 +71,12 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_file_mprotect(struct vm_area_struct *vma,
|
||||
unsigned long prot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_load_data(enum kernel_load_data_id id)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -241,7 +241,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
|
|||
|
||||
/* Portable EVM signatures must include an IMA hash */
|
||||
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
|
||||
return -EPERM;
|
||||
error = -EPERM;
|
||||
out:
|
||||
kfree(xattr_value);
|
||||
kfree(desc);
|
||||
|
|
|
@ -36,7 +36,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
|
|||
#define IMA_DIGEST_SIZE SHA1_DIGEST_SIZE
|
||||
#define IMA_EVENT_NAME_LEN_MAX 255
|
||||
|
||||
#define IMA_HASH_BITS 9
|
||||
#define IMA_HASH_BITS 10
|
||||
#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
|
||||
|
||||
#define IMA_TEMPLATE_FIELD_ID_MAX_LEN 16
|
||||
|
@ -45,13 +45,19 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
|
|||
#define IMA_TEMPLATE_IMA_NAME "ima"
|
||||
#define IMA_TEMPLATE_IMA_FMT "d|n"
|
||||
|
||||
#define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0)
|
||||
|
||||
/* current content of the policy */
|
||||
extern int ima_policy_flag;
|
||||
|
||||
/* set during initialization */
|
||||
extern int ima_hash_algo;
|
||||
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;
|
||||
extern int ima_appraise;
|
||||
extern struct tpm_chip *ima_tpm_chip;
|
||||
extern const char boot_aggregate_name[];
|
||||
|
||||
/* IMA event related data */
|
||||
struct ima_event_data {
|
||||
|
@ -92,7 +98,7 @@ struct ima_template_desc {
|
|||
|
||||
struct ima_template_entry {
|
||||
int pcr;
|
||||
u8 digest[TPM_DIGEST_SIZE]; /* sha1 or md5 measurement hash */
|
||||
struct tpm_digest *digests;
|
||||
struct ima_template_desc *template_desc; /* template descriptor */
|
||||
u32 template_data_len;
|
||||
struct ima_field_data template_data[0]; /* template related data */
|
||||
|
@ -138,9 +144,8 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash);
|
|||
int ima_calc_buffer_hash(const void *buf, loff_t len,
|
||||
struct ima_digest_data *hash);
|
||||
int ima_calc_field_array_hash(struct ima_field_data *field_data,
|
||||
struct ima_template_desc *desc, int num_fields,
|
||||
struct ima_digest_data *hash);
|
||||
int __init ima_calc_boot_aggregate(struct ima_digest_data *hash);
|
||||
struct ima_template_entry *entry);
|
||||
int ima_calc_boot_aggregate(struct ima_digest_data *hash);
|
||||
void ima_add_violation(struct file *file, const unsigned char *filename,
|
||||
struct integrity_iint_cache *iint,
|
||||
const char *op, const char *cause);
|
||||
|
@ -175,9 +180,10 @@ struct ima_h_table {
|
|||
};
|
||||
extern struct ima_h_table ima_htable;
|
||||
|
||||
static inline unsigned long ima_hash_key(u8 *digest)
|
||||
static inline unsigned int ima_hash_key(u8 *digest)
|
||||
{
|
||||
return hash_long(*digest, IMA_HASH_BITS);
|
||||
/* there is no point in taking a hash of part of a digest */
|
||||
return (digest[0] | digest[1] << 8) % IMA_MEASURE_HTABLE_SIZE;
|
||||
}
|
||||
|
||||
#define __ima_hooks(hook) \
|
||||
|
|
|
@ -27,6 +27,7 @@ void ima_free_template_entry(struct ima_template_entry *entry)
|
|||
for (i = 0; i < entry->template_desc->num_fields; i++)
|
||||
kfree(entry->template_data[i].data);
|
||||
|
||||
kfree(entry->digests);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
|
@ -38,6 +39,7 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
|
|||
struct ima_template_desc *desc)
|
||||
{
|
||||
struct ima_template_desc *template_desc;
|
||||
struct tpm_digest *digests;
|
||||
int i, result = 0;
|
||||
|
||||
if (desc)
|
||||
|
@ -50,6 +52,15 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
|
|||
if (!*entry)
|
||||
return -ENOMEM;
|
||||
|
||||
digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
|
||||
sizeof(*digests), GFP_NOFS);
|
||||
if (!digests) {
|
||||
kfree(*entry);
|
||||
*entry = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
(*entry)->digests = digests;
|
||||
(*entry)->template_desc = template_desc;
|
||||
for (i = 0; i < template_desc->num_fields; i++) {
|
||||
const struct ima_template_field *field =
|
||||
|
@ -96,26 +107,16 @@ int ima_store_template(struct ima_template_entry *entry,
|
|||
static const char audit_cause[] = "hashing_error";
|
||||
char *template_name = entry->template_desc->name;
|
||||
int result;
|
||||
struct {
|
||||
struct ima_digest_data hdr;
|
||||
char digest[TPM_DIGEST_SIZE];
|
||||
} hash;
|
||||
|
||||
if (!violation) {
|
||||
int num_fields = entry->template_desc->num_fields;
|
||||
|
||||
/* this function uses default algo */
|
||||
hash.hdr.algo = HASH_ALGO_SHA1;
|
||||
result = ima_calc_field_array_hash(&entry->template_data[0],
|
||||
entry->template_desc,
|
||||
num_fields, &hash.hdr);
|
||||
entry);
|
||||
if (result < 0) {
|
||||
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
|
||||
template_name, op,
|
||||
audit_cause, result, 0);
|
||||
return result;
|
||||
}
|
||||
memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
|
||||
}
|
||||
entry->pcr = pcr;
|
||||
result = ima_add_template_entry(entry, violation, op, inode, filename);
|
||||
|
|
|
@ -57,7 +57,22 @@ MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size");
|
|||
static struct crypto_shash *ima_shash_tfm;
|
||||
static struct crypto_ahash *ima_ahash_tfm;
|
||||
|
||||
int __init ima_init_crypto(void)
|
||||
struct ima_algo_desc {
|
||||
struct crypto_shash *tfm;
|
||||
enum hash_algo algo;
|
||||
};
|
||||
|
||||
int ima_sha1_idx __ro_after_init;
|
||||
int ima_hash_algo_idx __ro_after_init;
|
||||
/*
|
||||
* Additional number of slots reserved, as needed, for SHA1
|
||||
* and IMA default algo.
|
||||
*/
|
||||
int ima_extra_slots __ro_after_init;
|
||||
|
||||
static struct ima_algo_desc *ima_algo_array;
|
||||
|
||||
static int __init ima_init_ima_crypto(void)
|
||||
{
|
||||
long rc;
|
||||
|
||||
|
@ -76,25 +91,136 @@ int __init ima_init_crypto(void)
|
|||
static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
|
||||
{
|
||||
struct crypto_shash *tfm = ima_shash_tfm;
|
||||
int rc;
|
||||
int rc, i;
|
||||
|
||||
if (algo < 0 || algo >= HASH_ALGO__LAST)
|
||||
algo = ima_hash_algo;
|
||||
|
||||
if (algo != ima_hash_algo) {
|
||||
if (algo == ima_hash_algo)
|
||||
return tfm;
|
||||
|
||||
for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++)
|
||||
if (ima_algo_array[i].tfm && ima_algo_array[i].algo == algo)
|
||||
return ima_algo_array[i].tfm;
|
||||
|
||||
tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
rc = PTR_ERR(tfm);
|
||||
pr_err("Can not allocate %s (reason: %d)\n",
|
||||
hash_algo_name[algo], rc);
|
||||
}
|
||||
}
|
||||
return tfm;
|
||||
}
|
||||
|
||||
int __init ima_init_crypto(void)
|
||||
{
|
||||
enum hash_algo algo;
|
||||
long rc;
|
||||
int i;
|
||||
|
||||
rc = ima_init_ima_crypto();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ima_sha1_idx = -1;
|
||||
ima_hash_algo_idx = -1;
|
||||
|
||||
for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) {
|
||||
algo = ima_tpm_chip->allocated_banks[i].crypto_id;
|
||||
if (algo == HASH_ALGO_SHA1)
|
||||
ima_sha1_idx = i;
|
||||
|
||||
if (algo == ima_hash_algo)
|
||||
ima_hash_algo_idx = i;
|
||||
}
|
||||
|
||||
if (ima_sha1_idx < 0) {
|
||||
ima_sha1_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;
|
||||
if (ima_hash_algo == HASH_ALGO_SHA1)
|
||||
ima_hash_algo_idx = ima_sha1_idx;
|
||||
}
|
||||
|
||||
if (ima_hash_algo_idx < 0)
|
||||
ima_hash_algo_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;
|
||||
|
||||
ima_algo_array = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
|
||||
sizeof(*ima_algo_array), GFP_KERNEL);
|
||||
if (!ima_algo_array) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) {
|
||||
algo = ima_tpm_chip->allocated_banks[i].crypto_id;
|
||||
ima_algo_array[i].algo = algo;
|
||||
|
||||
/* unknown TPM algorithm */
|
||||
if (algo == HASH_ALGO__LAST)
|
||||
continue;
|
||||
|
||||
if (algo == ima_hash_algo) {
|
||||
ima_algo_array[i].tfm = ima_shash_tfm;
|
||||
continue;
|
||||
}
|
||||
|
||||
ima_algo_array[i].tfm = ima_alloc_tfm(algo);
|
||||
if (IS_ERR(ima_algo_array[i].tfm)) {
|
||||
if (algo == HASH_ALGO_SHA1) {
|
||||
rc = PTR_ERR(ima_algo_array[i].tfm);
|
||||
ima_algo_array[i].tfm = NULL;
|
||||
goto out_array;
|
||||
}
|
||||
|
||||
ima_algo_array[i].tfm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip)) {
|
||||
if (ima_hash_algo == HASH_ALGO_SHA1) {
|
||||
ima_algo_array[ima_sha1_idx].tfm = ima_shash_tfm;
|
||||
} else {
|
||||
ima_algo_array[ima_sha1_idx].tfm =
|
||||
ima_alloc_tfm(HASH_ALGO_SHA1);
|
||||
if (IS_ERR(ima_algo_array[ima_sha1_idx].tfm)) {
|
||||
rc = PTR_ERR(ima_algo_array[ima_sha1_idx].tfm);
|
||||
goto out_array;
|
||||
}
|
||||
}
|
||||
|
||||
ima_algo_array[ima_sha1_idx].algo = HASH_ALGO_SHA1;
|
||||
}
|
||||
|
||||
if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) &&
|
||||
ima_hash_algo_idx != ima_sha1_idx) {
|
||||
ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm;
|
||||
ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_array:
|
||||
for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) {
|
||||
if (!ima_algo_array[i].tfm ||
|
||||
ima_algo_array[i].tfm == ima_shash_tfm)
|
||||
continue;
|
||||
|
||||
crypto_free_shash(ima_algo_array[i].tfm);
|
||||
}
|
||||
out:
|
||||
crypto_free_shash(ima_shash_tfm);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ima_free_tfm(struct crypto_shash *tfm)
|
||||
{
|
||||
if (tfm != ima_shash_tfm)
|
||||
int i;
|
||||
|
||||
if (tfm == ima_shash_tfm)
|
||||
return;
|
||||
|
||||
for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++)
|
||||
if (ima_algo_array[i].tfm == tfm)
|
||||
return;
|
||||
|
||||
crypto_free_shash(tfm);
|
||||
}
|
||||
|
||||
|
@ -464,17 +590,15 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
|
|||
* Calculate the hash of template data
|
||||
*/
|
||||
static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
|
||||
struct ima_template_desc *td,
|
||||
int num_fields,
|
||||
struct ima_digest_data *hash,
|
||||
struct crypto_shash *tfm)
|
||||
struct ima_template_entry *entry,
|
||||
int tfm_idx)
|
||||
{
|
||||
SHASH_DESC_ON_STACK(shash, tfm);
|
||||
SHASH_DESC_ON_STACK(shash, ima_algo_array[tfm_idx].tfm);
|
||||
struct ima_template_desc *td = entry->template_desc;
|
||||
int num_fields = entry->template_desc->num_fields;
|
||||
int rc, i;
|
||||
|
||||
shash->tfm = tfm;
|
||||
|
||||
hash->length = crypto_shash_digestsize(tfm);
|
||||
shash->tfm = ima_algo_array[tfm_idx].tfm;
|
||||
|
||||
rc = crypto_shash_init(shash);
|
||||
if (rc != 0)
|
||||
|
@ -504,27 +628,44 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
|
|||
}
|
||||
|
||||
if (!rc)
|
||||
rc = crypto_shash_final(shash, hash->digest);
|
||||
rc = crypto_shash_final(shash, entry->digests[tfm_idx].digest);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ima_calc_field_array_hash(struct ima_field_data *field_data,
|
||||
struct ima_template_desc *desc, int num_fields,
|
||||
struct ima_digest_data *hash)
|
||||
struct ima_template_entry *entry)
|
||||
{
|
||||
struct crypto_shash *tfm;
|
||||
int rc;
|
||||
u16 alg_id;
|
||||
int rc, i;
|
||||
|
||||
tfm = ima_alloc_tfm(hash->algo);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
rc = ima_calc_field_array_hash_tfm(field_data, entry, ima_sha1_idx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = ima_calc_field_array_hash_tfm(field_data, desc, num_fields,
|
||||
hash, tfm);
|
||||
entry->digests[ima_sha1_idx].alg_id = TPM_ALG_SHA1;
|
||||
|
||||
ima_free_tfm(tfm);
|
||||
for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) {
|
||||
if (i == ima_sha1_idx)
|
||||
continue;
|
||||
|
||||
if (i < NR_BANKS(ima_tpm_chip)) {
|
||||
alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
|
||||
entry->digests[i].alg_id = alg_id;
|
||||
}
|
||||
|
||||
/* for unmapped TPM algorithms digest is still a padded SHA1 */
|
||||
if (!ima_algo_array[i].tfm) {
|
||||
memcpy(entry->digests[i].digest,
|
||||
entry->digests[ima_sha1_idx].digest,
|
||||
TPM_DIGEST_SIZE);
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = ima_calc_field_array_hash_tfm(field_data, entry, i);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -655,18 +796,29 @@ static void __init ima_pcrread(u32 idx, struct tpm_digest *d)
|
|||
}
|
||||
|
||||
/*
|
||||
* Calculate the boot aggregate hash
|
||||
* The boot_aggregate is a cumulative hash over TPM registers 0 - 7. With
|
||||
* TPM 1.2 the boot_aggregate was based on reading the SHA1 PCRs, but with
|
||||
* TPM 2.0 hash agility, TPM chips could support multiple TPM PCR banks,
|
||||
* allowing firmware to configure and enable different banks.
|
||||
*
|
||||
* Knowing which TPM bank is read to calculate the boot_aggregate digest
|
||||
* needs to be conveyed to a verifier. For this reason, use the same
|
||||
* hash algorithm for reading the TPM PCRs as for calculating the boot
|
||||
* aggregate digest as stored in the measurement list.
|
||||
*/
|
||||
static int __init ima_calc_boot_aggregate_tfm(char *digest,
|
||||
static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
|
||||
struct crypto_shash *tfm)
|
||||
{
|
||||
struct tpm_digest d = { .alg_id = TPM_ALG_SHA1, .digest = {0} };
|
||||
struct tpm_digest d = { .alg_id = alg_id, .digest = {0} };
|
||||
int rc;
|
||||
u32 i;
|
||||
SHASH_DESC_ON_STACK(shash, tfm);
|
||||
|
||||
shash->tfm = tfm;
|
||||
|
||||
pr_devel("calculating the boot-aggregate based on TPM bank: %04x\n",
|
||||
d.alg_id);
|
||||
|
||||
rc = crypto_shash_init(shash);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
@ -675,24 +827,48 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest,
|
|||
for (i = TPM_PCR0; i < TPM_PCR8; i++) {
|
||||
ima_pcrread(i, &d);
|
||||
/* now accumulate with current aggregate */
|
||||
rc = crypto_shash_update(shash, d.digest, TPM_DIGEST_SIZE);
|
||||
rc = crypto_shash_update(shash, d.digest,
|
||||
crypto_shash_digestsize(tfm));
|
||||
}
|
||||
if (!rc)
|
||||
crypto_shash_final(shash, digest);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __init ima_calc_boot_aggregate(struct ima_digest_data *hash)
|
||||
int ima_calc_boot_aggregate(struct ima_digest_data *hash)
|
||||
{
|
||||
struct crypto_shash *tfm;
|
||||
int rc;
|
||||
u16 crypto_id, alg_id;
|
||||
int rc, i, bank_idx = -1;
|
||||
|
||||
for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) {
|
||||
crypto_id = ima_tpm_chip->allocated_banks[i].crypto_id;
|
||||
if (crypto_id == hash->algo) {
|
||||
bank_idx = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (crypto_id == HASH_ALGO_SHA256)
|
||||
bank_idx = i;
|
||||
|
||||
if (bank_idx == -1 && crypto_id == HASH_ALGO_SHA1)
|
||||
bank_idx = i;
|
||||
}
|
||||
|
||||
if (bank_idx == -1) {
|
||||
pr_err("No suitable TPM algorithm for boot aggregate\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hash->algo = ima_tpm_chip->allocated_banks[bank_idx].crypto_id;
|
||||
|
||||
tfm = ima_alloc_tfm(hash->algo);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
hash->length = crypto_shash_digestsize(tfm);
|
||||
rc = ima_calc_boot_aggregate_tfm(hash->digest, tfm);
|
||||
alg_id = ima_tpm_chip->allocated_banks[bank_idx].alg_id;
|
||||
rc = ima_calc_boot_aggregate_tfm(hash->digest, alg_id, tfm);
|
||||
|
||||
ima_free_tfm(tfm);
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
|
|||
ima_putc(m, &pcr, sizeof(e->pcr));
|
||||
|
||||
/* 2nd: template digest */
|
||||
ima_putc(m, e->digest, TPM_DIGEST_SIZE);
|
||||
ima_putc(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
|
||||
|
||||
/* 3rd: template name size */
|
||||
namelen = !ima_canonical_fmt ? strlen(template_name) :
|
||||
|
@ -233,7 +233,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
|
|||
seq_printf(m, "%2d ", e->pcr);
|
||||
|
||||
/* 2nd: SHA1 template hash */
|
||||
ima_print_digest(m, e->digest, TPM_DIGEST_SIZE);
|
||||
ima_print_digest(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
|
||||
|
||||
/* 3th: template name */
|
||||
seq_printf(m, " %s", template_name);
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
#include "ima.h"
|
||||
|
||||
/* name for boot aggregate entry */
|
||||
static const char boot_aggregate_name[] = "boot_aggregate";
|
||||
const char boot_aggregate_name[] = "boot_aggregate";
|
||||
struct tpm_chip *ima_tpm_chip;
|
||||
|
||||
/* Add the boot aggregate to the IMA measurement list and extend
|
||||
* the PCR register.
|
||||
*
|
||||
* Calculate the boot aggregate, a SHA1 over tpm registers 0-7,
|
||||
* Calculate the boot aggregate, a hash over tpm registers 0-7,
|
||||
* assuming a TPM chip exists, and zeroes if the TPM chip does not
|
||||
* exist. Add the boot aggregate measurement to the measurement
|
||||
* list and extend the PCR register.
|
||||
|
@ -49,15 +49,27 @@ static int __init ima_add_boot_aggregate(void)
|
|||
int violation = 0;
|
||||
struct {
|
||||
struct ima_digest_data hdr;
|
||||
char digest[TPM_DIGEST_SIZE];
|
||||
char digest[TPM_MAX_DIGEST_SIZE];
|
||||
} hash;
|
||||
|
||||
memset(iint, 0, sizeof(*iint));
|
||||
memset(&hash, 0, sizeof(hash));
|
||||
iint->ima_hash = &hash.hdr;
|
||||
iint->ima_hash->algo = HASH_ALGO_SHA1;
|
||||
iint->ima_hash->length = SHA1_DIGEST_SIZE;
|
||||
iint->ima_hash->algo = ima_hash_algo;
|
||||
iint->ima_hash->length = hash_digest_size[ima_hash_algo];
|
||||
|
||||
/*
|
||||
* With TPM 2.0 hash agility, TPM chips could support multiple TPM
|
||||
* PCR banks, allowing firmware to configure and enable different
|
||||
* banks. The SHA1 bank is not necessarily enabled.
|
||||
*
|
||||
* Use the same hash algorithm for reading the TPM PCRs as for
|
||||
* calculating the boot aggregate digest. Preference is given to
|
||||
* the configured IMA default hash algorithm. Otherwise, use the
|
||||
* TCG required banks - SHA256 for TPM 2.0, SHA1 for TPM 1.2.
|
||||
* Ultimately select SHA1 also for TPM 2.0 if the SHA256 PCR bank
|
||||
* is not found.
|
||||
*/
|
||||
if (ima_tpm_chip) {
|
||||
result = ima_calc_boot_aggregate(&hash.hdr);
|
||||
if (result < 0) {
|
||||
|
|
|
@ -393,6 +393,57 @@ int ima_file_mmap(struct file *file, unsigned long prot)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_file_mprotect - based on policy, limit mprotect change
|
||||
* @prot: contains the protection that will be applied by the kernel.
|
||||
*
|
||||
* Files can be mmap'ed read/write and later changed to execute to circumvent
|
||||
* IMA's mmap appraisal policy rules. Due to locking issues (mmap semaphore
|
||||
* would be taken before i_mutex), files can not be measured or appraised at
|
||||
* this point. Eliminate this integrity gap by denying the mprotect
|
||||
* PROT_EXECUTE change, if an mmap appraise policy rule exists.
|
||||
*
|
||||
* On mprotect change success, return 0. On failure, return -EACESS.
|
||||
*/
|
||||
int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
|
||||
{
|
||||
struct ima_template_desc *template;
|
||||
struct file *file = vma->vm_file;
|
||||
char filename[NAME_MAX];
|
||||
char *pathbuf = NULL;
|
||||
const char *pathname = NULL;
|
||||
struct inode *inode;
|
||||
int result = 0;
|
||||
int action;
|
||||
u32 secid;
|
||||
int pcr;
|
||||
|
||||
/* Is mprotect making an mmap'ed file executable? */
|
||||
if (!vma->vm_file || !(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC))
|
||||
return 0;
|
||||
|
||||
security_task_getsecid(current, &secid);
|
||||
inode = file_inode(vma->vm_file);
|
||||
action = ima_get_action(inode, current_cred(), secid, MAY_EXEC,
|
||||
MMAP_CHECK, &pcr, &template, 0);
|
||||
|
||||
/* Is the mmap'ed file in policy? */
|
||||
if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
|
||||
return 0;
|
||||
|
||||
if (action & IMA_APPRAISE_SUBMASK)
|
||||
result = -EPERM;
|
||||
|
||||
file = vma->vm_file;
|
||||
pathname = ima_d_path(&file->f_path, &pathbuf, filename);
|
||||
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, pathname,
|
||||
"collect_data", "failed-mprotect", result, 0);
|
||||
if (pathbuf)
|
||||
__putname(pathbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_bprm_check - based on policy, collect/store measurement.
|
||||
* @bprm: contains the linux_binprm structure
|
||||
|
@ -792,6 +843,9 @@ static int __init init_ima(void)
|
|||
error = ima_init();
|
||||
}
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = register_blocking_lsm_notifier(&ima_lsm_policy_notifier);
|
||||
if (error)
|
||||
pr_warn("Couldn't register LSM notifier, error %d\n", error);
|
||||
|
|
|
@ -204,7 +204,7 @@ static struct ima_rule_entry *arch_policy_entry __ro_after_init;
|
|||
static LIST_HEAD(ima_default_rules);
|
||||
static LIST_HEAD(ima_policy_rules);
|
||||
static LIST_HEAD(ima_temp_rules);
|
||||
static struct list_head *ima_rules;
|
||||
static struct list_head *ima_rules = &ima_default_rules;
|
||||
|
||||
/* Pre-allocated buffer used for matching keyrings. */
|
||||
static char *ima_keyrings;
|
||||
|
@ -644,9 +644,12 @@ static void add_rules(struct ima_rule_entry *entries, int count,
|
|||
list_add_tail(&entry->list, &ima_policy_rules);
|
||||
}
|
||||
if (entries[i].action == APPRAISE) {
|
||||
temp_ima_appraise |= ima_appraise_flag(entries[i].func);
|
||||
if (entries[i].func == POLICY_CHECK)
|
||||
temp_ima_appraise |= IMA_APPRAISE_POLICY;
|
||||
if (entries != build_appraise_rules)
|
||||
temp_ima_appraise |=
|
||||
ima_appraise_flag(entries[i].func);
|
||||
else
|
||||
build_ima_appraise |=
|
||||
ima_appraise_flag(entries[i].func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -765,7 +768,6 @@ void __init ima_init_policy(void)
|
|||
ARRAY_SIZE(default_appraise_rules),
|
||||
IMA_DEFAULT_POLICY);
|
||||
|
||||
ima_rules = &ima_default_rules;
|
||||
ima_update_policy_flag();
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,8 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
|
|||
key = ima_hash_key(digest_value);
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(qe, &ima_htable.queue[key], hnext) {
|
||||
rc = memcmp(qe->entry->digest, digest_value, TPM_DIGEST_SIZE);
|
||||
rc = memcmp(qe->entry->digests[ima_hash_algo_idx].digest,
|
||||
digest_value, hash_digest_size[ima_hash_algo]);
|
||||
if ((rc == 0) && (qe->entry->pcr == pcr)) {
|
||||
ret = qe;
|
||||
break;
|
||||
|
@ -75,7 +76,7 @@ static int get_binary_runtime_size(struct ima_template_entry *entry)
|
|||
int size = 0;
|
||||
|
||||
size += sizeof(u32); /* pcr */
|
||||
size += sizeof(entry->digest);
|
||||
size += TPM_DIGEST_SIZE;
|
||||
size += sizeof(int); /* template name size field */
|
||||
size += strlen(entry->template_desc->name);
|
||||
size += sizeof(entry->template_data_len);
|
||||
|
@ -107,7 +108,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry,
|
|||
|
||||
atomic_long_inc(&ima_htable.len);
|
||||
if (update_htable) {
|
||||
key = ima_hash_key(entry->digest);
|
||||
key = ima_hash_key(entry->digests[ima_hash_algo_idx].digest);
|
||||
hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
|
||||
}
|
||||
|
||||
|
@ -134,18 +135,14 @@ unsigned long ima_get_binary_runtime_size(void)
|
|||
return binary_runtime_size + sizeof(struct ima_kexec_hdr);
|
||||
};
|
||||
|
||||
static int ima_pcr_extend(const u8 *hash, int pcr)
|
||||
static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr)
|
||||
{
|
||||
int result = 0;
|
||||
int i;
|
||||
|
||||
if (!ima_tpm_chip)
|
||||
return result;
|
||||
|
||||
for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
|
||||
memcpy(digests[i].digest, hash, TPM_DIGEST_SIZE);
|
||||
|
||||
result = tpm_pcr_extend(ima_tpm_chip, pcr, digests);
|
||||
result = tpm_pcr_extend(ima_tpm_chip, pcr, digests_arg);
|
||||
if (result != 0)
|
||||
pr_err("Error Communicating to TPM chip, result: %d\n", result);
|
||||
return result;
|
||||
|
@ -163,7 +160,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
|
|||
const char *op, struct inode *inode,
|
||||
const unsigned char *filename)
|
||||
{
|
||||
u8 digest[TPM_DIGEST_SIZE];
|
||||
u8 *digest = entry->digests[ima_hash_algo_idx].digest;
|
||||
struct tpm_digest *digests_arg = entry->digests;
|
||||
const char *audit_cause = "hash_added";
|
||||
char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
|
||||
int audit_info = 1;
|
||||
|
@ -171,7 +169,6 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
|
|||
|
||||
mutex_lock(&ima_extend_list_mutex);
|
||||
if (!violation) {
|
||||
memcpy(digest, entry->digest, sizeof(digest));
|
||||
if (ima_lookup_digest_entry(digest, entry->pcr)) {
|
||||
audit_cause = "hash_exists";
|
||||
result = -EEXIST;
|
||||
|
@ -187,9 +184,9 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
|
|||
}
|
||||
|
||||
if (violation) /* invalidate pcr */
|
||||
memset(digest, 0xff, sizeof(digest));
|
||||
digests_arg = digests;
|
||||
|
||||
tpmresult = ima_pcr_extend(digest, entry->pcr);
|
||||
tpmresult = ima_pcr_extend(digests_arg, entry->pcr);
|
||||
if (tpmresult != 0) {
|
||||
snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
|
||||
tpmresult);
|
||||
|
@ -215,6 +212,8 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry)
|
|||
|
||||
int __init ima_init_digests(void)
|
||||
{
|
||||
u16 digest_size;
|
||||
u16 crypto_id;
|
||||
int i;
|
||||
|
||||
if (!ima_tpm_chip)
|
||||
|
@ -225,8 +224,17 @@ int __init ima_init_digests(void)
|
|||
if (!digests)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
|
||||
for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) {
|
||||
digests[i].alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
|
||||
digest_size = ima_tpm_chip->allocated_banks[i].digest_size;
|
||||
crypto_id = ima_tpm_chip->allocated_banks[i].crypto_id;
|
||||
|
||||
/* for unmapped TPM algorithms digest is still a padded SHA1 */
|
||||
if (crypto_id == HASH_ALGO__LAST)
|
||||
digest_size = SHA1_DIGEST_SIZE;
|
||||
|
||||
memset(digests[i].digest, 0xff, digest_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -301,6 +301,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
|
|||
int template_data_size,
|
||||
struct ima_template_entry **entry)
|
||||
{
|
||||
struct tpm_digest *digests;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
|
@ -309,11 +310,21 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
|
|||
if (!*entry)
|
||||
return -ENOMEM;
|
||||
|
||||
digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
|
||||
sizeof(*digests), GFP_NOFS);
|
||||
if (!digests) {
|
||||
kfree(*entry);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
(*entry)->digests = digests;
|
||||
|
||||
ret = ima_parse_buf(template_data, template_data + template_data_size,
|
||||
NULL, template_desc->num_fields,
|
||||
(*entry)->template_data, NULL, NULL,
|
||||
ENFORCE_FIELDS | ENFORCE_BUFEND, "template data");
|
||||
if (ret < 0) {
|
||||
kfree((*entry)->digests);
|
||||
kfree(*entry);
|
||||
return ret;
|
||||
}
|
||||
|
@ -346,6 +357,7 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
|
|||
int ima_restore_measurement_list(loff_t size, void *buf)
|
||||
{
|
||||
char template_name[MAX_TEMPLATE_NAME_LEN];
|
||||
unsigned char zero[TPM_DIGEST_SIZE] = { 0 };
|
||||
|
||||
struct ima_kexec_hdr *khdr = buf;
|
||||
struct ima_field_data hdr[HDR__LAST] = {
|
||||
|
@ -445,8 +457,17 @@ int ima_restore_measurement_list(loff_t size, void *buf)
|
|||
if (ret < 0)
|
||||
break;
|
||||
|
||||
memcpy(entry->digest, hdr[HDR_DIGEST].data,
|
||||
hdr[HDR_DIGEST].len);
|
||||
if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) {
|
||||
ret = ima_calc_field_array_hash(
|
||||
&entry->template_data[0],
|
||||
entry);
|
||||
if (ret < 0) {
|
||||
pr_err("cannot calculate template digest\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) :
|
||||
le32_to_cpu(*(hdr[HDR_PCR].data));
|
||||
ret = ima_restore_measurement_entry(entry);
|
||||
|
|
|
@ -286,6 +286,24 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if ((const char *)event_data->filename == boot_aggregate_name) {
|
||||
if (ima_tpm_chip) {
|
||||
hash.hdr.algo = HASH_ALGO_SHA1;
|
||||
result = ima_calc_boot_aggregate(&hash.hdr);
|
||||
|
||||
/* algo can change depending on available PCR banks */
|
||||
if (!result && hash.hdr.algo != HASH_ALGO_SHA1)
|
||||
result = -EINVAL;
|
||||
|
||||
if (result < 0)
|
||||
memset(&hash, 0, sizeof(hash));
|
||||
}
|
||||
|
||||
cur_digest = hash.hdr.digest;
|
||||
cur_digestsize = hash_digest_size[HASH_ALGO_SHA1];
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!event_data->file) /* missing info to re-calculate the digest */
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -1517,7 +1517,12 @@ int security_mmap_addr(unsigned long addr)
|
|||
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
|
||||
unsigned long prot)
|
||||
{
|
||||
return call_int_hook(file_mprotect, 0, vma, reqprot, prot);
|
||||
int ret;
|
||||
|
||||
ret = call_int_hook(file_mprotect, 0, vma, reqprot, prot);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ima_file_mprotect(vma, prot);
|
||||
}
|
||||
|
||||
int security_file_lock(struct file *file, unsigned int cmd)
|
||||
|
|
Loading…
Reference in New Issue
Block a user