Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread William Roberts
On Wed, May 17, 2017 at 10:00 AM, Sebastien Buisson
 wrote:
> 2017-05-17 18:04 GMT+02:00 William Roberts :
>> I'm assuming in the Lustre code you're going to call security_policy_brief(),
>> how would the caller know how big that buffer is going to be?
>
> We can determine it at configure time for instance, given that len as
> an output parameter would give the size necessary to store the policy
> brief info.
>
>> I'm looking at both v5 patches, I don't see where it's being called with 
>> alloc
>> set to false.
>
> It would be called with alloc set to false from network and
> distributed file systems like Lustre.

That doesn't seem like a good way at all.
1. What happens as the brief is changed, all callers with false
would potentially need there buffer size increased.
2. There is no guarantee at runtime that as brief changes,
that the size will remain bounded. fields could be
added/changed/removed.
3. If/when stacking needs to be supported, brief size can
change dramatically, bringing us back to issue 1.

-- 
Respectfully,

William C Roberts


Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread Sebastien Buisson
2017-05-17 18:04 GMT+02:00 William Roberts :
> I'm assuming in the Lustre code you're going to call security_policy_brief(),
> how would the caller know how big that buffer is going to be?

We can determine it at configure time for instance, given that len as
an output parameter would give the size necessary to store the policy
brief info.

> I'm looking at both v5 patches, I don't see where it's being called with alloc
> set to false.

It would be called with alloc set to false from network and
distributed file systems like Lustre.


Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread William Roberts
On Wed, May 17, 2017 at 8:43 AM, Sebastien Buisson
 wrote:
> 2017-05-17 17:34 GMT+02:00 William Roberts :
>> Is there a particular reason to not just return policybrief_len here as
>> well, for consistency in the interface?  How do you intend to use this
>> value in the caller?
>
> As called in the other patch to expose policy brief via selinuxfs
> (sel_read_policybrief), the intent is to provide the caller with the
> length of the string returned.
> Or should I set *len to policy brief_len here, and just make the
> caller aware that the returned length is in fact the length of the
> buffer (i.e. including terminating NUL byte)?

 What is the caller supposed to do with length? This interface seemed kind 
 of
 odd. If it's guaranteed NUL byte terminated, do they even need length?
>>>
>>> The length is useful as an input parameter in case the caller provides
>>> its own buffer (instead of letting the function allocate one), and as
>>
>> This is what I don't get, why doesn't the function just always allocate?
>
> For performance reasons mainly. The caller would have a statically
> allocated buffer, reused every time it needs to get the policy brief
> info.

I'm assuming in the Lustre code you're going to call security_policy_brief(),
how would the caller know how big that buffer is going to be?

I'm looking at both v5 patches, I don't see where it's being called with alloc
set to false.

I don't see how this works with LSM stacking, I would imagine the security
hook needs to call this routine for each LSM and join them together in
some module name spaced way, which was mentioned before, but I don't
see that either, am I missing it?


-- 
Respectfully,

William C Roberts


Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread Sebastien Buisson
2017-05-17 17:34 GMT+02:00 William Roberts :
> Is there a particular reason to not just return policybrief_len here as
> well, for consistency in the interface?  How do you intend to use this
> value in the caller?

 As called in the other patch to expose policy brief via selinuxfs
 (sel_read_policybrief), the intent is to provide the caller with the
 length of the string returned.
 Or should I set *len to policy brief_len here, and just make the
 caller aware that the returned length is in fact the length of the
 buffer (i.e. including terminating NUL byte)?
>>>
>>> What is the caller supposed to do with length? This interface seemed kind of
>>> odd. If it's guaranteed NUL byte terminated, do they even need length?
>>
>> The length is useful as an input parameter in case the caller provides
>> its own buffer (instead of letting the function allocate one), and as
>
> This is what I don't get, why doesn't the function just always allocate?

For performance reasons mainly. The caller would have a statically
allocated buffer, reused every time it needs to get the policy brief
info.


Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread Stephen Smalley
On Wed, 2017-05-17 at 16:59 +0200, Sebastien Buisson wrote:
> 2017-05-16 22:40 GMT+02:00 Stephen Smalley :
> > > + strcpy(*brief, policydb.policybrief);
> > > + /* *len is the length of the output string */
> > > + *len = policybrief_len - 1;
> > 
> > Is there a particular reason to not just return policybrief_len
> > here as
> > well, for consistency in the interface?  How do you intend to use
> > this
> > value in the caller?
> 
> As called in the other patch to expose policy brief via selinuxfs
> (sel_read_policybrief), the intent is to provide the caller with the
> length of the string returned.
> Or should I set *len to policy brief_len here, and just make the
> caller aware that the returned length is in fact the length of the
> buffer (i.e. including terminating NUL byte)?

