#endif /* CONFIG_IMA_APPRAISE */
 
 #ifdef CONFIG_IMA_APPRAISE_MODSIG
-bool ima_hook_supports_modsig(enum ima_hooks func);
 int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
                    struct modsig **modsig);
 void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size);
                       u32 *data_len);
 void ima_free_modsig(struct modsig *modsig);
 #else
-static inline bool ima_hook_supports_modsig(enum ima_hooks func)
-{
-       return false;
-}
-
 static inline int ima_read_modsig(enum ima_hooks func, const void *buf,
                                  loff_t buf_len, struct modsig **modsig)
 {
 
        u8 raw_pkcs7[];
 };
 
-/**
- * ima_hook_supports_modsig - can the policy allow modsig for this hook?
- *
- * modsig is only supported by hooks using ima_post_read_file(), because only
- * they preload the contents of the file in a buffer. FILE_CHECK does that in
- * some cases, but not when reached from vfs_open(). POLICY_CHECK can support
- * it, but it's not useful in practice because it's a text file so deny.
- */
-bool ima_hook_supports_modsig(enum ima_hooks func)
-{
-       switch (func) {
-       case KEXEC_KERNEL_CHECK:
-       case KEXEC_INITRAMFS_CHECK:
-       case MODULE_CHECK:
-               return true;
-       default:
-               return false;
-       }
-}
-
 /*
  * ima_read_modsig - Read modsig from buf.
  *
 
 
 static bool ima_validate_rule(struct ima_rule_entry *entry)
 {
-       /* Ensure that the action is set */
+       /* Ensure that the action is set and is compatible with the flags */
        if (entry->action == UNKNOWN)
                return false;
 
+       if (entry->action != MEASURE && entry->flags & IMA_PCR)
+               return false;
+
+       if (entry->action != APPRAISE &&
+           entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST))
+               return false;
+
+       /*
+        * The IMA_FUNC bit must be set if and only if there's a valid hook
+        * function specified, and vice versa. Enforcing this property allows
+        * for the NONE case below to validate a rule without an explicit hook
+        * function.
+        */
+       if (((entry->flags & IMA_FUNC) && entry->func == NONE) ||
+           (!(entry->flags & IMA_FUNC) && entry->func != NONE))
+               return false;
+
        /*
         * Ensure that the hook function is compatible with the other
         * components of the rule
        case BPRM_CHECK:
        case CREDS_CHECK:
        case POST_SETATTR:
-       case MODULE_CHECK:
        case FIRMWARE_CHECK:
+       case POLICY_CHECK:
+               if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC |
+                                    IMA_UID | IMA_FOWNER | IMA_FSUUID |
+                                    IMA_INMASK | IMA_EUID | IMA_PCR |
+                                    IMA_FSNAME | IMA_DIGSIG_REQUIRED |
+                                    IMA_PERMIT_DIRECTIO))
+                       return false;
+
+               break;
+       case MODULE_CHECK:
        case KEXEC_KERNEL_CHECK:
        case KEXEC_INITRAMFS_CHECK:
-       case POLICY_CHECK:
-               /* Validation of these hook functions is in ima_parse_rule() */
+               if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC |
+                                    IMA_UID | IMA_FOWNER | IMA_FSUUID |
+                                    IMA_INMASK | IMA_EUID | IMA_PCR |
+                                    IMA_FSNAME | IMA_DIGSIG_REQUIRED |
+                                    IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED |
+                                    IMA_CHECK_BLACKLIST))
+                       return false;
+
                break;
        case KEXEC_CMDLINE:
                if (entry->action & ~(MEASURE | DONT_MEASURE))
                        keyrings_len = strlen(args[0].from) + 1;
 
                        if ((entry->keyrings) ||
-                           (entry->func != KEY_CHECK) ||
                            (keyrings_len < 2)) {
                                result = -EINVAL;
                                break;
                                                   AUDIT_SUBJ_TYPE);
                        break;
                case Opt_appraise_type:
-                       if (entry->action != APPRAISE) {
-                               result = -EINVAL;
-                               break;
-                       }
-
                        ima_log_string(ab, "appraise_type", args[0].from);
                        if ((strcmp(args[0].from, "imasig")) == 0)
                                entry->flags |= IMA_DIGSIG_REQUIRED;
-                       else if (ima_hook_supports_modsig(entry->func) &&
+                       else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) &&
                                 strcmp(args[0].from, "imasig|modsig") == 0)
                                entry->flags |= IMA_DIGSIG_REQUIRED |
                                                IMA_MODSIG_ALLOWED;
                                result = -EINVAL;
                        break;
                case Opt_appraise_flag:
-                       if (entry->action != APPRAISE) {
-                               result = -EINVAL;
-                               break;
-                       }
-
                        ima_log_string(ab, "appraise_flag", args[0].from);
                        if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) &&
                            strstr(args[0].from, "blacklist"))
                        entry->flags |= IMA_PERMIT_DIRECTIO;
                        break;
                case Opt_pcr:
-                       if (entry->action != MEASURE) {
-                               result = -EINVAL;
-                               break;
-                       }
                        ima_log_string(ab, "pcr", args[0].from);
 
                        result = kstrtoint(args[0].from, 10, &entry->pcr);