Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2008 IBM Corporation
0004  *
0005  * Author: Mimi Zohar <zohar@us.ibm.com>
0006  *
0007  * File: ima_api.c
0008  *  Implements must_appraise_or_measure, collect_measurement,
0009  *  appraise_measurement, store_measurement and store_template.
0010  */
0011 #include <linux/slab.h>
0012 #include <linux/file.h>
0013 #include <linux/fs.h>
0014 #include <linux/xattr.h>
0015 #include <linux/evm.h>
0016 #include <linux/iversion.h>
0017 #include <linux/fsverity.h>
0018 
0019 #include "ima.h"
0020 
0021 /*
0022  * ima_free_template_entry - free an existing template entry
0023  */
0024 void ima_free_template_entry(struct ima_template_entry *entry)
0025 {
0026     int i;
0027 
0028     for (i = 0; i < entry->template_desc->num_fields; i++)
0029         kfree(entry->template_data[i].data);
0030 
0031     kfree(entry->digests);
0032     kfree(entry);
0033 }
0034 
0035 /*
0036  * ima_alloc_init_template - create and initialize a new template entry
0037  */
0038 int ima_alloc_init_template(struct ima_event_data *event_data,
0039                 struct ima_template_entry **entry,
0040                 struct ima_template_desc *desc)
0041 {
0042     struct ima_template_desc *template_desc;
0043     struct tpm_digest *digests;
0044     int i, result = 0;
0045 
0046     if (desc)
0047         template_desc = desc;
0048     else
0049         template_desc = ima_template_desc_current();
0050 
0051     *entry = kzalloc(struct_size(*entry, template_data,
0052                      template_desc->num_fields), GFP_NOFS);
0053     if (!*entry)
0054         return -ENOMEM;
0055 
0056     digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
0057               sizeof(*digests), GFP_NOFS);
0058     if (!digests) {
0059         kfree(*entry);
0060         *entry = NULL;
0061         return -ENOMEM;
0062     }
0063 
0064     (*entry)->digests = digests;
0065     (*entry)->template_desc = template_desc;
0066     for (i = 0; i < template_desc->num_fields; i++) {
0067         const struct ima_template_field *field =
0068             template_desc->fields[i];
0069         u32 len;
0070 
0071         result = field->field_init(event_data,
0072                        &((*entry)->template_data[i]));
0073         if (result != 0)
0074             goto out;
0075 
0076         len = (*entry)->template_data[i].len;
0077         (*entry)->template_data_len += sizeof(len);
0078         (*entry)->template_data_len += len;
0079     }
0080     return 0;
0081 out:
0082     ima_free_template_entry(*entry);
0083     *entry = NULL;
0084     return result;
0085 }
0086 
0087 /*
0088  * ima_store_template - store ima template measurements
0089  *
0090  * Calculate the hash of a template entry, add the template entry
0091  * to an ordered list of measurement entries maintained inside the kernel,
0092  * and also update the aggregate integrity value (maintained inside the
0093  * configured TPM PCR) over the hashes of the current list of measurement
0094  * entries.
0095  *
0096  * Applications retrieve the current kernel-held measurement list through
0097  * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
0098  * TPM PCR (called quote) can be retrieved using a TPM user space library
0099  * and is used to validate the measurement list.
0100  *
0101  * Returns 0 on success, error code otherwise
0102  */
0103 int ima_store_template(struct ima_template_entry *entry,
0104                int violation, struct inode *inode,
0105                const unsigned char *filename, int pcr)
0106 {
0107     static const char op[] = "add_template_measure";
0108     static const char audit_cause[] = "hashing_error";
0109     char *template_name = entry->template_desc->name;
0110     int result;
0111 
0112     if (!violation) {
0113         result = ima_calc_field_array_hash(&entry->template_data[0],
0114                            entry);
0115         if (result < 0) {
0116             integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
0117                         template_name, op,
0118                         audit_cause, result, 0);
0119             return result;
0120         }
0121     }
0122     entry->pcr = pcr;
0123     result = ima_add_template_entry(entry, violation, op, inode, filename);
0124     return result;
0125 }
0126 
0127 /*
0128  * ima_add_violation - add violation to measurement list.
0129  *
0130  * Violations are flagged in the measurement list with zero hash values.
0131  * By extending the PCR with 0xFF's instead of with zeroes, the PCR
0132  * value is invalidated.
0133  */
0134 void ima_add_violation(struct file *file, const unsigned char *filename,
0135                struct integrity_iint_cache *iint,
0136                const char *op, const char *cause)
0137 {
0138     struct ima_template_entry *entry;
0139     struct inode *inode = file_inode(file);
0140     struct ima_event_data event_data = { .iint = iint,
0141                          .file = file,
0142                          .filename = filename,
0143                          .violation = cause };
0144     int violation = 1;
0145     int result;
0146 
0147     /* can overflow, only indicator */
0148     atomic_long_inc(&ima_htable.violations);
0149 
0150     result = ima_alloc_init_template(&event_data, &entry, NULL);
0151     if (result < 0) {
0152         result = -ENOMEM;
0153         goto err_out;
0154     }
0155     result = ima_store_template(entry, violation, inode,
0156                     filename, CONFIG_IMA_MEASURE_PCR_IDX);
0157     if (result < 0)
0158         ima_free_template_entry(entry);
0159 err_out:
0160     integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
0161                 op, cause, result, 0);
0162 }
0163 
0164 /**
0165  * ima_get_action - appraise & measure decision based on policy.
0166  * @mnt_userns: user namespace of the mount the inode was found from
0167  * @inode: pointer to the inode associated with the object being validated
0168  * @cred: pointer to credentials structure to validate
0169  * @secid: secid of the task being validated
0170  * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
0171  *        MAY_APPEND)
0172  * @func: caller identifier
0173  * @pcr: pointer filled in if matched measure policy sets pcr=
0174  * @template_desc: pointer filled in if matched measure policy sets template=
0175  * @func_data: func specific data, may be NULL
0176  * @allowed_algos: allowlist of hash algorithms for the IMA xattr
0177  *
0178  * The policy is defined in terms of keypairs:
0179  *      subj=, obj=, type=, func=, mask=, fsmagic=
0180  *  subj,obj, and type: are LSM specific.
0181  *  func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
0182  *  | KEXEC_CMDLINE | KEY_CHECK | CRITICAL_DATA
0183  *  mask: contains the permission mask
0184  *  fsmagic: hex value
0185  *
0186  * Returns IMA_MEASURE, IMA_APPRAISE mask.
0187  *
0188  */
0189 int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
0190            const struct cred *cred, u32 secid, int mask,
0191            enum ima_hooks func, int *pcr,
0192            struct ima_template_desc **template_desc,
0193            const char *func_data, unsigned int *allowed_algos)
0194 {
0195     int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
0196 
0197     flags &= ima_policy_flag;
0198 
0199     return ima_match_policy(mnt_userns, inode, cred, secid, func, mask,
0200                 flags, pcr, template_desc, func_data,
0201                 allowed_algos);
0202 }
0203 
0204 static int ima_get_verity_digest(struct integrity_iint_cache *iint,
0205                  struct ima_max_digest_data *hash)
0206 {
0207     enum hash_algo verity_alg;
0208     int ret;
0209 
0210     /*
0211      * On failure, 'measure' policy rules will result in a file data
0212      * hash containing 0's.
0213      */
0214     ret = fsverity_get_digest(iint->inode, hash->digest, &verity_alg);
0215     if (ret)
0216         return ret;
0217 
0218     /*
0219      * Unlike in the case of actually calculating the file hash, in
0220      * the fsverity case regardless of the hash algorithm, return
0221      * the verity digest to be included in the measurement list. A
0222      * mismatch between the verity algorithm and the xattr signature
0223      * algorithm, if one exists, will be detected later.
0224      */
0225     hash->hdr.algo = verity_alg;
0226     hash->hdr.length = hash_digest_size[verity_alg];
0227     return 0;
0228 }
0229 
0230 /*
0231  * ima_collect_measurement - collect file measurement
0232  *
0233  * Calculate the file hash, if it doesn't already exist,
0234  * storing the measurement and i_version in the iint.
0235  *
0236  * Must be called with iint->mutex held.
0237  *
0238  * Return 0 on success, error code otherwise
0239  */
0240 int ima_collect_measurement(struct integrity_iint_cache *iint,
0241                 struct file *file, void *buf, loff_t size,
0242                 enum hash_algo algo, struct modsig *modsig)
0243 {
0244     const char *audit_cause = "failed";
0245     struct inode *inode = file_inode(file);
0246     const char *filename = file->f_path.dentry->d_name.name;
0247     struct ima_max_digest_data hash;
0248     int result = 0;
0249     int length;
0250     void *tmpbuf;
0251     u64 i_version;
0252 
0253     /*
0254      * Always collect the modsig, because IMA might have already collected
0255      * the file digest without collecting the modsig in a previous
0256      * measurement rule.
0257      */
0258     if (modsig)
0259         ima_collect_modsig(modsig, buf, size);
0260 
0261     if (iint->flags & IMA_COLLECTED)
0262         goto out;
0263 
0264     /*
0265      * Detecting file change is based on i_version. On filesystems
0266      * which do not support i_version, support was originally limited
0267      * to an initial measurement/appraisal/audit, but was modified to
0268      * assume the file changed.
0269      */
0270     i_version = inode_query_iversion(inode);
0271     hash.hdr.algo = algo;
0272     hash.hdr.length = hash_digest_size[algo];
0273 
0274     /* Initialize hash digest to 0's in case of failure */
0275     memset(&hash.digest, 0, sizeof(hash.digest));
0276 
0277     if (iint->flags & IMA_VERITY_REQUIRED) {
0278         result = ima_get_verity_digest(iint, &hash);
0279         switch (result) {
0280         case 0:
0281             break;
0282         case -ENODATA:
0283             audit_cause = "no-verity-digest";
0284             break;
0285         default:
0286             audit_cause = "invalid-verity-digest";
0287             break;
0288         }
0289     } else if (buf) {
0290         result = ima_calc_buffer_hash(buf, size, &hash.hdr);
0291     } else {
0292         result = ima_calc_file_hash(file, &hash.hdr);
0293     }
0294 
0295     if (result == -ENOMEM)
0296         goto out;
0297 
0298     length = sizeof(hash.hdr) + hash.hdr.length;
0299     tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
0300     if (!tmpbuf) {
0301         result = -ENOMEM;
0302         goto out;
0303     }
0304 
0305     iint->ima_hash = tmpbuf;
0306     memcpy(iint->ima_hash, &hash, length);
0307     iint->version = i_version;
0308 
0309     /* Possibly temporary failure due to type of read (eg. O_DIRECT) */
0310     if (!result)
0311         iint->flags |= IMA_COLLECTED;
0312 out:
0313     if (result) {
0314         if (file->f_flags & O_DIRECT)
0315             audit_cause = "failed(directio)";
0316 
0317         integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
0318                     filename, "collect_data", audit_cause,
0319                     result, 0);
0320     }
0321     return result;
0322 }
0323 
0324 /*
0325  * ima_store_measurement - store file measurement
0326  *
0327  * Create an "ima" template and then store the template by calling
0328  * ima_store_template.
0329  *
0330  * We only get here if the inode has not already been measured,
0331  * but the measurement could already exist:
0332  *  - multiple copies of the same file on either the same or
0333  *    different filesystems.
0334  *  - the inode was previously flushed as well as the iint info,
0335  *    containing the hashing info.
0336  *
0337  * Must be called with iint->mutex held.
0338  */
0339 void ima_store_measurement(struct integrity_iint_cache *iint,
0340                struct file *file, const unsigned char *filename,
0341                struct evm_ima_xattr_data *xattr_value,
0342                int xattr_len, const struct modsig *modsig, int pcr,
0343                struct ima_template_desc *template_desc)
0344 {
0345     static const char op[] = "add_template_measure";
0346     static const char audit_cause[] = "ENOMEM";
0347     int result = -ENOMEM;
0348     struct inode *inode = file_inode(file);
0349     struct ima_template_entry *entry;
0350     struct ima_event_data event_data = { .iint = iint,
0351                          .file = file,
0352                          .filename = filename,
0353                          .xattr_value = xattr_value,
0354                          .xattr_len = xattr_len,
0355                          .modsig = modsig };
0356     int violation = 0;
0357 
0358     /*
0359      * We still need to store the measurement in the case of MODSIG because
0360      * we only have its contents to put in the list at the time of
0361      * appraisal, but a file measurement from earlier might already exist in
0362      * the measurement list.
0363      */
0364     if (iint->measured_pcrs & (0x1 << pcr) && !modsig)
0365         return;
0366 
0367     result = ima_alloc_init_template(&event_data, &entry, template_desc);
0368     if (result < 0) {
0369         integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
0370                     op, audit_cause, result, 0);
0371         return;
0372     }
0373 
0374     result = ima_store_template(entry, violation, inode, filename, pcr);
0375     if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) {
0376         iint->flags |= IMA_MEASURED;
0377         iint->measured_pcrs |= (0x1 << pcr);
0378     }
0379     if (result < 0)
0380         ima_free_template_entry(entry);
0381 }
0382 
0383 void ima_audit_measurement(struct integrity_iint_cache *iint,
0384                const unsigned char *filename)
0385 {
0386     struct audit_buffer *ab;
0387     char *hash;
0388     const char *algo_name = hash_algo_name[iint->ima_hash->algo];
0389     int i;
0390 
0391     if (iint->flags & IMA_AUDITED)
0392         return;
0393 
0394     hash = kzalloc((iint->ima_hash->length * 2) + 1, GFP_KERNEL);
0395     if (!hash)
0396         return;
0397 
0398     for (i = 0; i < iint->ima_hash->length; i++)
0399         hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
0400     hash[i * 2] = '\0';
0401 
0402     ab = audit_log_start(audit_context(), GFP_KERNEL,
0403                  AUDIT_INTEGRITY_RULE);
0404     if (!ab)
0405         goto out;
0406 
0407     audit_log_format(ab, "file=");
0408     audit_log_untrustedstring(ab, filename);
0409     audit_log_format(ab, " hash=\"%s:%s\"", algo_name, hash);
0410 
0411     audit_log_task_info(ab);
0412     audit_log_end(ab);
0413 
0414     iint->flags |= IMA_AUDITED;
0415 out:
0416     kfree(hash);
0417     return;
0418 }
0419 
0420 /*
0421  * ima_d_path - return a pointer to the full pathname
0422  *
0423  * Attempt to return a pointer to the full pathname for use in the
0424  * IMA measurement list, IMA audit records, and auditing logs.
0425  *
0426  * On failure, return a pointer to a copy of the filename, not dname.
0427  * Returning a pointer to dname, could result in using the pointer
0428  * after the memory has been freed.
0429  */
0430 const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
0431 {
0432     char *pathname = NULL;
0433 
0434     *pathbuf = __getname();
0435     if (*pathbuf) {
0436         pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
0437         if (IS_ERR(pathname)) {
0438             __putname(*pathbuf);
0439             *pathbuf = NULL;
0440             pathname = NULL;
0441         }
0442     }
0443 
0444     if (!pathname) {
0445         strscpy(namebuf, path->dentry->d_name.name, NAME_MAX);
0446         pathname = namebuf;
0447     }
0448 
0449     return pathname;
0450 }