* [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA @ 2022-10-31 2:55 Denis Semakin 2022-10-31 2:59 ` [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace Denis Semakin ` (4 more replies) 0 siblings, 5 replies; 13+ messages in thread From: Denis Semakin @ 2022-10-31 2:55 UTC (permalink / raw) To: linux-integrity Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping, roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin The main goal of this series is to provide the opportunity for retrieving integrity information from containters (namespaces) in case of remote attestation requests and requests from another servers querying the state of integrity for any given container. The detailed description and architecture can be found here: https://www.usenix.org/system/files/raid2019-luo.pdf, this paper shows the basics for how it works in general but did not solve the some practical issues related to memoy allocation, TPM interaction etc. Summary: Let Ih is host integrity, and Ic1, Ic2, Icn the integrity of the first, second and etc container. Then the whole integrity of system would be: Ih = Ic1 + Ic2 + ... + Icn; where Ic1, Ic2 ... are integrity of corresponding containers (namespaces) Each container integrity consists of measurement lists and the value of virtual PCR (container PCR). vPCR = cPCR. Architecture scheme .---------. .---------. .---------. | C1 with | | C2 with | | Cn with | | IMA-ns | | IMA-ns | | IMA-ns | |---------| |---------| |---------| | vPCR1 |<--->| vPCR2 |... <---> | vPCRn | |---------| |---------| |---------| | | | | | | '---------' '---------' '---------' C1, C2, Cn - containers (with IMA namespaces) vPCRi - virtual PCR (in other words cPCR - container PCRs) Each IMA namespace which belongs to container should store its own PCR value (virtual vPCR or in other words container PCR = cPCR = vPCR, virtual PCR) and should perform a number of operation. Measurement: 1. records the history value of a specific PCR (historyPCR) which is not used in the current system. In our prototype based on TPM 2.0, we choose PCR12. 2. records the digest of all cPCRs (cPCR - container PCR or virtual PCR that is stored for namespace). During measurement perform: tempValue := cPCRi.value xor cPCRi.secret; tempPCR := HASH(tempPCR || tempValue); Where cPCRi.value - is a value of a given namespaces, cPCRi.secret - random generated sequence of bytes for namespace, || - concatenation. 3. extends the physical PCR12 with the final tempPCR. PCR12 := PCR_Extend(PCR12,tempPCR) Attestation: When receiving this request, the IMA (and TPM) should provide the following data: 1. the related PCR values, in our case this is PCR12 2. sendcPCRs list where sendcPCR for each namespace is calculated as: sendcPCRs = cPCRi.value xor cPCRi.secret 3. Measurement lists for namespace. This work is also based on Stefan Berger's patches from: https://github.com/stefanberger/linux-ima-namespaces Denis Semakin (4): ima: Introduce PCR virtualization for IMA namespace. ima: Use tpm_chip from init IMA namespace. ima: Create vpcr file on securityfs. ima: Extend the real PCR12 with tempPCR value. security/integrity/ima/ima.h | 13 +- security/integrity/ima/ima_fs.c | 147 +++++++++++++++++++++++ security/integrity/ima/ima_init_ima_ns.c | 21 ++++ security/integrity/ima/ima_ns.c | 3 + security/integrity/ima/ima_queue.c | 55 +++++++++ 5 files changed, 238 insertions(+), 1 deletion(-) v2: use sequential structure and methods for file on securityfs -- 2.38.GIT ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace. 2022-10-31 2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin @ 2022-10-31 2:59 ` Denis Semakin 2022-10-31 2:59 ` [RFC PATCH v2 2/4] ima: Use tpm_chip from init " Denis Semakin ` (3 subsequent siblings) 4 siblings, 0 replies; 13+ messages in thread From: Denis Semakin @ 2022-10-31 2:59 UTC (permalink / raw) To: linux-integrity Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping, roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin Define a structure for virtual PCR and corresponding function. This function is called when IMA extends the real PCR register and perform following operations: 1) Extends virtual PCR value in structure vpcr_entry; 2) XOR this vPCR with random secret; 3) Store xored value in specific field. vpcr_digest := HASH256(vpcr_digest || new_digest); vpcr_temp := vpcr_digest XOR vpcr_secret; Signed-off-by: Denis Semakin <denis.semakin@huawei.com> --- security/integrity/ima/ima.h | 11 +++++ security/integrity/ima/ima_init_ima_ns.c | 13 ++++++ security/integrity/ima/ima_ns.c | 3 ++ security/integrity/ima/ima_queue.c | 55 ++++++++++++++++++++++++ 4 files changed, 82 insertions(+) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 7f263c9b5d31..cca984301968 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -119,6 +119,16 @@ struct ima_h_table { struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; }; +struct vpcr_entry { + u8 vpcr_tmp[SHA256_DIGEST_SIZE]; + u8 vpcr_digest[SHA256_DIGEST_SIZE]; + u8 secret[SHA256_DIGEST_SIZE]; + struct list_head list; +}; + +extern struct mutex vpcr_list_mutex; +extern struct list_head vpcr_list; + struct ima_namespace { unsigned long ima_ns_flags; /* Bit numbers for above flags; use BIT() to get flag */ @@ -165,6 +175,7 @@ struct ima_namespace { * and IMA default algo. */ int ima_extra_slots; + struct vpcr_entry vpcr; } __randomize_layout; extern struct ima_namespace init_ima_ns; diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index 986f594dd179..d29d113a322c 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -6,8 +6,12 @@ * Stefan Berger <stefanb@linux.vnet.ibm.com> */ +#include <linux/random.h> #include "ima.h" +LIST_HEAD(vpcr_list); +struct mutex vpcr_list_mutex; + int ima_init_namespace(struct ima_namespace *ns) { int ret; @@ -50,8 +54,17 @@ int ima_init_namespace(struct ima_namespace *ns) ns->ima_tpm_chip = tpm_default_chip(); if (ns->ima_tpm_chip) pr_info("No TPM chip found, activating TPM-bypass!\n"); + + mutex_init(&vpcr_list_mutex); + list_add(&ns->vpcr.list, &vpcr_list); + } else { + mutex_lock(&vpcr_list_mutex); + list_add_tail(&ns->vpcr.list, &vpcr_list); + mutex_unlock(&vpcr_list_mutex); } + get_random_bytes(&ns->vpcr.secret, sizeof(ns->vpcr.secret)); + set_bit(IMA_NS_ACTIVE, &ns->ima_ns_flags); return 0; diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c index 9f6ee3423d34..3f65bfbba98d 100644 --- a/security/integrity/ima/ima_ns.c +++ b/security/integrity/ima/ima_ns.c @@ -32,6 +32,9 @@ static void destroy_ima_ns(struct ima_namespace *ns) ima_free_policy_rules(ns); ima_free_ns_status_tree(ns); ima_free_measurements(ns); + mutex_lock(&vpcr_list_mutex); + list_del(&ns->vpcr.list); + mutex_unlock(&vpcr_list_mutex); } void ima_free_ima_ns(struct ima_namespace *ns) diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index b7a3f608ee9d..6f1fcd4ee307 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -17,6 +17,7 @@ #include <linux/rculist.h> #include <linux/slab.h> +#include <crypto/algapi.h> #include "ima.h" #define AUDIT_CAUSE_LEN_MAX 32 @@ -127,6 +128,55 @@ unsigned long ima_get_binary_runtime_size(struct ima_namespace *ns) return ns->binary_runtime_size + sizeof(struct ima_kexec_hdr); } +/** + * This function extends the virtual PCR for namespace. + * It calculates the HASH for given digest, store it in structure + * and XOR it with random secret. + * vpcr_digest := HASH(vpcr_digest || new_digest); + * vpcr_temp := vpcr_digest XOR vpcr_secret; + */ + +static int ima_vpcr_extend(struct ima_namespace *ns, + struct tpm_digest *digests_arg, int pcr) +{ + int ret = 0; + u8 buf[IMA_MAX_DIGEST_SIZE * 2]; + struct { + struct ima_digest_data hdr; + char digest[IMA_MAX_DIGEST_SIZE]; + } hash = {}; + + size_t dig_len = hash_digest_size[ima_hash_algo]; + loff_t size = SHA256_DIGEST_SIZE + dig_len; + + /* paranoic zeroing */ + memset(buf, 0, sizeof(buf)); + memset(&hash.digest, 0, sizeof(hash.digest)); + + /* Use SHA256 hash for vPCR */ + hash.hdr.algo = HASH_ALGO_SHA256; + hash.hdr.length = SHA256_DIGEST_SIZE; + + memcpy(buf, ns->vpcr.vpcr_digest, SHA256_DIGEST_SIZE); + memcpy(buf + SHA256_DIGEST_SIZE, &digests_arg->digest[ns->ima_hash_algo_idx], + dig_len); + + ret = ima_calc_buffer_hash(ns, buf, size, &hash.hdr); + if (ret < 0) + goto out; + + if (mutex_lock_interruptible(&vpcr_list_mutex)) + return -EINTR; + + memcpy(ns->vpcr.vpcr_digest, &hash.digest, SHA256_DIGEST_SIZE); + crypto_xor_cpy(ns->vpcr.vpcr_tmp, ns->vpcr.vpcr_digest, + ns->vpcr.secret, SHA256_DIGEST_SIZE); + mutex_unlock(&vpcr_list_mutex); +out: + + return ret; +} + static int ima_pcr_extend(struct ima_namespace *ns, struct tpm_digest *digests_arg, int pcr) { @@ -135,9 +185,14 @@ static int ima_pcr_extend(struct ima_namespace *ns, if (!ns->ima_tpm_chip) return result; + result = ima_vpcr_extend(ns, digests_arg, pcr); + if (result != 0) + pr_err("Error extending vPCR, result: %d\n", result); + result = tpm_pcr_extend(ns->ima_tpm_chip, pcr, digests_arg); if (result != 0) pr_err("Error Communicating to TPM chip, result: %d\n", result); + return result; } -- 2.38.GIT ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v2 2/4] ima: Use tpm_chip from init IMA namespace. 2022-10-31 2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin 2022-10-31 2:59 ` [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace Denis Semakin @ 2022-10-31 2:59 ` Denis Semakin 2022-10-31 3:00 ` [RFC PATCH v2 3/4] ima: Create vpcr file on securityfs Denis Semakin ` (2 subsequent siblings) 4 siblings, 0 replies; 13+ messages in thread From: Denis Semakin @ 2022-10-31 2:59 UTC (permalink / raw) To: linux-integrity Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping, roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin For now a child namespace uses the same tpm chip descriptor from init namespace. Signed-off-by: Denis Semakin <denis.semakin@huawei.com> --- security/integrity/ima/ima_init_ima_ns.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index d29d113a322c..8093c61697a4 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -58,6 +58,14 @@ int ima_init_namespace(struct ima_namespace *ns) mutex_init(&vpcr_list_mutex); list_add(&ns->vpcr.list, &vpcr_list); } else { + /** + * Here we just assign tpm_chip from init_ima_ns + * with new IMA namespace. + * In future a new API should be used I think + * Stefan's ima_ns_set_tpm_chip() and etc. to get + * TPM chip descriptor and provider. + */ + ns->ima_tpm_chip = init_ima_ns.ima_tpm_chip; mutex_lock(&vpcr_list_mutex); list_add_tail(&ns->vpcr.list, &vpcr_list); mutex_unlock(&vpcr_list_mutex); -- 2.38.GIT ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v2 3/4] ima: Create vpcr file on securityfs. 2022-10-31 2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin 2022-10-31 2:59 ` [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace Denis Semakin 2022-10-31 2:59 ` [RFC PATCH v2 2/4] ima: Use tpm_chip from init " Denis Semakin @ 2022-10-31 3:00 ` Denis Semakin 2022-10-31 3:00 ` [RFC PATCH v2 4/4] ima: Extend the real PCR12 with tempPCR value Denis Semakin 2023-01-27 8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov 4 siblings, 0 replies; 13+ messages in thread From: Denis Semakin @ 2022-10-31 3:00 UTC (permalink / raw) To: linux-integrity Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping, roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin This file contains information of all virtual PCR registers that is extended by kernel when the real PCR extension operation is occurred. It provides the values of cPCRs and PCR12 register. During reading operation it calculates the final value of of cPCRs, store it in temp_vpcr_hash structure. Then this tempPCR value is used to extend the real PCR12 register. E.g.: $ sudo cat /sys/kernel/security/ima/vpcr cPCR: ab3c1c3ae0581168284738f01470d7be64b9a220bb4b7030b879ffc669a2e4b6 PCR12: 73b7267c1e9b74c573a6e243af1d574bf6141be162a51e6aef4cfc15c7550963 Signed-off-by: Denis Semakin <denis.semakin@huawei.com> --- security/integrity/ima/ima_fs.c | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index bb4c3d4493e2..d9e91b9f1564 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -25,6 +25,8 @@ #include "ima.h" +extern struct list_head vpcr_list; + bool ima_canonical_fmt; static int __init default_canonical_fmt_setup(char *str) { @@ -538,6 +540,65 @@ static const struct file_operations ima_active_ops = { .write = ima_write_active, }; +static void *vpcr_start(struct seq_file *m, loff_t *pos) +{ + int err; + + err = mutex_lock_interruptible(&vpcr_list_mutex); + if (err) + return ERR_PTR(err); + + return seq_list_start(&vpcr_list, *pos); +} + +static void *vpcr_next(struct seq_file *m, void *v, loff_t *pos) +{ + return seq_list_next(v, &vpcr_list, pos); +} + +static void vpcr_stop(struct seq_file *m, void *v) +{ + mutex_unlock(&vpcr_list_mutex); +} + +static int vpcr_show(struct seq_file *m, void *v) +{ + struct vpcr_entry *vpcr = list_entry(v, struct vpcr_entry, list); + + ima_putc(m, "cPCR: ", strlen("cPCR: ")); + ima_putc(m, vpcr->vpcr_tmp, SHA256_DIGEST_SIZE); + + return 0; +} + +const struct seq_operations vpcr_seq_ops = { + .start = vpcr_start, + .next = vpcr_next, + .stop = vpcr_stop, + .show = vpcr_show, +}; + +static int ima_vpcr_open(struct inode *inode, struct file *filp) +{ + struct user_namespace *user_ns = ima_user_ns_from_file(filp); + struct ima_namespace *ns = ima_ns_from_file(filp); + + if (!ns->ima_tpm_chip) + return -ENODEV; + + if (!ns_is_active(ns) || !mac_admin_ns_capable(user_ns)) + return -EACCES; + + return seq_open(filp, &vpcr_seq_ops); +} + +static const struct file_operations ima_vpcr_fops = { + .open = ima_vpcr_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) { struct ima_namespace *ns = ima_ns_from_user_ns(user_ns); @@ -549,6 +610,7 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) struct dentry *runtime_measurements_count = NULL; struct dentry *violations = NULL; struct dentry *active = NULL; + struct dentry *vpcr = NULL; int ret; /* @@ -625,6 +687,15 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) goto out; } + if (ns == &init_ima_ns) { + vpcr = securityfs_create_file("vpcr", S_IRUSR | S_IRGRP, + ima_dir, NULL, &ima_vpcr_fops); + if (IS_ERR(vpcr)) { + ret = PTR_ERR(vpcr); + goto out; + } + } + if (!ns->ima_policy_removed) { ns->ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS, @@ -652,6 +723,7 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) return 0; out: + securityfs_remove(vpcr); securityfs_remove(active); securityfs_remove(ns->ima_policy); securityfs_remove(violations); -- 2.38.GIT ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v2 4/4] ima: Extend the real PCR12 with tempPCR value. 2022-10-31 2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin ` (2 preceding siblings ...) 2022-10-31 3:00 ` [RFC PATCH v2 3/4] ima: Create vpcr file on securityfs Denis Semakin @ 2022-10-31 3:00 ` Denis Semakin 2023-01-27 8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov 4 siblings, 0 replies; 13+ messages in thread From: Denis Semakin @ 2022-10-31 3:00 UTC (permalink / raw) To: linux-integrity Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping, roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin For each namespace do this calculation: tempPCR := HASH(tempPCR || tempValue); And finally extend the real PCR12P: PCR12 := PCR_Extend(PCR12,tempPCR); Then read the PCR12 and return its value to user-space. Signed-off-by: Denis Semakin <denis.semakin@huawei.com> --- security/integrity/ima/ima.h | 2 +- security/integrity/ima/ima_fs.c | 83 +++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index cca984301968..02d7b66098ca 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -27,7 +27,7 @@ enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII }; -enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 }; +enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10, TPM_PCR12 = 12 }; /* digest size for IMA, fits SHA1 or MD5 */ #define IMA_DIGEST_SIZE SHA1_DIGEST_SIZE diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index d9e91b9f1564..8e517be7bba2 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -26,6 +26,7 @@ #include "ima.h" extern struct list_head vpcr_list; +static bool vpcr_mutex_acquired; bool ima_canonical_fmt; static int __init default_canonical_fmt_setup(char *str) @@ -540,13 +541,28 @@ static const struct file_operations ima_active_ops = { .write = ima_write_active, }; +struct { + struct ima_digest_data hdr; + char digest[SHA256_DIGEST_SIZE]; +} temp_vpcr_hash = { + .hdr = { + .algo = HASH_ALGO_SHA256, + .length = SHA256_DIGEST_SIZE, + }, +}; + static void *vpcr_start(struct seq_file *m, loff_t *pos) { int err; - err = mutex_lock_interruptible(&vpcr_list_mutex); - if (err) - return ERR_PTR(err); + if (*pos == 0) { + err = mutex_lock_interruptible(&vpcr_list_mutex); + if (err) { + vpcr_mutex_acquired = false; + return ERR_PTR(err); + } + vpcr_mutex_acquired = true; + } return seq_list_start(&vpcr_list, *pos); } @@ -558,17 +574,76 @@ static void *vpcr_next(struct seq_file *m, void *v, loff_t *pos) static void vpcr_stop(struct seq_file *m, void *v) { + int j; + int ret; + struct tpm_chip *tpm_chip; + struct tpm_digest *temp_tpm; + struct tpm_digest pcr12_digest; + struct ima_namespace *curr_ns = ima_ns_from_file(m->file); + + if (!vpcr_mutex_acquired) + return; + + tpm_chip = curr_ns->ima_tpm_chip; + pcr12_digest.alg_id = TPM_ALG_SHA256; + + temp_tpm = kcalloc(tpm_chip->nr_allocated_banks, + sizeof(*curr_ns->digests), GFP_NOFS); + if (!temp_tpm) + goto ex; + + for (j = 0; j < tpm_chip->nr_allocated_banks; j++) { + temp_tpm[j].alg_id = tpm_chip->allocated_banks[j].alg_id; + + + if (temp_tpm[j].alg_id == TPM_ALG_SHA256) + memcpy(&temp_tpm[j].digest, &temp_vpcr_hash.digest, + SHA256_DIGEST_SIZE); + else + memset(&temp_tpm[j].digest, 0, + hash_digest_size[tpm_chip->allocated_banks[j].crypto_id]); + } + + ret = tpm_pcr_extend(tpm_chip, TPM_PCR12, temp_tpm); + if (ret != 0) { + seq_puts(m, "TPM extend error\n"); + goto free_mem; + } + + ret = tpm_pcr_read(tpm_chip, TPM_PCR12, &pcr12_digest); + if (ret != 0) { + seq_puts(m, "TPM read error\n"); + goto free_mem; + } + + ima_putc(m, "PCR12: ", strlen("PCR12: ")); + ima_putc(m, pcr12_digest.digest, SHA256_DIGEST_SIZE); + +free_mem: + kfree(temp_tpm); +ex: mutex_unlock(&vpcr_list_mutex); + vpcr_mutex_acquired = false; } static int vpcr_show(struct seq_file *m, void *v) { + int ret = 0; + u8 buf[IMA_MAX_DIGEST_SIZE * 2] = {0}; struct vpcr_entry *vpcr = list_entry(v, struct vpcr_entry, list); + struct ima_namespace *curr_ns = container_of(vpcr, struct ima_namespace, + vpcr); ima_putc(m, "cPCR: ", strlen("cPCR: ")); ima_putc(m, vpcr->vpcr_tmp, SHA256_DIGEST_SIZE); - return 0; + memcpy(buf, &temp_vpcr_hash.digest, SHA256_DIGEST_SIZE); + memcpy(buf + SHA256_DIGEST_SIZE, vpcr->vpcr_tmp, + SHA256_DIGEST_SIZE); + + ret = ima_calc_buffer_hash(curr_ns, buf, SHA256_DIGEST_SIZE * 2, + &temp_vpcr_hash.hdr); + return ret; } const struct seq_operations vpcr_seq_ops = { -- 2.38.GIT ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v1 0/3] ima: vPCR debug/security 2022-10-31 2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin ` (3 preceding siblings ...) 2022-10-31 3:00 ` [RFC PATCH v2 4/4] ima: Extend the real PCR12 with tempPCR value Denis Semakin @ 2023-01-27 8:19 ` Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR Ilya Hanov ` (4 more replies) 4 siblings, 5 replies; 13+ messages in thread From: Ilya Hanov @ 2023-01-27 8:19 UTC (permalink / raw) To: linux-integrity Cc: yusongping, hukeping, denis.semakin, artem.kuzin, konstantin.meskhidze, ilya.hanov 1. UUID value for each vPCR. There's no way to identify vPCR values reading /sys/kernel/security/ima/vpcr. It shows only vPCR values (which are in turn XORed with vPCR.secret, next cPCR = vPCR; vPCR value means vPCR.value XOR vPCR.secret), so imagine a situation when a server has hundreds of containers. In order to identify them it needs to keep in mind the order vPCR is created in. To solve this problem UUID values were added for each vPCR. They appear in the following form - "<cPCR-pfx><UUID-value><cPCR-val>...": # xxd /sys/kernel/security/ima/binary_vpcr 00000000: 6350 4352 3a20 c57f 9efc 7149 4df5 a1b3 cPCR: ....qIM... 00000010: 66fb 03db 4006 8780 7247 57d7 96e2 1b24 f...@...rGW....$ 00000020: 2f9b c891 2c09 05d2 4dfb 2011 a74f d1e9 /...,...M. ..O.. 00000030: 1134 b247 bf80 .... .... .... .... .... ................ (output truncated) 6350 4352 3a20 - cPCR prefix. 6 bytes long. c57f 9efc 7149 4df5 a1b3 66fb 03db 4006 - UUID value. 16 bytes long. 8780 7247 57d7 96e2 1b24 2f9b c891 .... - cPCR value. 32 bytes long. ... 2. ascii_vpcr pseudo-file for sysadmins. Dump cPCR values in human-readable format. This may add some flexibility for debugging. ima/vpcr also was renamed to ima/binary_vpcr. When something went wrong System Administrator is able to see cPCR values without doing PCR_Extend operations (for PCR12), this invokes only PCR_Read. ascii_vpcr has the same format as binary_vpcr, but can be read by humans: # cat /sys/kernel/security/ima/ascii_vpcr cPCR: c57f9efc-7149-4df5-a1b3-66fb03db4006 8780724757d796e21b242f9bc8912c0905d24dfb2011a74fd1e91134b247bf80 (output truncated) 3. TPM RNG for vPCR.secret if it's presented. It adds some security because vPCR.secret will be generated using only TPM Hardware (as a Root Of Trust) without any Software Implementations. If there's no shipped TPM for a system - then use Software get_random_bytes(). To identify whether a system has been shipped with TPM RNG or not the code checks for CONFIG_HW_RANDOM_TPM. Note: UUID values are always generated using get_random_bytes under the hood. Here using Hardware is optional because UUIDs are not used inside TPM like cPCRs (PCR_Extend{PCR12}). Ilya Hanov (3): ima: Add a UUID value for each vPCR ima: ascii_vpcr pseudo-file for sysadmins ima: Use TPM RNG for vPCR.secret if it's presented. security/integrity/ima/ima.h | 2 + security/integrity/ima/ima_fs.c | 130 ++++++++++++++++++++--- security/integrity/ima/ima_init_ima_ns.c | 12 +++ 3 files changed, 128 insertions(+), 16 deletions(-) -- 2.17.1 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR 2023-01-27 8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov @ 2023-01-27 8:19 ` Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 2/3] ima: ascii_vpcr pseudo-file for sysadmins Ilya Hanov ` (3 subsequent siblings) 4 siblings, 0 replies; 13+ messages in thread From: Ilya Hanov @ 2023-01-27 8:19 UTC (permalink / raw) To: linux-integrity Cc: yusongping, hukeping, denis.semakin, artem.kuzin, konstantin.meskhidze, ilya.hanov Signed-off-by: Ilya Hanov <ilya.hanov@huawei-partners.com> --- security/integrity/ima/ima.h | 2 ++ security/integrity/ima/ima_fs.c | 1 + security/integrity/ima/ima_init_ima_ns.c | 1 + 3 files changed, 4 insertions(+) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 91da4dd11390..a717be9685ed 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -14,6 +14,7 @@ #define __LINUX_IMA_H #include <linux/types.h> +#include <linux/uuid.h> #include <linux/crypto.h> #include <linux/fs.h> #include <linux/security.h> @@ -176,6 +177,7 @@ struct ima_namespace { */ int ima_extra_slots; struct vpcr_entry vpcr; + uuid_t uuid; } __randomize_layout; extern struct ima_namespace init_ima_ns; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index d2dc7749949b..cf9164d31599 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -635,6 +635,7 @@ static int vpcr_show(struct seq_file *m, void *v) vpcr); ima_putc(m, "cPCR: ", strlen("cPCR: ")); + ima_putc(m, curr_ns->uuid.b, UUID_SIZE); ima_putc(m, vpcr->vpcr_tmp, SHA256_DIGEST_SIZE); memcpy(buf, &temp_vpcr_hash.digest, SHA256_DIGEST_SIZE); diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index f22062b70977..33e6a18dc560 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -71,6 +71,7 @@ int ima_init_namespace(struct ima_namespace *ns) mutex_unlock(&vpcr_list_mutex); } + generate_random_uuid(ns->uuid.b); get_random_bytes(&ns->vpcr.secret, sizeof(ns->vpcr.secret)); set_bit(IMA_NS_ACTIVE, &ns->ima_ns_flags); -- 2.17.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v1 2/3] ima: ascii_vpcr pseudo-file for sysadmins 2023-01-27 8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR Ilya Hanov @ 2023-01-27 8:19 ` Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 3/3] ima: Use TPM RNG for vPCR.secret if it's presented Ilya Hanov ` (2 subsequent siblings) 4 siblings, 0 replies; 13+ messages in thread From: Ilya Hanov @ 2023-01-27 8:19 UTC (permalink / raw) To: linux-integrity Cc: yusongping, hukeping, denis.semakin, artem.kuzin, konstantin.meskhidze, ilya.hanov Dump cPCR values in human-readable format. This may add some flexibility for debugging. ima/vpcr also was renamed to ima/binary_vpcr. When something went wrong System Administrator is able to see cPCR values without doing PCR_Extend operations (for PCR12), this invokes only PCR_Read. ascii_vpcr has the same format as binary_vpcr, but can be read by humans: $ sudo cat /sys/kernel/security/ima/ascii_vpcr cPCR: c57f9efc-7149-4df5-a1b3-66fb03db4006 8780724757d796e21b242f9bc8912c0905d24dfb2011a74fd1e91134b247bf80 (output truncated) Signed-off-by: Ilya Hanov <ilya.hanov@huawei-partners.com> --- security/integrity/ima/ima_fs.c | 129 ++++++++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 16 deletions(-) diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index cf9164d31599..2ebbdfa708df 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -572,7 +572,7 @@ static void *vpcr_next(struct seq_file *m, void *v, loff_t *pos) return seq_list_next(v, &vpcr_list, pos); } -static void vpcr_stop(struct seq_file *m, void *v) +static void binary_vpcr_stop(struct seq_file *m, void *v) { int j; int ret; @@ -585,8 +585,10 @@ static void vpcr_stop(struct seq_file *m, void *v) return; tpm_chip = curr_ns->ima_tpm_chip; - pcr12_digest.alg_id = TPM_ALG_SHA256; + if (!tpm_chip) + goto ex; + pcr12_digest.alg_id = TPM_ALG_SHA256; temp_tpm = kcalloc(tpm_chip->nr_allocated_banks, sizeof(*curr_ns->digests), GFP_NOFS); if (!temp_tpm) @@ -626,7 +628,7 @@ static void vpcr_stop(struct seq_file *m, void *v) mutex_unlock(&vpcr_list_mutex); } -static int vpcr_show(struct seq_file *m, void *v) +static int binary_vpcr_show(struct seq_file *m, void *v) { int ret = 0; u8 buf[IMA_MAX_DIGEST_SIZE * 2] = {0}; @@ -647,14 +649,96 @@ static int vpcr_show(struct seq_file *m, void *v) return ret; } -const struct seq_operations vpcr_seq_ops = { +const struct seq_operations binary_vpcr_seq_ops = { + .start = vpcr_start, + .next = vpcr_next, + .stop = binary_vpcr_stop, + .show = binary_vpcr_show, +}; + +static int ima_binary_vpcr_open(struct inode *inode, struct file *filp) +{ + struct user_namespace *user_ns = ima_user_ns_from_file(filp); + struct ima_namespace *ns = ima_ns_from_file(filp); + + if (!ns->ima_tpm_chip) + return -ENODEV; + + if (!ns_is_active(ns) || !mac_admin_ns_capable(user_ns)) + return -EACCES; + + return seq_open(filp, &binary_vpcr_seq_ops); +} + +static const struct file_operations ima_binary_vpcr_fops = { + .open = ima_binary_vpcr_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static void ascii_vpcr_stop(struct seq_file *m, void *v) +{ + int ret; + struct tpm_chip *tpm_chip; + struct tpm_digest pcr12_digest; + struct ima_namespace *curr_ns = ima_ns_from_file(m->file); + + if (!vpcr_mutex_acquired) + return; + + tpm_chip = curr_ns->ima_tpm_chip; + if (!tpm_chip) + goto ex; + + pcr12_digest.alg_id = TPM_ALG_SHA256; + ret = tpm_pcr_read(tpm_chip, TPM_PCR12, &pcr12_digest); + if (ret != 0) { + seq_puts(m, "TPM read error\n"); + goto ex; + } + + /* 1st: PCR12 Prefix */ + seq_printf(m, "\nPCR12: "); + + /* 2nd: PCR12 Hash */ + seq_printf(m, "%*phN", SHA256_DIGEST_SIZE, pcr12_digest.digest); + seq_printf(m, "\n"); +ex: + WRITE_ONCE(vpcr_mutex_acquired, false); + mutex_unlock(&vpcr_list_mutex); +} + +static int ascii_vpcr_show(struct seq_file *m, void *v) +{ + struct vpcr_entry *vpcr = list_entry(v, struct vpcr_entry, list); + struct ima_namespace *curr_ns = container_of(vpcr, struct ima_namespace, + vpcr); + + if (!vpcr) + return -ENOENT; + + /* 1st: cPCR Prefix */ + seq_printf(m, "cPCR: "); + + /* 2nd: cPCR UUID Value */ + seq_printf(m, "%pUb ", &curr_ns->uuid); + + /* 3rd: cPCR.Value XOR cPCR.Secret */ + seq_printf(m, "%*phN", SHA256_DIGEST_SIZE, vpcr->vpcr_tmp); + seq_printf(m, "\n"); + + return 0; +} + +const struct seq_operations ascii_vpcr_seq_ops = { .start = vpcr_start, .next = vpcr_next, - .stop = vpcr_stop, - .show = vpcr_show, + .stop = ascii_vpcr_stop, + .show = ascii_vpcr_show, }; -static int ima_vpcr_open(struct inode *inode, struct file *filp) +static int ima_ascii_vpcr_open(struct inode *inode, struct file *filp) { struct user_namespace *user_ns = ima_user_ns_from_file(filp); struct ima_namespace *ns = ima_ns_from_file(filp); @@ -665,11 +749,11 @@ static int ima_vpcr_open(struct inode *inode, struct file *filp) if (!ns_is_active(ns) || !mac_admin_ns_capable(user_ns)) return -EACCES; - return seq_open(filp, &vpcr_seq_ops); + return seq_open(filp, &ascii_vpcr_seq_ops); } -static const struct file_operations ima_vpcr_fops = { - .open = ima_vpcr_open, +static const struct file_operations ima_ascii_vpcr_fops = { + .open = ima_ascii_vpcr_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, @@ -686,7 +770,8 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) struct dentry *runtime_measurements_count = NULL; struct dentry *violations = NULL; struct dentry *active = NULL; - struct dentry *vpcr = NULL; + struct dentry *binary_vpcr = NULL; + struct dentry *ascii_vpcr = NULL; int ret; /* @@ -764,10 +849,21 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) } if (ns == &init_ima_ns) { - vpcr = securityfs_create_file("vpcr", S_IRUSR | S_IRGRP, - ima_dir, NULL, &ima_vpcr_fops); - if (IS_ERR(vpcr)) { - ret = PTR_ERR(vpcr); + binary_vpcr = + securityfs_create_file("binary_vpcr", + S_IRUSR | S_IRGRP, ima_dir, NULL, + &ima_binary_vpcr_fops); + if (IS_ERR(binary_vpcr)) { + ret = PTR_ERR(binary_vpcr); + goto out; + } + + ascii_vpcr = + securityfs_create_file("ascii_vpcr", + S_IRUSR | S_IRGRP, ima_dir, NULL, + &ima_ascii_vpcr_fops); + if (IS_ERR(ascii_vpcr)) { + ret = PTR_ERR(ascii_vpcr); goto out; } } @@ -799,7 +895,8 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) return 0; out: - securityfs_remove(vpcr); + securityfs_remove(ascii_vpcr); + securityfs_remove(binary_vpcr); securityfs_remove(active); securityfs_remove(ns->ima_policy); securityfs_remove(violations); -- 2.17.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v1 3/3] ima: Use TPM RNG for vPCR.secret if it's presented. 2023-01-27 8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 2/3] ima: ascii_vpcr pseudo-file for sysadmins Ilya Hanov @ 2023-01-27 8:19 ` Ilya Hanov 2023-03-29 8:58 ` [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace Denis Semakin 2023-03-29 9:03 ` [RFC PATCH v1 1/1] " Denis Semakin 4 siblings, 0 replies; 13+ messages in thread From: Ilya Hanov @ 2023-01-27 8:19 UTC (permalink / raw) To: linux-integrity Cc: yusongping, hukeping, denis.semakin, artem.kuzin, konstantin.meskhidze, ilya.hanov Signed-off-by: Ilya Hanov <ilya.hanov@huawei-partners.com> --- security/integrity/ima/ima_init_ima_ns.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index 33e6a18dc560..5ce3e42b6caa 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -6,7 +6,11 @@ * Stefan Berger <stefanb@linux.vnet.ibm.com> */ +#ifdef CONFIG_HW_RANDOM_TPM +#include <linux/tpm.h> +#else /* !CONFIG_HW_RANDOM_TPM */ #include <linux/random.h> +#endif /* CONFIG_HW_RANDOM_TPM */ #include "ima.h" LIST_HEAD(vpcr_list); @@ -72,7 +76,14 @@ int ima_init_namespace(struct ima_namespace *ns) } generate_random_uuid(ns->uuid.b); +#ifdef CONFIG_HW_RANDOM_TPM + ret = tpm_get_random(ns->ima_tpm_chip, ns->vpcr.secret, + sizeof(ns->vpcr.secret)); + if (ret < 0) + goto err_destroy_cache; +#else /* !CONFIG_HW_RANDOM_TPM */ get_random_bytes(&ns->vpcr.secret, sizeof(ns->vpcr.secret)); +#endif /* CONFIG_HW_RANDOM_TPM */ set_bit(IMA_NS_ACTIVE, &ns->ima_ns_flags); -- 2.17.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace 2023-01-27 8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov ` (2 preceding siblings ...) 2023-01-27 8:19 ` [RFC PATCH v1 3/3] ima: Use TPM RNG for vPCR.secret if it's presented Ilya Hanov @ 2023-03-29 8:58 ` Denis Semakin 2023-05-02 13:36 ` Stefan Berger 2023-03-29 9:03 ` [RFC PATCH v1 1/1] " Denis Semakin 4 siblings, 1 reply; 13+ messages in thread From: Denis Semakin @ 2023-03-29 8:58 UTC (permalink / raw) To: linux-integrity Cc: artem.kuzin, konstantin.meskhidze, ilya.hanov, yusongping, hukeping, denis.semakin This patch allows to read measurement lists of child namespaces form init IMA namespace in order to obtain the values of hashes to perform operations and procedures of remote attestation. Denis Semakin (1): ima: obtain child measurement list from init namespace security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_fs.c | 164 ++++++++++++++++++++++- security/integrity/ima/ima_init_ima_ns.c | 2 + security/integrity/ima/ima_ns.c | 31 +++++ 4 files changed, 193 insertions(+), 5 deletions(-) -- 2.38.GIT ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace 2023-03-29 8:58 ` [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace Denis Semakin @ 2023-05-02 13:36 ` Stefan Berger 2023-05-02 14:00 ` Denis Semakin 0 siblings, 1 reply; 13+ messages in thread From: Stefan Berger @ 2023-05-02 13:36 UTC (permalink / raw) To: Denis Semakin, linux-integrity Cc: artem.kuzin, konstantin.meskhidze, ilya.hanov, yusongping, hukeping, denis.semakin On 3/29/23 04:58, Denis Semakin wrote: > This patch allows to read measurement lists of child namespaces > form init IMA namespace in order to obtain the values of hashes > to perform operations and procedures of remote attestation. I supposed this type of support would go onto the next stage (current posted 'stage' is auditing support, next would be measurement support)? Stefan > > Denis Semakin (1): > ima: obtain child measurement list from init namespace > > security/integrity/ima/ima.h | 1 + > security/integrity/ima/ima_fs.c | 164 ++++++++++++++++++++++- > security/integrity/ima/ima_init_ima_ns.c | 2 + > security/integrity/ima/ima_ns.c | 31 +++++ > 4 files changed, 193 insertions(+), 5 deletions(-) > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace 2023-05-02 13:36 ` Stefan Berger @ 2023-05-02 14:00 ` Denis Semakin 0 siblings, 0 replies; 13+ messages in thread From: Denis Semakin @ 2023-05-02 14:00 UTC (permalink / raw) To: Stefan Berger, Denis Semakin, linux-integrity Cc: artem.kuzin, konstantin.meskhidze, ilya.hanov, yusongping, hukeping On 02.05.2023 16:36, Stefan Berger wrote: > > > On 3/29/23 04:58, Denis Semakin wrote: >> This patch allows to read measurement lists of child namespaces >> form init IMA namespace in order to obtain the values of hashes >> to perform operations and procedures of remote attestation. > > I supposed this type of support would go onto the next stage (current > posted > 'stage' is auditing support, next would be measurement support)? Yes. I agree. > > Stefan > >> >> Denis Semakin (1): >> ima: obtain child measurement list from init namespace >> >> security/integrity/ima/ima.h | 1 + >> security/integrity/ima/ima_fs.c | 164 ++++++++++++++++++++++- >> security/integrity/ima/ima_init_ima_ns.c | 2 + >> security/integrity/ima/ima_ns.c | 31 +++++ >> 4 files changed, 193 insertions(+), 5 deletions(-) >> ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH v1 1/1] ima: obtain child measurement list from init namespace 2023-01-27 8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov ` (3 preceding siblings ...) 2023-03-29 8:58 ` [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace Denis Semakin @ 2023-03-29 9:03 ` Denis Semakin 4 siblings, 0 replies; 13+ messages in thread From: Denis Semakin @ 2023-03-29 9:03 UTC (permalink / raw) To: linux-integrity Cc: artem.kuzin, konstantin.meskhidze, ilya.hanov, yusongping, hukeping, denis.semakin Signed-off-by: Denis Semakin <denis.semakin@huawei.com> --- security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_fs.c | 164 ++++++++++++++++++++++- security/integrity/ima/ima_init_ima_ns.c | 2 + security/integrity/ima/ima_ns.c | 31 +++++ 4 files changed, 193 insertions(+), 5 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index a717be9685ed..b46d6944f6ca 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -178,6 +178,7 @@ struct ima_namespace { int ima_extra_slots; struct vpcr_entry vpcr; uuid_t uuid; + struct dentry *parent_dentry; } __randomize_layout; extern struct ima_namespace init_ima_ns; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 570e5d00a454..78d9f967e1f4 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -24,6 +24,7 @@ #include <linux/ima.h> #include "ima.h" +#define INUM_BUF_SIZE 16 extern struct list_head vpcr_list; static bool vpcr_mutex_acquired; @@ -84,9 +85,8 @@ static const struct file_operations ima_measurements_count_ops = { }; /* returns pointer to hlist_node */ -static void *ima_measurements_start(struct seq_file *m, loff_t *pos) +static void *__ima_measurements_start(struct ima_namespace *ns, loff_t *pos) { - struct ima_namespace *ns = ima_ns_from_file(m->file); loff_t l = *pos; struct ima_queue_entry *qe; @@ -102,9 +102,16 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos) return NULL; } -static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) +static void *ima_measurements_start(struct seq_file *m, loff_t *pos) { struct ima_namespace *ns = ima_ns_from_file(m->file); + + return __ima_measurements_start(ns, pos); +} + +static void *__ima_measurements_next(struct ima_namespace *ns, void *v, + loff_t *pos) +{ struct ima_queue_entry *qe = v; /* lock protects when reading beyond last element @@ -118,6 +125,13 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) return (&qe->later == &ns->ima_measurements) ? NULL : qe; } +static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct ima_namespace *ns = ima_ns_from_file(m->file); + + return __ima_measurements_next(ns, v, pos); +} + static void ima_measurements_stop(struct seq_file *m, void *v) { } @@ -237,10 +251,10 @@ void ima_print_digest(struct seq_file *m, u8 *digest, u32 size) } /* print in ascii */ -static int ima_ascii_measurements_show(struct seq_file *m, void *v) +static int __ima_ascii_measurements_show(struct ima_namespace *ns, + struct seq_file *m, void *v) { /* the list never shrinks, so we don't need a lock here */ - struct ima_namespace *ns = ima_ns_from_file(m->file); struct ima_queue_entry *qe = v; struct ima_template_entry *e; char *template_name; @@ -276,6 +290,13 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) return 0; } +static int ima_ascii_measurements_show(struct seq_file *m, void *v) +{ + struct ima_namespace *ns = ima_ns_from_file(m->file); + + return __ima_ascii_measurements_show(ns, m, v); +} + static const struct seq_operations ima_ascii_measurements_seqops = { .start = ima_measurements_start, .next = ima_measurements_next, @@ -706,6 +727,94 @@ static const struct file_operations ima_ascii_vpcr_fops = { .release = seq_release, }; +static void *child_ns_measure_start(struct seq_file *m, loff_t *pos) +{ + struct ima_namespace *ns = (struct ima_namespace *)m->private; + + return __ima_measurements_start(ns, pos); +} + +static void *child_ns_measure_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct ima_namespace *ns = (struct ima_namespace *)m->private; + + return __ima_measurements_next(ns, v, pos); +} + +static void child_ns_measure_stop(struct seq_file *m, void *v) +{ +} + +static int ascii_child_ns_measure_show(struct seq_file *m, void *v) +{ + struct ima_namespace *ns = (struct ima_namespace *)m->private; + + return __ima_ascii_measurements_show(ns, m, v); +} + +static int child_ns_measure_show(struct seq_file *m, void *v) +{ + struct ima_namespace *ns = (struct ima_namespace *)m->private; + + return ima_ns_measurements_show(ns, m, v); +} + + +const struct seq_operations ascii_child_ns_measure_seqops = { + .start = child_ns_measure_start, + .next = child_ns_measure_next, + .stop = child_ns_measure_stop, + .show = ascii_child_ns_measure_show, +}; + +const struct seq_operations child_ns_measure_seqops = { + .start = child_ns_measure_start, + .next = child_ns_measure_next, + .stop = child_ns_measure_stop, + .show = child_ns_measure_show, +}; + +static int child_ns_measure_open(struct inode *inode, struct file *filp, + struct seq_operations *seq_ops) +{ + int ret; + struct seq_file *m; + + ret = seq_open(filp, seq_ops); + if (ret) + return ret; + + m = filp->private_data; + m->private = inode->i_private; + + return 0; +} + +static int ascii_child_ns_measure_open(struct inode *inode, struct file *filp) +{ + return child_ns_measure_open(inode, filp, + &ascii_child_ns_measure_seqops); +} +static int bin_child_ns_measure_open(struct inode *inode, struct file *filp) +{ + return child_ns_measure_open(inode, filp, &child_ns_measure_seqops); +} + + +static const struct file_operations ascii_ima_child_ns_measure_fops = { + .open = ascii_child_ns_measure_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const struct file_operations ima_child_ns_measure_fops = { + .open = bin_child_ns_measure_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) { struct ima_namespace *ns = ima_ns_from_user_ns(user_ns); @@ -718,6 +827,9 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) struct dentry *violations = NULL; struct dentry *binary_vpcr = NULL; struct dentry *ascii_vpcr = NULL; + struct dentry *child_dir; + struct dentry *child_ascii_dentry; + struct dentry *child_bin_dentry; int ret; /* @@ -821,6 +933,12 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) ret = PTR_ERR(ascii_vpcr); goto out; } + + ns->parent_dentry = securityfs_create_dir("children", ima_dir); + if (IS_ERR(ima_dir)) { + ret = PTR_ERR(ima_dir); + goto out; + } } if (!ns->ima_policy_removed) { @@ -834,11 +952,47 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) } } + if (ns != &init_ima_ns) { + char buf[INUM_BUF_SIZE]; + snprintf(buf, INUM_BUF_SIZE, "%u", user_ns->ns.inum); + child_dir = + securityfs_create_dir(buf, init_ima_ns.parent_dentry); + + if (IS_ERR(child_dir)) { + ret = PTR_ERR(child_dir); + if (ret != -EEXIST) /* Ignore only EEXIST */ + goto out; + } else { + child_ascii_dentry = + securityfs_create_file("ascii_measurement", + S_IRUSR | S_IWUSR | S_IRGRP, + child_dir, ns, + &ascii_ima_child_ns_measure_fops); + if (IS_ERR(child_ascii_dentry)) { + ret = PTR_ERR(child_ascii_dentry); + goto out; + } + + child_bin_dentry = + securityfs_create_file("binary_measurement", + S_IRUSR | S_IWUSR | S_IRGRP, + child_dir, ns, + &ima_child_ns_measure_fops); + if (IS_ERR(child_bin_dentry)) { + ret = PTR_ERR(child_bin_dentry); + goto out; + } + } + } + if (!ima_ns_from_user_ns(user_ns)) user_ns_set_ima_ns(user_ns, ns); return 0; out: + securityfs_remove(child_bin_dentry); + securityfs_remove(child_ascii_dentry); + securityfs_remove(child_dir); securityfs_remove(ascii_vpcr); securityfs_remove(binary_vpcr); securityfs_remove(ns->ima_policy); diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index 53d5539f67d6..c989bbb22a97 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -86,6 +86,8 @@ int ima_init_namespace(struct ima_namespace *ns) /* Also the child ns inherits the algo array from init ns */ ns->ima_algo_array = init_ima_ns.ima_algo_array; + ns->parent_dentry = init_ima_ns.parent_dentry; + mutex_lock(&vpcr_list_mutex); list_add_tail(&ns->vpcr.list, &vpcr_list); mutex_unlock(&vpcr_list_mutex); diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c index 3f65bfbba98d..de49abfdf9e9 100644 --- a/security/integrity/ima/ima_ns.c +++ b/security/integrity/ima/ima_ns.c @@ -7,6 +7,7 @@ */ #include <linux/ima.h> +#include <linux/namei.h> #include "ima.h" @@ -48,11 +49,41 @@ void ima_free_ima_ns(struct ima_namespace *ns) kmem_cache_free(imans_cachep, ns); } +#define DENTRY_BUF_SIZE 16 + +static void remove_ima_child_dentry(struct user_namespace *user_ns) +{ + char inum_dir[DENTRY_BUF_SIZE]; + char ascii_fname[DENTRY_BUF_SIZE * 2]; + char bin_fname[DENTRY_BUF_SIZE * 2]; + struct dentry *dentry_dir, *ascii_file, *bin_file; + + snprintf(inum_dir, DENTRY_BUF_SIZE, "%u", user_ns->ns.inum); + snprintf(ascii_fname, DENTRY_BUF_SIZE * 2, "%u/ascii", user_ns->ns.inum); + snprintf(bin_fname, DENTRY_BUF_SIZE * 2, "%u/bin", user_ns->ns.inum); + + inode_lock(d_inode(init_ima_ns.parent_dentry)); + + dentry_dir = lookup_one_len(inum_dir, init_ima_ns.parent_dentry, + strlen(inum_dir)); + ascii_file = lookup_one_len(ascii_fname, init_ima_ns.parent_dentry, + strlen(ascii_fname)); + bin_file = lookup_one_len(bin_fname, init_ima_ns.parent_dentry, + strlen(bin_fname)); + + inode_unlock(d_inode(init_ima_ns.parent_dentry)); + + securityfs_remove(ascii_file); + securityfs_remove(bin_file); + securityfs_remove(dentry_dir); +} + void free_ima_ns(struct user_namespace *user_ns) { struct ima_namespace *ns = ima_ns_from_user_ns(user_ns); ima_free_ima_ns(ns); + remove_ima_child_dentry(user_ns); user_ns->ima_ns = NULL; } -- 2.38.GIT ^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2023-05-02 13:58 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2022-10-31 2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin 2022-10-31 2:59 ` [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace Denis Semakin 2022-10-31 2:59 ` [RFC PATCH v2 2/4] ima: Use tpm_chip from init " Denis Semakin 2022-10-31 3:00 ` [RFC PATCH v2 3/4] ima: Create vpcr file on securityfs Denis Semakin 2022-10-31 3:00 ` [RFC PATCH v2 4/4] ima: Extend the real PCR12 with tempPCR value Denis Semakin 2023-01-27 8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 2/3] ima: ascii_vpcr pseudo-file for sysadmins Ilya Hanov 2023-01-27 8:19 ` [RFC PATCH v1 3/3] ima: Use TPM RNG for vPCR.secret if it's presented Ilya Hanov 2023-03-29 8:58 ` [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace Denis Semakin 2023-05-02 13:36 ` Stefan Berger 2023-05-02 14:00 ` Denis Semakin 2023-03-29 9:03 ` [RFC PATCH v1 1/1] " Denis Semakin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).