Looking at the caller usage in the other patch, I guess it makes sense
in its current form.




Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread William Roberts
On Wed, May 17, 2017 at 8:24 AM, Sebastien Buisson
 wrote:
> 2017-05-17 17:09 GMT+02:00 William Roberts :
>> On Wed, May 17, 2017 at 7:59 AM, Sebastien Buisson
>>  wrote:
>>> 2017-05-16 22:40 GMT+02:00 Stephen Smalley :
> + strcpy(*brief, policydb.policybrief);
> + /* *len is the length of the output string */
> + *len = policybrief_len - 1;

 Is there a particular reason to not just return policybrief_len here as
 well, for consistency in the interface?  How do you intend to use this
 value in the caller?
>>>
>>> As called in the other patch to expose policy brief via selinuxfs
>>> (sel_read_policybrief), the intent is to provide the caller with the
>>> length of the string returned.
>>> Or should I set *len to policy brief_len here, and just make the
>>> caller aware that the returned length is in fact the length of the
>>> buffer (i.e. including terminating NUL byte)?
>>
>> What is the caller supposed to do with length? This interface seemed kind of
>> odd. If it's guaranteed NUL byte terminated, do they even need length?
>
> The length is useful as an input parameter in case the caller provides
> its own buffer (instead of letting the function allocate one), and as

This is what I don't get, why doesn't the function just always allocate?

> an output parameter in case the buffer given in input is not large
> enough.

This interface seems "Windowsy" (inout parameters)... Iv'e been looking at
it on and off for a few days and it just seems odd. Not odd enough for me
to give it more negative review comments.

> In any case, it can spare the caller the effort of recomputing the
> length. As an example, sel_read_policybrief() in the 2/2 patch needs
> to know the length of the string to put in the user buffer.

Oh yeah, IIRC offhand, you're adding each LSMs brief info and using strcpy
+ length instead of strcat avoiding the null iteration?


Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread Sebastien Buisson
2017-05-17 17:09 GMT+02:00 William Roberts :
> On Wed, May 17, 2017 at 7:59 AM, Sebastien Buisson
>  wrote:
>> 2017-05-16 22:40 GMT+02:00 Stephen Smalley :
 + strcpy(*brief, policydb.policybrief);
 + /* *len is the length of the output string */
 + *len = policybrief_len - 1;
>>>
>>> Is there a particular reason to not just return policybrief_len here as
>>> well, for consistency in the interface?  How do you intend to use this
>>> value in the caller?
>>
>> As called in the other patch to expose policy brief via selinuxfs
>> (sel_read_policybrief), the intent is to provide the caller with the
>> length of the string returned.
>> Or should I set *len to policy brief_len here, and just make the
>> caller aware that the returned length is in fact the length of the
>> buffer (i.e. including terminating NUL byte)?
>
> What is the caller supposed to do with length? This interface seemed kind of
> odd. If it's guaranteed NUL byte terminated, do they even need length?

The length is useful as an input parameter in case the caller provides
its own buffer (instead of letting the function allocate one), and as
an output parameter in case the buffer given in input is not large
enough.
In any case, it can spare the caller the effort of recomputing the
length. As an example, sel_read_policybrief() in the 2/2 patch needs
to know the length of the string to put in the user buffer.


Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread William Roberts
On Wed, May 17, 2017 at 7:59 AM, Sebastien Buisson
 wrote:
> 2017-05-16 22:40 GMT+02:00 Stephen Smalley :
>>> + strcpy(*brief, policydb.policybrief);
>>> + /* *len is the length of the output string */
>>> + *len = policybrief_len - 1;
>>
>> Is there a particular reason to not just return policybrief_len here as
>> well, for consistency in the interface?  How do you intend to use this
>> value in the caller?
>
> As called in the other patch to expose policy brief via selinuxfs
> (sel_read_policybrief), the intent is to provide the caller with the
> length of the string returned.
> Or should I set *len to policy brief_len here, and just make the
> caller aware that the returned length is in fact the length of the
> buffer (i.e. including terminating NUL byte)?

What is the caller supposed to do with length? This interface seemed kind of
odd. If it's guaranteed NUL byte terminated, do they even need length?


Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-17 Thread Sebastien Buisson
2017-05-16 22:40 GMT+02:00 Stephen Smalley :
>> + strcpy(*brief, policydb.policybrief);
>> + /* *len is the length of the output string */
>> + *len = policybrief_len - 1;
>
> Is there a particular reason to not just return policybrief_len here as
> well, for consistency in the interface?  How do you intend to use this
> value in the caller?

