root/security/integrity/ima/ima_api.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ima_free_template_entry
  2. ima_alloc_init_template
  3. ima_store_template
  4. ima_add_violation
  5. ima_get_action
  6. ima_collect_measurement
  7. ima_store_measurement
  8. ima_audit_measurement
  9. ima_d_path

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2008 IBM Corporation
   4  *
   5  * Author: Mimi Zohar <zohar@us.ibm.com>
   6  *
   7  * File: ima_api.c
   8  *      Implements must_appraise_or_measure, collect_measurement,
   9  *      appraise_measurement, store_measurement and store_template.
  10  */
  11 #include <linux/slab.h>
  12 #include <linux/file.h>
  13 #include <linux/fs.h>
  14 #include <linux/xattr.h>
  15 #include <linux/evm.h>
  16 #include <linux/iversion.h>
  17 
  18 #include "ima.h"
  19 
  20 /*
  21  * ima_free_template_entry - free an existing template entry
  22  */
  23 void ima_free_template_entry(struct ima_template_entry *entry)
  24 {
  25         int i;
  26 
  27         for (i = 0; i < entry->template_desc->num_fields; i++)
  28                 kfree(entry->template_data[i].data);
  29 
  30         kfree(entry);
  31 }
  32 
  33 /*
  34  * ima_alloc_init_template - create and initialize a new template entry
  35  */
  36 int ima_alloc_init_template(struct ima_event_data *event_data,
  37                             struct ima_template_entry **entry,
  38                             struct ima_template_desc *desc)
  39 {
  40         struct ima_template_desc *template_desc;
  41         int i, result = 0;
  42 
  43         if (desc)
  44                 template_desc = desc;
  45         else
  46                 template_desc = ima_template_desc_current();
  47 
  48         *entry = kzalloc(struct_size(*entry, template_data,
  49                                      template_desc->num_fields), GFP_NOFS);
  50         if (!*entry)
  51                 return -ENOMEM;
  52 
  53         (*entry)->template_desc = template_desc;
  54         for (i = 0; i < template_desc->num_fields; i++) {
  55                 const struct ima_template_field *field =
  56                         template_desc->fields[i];
  57                 u32 len;
  58 
  59                 result = field->field_init(event_data,
  60                                            &((*entry)->template_data[i]));
  61                 if (result != 0)
  62                         goto out;
  63 
  64                 len = (*entry)->template_data[i].len;
  65                 (*entry)->template_data_len += sizeof(len);
  66                 (*entry)->template_data_len += len;
  67         }
  68         return 0;
  69 out:
  70         ima_free_template_entry(*entry);
  71         *entry = NULL;
  72         return result;
  73 }
  74 
  75 /*
  76  * ima_store_template - store ima template measurements
  77  *
  78  * Calculate the hash of a template entry, add the template entry
  79  * to an ordered list of measurement entries maintained inside the kernel,
  80  * and also update the aggregate integrity value (maintained inside the
  81  * configured TPM PCR) over the hashes of the current list of measurement
  82  * entries.
  83  *
  84  * Applications retrieve the current kernel-held measurement list through
  85  * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
  86  * TPM PCR (called quote) can be retrieved using a TPM user space library
  87  * and is used to validate the measurement list.
  88  *
  89  * Returns 0 on success, error code otherwise
  90  */
  91 int ima_store_template(struct ima_template_entry *entry,
  92                        int violation, struct inode *inode,
  93                        const unsigned char *filename, int pcr)
  94 {
  95         static const char op[] = "add_template_measure";
  96         static const char audit_cause[] = "hashing_error";
  97         char *template_name = entry->template_desc->name;
  98         int result;
  99         struct {
 100                 struct ima_digest_data hdr;
 101                 char digest[TPM_DIGEST_SIZE];
 102         } hash;
 103 
 104         if (!violation) {
 105                 int num_fields = entry->template_desc->num_fields;
 106 
 107                 /* this function uses default algo */
 108                 hash.hdr.algo = HASH_ALGO_SHA1;
 109                 result = ima_calc_field_array_hash(&entry->template_data[0],
 110                                                    entry->template_desc,
 111                                                    num_fields, &hash.hdr);
 112                 if (result < 0) {
 113                         integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
 114                                             template_name, op,
 115                                             audit_cause, result, 0);
 116                         return result;
 117                 }
 118                 memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
 119         }
 120         entry->pcr = pcr;
 121         result = ima_add_template_entry(entry, violation, op, inode, filename);
 122         return result;
 123 }
 124 
 125 /*
 126  * ima_add_violation - add violation to measurement list.
 127  *
 128  * Violations are flagged in the measurement list with zero hash values.
 129  * By extending the PCR with 0xFF's instead of with zeroes, the PCR
 130  * value is invalidated.
 131  */
 132 void ima_add_violation(struct file *file, const unsigned char *filename,
 133                        struct integrity_iint_cache *iint,
 134                        const char *op, const char *cause)
 135 {
 136         struct ima_template_entry *entry;
 137         struct inode *inode = file_inode(file);
 138         struct ima_event_data event_data = { .iint = iint,
 139                                              .file = file,
 140                                              .filename = filename,
 141                                              .violation = cause };
 142         int violation = 1;
 143         int result;
 144 
 145         /* can overflow, only indicator */
 146         atomic_long_inc(&ima_htable.violations);
 147 
 148         result = ima_alloc_init_template(&event_data, &entry, NULL);
 149         if (result < 0) {
 150                 result = -ENOMEM;
 151                 goto err_out;
 152         }
 153         result = ima_store_template(entry, violation, inode,
 154                                     filename, CONFIG_IMA_MEASURE_PCR_IDX);
 155         if (result < 0)
 156                 ima_free_template_entry(entry);
 157 err_out:
 158         integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 159                             op, cause, result, 0);
 160 }
 161 
 162 /**
 163  * ima_get_action - appraise & measure decision based on policy.
 164  * @inode: pointer to inode to measure
 165  * @cred: pointer to credentials structure to validate
 166  * @secid: secid of the task being validated
 167  * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
 168  *        MAY_APPEND)
 169  * @func: caller identifier
 170  * @pcr: pointer filled in if matched measure policy sets pcr=
 171  * @template_desc: pointer filled in if matched measure policy sets template=
 172  *
 173  * The policy is defined in terms of keypairs:
 174  *              subj=, obj=, type=, func=, mask=, fsmagic=
 175  *      subj,obj, and type: are LSM specific.
 176  *      func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
 177  *      | KEXEC_CMDLINE
 178  *      mask: contains the permission mask
 179  *      fsmagic: hex value
 180  *
 181  * Returns IMA_MEASURE, IMA_APPRAISE mask.
 182  *
 183  */
 184 int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
 185                    int mask, enum ima_hooks func, int *pcr,
 186                    struct ima_template_desc **template_desc)
 187 {
 188         int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
 189 
 190         flags &= ima_policy_flag;
 191 
 192         return ima_match_policy(inode, cred, secid, func, mask, flags, pcr,
 193                                 template_desc);
 194 }
 195 
 196 /*
 197  * ima_collect_measurement - collect file measurement
 198  *
 199  * Calculate the file hash, if it doesn't already exist,
 200  * storing the measurement and i_version in the iint.
 201  *
 202  * Must be called with iint->mutex held.
 203  *
 204  * Return 0 on success, error code otherwise
 205  */
 206 int ima_collect_measurement(struct integrity_iint_cache *iint,
 207                             struct file *file, void *buf, loff_t size,
 208                             enum hash_algo algo, struct modsig *modsig)
 209 {
 210         const char *audit_cause = "failed";
 211         struct inode *inode = file_inode(file);
 212         const char *filename = file->f_path.dentry->d_name.name;
 213         int result = 0;
 214         int length;
 215         void *tmpbuf;
 216         u64 i_version;
 217         struct {
 218                 struct ima_digest_data hdr;
 219                 char digest[IMA_MAX_DIGEST_SIZE];
 220         } hash;
 221 
 222         /*
 223          * Always collect the modsig, because IMA might have already collected
 224          * the file digest without collecting the modsig in a previous
 225          * measurement rule.
 226          */
 227         if (modsig)
 228                 ima_collect_modsig(modsig, buf, size);
 229 
 230         if (iint->flags & IMA_COLLECTED)
 231                 goto out;
 232 
 233         /*
 234          * Dectecting file change is based on i_version. On filesystems
 235          * which do not support i_version, support is limited to an initial
 236          * measurement/appraisal/audit.
 237          */
 238         i_version = inode_query_iversion(inode);
 239         hash.hdr.algo = algo;
 240 
 241         /* Initialize hash digest to 0's in case of failure */
 242         memset(&hash.digest, 0, sizeof(hash.digest));
 243 
 244         if (buf)
 245                 result = ima_calc_buffer_hash(buf, size, &hash.hdr);
 246         else
 247                 result = ima_calc_file_hash(file, &hash.hdr);
 248 
 249         if (result && result != -EBADF && result != -EINVAL)
 250                 goto out;
 251 
 252         length = sizeof(hash.hdr) + hash.hdr.length;
 253         tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
 254         if (!tmpbuf) {
 255                 result = -ENOMEM;
 256                 goto out;
 257         }
 258 
 259         iint->ima_hash = tmpbuf;
 260         memcpy(iint->ima_hash, &hash, length);
 261         iint->version = i_version;
 262 
 263         /* Possibly temporary failure due to type of read (eg. O_DIRECT) */
 264         if (!result)
 265                 iint->flags |= IMA_COLLECTED;
 266 out:
 267         if (result) {
 268                 if (file->f_flags & O_DIRECT)
 269                         audit_cause = "failed(directio)";
 270 
 271                 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
 272                                     filename, "collect_data", audit_cause,
 273                                     result, 0);
 274         }
 275         return result;
 276 }
 277 
 278 /*
 279  * ima_store_measurement - store file measurement
 280  *
 281  * Create an "ima" template and then store the template by calling
 282  * ima_store_template.
 283  *
 284  * We only get here if the inode has not already been measured,
 285  * but the measurement could already exist:
 286  *      - multiple copies of the same file on either the same or
 287  *        different filesystems.
 288  *      - the inode was previously flushed as well as the iint info,
 289  *        containing the hashing info.
 290  *
 291  * Must be called with iint->mutex held.
 292  */
 293 void ima_store_measurement(struct integrity_iint_cache *iint,
 294                            struct file *file, const unsigned char *filename,
 295                            struct evm_ima_xattr_data *xattr_value,
 296                            int xattr_len, const struct modsig *modsig, int pcr,
 297                            struct ima_template_desc *template_desc)
 298 {
 299         static const char op[] = "add_template_measure";
 300         static const char audit_cause[] = "ENOMEM";
 301         int result = -ENOMEM;
 302         struct inode *inode = file_inode(file);
 303         struct ima_template_entry *entry;
 304         struct ima_event_data event_data = { .iint = iint,
 305                                              .file = file,
 306                                              .filename = filename,
 307                                              .xattr_value = xattr_value,
 308                                              .xattr_len = xattr_len,
 309                                              .modsig = modsig };
 310         int violation = 0;
 311 
 312         /*
 313          * We still need to store the measurement in the case of MODSIG because
 314          * we only have its contents to put in the list at the time of
 315          * appraisal, but a file measurement from earlier might already exist in
 316          * the measurement list.
 317          */
 318         if (iint->measured_pcrs & (0x1 << pcr) && !modsig)
 319                 return;
 320 
 321         result = ima_alloc_init_template(&event_data, &entry, template_desc);
 322         if (result < 0) {
 323                 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 324                                     op, audit_cause, result, 0);
 325                 return;
 326         }
 327 
 328         result = ima_store_template(entry, violation, inode, filename, pcr);
 329         if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) {
 330                 iint->flags |= IMA_MEASURED;
 331                 iint->measured_pcrs |= (0x1 << pcr);
 332         }
 333         if (result < 0)
 334                 ima_free_template_entry(entry);
 335 }
 336 
 337 void ima_audit_measurement(struct integrity_iint_cache *iint,
 338                            const unsigned char *filename)
 339 {
 340         struct audit_buffer *ab;
 341         char *hash;
 342         const char *algo_name = hash_algo_name[iint->ima_hash->algo];
 343         int i;
 344 
 345         if (iint->flags & IMA_AUDITED)
 346                 return;
 347 
 348         hash = kzalloc((iint->ima_hash->length * 2) + 1, GFP_KERNEL);
 349         if (!hash)
 350                 return;
 351 
 352         for (i = 0; i < iint->ima_hash->length; i++)
 353                 hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
 354         hash[i * 2] = '\0';
 355 
 356         ab = audit_log_start(audit_context(), GFP_KERNEL,
 357                              AUDIT_INTEGRITY_RULE);
 358         if (!ab)
 359                 goto out;
 360 
 361         audit_log_format(ab, "file=");
 362         audit_log_untrustedstring(ab, filename);
 363         audit_log_format(ab, " hash=\"%s:%s\"", algo_name, hash);
 364 
 365         audit_log_task_info(ab);
 366         audit_log_end(ab);
 367 
 368         iint->flags |= IMA_AUDITED;
 369 out:
 370         kfree(hash);
 371         return;
 372 }
 373 
 374 /*
 375  * ima_d_path - return a pointer to the full pathname
 376  *
 377  * Attempt to return a pointer to the full pathname for use in the
 378  * IMA measurement list, IMA audit records, and auditing logs.
 379  *
 380  * On failure, return a pointer to a copy of the filename, not dname.
 381  * Returning a pointer to dname, could result in using the pointer
 382  * after the memory has been freed.
 383  */
 384 const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
 385 {
 386         char *pathname = NULL;
 387 
 388         *pathbuf = __getname();
 389         if (*pathbuf) {
 390                 pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
 391                 if (IS_ERR(pathname)) {
 392                         __putname(*pathbuf);
 393                         *pathbuf = NULL;
 394                         pathname = NULL;
 395                 }
 396         }
 397 
 398         if (!pathname) {
 399                 strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX);
 400                 pathname = namebuf;
 401         }
 402 
 403         return pathname;
 404 }

/* [<][>][^][v][top][bottom][index][help] */