extern int ima_policy_flag;
 
 /* set during initialization */
-extern int ima_hash_algo;
+extern int ima_hash_algo __ro_after_init;
 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;
                   const struct cred *cred, u32 secid, int mask,
                   enum ima_hooks func, int *pcr,
                   struct ima_template_desc **template_desc,
-                  const char *func_data);
+                  const char *func_data, unsigned int *allowed_algos);
 int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
 int ima_collect_measurement(struct integrity_iint_cache *iint,
                            struct file *file, void *buf, loff_t size,
                     const struct cred *cred, u32 secid, enum ima_hooks func,
                     int mask, int flags, int *pcr,
                     struct ima_template_desc **template_desc,
-                    const char *func_data);
+                    const char *func_data, unsigned int *allowed_algos);
 void ima_init_policy(void);
 void ima_update_policy(void);
 void ima_update_policy_flag(void);
 
  * @pcr: pointer filled in if matched measure policy sets pcr=
  * @template_desc: pointer filled in if matched measure policy sets template=
  * @func_data: func specific data, may be NULL
+ * @allowed_algos: allowlist of hash algorithms for the IMA xattr
  *
  * The policy is defined in terms of keypairs:
  *             subj=, obj=, type=, func=, mask=, fsmagic=
                   const struct cred *cred, u32 secid, int mask,
                   enum ima_hooks func, int *pcr,
                   struct ima_template_desc **template_desc,
-                  const char *func_data)
+                  const char *func_data, unsigned int *allowed_algos)
 {
        int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
 
        flags &= ima_policy_flag;
 
        return ima_match_policy(mnt_userns, inode, cred, secid, func, mask,
-                               flags, pcr, template_desc, func_data);
+                               flags, pcr, template_desc, func_data,
+                               allowed_algos);
 }
 
 /*
 
                return 0;
 
        security_task_getsecid_subj(current, &secid);
-       return ima_match_policy(mnt_userns, inode, current_cred(), secid, func,
-                               mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL);
+       return ima_match_policy(mnt_userns, inode, current_cred(), secid,
+                               func, mask, IMA_APPRAISE | IMA_HASH, NULL,
+                               NULL, NULL, NULL);
 }
 
 static int ima_fix_xattr(struct dentry *dentry,
 
        int xattr_len = 0;
        bool violation_check;
        enum hash_algo hash_algo;
+       unsigned int allowed_algos = 0;
 
        if (!ima_policy_flag || !S_ISREG(inode->i_mode))
                return 0;
         * Included is the appraise submask.
         */
        action = ima_get_action(file_mnt_user_ns(file), inode, cred, secid,
-                               mask, func, &pcr, &template_desc, NULL);
+                               mask, func, &pcr, &template_desc, NULL,
+                               &allowed_algos);
        violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
                           (ima_policy_flag & IMA_MEASURE));
        if (!action && !violation_check)
 
        if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO))
                rc = 0;
+
+       /* Ensure the digest was generated using an allowed algorithm */
+       if (rc == 0 && must_appraise && allowed_algos != 0 &&
+           (allowed_algos & (1U << hash_algo)) == 0) {
+               rc = -EACCES;
+
+               integrity_audit_msg(AUDIT_INTEGRITY_DATA, file_inode(file),
+                                   pathname, "collect_data",
+                                   "denied-hash-algorithm", rc, 0);
+       }
 out_locked:
        if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) &&
             !(iint->flags & IMA_NEW_FILE))
        inode = file_inode(vma->vm_file);
        action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
                                current_cred(), secid, MAY_EXEC, MMAP_CHECK,
-                               &pcr, &template, NULL);
+                               &pcr, &template, NULL, NULL);
 
        /* Is the mmap'ed file in policy? */
        if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
                security_task_getsecid_subj(current, &secid);
                action = ima_get_action(mnt_userns, inode, current_cred(),
                                        secid, 0, func, &pcr, &template,
-                                       func_data);
+                                       func_data, NULL);
                if (!(action & IMA_MEASURE) && !digest)
                        return -ENOENT;
        }
 
 #define IMA_FSNAME     0x0200
 #define IMA_KEYRINGS   0x0400
 #define IMA_LABEL      0x0800
+#define IMA_VALIDATE_ALGOS     0x1000
 
 #define UNKNOWN                0
 #define MEASURE                0x0001  /* same as IMA_MEASURE */
        bool (*uid_op)(kuid_t, kuid_t);    /* Handlers for operators       */
        bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */
        int pcr;
+       unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
        struct {
                void *rule;     /* LSM file metadata specific */
                char *args_p;   /* audit value */
        struct ima_template_desc *template;
 };
 
+/*
+ * sanity check in case the kernels gains more hash algorithms that can
+ * fit in an unsigned int
+ */
+static_assert(
+       8 * sizeof(unsigned int) >= HASH_ALGO__LAST,
+       "The bitfield allowed_algos in ima_rule_entry is too small to contain all the supported hash algorithms, consider using a bigger type");
+
 /*
  * Without LSM specific knowledge, the default policy can only be
  * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
  * @pcr: set the pcr to extend
  * @template_desc: the template that should be used for this rule
  * @func_data: func specific data, may be NULL
+ * @allowed_algos: allowlist of hash algorithms for the IMA xattr
  *
  * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
  * conditions.
                     const struct cred *cred, u32 secid, enum ima_hooks func,
                     int mask, int flags, int *pcr,
                     struct ima_template_desc **template_desc,
-                    const char *func_data)
+                    const char *func_data, unsigned int *allowed_algos)
 {
        struct ima_rule_entry *entry;
        int action = 0, actmask = flags | (flags << 1);
                        action &= ~IMA_HASH;
                        if (ima_fail_unverifiable_sigs)
                                action |= IMA_FAIL_UNVERIFIABLE_SIGS;
-               }
 
+                       if (allowed_algos &&
+                           entry->flags & IMA_VALIDATE_ALGOS)
+                               *allowed_algos = entry->allowed_algos;
+               }
 
                if (entry->action & IMA_DO_MASK)
                        actmask &= ~(entry->action | entry->action << 1);