diff mbox

[11/17] flask: improve unknown permission handling

Message ID 1466431466-28055-12-git-send-email-dgdegra@tycho.nsa.gov (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel De Graaf June 20, 2016, 2:04 p.m. UTC
When an unknown domctl, sysctl, or other operation is encountered in the
FLASK security server, use the allow_unknown bit in the security policy
to decide if the permission should be allowed or denied.  This allows
new operations to be tested without needing to immediately add security
checks; however, it is not flexible enough to avoid adding the actual
permission checks.  An error message is printed to the hypervisor
console when this fallback is encountered.

This patch will allow operations that are not handled by the existing
hooks only if the policy was compiled with "checkpolicy -U allow".  In
previous releases, this bit did nothing, and the default remains to deny
the unknown operations.

Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
---
 xen/xsm/flask/hooks.c            | 45 ++++++++++++++++++++++++++--------------
 xen/xsm/flask/include/security.h |  2 ++
 xen/xsm/flask/ss/policydb.c      |  1 +
 xen/xsm/flask/ss/policydb.h      |  6 ++++++
 xen/xsm/flask/ss/services.c      |  5 +++++
 5 files changed, 43 insertions(+), 16 deletions(-)

Comments

Douglas Goldstein June 20, 2016, 2:37 p.m. UTC | #1
On 6/20/16 9:04 AM, Daniel De Graaf wrote:
> When an unknown domctl, sysctl, or other operation is encountered in the
> FLASK security server, use the allow_unknown bit in the security policy
> to decide if the permission should be allowed or denied.  This allows
> new operations to be tested without needing to immediately add security
> checks; however, it is not flexible enough to avoid adding the actual
> permission checks.  An error message is printed to the hypervisor
> console when this fallback is encountered.
> 
> This patch will allow operations that are not handled by the existing
> hooks only if the policy was compiled with "checkpolicy -U allow".  In
> previous releases, this bit did nothing, and the default remains to deny
> the unknown operations.
> 
> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>

Reviewed-by: Doug Goldstein <cardoe@cardoe.com>
diff mbox

Patch

diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index a8d45e7..543406b 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -136,6 +136,24 @@  static int get_irq_sid(int irq, u32 *sid, struct avc_audit_data *ad)
     return 0;
 }
 
+static int avc_unknown_permission(const char *name, int id)
+{
+    int rc;
+
+    if ( !flask_enforcing || security_get_allow_unknown() )
+    {
+        printk(XENLOG_G_WARNING "FLASK: Allowing unknown %s: %d.\n", name, id);
+        rc = 0;
+    }
+    else
+    {
+        printk(XENLOG_G_ERR "FLASK: Denying unknown %s: %d.\n", name, id);
+        rc = -EPERM;
+    }
+
+    return rc;
+}
+
 static int flask_domain_alloc_security(struct domain *d)
 {
     struct domain_security_struct *dsec;
@@ -271,7 +289,7 @@  static int flask_evtchn_send(struct domain *d, struct evtchn *chn)
         rc = 0;
         break;
     default:
-        rc = -EPERM;
+        rc = avc_unknown_permission("event channel state", chn->state);
     }
 
     return rc;
@@ -423,7 +441,7 @@  static int flask_console_io(struct domain *d, int cmd)
         perm = XEN__WRITECONSOLE;
         break;
     default:
-        return -EPERM;
+        return avc_unknown_permission("console_io", cmd);
     }
 
     return domain_has_xen(d, perm);
@@ -455,7 +473,7 @@  static int flask_profile(struct domain *d, int op)
         perm = XEN__PRIVPROFILE;
         break;
     default:
-        return -EPERM;
+        return avc_unknown_permission("xenoprof op", op);
     }
 
     return domain_has_xen(d, perm);
@@ -521,8 +539,7 @@  static int flask_domctl_scheduler_op(struct domain *d, int op)
         return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETSCHEDULER);
 
     default:
-        printk("flask_domctl_scheduler_op: Unknown op %d\n", op);
-        return -EPERM;
+        return avc_unknown_permission("domctl_scheduler_op", op);
     }
 }
 
@@ -537,8 +554,7 @@  static int flask_sysctl_scheduler_op(int op)
         return domain_has_xen(current->domain, XEN__GETSCHEDULER);
 
     default:
-        printk("flask_sysctl_scheduler_op: Unknown op %d\n", op);
-        return -EPERM;
+        return avc_unknown_permission("sysctl_scheduler_op", op);
     }
 }
 
