/* current content of the policy */
 extern int ima_policy_flag;
 
+/* bitset of digests algorithms allowed in the setxattr hook */
+extern atomic_t ima_setxattr_allowed_hash_algorithms;
+
 /* set during initialization */
 extern int ima_hash_algo __ro_after_init;
 extern int ima_sha1_idx __ro_after_init;
        hook(KEXEC_CMDLINE, kexec_cmdline)              \
        hook(KEY_CHECK, key)                            \
        hook(CRITICAL_DATA, critical_data)              \
+       hook(SETXATTR_CHECK, setxattr_check)            \
        hook(MAX_CHECK, none)
 
 #define __ima_hook_enumify(ENUM, str)  ENUM,
                     const char *func_data, unsigned int *allowed_algos);
 void ima_init_policy(void);
 void ima_update_policy(void);
-void ima_update_policy_flag(void);
+void ima_update_policy_flags(void);
 ssize_t ima_parse_add_rule(char *);
 void ima_delete_rules(void);
 int ima_check_policy(void);
 
 {
        char *path = NULL, *pathbuf = NULL;
        enum hash_algo xattr_hash_algo;
+       const char *errmsg = "unavailable-hash-algorithm";
+       unsigned int allowed_hashes;
 
        xattr_hash_algo = ima_get_hash_algo(xattr_value, xattr_value_len);
 
-       if (likely(xattr_hash_algo == ima_hash_algo ||
-                  crypto_has_alg(hash_algo_name[xattr_hash_algo], 0, 0)))
-               return 0;
+       allowed_hashes = atomic_read(&ima_setxattr_allowed_hash_algorithms);
+
+       if (allowed_hashes) {
+               /* success if the algorithm is allowed in the ima policy */
+               if (allowed_hashes & (1U << xattr_hash_algo))
+                       return 0;
+
+               /*
+                * We use a different audit message when the hash algorithm
+                * is denied by a policy rule, instead of not being built
+                * in the kernel image
+                */
+               errmsg = "denied-hash-algorithm";
+       } else {
+               if (likely(xattr_hash_algo == ima_hash_algo))
+                       return 0;
+
+               /* allow any xattr using an algorithm built in the kernel */
+               if (crypto_has_alg(hash_algo_name[xattr_hash_algo], 0, 0))
+                       return 0;
+       }
 
        pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
        if (!pathbuf)
        path = dentry_path(dentry, pathbuf, PATH_MAX);
 
        integrity_audit_msg(AUDIT_INTEGRITY_DATA, d_inode(dentry), path,
-                           "set_data", "unavailable-hash-algorithm",
-                           -EACCES, 0);
+                           "set_data", errmsg, -EACCES, 0);
 
        kfree(pathbuf);
 
 
 static int temp_ima_appraise;
 static int build_ima_appraise __ro_after_init;
 
+atomic_t ima_setxattr_allowed_hash_algorithms;
+
 #define MAX_LSM_RULES 6
 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
        LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
        return action;
 }
 
-/*
- * Initialize the ima_policy_flag variable based on the currently
- * loaded policy.  Based on this flag, the decision to short circuit
- * out of a function or not call the function in the first place
- * can be made earlier.
+/**
+ * ima_update_policy_flags() - Update global IMA variables
+ *
+ * Update ima_policy_flag and ima_setxattr_allowed_hash_algorithms
+ * based on the currently loaded policy.
+ *
+ * With ima_policy_flag, the decision to short circuit out of a function
+ * or not call the function in the first place can be made earlier.
+ *
+ * With ima_setxattr_allowed_hash_algorithms, the policy can restrict the
+ * set of hash algorithms accepted when updating the security.ima xattr of
+ * a file.
+ *
+ * Context: called after a policy update and at system initialization.
  */
-void ima_update_policy_flag(void)
+void ima_update_policy_flags(void)
 {
        struct ima_rule_entry *entry;
+       int new_policy_flag = 0;
 
+       rcu_read_lock();
        list_for_each_entry(entry, ima_rules, list) {
+               /*
+                * SETXATTR_CHECK rules do not implement a full policy check
+                * because rule checking would probably have an important
+                * performance impact on setxattr(). As a consequence, only one
+                * SETXATTR_CHECK can be active at a given time.
+                * Because we want to preserve that property, we set out to use
+                * atomic_cmpxchg. Either:
+                * - the atomic was non-zero: a setxattr hash policy is
+                *   already enforced, we do nothing
+                * - the atomic was zero: no setxattr policy was set, enable
+                *   the setxattr hash policy
+                */
+               if (entry->func == SETXATTR_CHECK) {
+                       atomic_cmpxchg(&ima_setxattr_allowed_hash_algorithms,
+                                      0, entry->allowed_algos);
+                       /* SETXATTR_CHECK doesn't impact ima_policy_flag */
+                       continue;
+               }
+
                if (entry->action & IMA_DO_MASK)
-                       ima_policy_flag |= entry->action;
+                       new_policy_flag |= entry->action;
        }
+       rcu_read_unlock();
 
        ima_appraise |= (build_ima_appraise | temp_ima_appraise);
        if (!ima_appraise)
-               ima_policy_flag &= ~IMA_APPRAISE;
+               new_policy_flag &= ~IMA_APPRAISE;
+
+       ima_policy_flag = new_policy_flag;
 }
 
 static int ima_appraise_flag(enum ima_hooks func)
                          ARRAY_SIZE(critical_data_rules),
                          IMA_DEFAULT_POLICY);
 
-       ima_update_policy_flag();
+       atomic_set(&ima_setxattr_allowed_hash_algorithms, 0);
+
+       ima_update_policy_flags();
 }
 
 /* Make sure we have a valid policy, at least containing some rules. */
                 */
                kfree(arch_policy_entry);
        }
-       ima_update_policy_flag();
+       ima_update_policy_flags();
 
        /* Custom IMA policy has been loaded */
        ima_process_queued_keys();
                if (ima_rule_contains_lsm_cond(entry))
                        return false;
 
+               break;
+       case SETXATTR_CHECK:
+               /* any action other than APPRAISE is unsupported */
+               if (entry->action != APPRAISE)
+                       return false;
+
+               /* SETXATTR_CHECK requires an appraise_algos parameter */
+               if (!(entry->flags & IMA_VALIDATE_ALGOS))
+                       return false;
+
+               /*
+                * full policies are not supported, they would have too
+                * much of a performance impact
+                */
+               if (entry->flags & ~(IMA_FUNC | IMA_VALIDATE_ALGOS))
+                       return false;
+
                break;
        default:
                return false;
                                entry->func = KEY_CHECK;
                        else if (strcmp(args[0].from, "CRITICAL_DATA") == 0)
                                entry->func = CRITICAL_DATA;
+                       else if (strcmp(args[0].from, "SETXATTR_CHECK") == 0)
+                               entry->func = SETXATTR_CHECK;
                        else
                                result = -EINVAL;
                        if (!result)