diff mbox

[11/15] flask: improve unknown permission handling

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

Commit Message

Daniel De Graaf June 9, 2016, 2:47 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 bit is
off by default, but it can be set by using checkpolicy -U allow when
compiling the policy.  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.

Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
---
 xen/xsm/flask/hooks.c            | 44 +++++++++++++++++++++++++---------------
 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, 42 insertions(+), 16 deletions(-)

Comments

Konrad Rzeszutek Wilk June 17, 2016, 3:45 p.m. UTC | #1
On Thu, Jun 09, 2016 at 10:47:14AM -0400, 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 bit is
> off by default, but it can be set by using checkpolicy -U allow when
> compiling the policy.  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.

.. and the operation is permitted.

> 
> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
> ---
>  xen/xsm/flask/hooks.c            | 44 +++++++++++++++++++++++++---------------
>  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, 42 insertions(+), 16 deletions(-)
> 
> diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
> index a8d45e7..3ab3fbf 100644
> --- a/xen/xsm/flask/hooks.c
> +++ b/xen/xsm/flask/hooks.c
> @@ -136,6 +136,23 @@ 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;

I would add a new line here.
> +    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;
> +}
> +

The rest looks OK, but I have a question: Is this how Linux operates?
Daniel De Graaf June 17, 2016, 5:02 p.m. UTC | #2
On 06/17/2016 11:45 AM, Konrad Rzeszutek Wilk wrote:
> On Thu, Jun 09, 2016 at 10:47:14AM -0400, 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 bit is
>> off by default, but it can be set by using checkpolicy -U allow when
>> compiling the policy.  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.
>
> .. and the operation is permitted.

The error message is printed either way (with a different priority).  Were
you suggesting I expand this explanation to include both the error and
warning messages separately?

>>
>> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
>> ---
>>  xen/xsm/flask/hooks.c            | 44 +++++++++++++++++++++++++---------------
>>  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, 42 insertions(+), 16 deletions(-)
>>
>> diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
>> index a8d45e7..3ab3fbf 100644
>> --- a/xen/xsm/flask/hooks.c
>> +++ b/xen/xsm/flask/hooks.c
>> @@ -136,6 +136,23 @@ 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;
>
> I would add a new line here.

OK

>> +    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;
>> +}
>> +
>
> The rest looks OK, but I have a question: Is this how Linux operates?

Yes; selinux_nlmsg_perm for an unknown netlink message seems to be an
example there.
Konrad Rzeszutek Wilk June 17, 2016, 5:13 p.m. UTC | #3
On Fri, Jun 17, 2016 at 01:02:58PM -0400, Daniel De Graaf wrote:
> On 06/17/2016 11:45 AM, Konrad Rzeszutek Wilk wrote:
> >On Thu, Jun 09, 2016 at 10:47:14AM -0400, 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 bit is
> >>off by default, but it can be set by using checkpolicy -U allow when
> >>compiling the policy.  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.
> >
> >.. and the operation is permitted.
> 
> The error message is printed either way (with a different priority).  Were

correct.
> you suggesting I expand this explanation to include both the error and
> warning messages separately?

It just that the patch changes the behavior. That is in the past if
you had created an policy using checkpolicy -U allow it would print an
error and return -EPERM.

But now it will print an error and return 0 and pass the XSM check 
(aka operation ends being permitted).

> 
> >>
> >>Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
> >>---
> >> xen/xsm/flask/hooks.c            | 44 +++++++++++++++++++++++++---------------
> >> 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, 42 insertions(+), 16 deletions(-)
> >>
> >>diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
> >>index a8d45e7..3ab3fbf 100644
> >>--- a/xen/xsm/flask/hooks.c
> >>+++ b/xen/xsm/flask/hooks.c
> >>@@ -136,6 +136,23 @@ 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;
> >
> >I would add a new line here.
> 
> OK
> 
> >>+    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;
> >>+}
> >>+
> >
> >The rest looks OK, but I have a question: Is this how Linux operates?
> 
> Yes; selinux_nlmsg_perm for an unknown netlink message seems to be an
> example there.
> 
> -- 
> Daniel De Graaf
> National Security Agency
Daniel De Graaf June 17, 2016, 5:20 p.m. UTC | #4
On 06/17/2016 01:13 PM, Konrad Rzeszutek Wilk wrote:
> On Fri, Jun 17, 2016 at 01:02:58PM -0400, Daniel De Graaf wrote:
>> On 06/17/2016 11:45 AM, Konrad Rzeszutek Wilk wrote:
>>> On Thu, Jun 09, 2016 at 10:47:14AM -0400, 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 bit is
>>>> off by default, but it can be set by using checkpolicy -U allow when
>>>> compiling the policy.  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.
>>>
>>> .. and the operation is permitted.
>>
>> The error message is printed either way (with a different priority).  Were
>
> correct.
>> you suggesting I expand this explanation to include both the error and
>> warning messages separately?
>
> It just that the patch changes the behavior. That is in the past if
> you had created an policy using checkpolicy -U allow it would print an
> error and return -EPERM.
>
> But now it will print an error and return 0 and pass the XSM check
> (aka operation ends being permitted).

I would be surprised if someone actually used allow_unknown before now,
since it did nothing and required manually enabling.  But if they did,
this is a functionality change.  I'll add a note of that.
diff mbox

Patch

diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index a8d45e7..3ab3fbf 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -136,6 +136,23 @@  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 +288,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 +440,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 +472,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 +538,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 +553,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 +750,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 +825,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 +1142,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 +1415,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 +1446,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 +1550,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 8aa88c1..46574c3 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 50e22f3..eb1e44d 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 c9b27a0..ce880e9 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