@@ -735,8 +751,7 @@  static int flask_domctl(struct domain *d, int cmd)
         return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SOFT_RESET);
 
     default:
-        printk("flask_domctl: Unknown op %d\n", cmd);
-        return -EPERM;
+        return avc_unknown_permission("domctl", cmd);
     }
 }
 
@@ -811,8 +826,7 @@  static int flask_sysctl(int cmd)
                                     XEN2__LIVEPATCH_OP, NULL);
 
     default:
-        printk("flask_sysctl: Unknown op %d\n", cmd);
-        return -EPERM;
+        return avc_unknown_permission("sysctl", cmd);
     }
 }
 
@@ -1129,7 +1143,7 @@  static inline int flask_page_offline(uint32_t cmd)
     case sysctl_query_page_offline:
         return flask_resource_use_core();
     default:
-        return -EPERM;
+        return avc_unknown_permission("page_offline", cmd);
     }
 }
 
@@ -1402,8 +1416,7 @@  static int flask_platform_op(uint32_t op)
                             SECCLASS_XEN2, XEN2__GET_SYMBOL, NULL);
 
     default:
-        printk("flask_platform_op: Unknown op %d\n", op);
-        return -EPERM;
+        return avc_unknown_permission("platform_op", op);
     }
 }
 
@@ -1434,7 +1447,7 @@  static int flask_shadow_control(struct domain *d, uint32_t op)
         perm = SHADOW__LOGDIRTY;
         break;
     default:
-        return -EPERM;
+        return avc_unknown_permission("shadow_control", op);
     }
 
     return current_has_perm(d, SECCLASS_SHADOW, perm);
@@ -1538,7 +1551,7 @@  static int flask_apic(struct domain *d, int cmd)
         perm = XEN__WRITEAPIC;
         break;
     default:
-        return -EPERM;
+        return avc_unknown_permission("apic", cmd);
     }
 
     return domain_has_xen(d, perm);
diff --git a/xen/xsm/flask/include/security.h b/xen/xsm/flask/include/security.h
index 2b00177..1da020d 100644
--- a/xen/xsm/flask/include/security.h
+++ b/xen/xsm/flask/include/security.h
@@ -78,6 +78,8 @@  int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len);
 
 int security_context_to_sid(char *scontext, u32 scontext_len, u32 *out_sid);
 
+int security_get_allow_unknown(void);
+
 int security_irq_sid(int pirq, u32 *out_sid);
 
 int security_iomem_sid(unsigned long, u32 *out_sid);
diff --git a/xen/xsm/flask/ss/policydb.c b/xen/xsm/flask/ss/policydb.c
index 00b5390..3a12d96 100644
--- a/xen/xsm/flask/ss/policydb.c
+++ b/xen/xsm/flask/ss/policydb.c
@@ -1843,6 +1843,7 @@  int policydb_read(struct policydb *p, void *fp)
             goto bad;
         }
     }
+    p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
 
     if ( p->policyvers >= POLICYDB_VERSION_POLCAP &&
          ebitmap_read(&p->policycaps, fp) != 0 )
diff --git a/xen/xsm/flask/ss/policydb.h b/xen/xsm/flask/ss/policydb.h
index f158ce3..238a042 100644
--- a/xen/xsm/flask/ss/policydb.h
+++ b/xen/xsm/flask/ss/policydb.h
@@ -246,6 +246,8 @@  struct policydb {
 
     unsigned int policyvers;
 
+    unsigned int allow_unknown : 1;
+
     u16 target_type;
 };
 
@@ -261,6 +263,10 @@  extern int policydb_read(struct policydb *p, void *fp);
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* the config flags related to unknown classes/perms are bits 2 and 3 */
+#define REJECT_UNKNOWN 0x00000002
+#define ALLOW_UNKNOWN  0x00000004
+
 #define OBJECT_R "object_r"
 #define OBJECT_R_VAL 1
 
diff --git a/xen/xsm/flask/ss/services.c b/xen/xsm/flask/ss/services.c
index 6a07fc0..86f94c9 100644
--- a/xen/xsm/flask/ss/services.c
+++ b/xen/xsm/flask/ss/services.c
@@ -1465,6 +1465,11 @@  err:
 
 }
 
+int security_get_allow_unknown(void)
+{
+    return policydb.allow_unknown;
+}
+
 /**
  * security_irq_sid - Obtain the SID for a physical irq.
  * @pirq: physical irq