lsm:    [[subj_user=] [subj_role=] [subj_type=]
                                 [obj_user=] [obj_role=] [obj_type=]]
                        option: [[appraise_type=]] [template=] [permit_directio]
-                               [appraise_flag=] [keyrings=]
+                               [appraise_flag=] [appraise_algos=] [keyrings=]
                  base:
                        func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
                                [FIRMWARE_CHECK]
                        label:= [selinux]|[kernel_info]|[data_label]
                        data_label:= a unique string used for grouping and limiting critical data.
                        For example, "selinux" to measure critical data for SELinux.
+                       appraise_algos:= comma-separated list of hash algorithms
+                       For example, "sha256,sha512" to only accept to appraise
+                       files where the security.ima xattr was hashed with one
+                       of these two algorithms.
 
                  default policy:
                        # PROC_SUPER_MAGIC
 
        Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
        Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
        Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
-       Opt_appraise_type, Opt_appraise_flag,
+       Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
        Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
        Opt_label, Opt_err
 };
        {Opt_fowner_lt, "fowner<%s"},
        {Opt_appraise_type, "appraise_type=%s"},
        {Opt_appraise_flag, "appraise_flag=%s"},
+       {Opt_appraise_algos, "appraise_algos=%s"},
        {Opt_permit_directio, "permit_directio"},
        {Opt_pcr, "pcr=%s"},
        {Opt_template, "template=%s"},
                return false;
 
        if (entry->action != APPRAISE &&
-           entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST))
+           entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
+                           IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
                return false;
 
        /*
                                     IMA_UID | IMA_FOWNER | IMA_FSUUID |
                                     IMA_INMASK | IMA_EUID | IMA_PCR |
                                     IMA_FSNAME | IMA_DIGSIG_REQUIRED |
-                                    IMA_PERMIT_DIRECTIO))
+                                    IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS))
                        return false;
 
                break;
                                     IMA_INMASK | IMA_EUID | IMA_PCR |
                                     IMA_FSNAME | IMA_DIGSIG_REQUIRED |
                                     IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED |
-                                    IMA_CHECK_BLACKLIST))
+                                    IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
                        return false;
 
                break;
        return true;
 }
 
+static unsigned int ima_parse_appraise_algos(char *arg)
+{
+       unsigned int res = 0;
+       int idx;
+       char *token;
+
+       while ((token = strsep(&arg, ",")) != NULL) {
+               idx = match_string(hash_algo_name, HASH_ALGO__LAST, token);
+
+               if (idx < 0) {
+                       pr_err("unknown hash algorithm \"%s\"",
+                              token);
+                       return 0;
+               }
+
+               /* Add the hash algorithm to the 'allowed' bitfield */
+               res |= (1U << idx);
+       }
+
+       return res;
+}
+
 static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 {
        struct audit_buffer *ab;
                        else
                                result = -EINVAL;
                        break;
+               case Opt_appraise_algos:
+                       ima_log_string(ab, "appraise_algos", args[0].from);
+
+                       if (entry->allowed_algos) {
+                               result = -EINVAL;
+                               break;
+                       }
+
+                       entry->allowed_algos =
+                               ima_parse_appraise_algos(args[0].from);
+                       /* invalid or empty list of algorithms */
+                       if (!entry->allowed_algos) {
+                               result = -EINVAL;
+                               break;
+                       }
+
+                       entry->flags |= IMA_VALIDATE_ALGOS;
+
+                       break;
                case Opt_permit_directio:
                        entry->flags |= IMA_PERMIT_DIRECTIO;
                        break;
                seq_printf(m, "%s%s", i ? "|" : "", opt_list->items[i]);
 }
 
+static void ima_policy_show_appraise_algos(struct seq_file *m,
+                                          unsigned int allowed_hashes)
+{
+       int idx, list_size = 0;
+
+       for (idx = 0; idx < HASH_ALGO__LAST; idx++) {
+               if (!(allowed_hashes & (1U << idx)))
+                       continue;
+
+               /* only add commas if the list contains multiple entries */
+               if (list_size++)
+                       seq_puts(m, ",");
+
+               seq_puts(m, hash_algo_name[idx]);
+       }
+}
+
 int ima_policy_show(struct seq_file *m, void *v)
 {
        struct ima_rule_entry *entry = v;
                seq_puts(m, " ");
        }
 
+       if (entry->flags & IMA_VALIDATE_ALGOS) {
+               seq_puts(m, "appraise_algos=");
+               ima_policy_show_appraise_algos(m, entry->allowed_algos);
+               seq_puts(m, " ");
+       }
+
        for (i = 0; i < MAX_LSM_RULES; i++) {
                if (entry->lsm[i].rule) {
                        switch (i) {