As called in the other patch to expose policy brief via selinuxfs
(sel_read_policybrief), the intent is to provide the caller with the
length of the string returned.
Or should I set *len to policy brief_len here, and just make the
caller aware that the returned length is in fact the length of the
buffer (i.e. including terminating NUL byte)?


Re: [PATCH v5 1/2] selinux: add brief info to policydb

2017-05-16 Thread Stephen Smalley
On Tue, 2017-05-16 at 18:51 +0900, Sebastien Buisson wrote:
> Add policybrief field to struct policydb. It holds a brief info
> of the policydb, made of colon separated name and value pairs
> that give information about how the policy is applied in the
> security module(s).
> Note that the ordering of the fields in the string may change.
> 
> Policy brief is computed every time the policy is loaded, and when
> enforce or checkreqprot are changed.
> 
> Add security_policy_brief hook to give access to policy brief to
> the rest of the kernel. It is useful for any network or
> distributed file system that cares about how SELinux is enforced
> on its client nodes. This information is used to detect changes
> to the policy on file system client nodes, and can be forwarded
> to file system server nodes. Depending on how the policy is
> enforced on client side, server can refuse connection.
> 
> Signed-off-by: Sebastien Buisson 
> ---
>  include/linux/lsm_hooks.h   | 20 +
>  include/linux/security.h|  7 +++
>  security/security.c |  8 
>  security/selinux/hooks.c|  7 +++
>  security/selinux/include/security.h |  2 +
>  security/selinux/selinuxfs.c|  2 +
>  security/selinux/ss/policydb.c  | 85
> +
>  security/selinux/ss/policydb.h  |  3 ++
>  security/selinux/ss/services.c  | 67
> +
>  9 files changed, 201 insertions(+)
> 
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 1aa6333..e4dc2b4 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -1331,6 +1331,24 @@
>   *   @inode we wish to get the security context of.
>   *   @ctx is a pointer in which to place the allocated security
> context.
>   *   @ctxlen points to the place to put the length of @ctx.
> + *
> + * Security hooks for policy brief
> + *
> + * @policy_brief:
> + *
> + *   Returns a string containing a brief info of the policydb.
> The string
> + *   contains colon separated name and value pairs that give
> information
> + *   about how the policy is applied in the security module(s).
> + *   Note that the ordering of the fields in the string may
> change.
> + *
> + *   @brief: pointer to buffer holding brief
> + *   @len: in: brief buffer length if no alloc, out: brief
> string len
> + *   @alloc: whether to allocate buffer for brief or not
> + *   If @alloc, *brief must be kfreed by caller.
> + *   If not @alloc, caller must pass a buffer that can hold
> policy brief
> + *   info (including terminating NUL).
> + *   On success 0 is returned , or negative value on error.
> + *
>   * This is the main security structure.
>   */
>  
> @@ -1562,6 +1580,7 @@
>   int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32
> ctxlen);
>   int (*inode_getsecctx)(struct inode *inode, void **ctx, u32
> *ctxlen);
>  
> + int (*policy_brief)(char **brief, size_t *len, bool alloc);
>  #ifdef CONFIG_SECURITY_NETWORK
>   int (*unix_stream_connect)(struct sock *sock, struct sock
> *other,
>   struct sock *newsk);
> @@ -1806,6 +1825,7 @@ struct security_hook_heads {
>   struct list_head inode_notifysecctx;
>   struct list_head inode_setsecctx;
>   struct list_head inode_getsecctx;
> + struct list_head policy_brief;
>  #ifdef CONFIG_SECURITY_NETWORK
>   struct list_head unix_stream_connect;
>   struct list_head unix_may_send;
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 97df7ba..35ac97f 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -376,6 +376,8 @@ int security_sem_semop(struct sem_array *sma,
> struct sembuf *sops,
>  int security_inode_notifysecctx(struct inode *inode, void *ctx, u32
> ctxlen);
>  int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32
> ctxlen);
>  int security_inode_getsecctx(struct inode *inode, void **ctx, u32
> *ctxlen);
> +
> +int security_policy_brief(char **brief, size_t *len, bool alloc);
>  #else /* CONFIG_SECURITY */
>  struct security_mnt_opts {
>  };
> @@ -1159,6 +1161,11 @@ static inline int
> security_inode_getsecctx(struct inode *inode, void **ctx, u32
>  {
>   return -EOPNOTSUPP;
>  }
> +
> +static inline int security_policy_brief(char **brief, size_t *len,
> bool alloc)
> +{
> + return -EOPNOTSUPP;
> +}
>  #endif   /* CONFIG_SECURITY */
>  
>  #ifdef CONFIG_SECURITY_NETWORK
> diff --git a/security/security.c b/security/security.c
> index d6d18a3..46052d3 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1269,6 +1269,12 @@ int security_inode_getsecctx(struct inode
> *inode, void **ctx, u32 *ctxlen)
>  }
>  EXPORT_SYMBOL(security_inode_getsecctx);
>  
> +int security_policy_brief(char **brief, size_t *len, bool alloc)
> +{
> + return call_int_hook(policy_brief, -EOPNOTSUPP, brief, len,
> alloc);
> +}
> +EXPORT_SYMBOL(security_policy_brief);

[PATCH v5 1/2] selinux: add brief info to policydb

2017-05-16 Thread Sebastien Buisson
Add policybrief field to struct policydb. It holds a brief info
of the policydb, made of colon separated name and value pairs
that give information about how the policy is applied in the
security module(s).
Note that the ordering of the fields in the string may change.

Policy brief is computed every time the policy is loaded, and when
enforce or checkreqprot are changed.

Add security_policy_brief hook to give access to policy brief to
the rest of the kernel. It is useful for any network or
distributed file system that cares about how SELinux is enforced
on its client nodes. This information is used to detect changes
to the policy on file system client nodes, and can be forwarded
to file system server nodes. Depending on how the policy is
enforced on client side, server can refuse connection.

Signed-off-by: Sebastien Buisson 
---
 include/linux/lsm_hooks.h   | 20 +
 include/linux/security.h|  7 +++
 security/security.c |  8 
 security/selinux/hooks.c|  7 +++
 security/selinux/include/security.h |  2 +
 security/selinux/selinuxfs.c|  2 +
 security/selinux/ss/policydb.c  | 85 +
 security/selinux/ss/policydb.h  |  3 ++
 security/selinux/ss/services.c  | 67 +
 9 files changed, 201 insertions(+)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 1aa6333..e4dc2b4 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1331,6 +1331,24 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for policy brief
+ *
+ * @policy_brief:
+ *
+ * Returns a string containing a brief info of the policydb. The string
+ * contains colon separated name and value pairs that give information
+ * about how the policy is applied in the security module(s).
+ * Note that the ordering of the fields in the string may change.
+ *
+ * @brief: pointer to buffer holding brief
+ * @len: in: brief buffer length if no alloc, out: brief string len
+ * @alloc: whether to allocate buffer for brief or not
+ * If @alloc, *brief must be kfreed by caller.
+ * If not @alloc, caller must pass a buffer that can hold policy brief
+ * info (including terminating NUL).
+ * On success 0 is returned , or negative value on error.
+ *
  * This is the main security structure.
  */
 
@@ -1562,6 +1580,7 @@
int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
 
+   int (*policy_brief)(char **brief, size_t *len, bool alloc);
 #ifdef CONFIG_SECURITY_NETWORK
int (*unix_stream_connect)(struct sock *sock, struct sock *other,
struct sock *newsk);
@@ -1806,6 +1825,7 @@ struct security_hook_heads {
struct list_head inode_notifysecctx;
struct list_head inode_setsecctx;
struct list_head inode_getsecctx;
+   struct list_head policy_brief;
 #ifdef CONFIG_SECURITY_NETWORK
struct list_head unix_stream_connect;
struct list_head unix_may_send;
diff --git a/include/linux/security.h b/include/linux/security.h
index 97df7ba..35ac97f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -376,6 +376,8 @@ int security_sem_semop(struct sem_array *sma, struct sembuf 
*sops,
 int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
 int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
 int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
+
+int security_policy_brief(char **brief, size_t *len, bool alloc);
 #else /* CONFIG_SECURITY */
 struct security_mnt_opts {
 };
@@ -1159,6 +1161,11 @@ static inline int security_inode_getsecctx(struct inode 
*inode, void **ctx, u32
 {
return -EOPNOTSUPP;
 }
+
+static inline int security_policy_brief(char **brief, size_t *len, bool alloc)
+{
+   return -EOPNOTSUPP;
+}
 #endif /* CONFIG_SECURITY */
 
 #ifdef CONFIG_SECURITY_NETWORK
diff --git a/security/security.c b/security/security.c
index d6d18a3..46052d3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1269,6 +1269,12 @@ int security_inode_getsecctx(struct inode *inode, void 
**ctx, u32 *ctxlen)
 }
 EXPORT_SYMBOL(security_inode_getsecctx);
 
+int security_policy_brief(char **brief, size_t *len, bool alloc)
+{
+   return call_int_hook(policy_brief, -EOPNOTSUPP, brief, len, alloc);
+}
+EXPORT_SYMBOL(security_policy_brief);
+
 #ifdef CONFIG_SECURITY_NETWORK
 
 int security_unix_stream_connect(struct sock *sock, struct sock *other, struct 
sock *newsk)
@@ -1868,6 +1874,8 @@ struct security_hook_heads security_hook_heads 
__lsm_ro_after_init = {