Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-13 Thread Yuichi Nakamura

On Thu, 13 Sep 2007 08:58:32 -0400
Stephen Smalley wrote:
> On Wed, 2007-09-12 at 17:51 +0900, Yuichi Nakamura wrote:

> Thanks, a few comments below.
Thanks for comments!

> > 
> > * Description of patch
> > This patch improves performance of read/write in SELinux.
> > It improves performance by skipping permission check in 
> > selinux_file_permission. Permission is only checked when 
> > sid change or policy load is detected after file open.
> > To detect sid change, new LSM hook securiy_dentry_open is added.
> 
> I think I'd reword this a little, e.g.
> 
> It reduces the selinux overhead on read/write by only revalidating
> permissions in selinux_file_permission if the task or inode labels have
> changed or the policy has changed since the open-time check.  A new LSM
> hook, security_dentry_open, is added to capture the necessary state at
> open time to allow this optimization.
I see, I will use that.

> > 
> > Signed-off-by: Yuichi Nakamura<[EMAIL PROTECTED]>
> > ---
> >  fs/open.c |5 
> >  include/linux/security.h  |   16 ++
> >  security/dummy.c  |6 +
> >  security/selinux/avc.c|5 
> >  security/selinux/hooks.c  |   43 
> > +-
> >  security/selinux/include/avc.h|2 +
> >  security/selinux/include/objsec.h |2 +
> >  7 files changed, 78 insertions(+), 1 deletion(-)
> 
> > diff -purN -X linux-2.6.22/Documentation/dontdiff 
> > linux-2.6.22.orig/security/selinux/hooks.c 
> > linux-2.6.22/security/selinux/hooks.c
> > --- linux-2.6.22.orig/security/selinux/hooks.c  2007-07-09 
> > 08:32:17.0 +0900
> > +++ linux-2.6.22/security/selinux/hooks.c   2007-09-12 08:42:49.0 
> > +0900
> > @@ -80,6 +82,7 @@
> >  
> >  #define XATTR_SELINUX_SUFFIX "selinux"
> >  #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
> > +#define ACC_MODE(x) ("\000\004\002\006"[(x)_ACCMODE])
> 
> Leftover from prior version of the patch, no longer needed.
Fixed.

> 
> 
> > @@ -2715,6 +2737,23 @@ static int selinux_file_receive(struct f
> > return file_has_perm(current, file, file_to_av(file));
> >  }
> >  
> > +static int selinux_dentry_open(struct file *file)
> > +{
> > +   struct file_security_struct *fsec;
> > +   struct inode *inode;
> > +   struct inode_security_struct *isec;
> > +   inode = file->f_path.dentry->d_inode;
> > +   fsec = file->f_security;
> > +   isec = inode->i_security;
> 
> I'd add a comment here, e.g.
> /* 
>  * Save inode label and policy sequence number
>  * at open-time so that selinux_file_permission
>  * can determine whether revalidation is necessary.
>  * Task label is already saved in the file security
>* struct as its SID.
>  */
Fixed.

> 
> > +   fsec->isid = isec->sid;
> > +   fsec->pseqno = avc_policy_seqno();
> > +
> > +   /*Permission has to be rechecked here.
> > + Policy load of inode sid can happen between
> > + may_open and selinux_dentry_open.*/
> 
> Typo in the comment (s/of/or/), coding style isn't right for a
> multi-line comment, and likely needs clarification, e.g.
>   /*
>* Since the inode label or policy seqno may have changed
>* between the selinux_inode_permission check and the saving
>* of state above, recheck that access is still permitted.
>* Otherwise, access might never be revalidated against the
>* new inode label or new policy.
>* This check is not redundant - do not remove. 
>*/
Fixed.


> 
> > +   return inode_has_perm(current, inode, file_to_av(file), NULL);
> > +}
> > +
> >  /* task security operations */
> >  
> >  static int selinux_task_create(unsigned long clone_flags)
> 
> > diff -purN -X linux-2.6.22/Documentation/dontdiff 
> > linux-2.6.22.orig/fs/open.c linux-2.6.22/fs/open.c
> > --- linux-2.6.22.orig/fs/open.c 2007-07-09 08:32:17.0 +0900
> > +++ linux-2.6.22/fs/open.c  2007-09-12 08:31:24.0 +0900
> > @@ -696,8 +696,13 @@ static struct file *__dentry_open(struct
> > f->f_op = fops_get(inode->i_fop);
> > file_move(f, >i_sb->s_files);
> >  
> > +   error = security_dentry_open(f);
> > +   if (error)
> > +   goto cleanup_all;
> > +
> > if (!open && f->f_op)
> > open = f->f_op->open;
> > +
> 
> Extraneous whitespace leftover from prior version of the patch.
Fixed.

> 
> > if (open) {
> > error = open(inode, f);
> > if (error)
> > diff -purN -X linux-2.6.22/Documentation/dontdiff 
> > linux-2.6.22.orig/include/linux/security.h 
> > linux-2.6.22/include/linux/security.h
> > --- linux-2.6.22.orig/include/linux/security.h  2007-07-09 
> > 08:32:17.0 +0900
> > +++ linux-2.6.22/include/linux/security.h   2007-09-12 08:30:16.0 
> > +0900
> > @@ -503,6 +503,11 @@ struct request_sock;
> >   * @file contains the file structure being received.
> >   * Return 0 if 

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-13 Thread Stephen Smalley
On Wed, 2007-09-12 at 17:51 +0900, Yuichi Nakamura wrote:
> Hi. 
> 
> Stephen Smalley pointed out possibility of race condition
> in off-list discussion.
> Stephen Smalley said:
> > One other observation about the patch:  it presently leaves open a
> > (small) race window in which the file could get relabeled or policy gets
> > reloaded between the time of the normal permission check (from
> > selinux_inode_permission) and the time you copy the inode SID and policy
> > seqno to the file security struct.  In which case you might end up never
> > revalidating access upon read/write even though conditions changed since
> > the open-time permission check.  Not sure how to cleanly fix in a
> > lock-free manner, and adding locks here will only make matters worse.
> 
> To fix that, permission has to be checked in selinux_dentry_open.
> Therefore, in open, number of permission checks increased.
> As shown in benchmark result below, it does not affect open/close 
> performance so much.
> 
> Following is benchmark result.
> * Benchmark
> lmbench simple read,write,open/close.
> 
> * Before tuning
> 1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
> Base  SELinux  Overhead(%)
> Simple read 1.10  1.24 12.3
> Simple write1.02  1.14 14.0
> open/close  5.97  7.45 24.9
> * Base: kernel compiled without SELinux support
> 
> 2) Result for SH(SH4, SH7751R), kernel 2.6.22
> BaseSELinux   Overhead(%)
> Simple read 2.395.49  130.5
> Simple write2.075.10  146.6
> open/close  32.662.8  93.0
> 
> * After tuning
> 1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
> Base  SELinux  Overhead(%)
> Simple read 1.10  1.13 2.3(Before 12.3)
> Simple write1.02  1.0240.6(Before 14.0)
> open/close  5.97  7.48 25.3(Before 24.9)
> * Base: kernel compiled without SELinux support
> 
> 2) Result for SH(SH4, SH7751R), kernel 2.6.22
> BaseSELinux   Overhead(%)
> Simple read 2.392.63  10.4(Before 130.5)
> Simple write2.072.34  13.1(Before 146.6)
> open/close  32.658.7  80.2(before 93.0)
> 
> Next is a patch.

Thanks, a few comments below.

> 
> * Description of patch
> This patch improves performance of read/write in SELinux.
> It improves performance by skipping permission check in 
> selinux_file_permission. Permission is only checked when 
> sid change or policy load is detected after file open.
> To detect sid change, new LSM hook securiy_dentry_open is added.

I think I'd reword this a little, e.g.

It reduces the selinux overhead on read/write by only revalidating
permissions in selinux_file_permission if the task or inode labels have
changed or the policy has changed since the open-time check.  A new LSM
hook, security_dentry_open, is added to capture the necessary state at
open time to allow this optimization.

> 
> Signed-off-by: Yuichi Nakamura<[EMAIL PROTECTED]>
> ---
>  fs/open.c |5 
>  include/linux/security.h  |   16 ++
>  security/dummy.c  |6 +
>  security/selinux/avc.c|5 
>  security/selinux/hooks.c  |   43 
> +-
>  security/selinux/include/avc.h|2 +
>  security/selinux/include/objsec.h |2 +
>  7 files changed, 78 insertions(+), 1 deletion(-)

> diff -purN -X linux-2.6.22/Documentation/dontdiff 
> linux-2.6.22.orig/security/selinux/hooks.c 
> linux-2.6.22/security/selinux/hooks.c
> --- linux-2.6.22.orig/security/selinux/hooks.c2007-07-09 
> 08:32:17.0 +0900
> +++ linux-2.6.22/security/selinux/hooks.c 2007-09-12 08:42:49.0 
> +0900
> @@ -80,6 +82,7 @@
>  
>  #define XATTR_SELINUX_SUFFIX "selinux"
>  #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
> +#define ACC_MODE(x) ("\000\004\002\006"[(x)_ACCMODE])

Leftover from prior version of the patch, no longer needed.


> @@ -2715,6 +2737,23 @@ static int selinux_file_receive(struct f
>   return file_has_perm(current, file, file_to_av(file));
>  }
>  
> +static int selinux_dentry_open(struct file *file)
> +{
> + struct file_security_struct *fsec;
> + struct inode *inode;
> + struct inode_security_struct *isec;
> + inode = file->f_path.dentry->d_inode;
> + fsec = file->f_security;
> + isec = inode->i_security;

I'd add a comment here, e.g.
  /* 
   * Save inode label and policy sequence number
   * at open-time so that selinux_file_permission
   * can determine whether revalidation is necessary.
   * Task label is already saved in the file security
   * struct as its SID.
   */

> + fsec->isid = isec->sid;
> + fsec->pseqno = avc_policy_seqno();
> +
> + /*Permission has to be rechecked here.
> +   Policy load of inode sid can happen between
> +   may_open and selinux_dentry_open.*/

Typo in the comment 

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-13 Thread Stephen Smalley
On Wed, 2007-09-12 at 17:51 +0900, Yuichi Nakamura wrote:
 Hi. 
 
 Stephen Smalley pointed out possibility of race condition
 in off-list discussion.
 Stephen Smalley said:
  One other observation about the patch:  it presently leaves open a
  (small) race window in which the file could get relabeled or policy gets
  reloaded between the time of the normal permission check (from
  selinux_inode_permission) and the time you copy the inode SID and policy
  seqno to the file security struct.  In which case you might end up never
  revalidating access upon read/write even though conditions changed since
  the open-time permission check.  Not sure how to cleanly fix in a
  lock-free manner, and adding locks here will only make matters worse.
 
 To fix that, permission has to be checked in selinux_dentry_open.
 Therefore, in open, number of permission checks increased.
 As shown in benchmark result below, it does not affect open/close 
 performance so much.
 
 Following is benchmark result.
 * Benchmark
 lmbench simple read,write,open/close.
 
 * Before tuning
 1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
 Base  SELinux  Overhead(%)
 Simple read 1.10  1.24 12.3
 Simple write1.02  1.14 14.0
 open/close  5.97  7.45 24.9
 * Base: kernel compiled without SELinux support
 
 2) Result for SH(SH4, SH7751R), kernel 2.6.22
 BaseSELinux   Overhead(%)
 Simple read 2.395.49  130.5
 Simple write2.075.10  146.6
 open/close  32.662.8  93.0
 
 * After tuning
 1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
 Base  SELinux  Overhead(%)
 Simple read 1.10  1.13 2.3(Before 12.3)
 Simple write1.02  1.0240.6(Before 14.0)
 open/close  5.97  7.48 25.3(Before 24.9)
 * Base: kernel compiled without SELinux support
 
 2) Result for SH(SH4, SH7751R), kernel 2.6.22
 BaseSELinux   Overhead(%)
 Simple read 2.392.63  10.4(Before 130.5)
 Simple write2.072.34  13.1(Before 146.6)
 open/close  32.658.7  80.2(before 93.0)
 
 Next is a patch.

Thanks, a few comments below.

 
 * Description of patch
 This patch improves performance of read/write in SELinux.
 It improves performance by skipping permission check in 
 selinux_file_permission. Permission is only checked when 
 sid change or policy load is detected after file open.
 To detect sid change, new LSM hook securiy_dentry_open is added.

I think I'd reword this a little, e.g.

It reduces the selinux overhead on read/write by only revalidating
permissions in selinux_file_permission if the task or inode labels have
changed or the policy has changed since the open-time check.  A new LSM
hook, security_dentry_open, is added to capture the necessary state at
open time to allow this optimization.

 
 Signed-off-by: Yuichi Nakamura[EMAIL PROTECTED]
 ---
  fs/open.c |5 
  include/linux/security.h  |   16 ++
  security/dummy.c  |6 +
  security/selinux/avc.c|5 
  security/selinux/hooks.c  |   43 
 +-
  security/selinux/include/avc.h|2 +
  security/selinux/include/objsec.h |2 +
  7 files changed, 78 insertions(+), 1 deletion(-)
snip
 diff -purN -X linux-2.6.22/Documentation/dontdiff 
 linux-2.6.22.orig/security/selinux/hooks.c 
 linux-2.6.22/security/selinux/hooks.c
 --- linux-2.6.22.orig/security/selinux/hooks.c2007-07-09 
 08:32:17.0 +0900
 +++ linux-2.6.22/security/selinux/hooks.c 2007-09-12 08:42:49.0 
 +0900
 @@ -80,6 +82,7 @@
  
  #define XATTR_SELINUX_SUFFIX selinux
  #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
 +#define ACC_MODE(x) (\000\004\002\006[(x)O_ACCMODE])

Leftover from prior version of the patch, no longer needed.

snip
 @@ -2715,6 +2737,23 @@ static int selinux_file_receive(struct f
   return file_has_perm(current, file, file_to_av(file));
  }
  
 +static int selinux_dentry_open(struct file *file)
 +{
 + struct file_security_struct *fsec;
 + struct inode *inode;
 + struct inode_security_struct *isec;
 + inode = file-f_path.dentry-d_inode;
 + fsec = file-f_security;
 + isec = inode-i_security;

I'd add a comment here, e.g.
  /* 
   * Save inode label and policy sequence number
   * at open-time so that selinux_file_permission
   * can determine whether revalidation is necessary.
   * Task label is already saved in the file security
   * struct as its SID.
   */

 + fsec-isid = isec-sid;
 + fsec-pseqno = avc_policy_seqno();
 +
 + /*Permission has to be rechecked here.
 +   Policy load of inode sid can happen between
 +   may_open and selinux_dentry_open.*/

Typo in the comment (s/of/or/), coding style isn't right for a
multi-line comment, and likely needs clarification, e.g.
/*
  

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-13 Thread Yuichi Nakamura

On Thu, 13 Sep 2007 08:58:32 -0400
Stephen Smalley wrote:
 On Wed, 2007-09-12 at 17:51 +0900, Yuichi Nakamura wrote:
snip
 Thanks, a few comments below.
Thanks for comments!

  
  * Description of patch
  This patch improves performance of read/write in SELinux.
  It improves performance by skipping permission check in 
  selinux_file_permission. Permission is only checked when 
  sid change or policy load is detected after file open.
  To detect sid change, new LSM hook securiy_dentry_open is added.
 
 I think I'd reword this a little, e.g.
 
 It reduces the selinux overhead on read/write by only revalidating
 permissions in selinux_file_permission if the task or inode labels have
 changed or the policy has changed since the open-time check.  A new LSM
 hook, security_dentry_open, is added to capture the necessary state at
 open time to allow this optimization.
I see, I will use that.

  
  Signed-off-by: Yuichi Nakamura[EMAIL PROTECTED]
  ---
   fs/open.c |5 
   include/linux/security.h  |   16 ++
   security/dummy.c  |6 +
   security/selinux/avc.c|5 
   security/selinux/hooks.c  |   43 
  +-
   security/selinux/include/avc.h|2 +
   security/selinux/include/objsec.h |2 +
   7 files changed, 78 insertions(+), 1 deletion(-)
 snip
  diff -purN -X linux-2.6.22/Documentation/dontdiff 
  linux-2.6.22.orig/security/selinux/hooks.c 
  linux-2.6.22/security/selinux/hooks.c
  --- linux-2.6.22.orig/security/selinux/hooks.c  2007-07-09 
  08:32:17.0 +0900
  +++ linux-2.6.22/security/selinux/hooks.c   2007-09-12 08:42:49.0 
  +0900
  @@ -80,6 +82,7 @@
   
   #define XATTR_SELINUX_SUFFIX selinux
   #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
  +#define ACC_MODE(x) (\000\004\002\006[(x)O_ACCMODE])
 
 Leftover from prior version of the patch, no longer needed.
Fixed.

 
 snip
  @@ -2715,6 +2737,23 @@ static int selinux_file_receive(struct f
  return file_has_perm(current, file, file_to_av(file));
   }
   
  +static int selinux_dentry_open(struct file *file)
  +{
  +   struct file_security_struct *fsec;
  +   struct inode *inode;
  +   struct inode_security_struct *isec;
  +   inode = file-f_path.dentry-d_inode;
  +   fsec = file-f_security;
  +   isec = inode-i_security;
 
 I'd add a comment here, e.g.
 /* 
  * Save inode label and policy sequence number
  * at open-time so that selinux_file_permission
  * can determine whether revalidation is necessary.
  * Task label is already saved in the file security
* struct as its SID.
  */
Fixed.

 
  +   fsec-isid = isec-sid;
  +   fsec-pseqno = avc_policy_seqno();
  +
  +   /*Permission has to be rechecked here.
  + Policy load of inode sid can happen between
  + may_open and selinux_dentry_open.*/
 
 Typo in the comment (s/of/or/), coding style isn't right for a
 multi-line comment, and likely needs clarification, e.g.
   /*
* Since the inode label or policy seqno may have changed
* between the selinux_inode_permission check and the saving
* of state above, recheck that access is still permitted.
* Otherwise, access might never be revalidated against the
* new inode label or new policy.
* This check is not redundant - do not remove. 
*/
Fixed.


 
  +   return inode_has_perm(current, inode, file_to_av(file), NULL);
  +}
  +
   /* task security operations */
   
   static int selinux_task_create(unsigned long clone_flags)
 
  diff -purN -X linux-2.6.22/Documentation/dontdiff 
  linux-2.6.22.orig/fs/open.c linux-2.6.22/fs/open.c
  --- linux-2.6.22.orig/fs/open.c 2007-07-09 08:32:17.0 +0900
  +++ linux-2.6.22/fs/open.c  2007-09-12 08:31:24.0 +0900
  @@ -696,8 +696,13 @@ static struct file *__dentry_open(struct
  f-f_op = fops_get(inode-i_fop);
  file_move(f, inode-i_sb-s_files);
   
  +   error = security_dentry_open(f);
  +   if (error)
  +   goto cleanup_all;
  +
  if (!open  f-f_op)
  open = f-f_op-open;
  +
 
 Extraneous whitespace leftover from prior version of the patch.
Fixed.

 
  if (open) {
  error = open(inode, f);
  if (error)
  diff -purN -X linux-2.6.22/Documentation/dontdiff 
  linux-2.6.22.orig/include/linux/security.h 
  linux-2.6.22/include/linux/security.h
  --- linux-2.6.22.orig/include/linux/security.h  2007-07-09 
  08:32:17.0 +0900
  +++ linux-2.6.22/include/linux/security.h   2007-09-12 08:30:16.0 
  +0900
  @@ -503,6 +503,11 @@ struct request_sock;
* @file contains the file structure being received.
* Return 0 if permission is granted.
*
  + * Security hook for dentry
  + *
  + * @dentry_open
  + *   Check permission or get additional information before opening dentry.
  + *
 
 More precisely, Save open-time 

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-12 Thread Yuichi Nakamura
Hi. 

Stephen Smalley pointed out possibility of race condition
in off-list discussion.
Stephen Smalley said:
> One other observation about the patch:  it presently leaves open a
> (small) race window in which the file could get relabeled or policy gets
> reloaded between the time of the normal permission check (from
> selinux_inode_permission) and the time you copy the inode SID and policy
> seqno to the file security struct.  In which case you might end up never
> revalidating access upon read/write even though conditions changed since
> the open-time permission check.  Not sure how to cleanly fix in a
> lock-free manner, and adding locks here will only make matters worse.

To fix that, permission has to be checked in selinux_dentry_open.
Therefore, in open, number of permission checks increased.
As shown in benchmark result below, it does not affect open/close 
performance so much.

Following is benchmark result.
* Benchmark
lmbench simple read,write,open/close.

* Before tuning
1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
Base  SELinux  Overhead(%)
Simple read 1.10  1.24 12.3
Simple write1.02  1.14 14.0
open/close  5.97  7.45 24.9
* Base: kernel compiled without SELinux support

2) Result for SH(SH4, SH7751R), kernel 2.6.22
BaseSELinux   Overhead(%)
Simple read 2.395.49  130.5
Simple write2.075.10  146.6
open/close  32.662.8  93.0

* After tuning
1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
Base  SELinux  Overhead(%)
Simple read 1.10  1.13 2.3(Before 12.3)
Simple write1.02  1.0240.6(Before 14.0)
open/close  5.97  7.48 25.3(Before 24.9)
* Base: kernel compiled without SELinux support

2) Result for SH(SH4, SH7751R), kernel 2.6.22
BaseSELinux   Overhead(%)
Simple read 2.392.63  10.4(Before 130.5)
Simple write2.072.34  13.1(Before 146.6)
open/close  32.658.7  80.2(before 93.0)

Next is a patch.

* Description of patch
This patch improves performance of read/write in SELinux.
It improves performance by skipping permission check in 
selinux_file_permission. Permission is only checked when 
sid change or policy load is detected after file open.
To detect sid change, new LSM hook securiy_dentry_open is added.

Signed-off-by: Yuichi Nakamura<[EMAIL PROTECTED]>
---
 fs/open.c |5 
 include/linux/security.h  |   16 ++
 security/dummy.c  |6 +
 security/selinux/avc.c|5 
 security/selinux/hooks.c  |   43 +-
 security/selinux/include/avc.h|2 +
 security/selinux/include/objsec.h |2 +
 7 files changed, 78 insertions(+), 1 deletion(-)
diff -purN -X linux-2.6.22/Documentation/dontdiff 
linux-2.6.22.orig/security/selinux/avc.c linux-2.6.22/security/selinux/avc.c
--- linux-2.6.22.orig/security/selinux/avc.c2007-07-09 08:32:17.0 
+0900
+++ linux-2.6.22/security/selinux/avc.c 2007-09-12 08:24:27.0 +0900
@@ -913,3 +913,8 @@ int avc_has_perm(u32 ssid, u32 tsid, u16
avc_audit(ssid, tsid, tclass, requested, , rc, auditdata);
return rc;
 }
+
+u32 avc_policy_seqno(void)
+{
+   return avc_cache.latest_notif;
+}
diff -purN -X linux-2.6.22/Documentation/dontdiff 
linux-2.6.22.orig/security/selinux/hooks.c linux-2.6.22/security/selinux/hooks.c
--- linux-2.6.22.orig/security/selinux/hooks.c  2007-07-09 08:32:17.0 
+0900
+++ linux-2.6.22/security/selinux/hooks.c   2007-09-12 08:42:49.0 
+0900
@@ -14,6 +14,8 @@
  *  <[EMAIL PROTECTED]>
  *  Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
  * Paul Moore, <[EMAIL PROTECTED]>
+ *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
+ * Yuichi Nakamura <[EMAIL PROTECTED]>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2,
@@ -80,6 +82,7 @@
 
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+#define ACC_MODE(x) ("\000\004\002\006"[(x)_ACCMODE])
 
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@ -2458,7 +2461,7 @@ static int selinux_inode_listsecurity(st
 
 /* file security operations */
 
-static int selinux_file_permission(struct file *file, int mask)
+static int selinux_revalidate_file_permission(struct file *file, int mask)
 {
int rc;
struct inode *inode = file->f_path.dentry->d_inode;
@@ -2480,6 +2483,25 @@ static int selinux_file_permission(struc
return selinux_netlbl_inode_permission(inode, mask);
 }
 
+static int selinux_file_permission(struct file *file, int mask)
+{
+   struct inode *inode = file->f_path.dentry->d_inode;
+   

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-12 Thread Yuichi Nakamura
Hi. 

Stephen Smalley pointed out possibility of race condition
in off-list discussion.
Stephen Smalley said:
 One other observation about the patch:  it presently leaves open a
 (small) race window in which the file could get relabeled or policy gets
 reloaded between the time of the normal permission check (from
 selinux_inode_permission) and the time you copy the inode SID and policy
 seqno to the file security struct.  In which case you might end up never
 revalidating access upon read/write even though conditions changed since
 the open-time permission check.  Not sure how to cleanly fix in a
 lock-free manner, and adding locks here will only make matters worse.

To fix that, permission has to be checked in selinux_dentry_open.
Therefore, in open, number of permission checks increased.
As shown in benchmark result below, it does not affect open/close 
performance so much.

Following is benchmark result.
* Benchmark
lmbench simple read,write,open/close.

* Before tuning
1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
Base  SELinux  Overhead(%)
Simple read 1.10  1.24 12.3
Simple write1.02  1.14 14.0
open/close  5.97  7.45 24.9
* Base: kernel compiled without SELinux support

2) Result for SH(SH4, SH7751R), kernel 2.6.22
BaseSELinux   Overhead(%)
Simple read 2.395.49  130.5
Simple write2.075.10  146.6
open/close  32.662.8  93.0

* After tuning
1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
Base  SELinux  Overhead(%)
Simple read 1.10  1.13 2.3(Before 12.3)
Simple write1.02  1.0240.6(Before 14.0)
open/close  5.97  7.48 25.3(Before 24.9)
* Base: kernel compiled without SELinux support

2) Result for SH(SH4, SH7751R), kernel 2.6.22
BaseSELinux   Overhead(%)
Simple read 2.392.63  10.4(Before 130.5)
Simple write2.072.34  13.1(Before 146.6)
open/close  32.658.7  80.2(before 93.0)

Next is a patch.

* Description of patch
This patch improves performance of read/write in SELinux.
It improves performance by skipping permission check in 
selinux_file_permission. Permission is only checked when 
sid change or policy load is detected after file open.
To detect sid change, new LSM hook securiy_dentry_open is added.

Signed-off-by: Yuichi Nakamura[EMAIL PROTECTED]
---
 fs/open.c |5 
 include/linux/security.h  |   16 ++
 security/dummy.c  |6 +
 security/selinux/avc.c|5 
 security/selinux/hooks.c  |   43 +-
 security/selinux/include/avc.h|2 +
 security/selinux/include/objsec.h |2 +
 7 files changed, 78 insertions(+), 1 deletion(-)
diff -purN -X linux-2.6.22/Documentation/dontdiff 
linux-2.6.22.orig/security/selinux/avc.c linux-2.6.22/security/selinux/avc.c
--- linux-2.6.22.orig/security/selinux/avc.c2007-07-09 08:32:17.0 
+0900
+++ linux-2.6.22/security/selinux/avc.c 2007-09-12 08:24:27.0 +0900
@@ -913,3 +913,8 @@ int avc_has_perm(u32 ssid, u32 tsid, u16
avc_audit(ssid, tsid, tclass, requested, avd, rc, auditdata);
return rc;
 }
+
+u32 avc_policy_seqno(void)
+{
+   return avc_cache.latest_notif;
+}
diff -purN -X linux-2.6.22/Documentation/dontdiff 
linux-2.6.22.orig/security/selinux/hooks.c linux-2.6.22/security/selinux/hooks.c
--- linux-2.6.22.orig/security/selinux/hooks.c  2007-07-09 08:32:17.0 
+0900
+++ linux-2.6.22/security/selinux/hooks.c   2007-09-12 08:42:49.0 
+0900
@@ -14,6 +14,8 @@
  *  [EMAIL PROTECTED]
  *  Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
  * Paul Moore, [EMAIL PROTECTED]
+ *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
+ * Yuichi Nakamura [EMAIL PROTECTED]
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2,
@@ -80,6 +82,7 @@
 
 #define XATTR_SELINUX_SUFFIX selinux
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+#define ACC_MODE(x) (\000\004\002\006[(x)O_ACCMODE])
 
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@ -2458,7 +2461,7 @@ static int selinux_inode_listsecurity(st
 
 /* file security operations */
 
-static int selinux_file_permission(struct file *file, int mask)
+static int selinux_revalidate_file_permission(struct file *file, int mask)
 {
int rc;
struct inode *inode = file-f_path.dentry-d_inode;
@@ -2480,6 +2483,25 @@ static int selinux_file_permission(struc
return selinux_netlbl_inode_permission(inode, mask);
 }
 
+static int selinux_file_permission(struct file *file, int mask)
+{
+   struct inode *inode = file-f_path.dentry-d_inode;
+   struct 

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-10 Thread Stephen Smalley
On Mon, 2007-09-10 at 10:31 +0900, Yuichi Nakamura wrote:
> Next is updated patch.

Thanks.
Please include the short description of the patch though when
re-submitting.

> Signed-off-by: Yuichi Nakamura<[EMAIL PROTECTED]>
> ---
>  fs/open.c |5 +
>  include/linux/security.h  |   16 
>  security/selinux/avc.c|5 +
>  security/selinux/hooks.c  |   36 +++-
>  security/selinux/include/avc.h|2 ++
>  security/selinux/include/objsec.h |2 ++
>  6 files changed, 65 insertions(+), 1 deletion(-)

Still missing the necessary changes to security/dummy.c (add
dummy_dentry_open() and update security_fixup_ops()).  For
CONFIG_SECURITY=y but SELinux disabled.

Also, have you re-run your benchmarks with this version of the patch?
   
> diff -purN -X linux-2.6.22/Documentation/dontdiff 
> linux-2.6.22.orig/security/selinux/avc.c linux-2.6.22/security/selinux/avc.c
> --- linux-2.6.22.orig/security/selinux/avc.c  2007-07-09 08:32:17.0 
> +0900
> +++ linux-2.6.22/security/selinux/avc.c   2007-09-10 09:56:22.0 
> +0900
> @@ -913,3 +913,8 @@ int avc_has_perm(u32 ssid, u32 tsid, u16
>   avc_audit(ssid, tsid, tclass, requested, , rc, auditdata);
>   return rc;
>  }
> +
> +u32 avc_policy_seqno(void)
> +{
> + return avc_cache.latest_notif;
> +}
> diff -purN -X linux-2.6.22/Documentation/dontdiff 
> linux-2.6.22.orig/security/selinux/hooks.c 
> linux-2.6.22/security/selinux/hooks.c
> --- linux-2.6.22.orig/security/selinux/hooks.c2007-07-09 
> 08:32:17.0 +0900
> +++ linux-2.6.22/security/selinux/hooks.c 2007-09-10 10:11:13.0 
> +0900
> @@ -14,6 +14,8 @@
>   *  <[EMAIL PROTECTED]>
>   *  Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
>   * Paul Moore, <[EMAIL PROTECTED]>
> + *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
> + * Yuichi Nakamura <[EMAIL PROTECTED]>
>   *
>   *   This program is free software; you can redistribute it and/or modify
>   *   it under the terms of the GNU General Public License version 2,
> @@ -2458,7 +2460,7 @@ static int selinux_inode_listsecurity(st
>  
>  /* file security operations */
>  
> -static int selinux_file_permission(struct file *file, int mask)
> +static int selinux_revalidate_file_permission(struct file *file, int mask)
>  {
>   int rc;
>   struct inode *inode = file->f_path.dentry->d_inode;
> @@ -2480,6 +2482,25 @@ static int selinux_file_permission(struc
>   return selinux_netlbl_inode_permission(inode, mask);
>  }
>  
> +static int selinux_file_permission(struct file *file, int mask)
> +{
> + struct inode *inode = file->f_path.dentry->d_inode;
> + struct task_security_struct *tsec = current->security;
> + struct file_security_struct *fsec = file->f_security;
> + struct inode_security_struct *isec = inode->i_security;
> +
> + if (!mask) {
> + /* No permission to check.  Existence test. */
> + return 0;
> + }
> +
> + if (tsec->sid == fsec->sid && fsec->isid == isec->sid
> + && fsec->pseqno == avc_policy_seqno())
> + return selinux_netlbl_inode_permission(inode, mask);
> +
> + return selinux_revalidate_file_permission(file, mask);
> +}
> +
>  static int selinux_file_alloc_security(struct file *file)
>  {
>   return file_alloc_security(file);
> @@ -2715,6 +2736,17 @@ static int selinux_file_receive(struct f
>   return file_has_perm(current, file, file_to_av(file));
>  }
>  
> +static int selinux_dentry_open(struct file *file, int flags)
> +{
> + struct file_security_struct *fsec;
> + struct inode_security_struct *isec;
> + fsec = file->f_security;
> + isec = file->f_path.dentry->d_inode->i_security;
> + fsec->isid = isec->sid;
> + fsec->pseqno = avc_policy_seqno();
> + return 0;
> +}
> +
>  /* task security operations */
>  
>  static int selinux_task_create(unsigned long clone_flags)
> @@ -4780,6 +4812,8 @@ static struct security_operations selinu
>   .file_send_sigiotask =  selinux_file_send_sigiotask,
>   .file_receive = selinux_file_receive,
>  
> + .dentry_open =  selinux_dentry_open,
> +
>   .task_create =  selinux_task_create,
>   .task_alloc_security =  selinux_task_alloc_security,
>   .task_free_security =   selinux_task_free_security,
> diff -purN -X linux-2.6.22/Documentation/dontdiff 
> linux-2.6.22.orig/security/selinux/include/avc.h 
> linux-2.6.22/security/selinux/include/avc.h
> --- linux-2.6.22.orig/security/selinux/include/avc.h  2007-07-09 
> 08:32:17.0 +0900
> +++ linux-2.6.22/security/selinux/include/avc.h   2007-09-10 
> 09:56:22.0 +0900
> @@ -110,6 +110,8 @@ int avc_has_perm(u32 ssid, u32 tsid,
>   u16 tclass, u32 requested,
>   

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-10 Thread Stephen Smalley
On Mon, 2007-09-10 at 10:31 +0900, Yuichi Nakamura wrote:
 Next is updated patch.

Thanks.
Please include the short description of the patch though when
re-submitting.

 Signed-off-by: Yuichi Nakamura[EMAIL PROTECTED]
 ---
  fs/open.c |5 +
  include/linux/security.h  |   16 
  security/selinux/avc.c|5 +
  security/selinux/hooks.c  |   36 +++-
  security/selinux/include/avc.h|2 ++
  security/selinux/include/objsec.h |2 ++
  6 files changed, 65 insertions(+), 1 deletion(-)

Still missing the necessary changes to security/dummy.c (add
dummy_dentry_open() and update security_fixup_ops()).  For
CONFIG_SECURITY=y but SELinux disabled.

Also, have you re-run your benchmarks with this version of the patch?
   
 diff -purN -X linux-2.6.22/Documentation/dontdiff 
 linux-2.6.22.orig/security/selinux/avc.c linux-2.6.22/security/selinux/avc.c
 --- linux-2.6.22.orig/security/selinux/avc.c  2007-07-09 08:32:17.0 
 +0900
 +++ linux-2.6.22/security/selinux/avc.c   2007-09-10 09:56:22.0 
 +0900
 @@ -913,3 +913,8 @@ int avc_has_perm(u32 ssid, u32 tsid, u16
   avc_audit(ssid, tsid, tclass, requested, avd, rc, auditdata);
   return rc;
  }
 +
 +u32 avc_policy_seqno(void)
 +{
 + return avc_cache.latest_notif;
 +}
 diff -purN -X linux-2.6.22/Documentation/dontdiff 
 linux-2.6.22.orig/security/selinux/hooks.c 
 linux-2.6.22/security/selinux/hooks.c
 --- linux-2.6.22.orig/security/selinux/hooks.c2007-07-09 
 08:32:17.0 +0900
 +++ linux-2.6.22/security/selinux/hooks.c 2007-09-10 10:11:13.0 
 +0900
 @@ -14,6 +14,8 @@
   *  [EMAIL PROTECTED]
   *  Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
   * Paul Moore, [EMAIL PROTECTED]
 + *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
 + * Yuichi Nakamura [EMAIL PROTECTED]
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License version 2,
 @@ -2458,7 +2460,7 @@ static int selinux_inode_listsecurity(st
  
  /* file security operations */
  
 -static int selinux_file_permission(struct file *file, int mask)
 +static int selinux_revalidate_file_permission(struct file *file, int mask)
  {
   int rc;
   struct inode *inode = file-f_path.dentry-d_inode;
 @@ -2480,6 +2482,25 @@ static int selinux_file_permission(struc
   return selinux_netlbl_inode_permission(inode, mask);
  }
  
 +static int selinux_file_permission(struct file *file, int mask)
 +{
 + struct inode *inode = file-f_path.dentry-d_inode;
 + struct task_security_struct *tsec = current-security;
 + struct file_security_struct *fsec = file-f_security;
 + struct inode_security_struct *isec = inode-i_security;
 +
 + if (!mask) {
 + /* No permission to check.  Existence test. */
 + return 0;
 + }
 +
 + if (tsec-sid == fsec-sid  fsec-isid == isec-sid
 +  fsec-pseqno == avc_policy_seqno())
 + return selinux_netlbl_inode_permission(inode, mask);
 +
 + return selinux_revalidate_file_permission(file, mask);
 +}
 +
  static int selinux_file_alloc_security(struct file *file)
  {
   return file_alloc_security(file);
 @@ -2715,6 +2736,17 @@ static int selinux_file_receive(struct f
   return file_has_perm(current, file, file_to_av(file));
  }
  
 +static int selinux_dentry_open(struct file *file, int flags)
 +{
 + struct file_security_struct *fsec;
 + struct inode_security_struct *isec;
 + fsec = file-f_security;
 + isec = file-f_path.dentry-d_inode-i_security;
 + fsec-isid = isec-sid;
 + fsec-pseqno = avc_policy_seqno();
 + return 0;
 +}
 +
  /* task security operations */
  
  static int selinux_task_create(unsigned long clone_flags)
 @@ -4780,6 +4812,8 @@ static struct security_operations selinu
   .file_send_sigiotask =  selinux_file_send_sigiotask,
   .file_receive = selinux_file_receive,
  
 + .dentry_open =  selinux_dentry_open,
 +
   .task_create =  selinux_task_create,
   .task_alloc_security =  selinux_task_alloc_security,
   .task_free_security =   selinux_task_free_security,
 diff -purN -X linux-2.6.22/Documentation/dontdiff 
 linux-2.6.22.orig/security/selinux/include/avc.h 
 linux-2.6.22/security/selinux/include/avc.h
 --- linux-2.6.22.orig/security/selinux/include/avc.h  2007-07-09 
 08:32:17.0 +0900
 +++ linux-2.6.22/security/selinux/include/avc.h   2007-09-10 
 09:56:22.0 +0900
 @@ -110,6 +110,8 @@ int avc_has_perm(u32 ssid, u32 tsid,
   u16 tclass, u32 requested,
   struct avc_audit_data *auditdata);
  
 +u32 avc_policy_seqno(void);
 +
  #define AVC_CALLBACK_GRANT   1
  #define AVC_CALLBACK_TRY_REVOKE 

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-09 Thread Yuichi Nakamura
On Thu, 06 Sep 2007 09:47:15 -0400
Stephen Smalley  wrote:

> >  
> > @@ -431,8 +432,10 @@ static int avc_latest_notif_update(int s
> > ret = -EAGAIN;
> > }
> > } else {
> > -   if (seqno > avc_cache.latest_notif)
> > +   if (seqno > avc_cache.latest_notif) {
> > avc_cache.latest_notif = seqno;
> > +   policy_seqno = seqno;
> > +   }
> 
> I would have just provided an avc interface for obtaining the seqno,
> e.g.
> u32 avc_policy_seqno(void)
> {
>   return avc_cache.latest_notif;
> }
Fixed.


> 
> > }
> > spin_unlock_irqrestore(_lock, flag);
> >  
> > diff -purN -X linux-2.6.22/Documentation/dontdiff 
> > linux-2.6.22.orig/security/selinux/hooks.c 
> > linux-2.6.22/security/selinux/hooks.c
> > --- linux-2.6.22.orig/security/selinux/hooks.c  2007-07-09 
> > 08:32:17.0 +0900
> > +++ linux-2.6.22/security/selinux/hooks.c   2007-09-06 16:08:36.0 
> > +0900
> > @@ -84,6 +84,7 @@
> >  extern unsigned int policydb_loaded_version;
> >  extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
> >  extern int selinux_compat_net;
> > +extern u32 policy_seqno;
> 
> I think that they frown upon extern declarations in .c files (versus
> in .h files), so we don't want to add more - we ultimately should clean
> up what we presently have.
Removed policy_seqno.

> 
> >  
> >  #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
> >  int selinux_enforcing = 0;
> > @@ -220,6 +221,8 @@ static int file_alloc_security(struct fi
> >  
> > fsec->file = file;
> > fsec->sid = tsec->sid;
> > +   fsec->tsid = tsec->sid;
> 
> I'm not sure why we need the separate field here, as fsec->sid already
> holds the allocating task SID and doesn't change.
I see.
removed fsec->tsid.

> > +   fsec->pseqno = policy_seqno;
> 
> Not sure that you want to set the seqno here versus from your new hook,
> as it could conceivably change in between.
Fixed, pseqno is set in selinux_dentry_open.


> > fsec->fown_sid = tsec->sid;
> > file->f_security = fsec;
> >  
> > @@ -2458,7 +2461,7 @@ static int selinux_inode_listsecurity(st
> >  
> >  /* file security operations */
> >  
> > -static int selinux_file_permission(struct file *file, int mask)
> > +static int do_selinux_file_permission(struct file *file, int mask)
> 
> Might want to rename for clarity, e.g. 
> selinux_revalidate_file_permission or
> selinux_file_permission_slow (slow path) or
> something similar.
Renamed to selinux_revalidate_file_permission.


> 
> >  {
> > int rc;
> > struct inode *inode = file->f_path.dentry->d_inode;
> > @@ -2480,6 +2483,43 @@ static int selinux_file_permission(struc
> > return selinux_netlbl_inode_permission(inode, mask);
> >  }
> >  
> > +static int selinux_file_permission(struct file *file, int mask)
> > +{
> > +   struct inode *inode = file->f_path.dentry->d_inode;
> > +   struct task_security_struct *tsec = current->security;
> > +   struct file_security_struct *fsec = file->f_security;
> > +   struct inode_security_struct *isec = inode->i_security;
> > +
> > +   if (!mask) {
> > +   /* No permission to check.  Existence test. */
> > +   return 0;
> > +   }
> > +
> > +   if (tsec->sid != fsec->tsid) {
> > +   if (tsec->sid != fsec->sid) {
> > +   struct vfsmount *mnt = file->f_path.mnt;
> > +   struct dentry *dentry = file->f_path.dentry;
> > +   struct avc_audit_data ad;
> > +   int rc;
> > +   AVC_AUDIT_DATA_INIT(, FS);
> > +   ad.u.fs.mnt = mnt;
> > +   ad.u.fs.dentry = dentry;
> > +   rc = avc_has_perm(tsec->sid, fsec->sid,
> > + SECCLASS_FD,
> > + FD__USE,
> > + );
> > +   if (rc)
> > +   return rc;
> > +   }
> 
> Why inline the FD_USE check here given that you are falling back to the
> full function call anyway?  I also don't see why you separate this from
> the rest of the comparison - I'd just make it something like:
>   if (tsec->sid == fsec->sid && isec->sid == fsec->isid &&
>   avc_seqno() == fsec->seqno)
>   return selinux_netlbl_inode_permission(inode, mask);
>   return selinux_revalidate_file_permission(file, mask);
Thanks, I missed that.
FD_USE check is called in file_permission..
Fixed like you pointed out.


> >  static int selinux_file_alloc_security(struct file *file)
> >  {
> > return file_alloc_security(file);
> > @@ -2715,6 +2755,16 @@ static int selinux_file_receive(struct f
> > return file_has_perm(current, file, file_to_av(file));
> >  }
> >  
> > +static int selinux_dentry_open(struct file *file, int flags)
> > +{
> > +   struct file_security_struct *fsec;
> > +   struct inode_security_struct *isec;
> > +   fsec = file->f_security;
> > +   isec = 

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-09 Thread Yuichi Nakamura
On Thu, 06 Sep 2007 09:47:15 -0400
Stephen Smalley  wrote:
snip
   
  @@ -431,8 +432,10 @@ static int avc_latest_notif_update(int s
  ret = -EAGAIN;
  }
  } else {
  -   if (seqno  avc_cache.latest_notif)
  +   if (seqno  avc_cache.latest_notif) {
  avc_cache.latest_notif = seqno;
  +   policy_seqno = seqno;
  +   }
 
 I would have just provided an avc interface for obtaining the seqno,
 e.g.
 u32 avc_policy_seqno(void)
 {
   return avc_cache.latest_notif;
 }
Fixed.


 
  }
  spin_unlock_irqrestore(notif_lock, flag);
   
  diff -purN -X linux-2.6.22/Documentation/dontdiff 
  linux-2.6.22.orig/security/selinux/hooks.c 
  linux-2.6.22/security/selinux/hooks.c
  --- linux-2.6.22.orig/security/selinux/hooks.c  2007-07-09 
  08:32:17.0 +0900
  +++ linux-2.6.22/security/selinux/hooks.c   2007-09-06 16:08:36.0 
  +0900
  @@ -84,6 +84,7 @@
   extern unsigned int policydb_loaded_version;
   extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
   extern int selinux_compat_net;
  +extern u32 policy_seqno;
 
 I think that they frown upon extern declarations in .c files (versus
 in .h files), so we don't want to add more - we ultimately should clean
 up what we presently have.
Removed policy_seqno.

 
   
   #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
   int selinux_enforcing = 0;
  @@ -220,6 +221,8 @@ static int file_alloc_security(struct fi
   
  fsec-file = file;
  fsec-sid = tsec-sid;
  +   fsec-tsid = tsec-sid;
 
 I'm not sure why we need the separate field here, as fsec-sid already
 holds the allocating task SID and doesn't change.
I see.
removed fsec-tsid.

  +   fsec-pseqno = policy_seqno;
 
 Not sure that you want to set the seqno here versus from your new hook,
 as it could conceivably change in between.
Fixed, pseqno is set in selinux_dentry_open.


  fsec-fown_sid = tsec-sid;
  file-f_security = fsec;
   
  @@ -2458,7 +2461,7 @@ static int selinux_inode_listsecurity(st
   
   /* file security operations */
   
  -static int selinux_file_permission(struct file *file, int mask)
  +static int do_selinux_file_permission(struct file *file, int mask)
 
 Might want to rename for clarity, e.g. 
 selinux_revalidate_file_permission or
 selinux_file_permission_slow (slow path) or
 something similar.
Renamed to selinux_revalidate_file_permission.


 
   {
  int rc;
  struct inode *inode = file-f_path.dentry-d_inode;
  @@ -2480,6 +2483,43 @@ static int selinux_file_permission(struc
  return selinux_netlbl_inode_permission(inode, mask);
   }
   
  +static int selinux_file_permission(struct file *file, int mask)
  +{
  +   struct inode *inode = file-f_path.dentry-d_inode;
  +   struct task_security_struct *tsec = current-security;
  +   struct file_security_struct *fsec = file-f_security;
  +   struct inode_security_struct *isec = inode-i_security;
  +
  +   if (!mask) {
  +   /* No permission to check.  Existence test. */
  +   return 0;
  +   }
  +
  +   if (tsec-sid != fsec-tsid) {
  +   if (tsec-sid != fsec-sid) {
  +   struct vfsmount *mnt = file-f_path.mnt;
  +   struct dentry *dentry = file-f_path.dentry;
  +   struct avc_audit_data ad;
  +   int rc;
  +   AVC_AUDIT_DATA_INIT(ad, FS);
  +   ad.u.fs.mnt = mnt;
  +   ad.u.fs.dentry = dentry;
  +   rc = avc_has_perm(tsec-sid, fsec-sid,
  + SECCLASS_FD,
  + FD__USE,
  + ad);
  +   if (rc)
  +   return rc;
  +   }
 
 Why inline the FD_USE check here given that you are falling back to the
 full function call anyway?  I also don't see why you separate this from
 the rest of the comparison - I'd just make it something like:
   if (tsec-sid == fsec-sid  isec-sid == fsec-isid 
   avc_seqno() == fsec-seqno)
   return selinux_netlbl_inode_permission(inode, mask);
   return selinux_revalidate_file_permission(file, mask);
Thanks, I missed that.
FD_USE check is called in file_permission..
Fixed like you pointed out.


   static int selinux_file_alloc_security(struct file *file)
   {
  return file_alloc_security(file);
  @@ -2715,6 +2755,16 @@ static int selinux_file_receive(struct f
  return file_has_perm(current, file, file_to_av(file));
   }
   
  +static int selinux_dentry_open(struct file *file, int flags)
  +{
  +   struct file_security_struct *fsec;
  +   struct inode_security_struct *isec;
  +   fsec = file-f_security;
  +   isec = file-f_path.dentry-d_inode-i_security;
  +   fsec-isid = isec-sid;
 
 Set the seqno here too.  Ideally, it would come straight from the AVC
 entry that was used for the open-time check, but that is a bit more
 invasive and there will always 

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-06 Thread Stephen Smalley
On Thu, 2007-09-06 at 16:27 +0900, Yuichi Nakamura wrote:
> Hello.
> 
> As I posted before in selinux list,
> I found big overhead of SELinux in read/write on some CPUs,
> and trying tuning.
> There were discussion in previous threads.
> Part 1:
> http://marc.info/?t=11884534341=1=2
> Part 2:
> http://marc.info/?t=11888074984=1=2
> 
> I would like to RFC again about this topic.

Thanks for your work on this, as this is clearly an important area to
improve.

> 1. Background
> Look at benchmark result below.
> lmbench simple read/write.
> Big overhead exists especially on SH(SuperH) arch.
> 
> 1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
> Base  SELinux  Overhead(%)
> Simple read 1.10  1.24 12.3
> Simple write1.00  1.14 14.0
> * Base: kernel compiled without SELinux support
> 
> 2) Result for SH(SH4, SH7751R), kernel 2.6.22
> BaseSELinux   Overhead(%)
> Simple read 2.395.49  130.5
> Simple write2.075.10  146.6
> # This result is a little different from previous threads, 
> # because I changed some kernel configs.
> 
> Overhead more than 100%
> I also found about 70-90% overhead in ARM.
> 
> 2. About patch
> I found a overhead in selinux_file_permission function.
> This is a function that is called in read/write calls, 
> and does SELinux permission check.
> SELinux checks permission both in open and read/write time.
> Stephen Smalley sugessted that we can usually skip permission check 
> in selinux_file_permission.
> By this patch, 
> permission check in selinux_file_permssion is done only when
> - sid of task has changed after file open
> - sid of inode has changed after file open
> - policy load or boolean change happen after file open
> 
> To detect these changes,
> I added entries in file_security struct and saving these values at file open.
> 
> And to save sid of inode at the time of file open,
> I had to add new LSM hook in __dentry_open function.
> 
> 3. Benchmark after applying this patch
> 1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
> Base  SELinux  Overhead(%)
> Simple read 1.10  1.12 1.6(Before 12.3)
> Simple write1.00  1.03 3.6(Before 14.0)
> 
> 2) Result for SH(SH4, SH7751R), kernel 2.6.22
> BaseSELinux   Overhead(%)
> Simple read 2.392.65  11.1(Before 130.5)
> Simple write2.072.28  10.5(Before 146.6)
> 
> Performance has improved a lot.
> I want comments from community.
> 
> Signed-off-by: Yuichi Nakamura<[EMAIL PROTECTED]>
> ---
>  fs/open.c |5 +++
>  include/linux/security.h  |   11 +++
>  security/selinux/avc.c|5 ++-
>  security/selinux/hooks.c  |   54 
> +-
>  security/selinux/include/objsec.h |3 ++
>  5 files changed, 76 insertions(+), 2 deletions(-)
> diff -purN -X linux-2.6.22/Documentation/dontdiff 
> linux-2.6.22.orig/security/selinux/avc.c linux-2.6.22/security/selinux/avc.c
> --- linux-2.6.22.orig/security/selinux/avc.c  2007-07-09 08:32:17.0 
> +0900
> +++ linux-2.6.22/security/selinux/avc.c   2007-09-06 14:33:35.0 
> +0900
> @@ -123,6 +123,7 @@ DEFINE_PER_CPU(struct avc_cache_stats, a
>  #endif
>  
>  static struct avc_cache avc_cache;
> +u32 policy_seqno = 0;
>  static struct avc_callback_node *avc_callbacks;
>  static struct kmem_cache *avc_node_cachep;
>  
> @@ -431,8 +432,10 @@ static int avc_latest_notif_update(int s
>   ret = -EAGAIN;
>   }
>   } else {
> - if (seqno > avc_cache.latest_notif)
> + if (seqno > avc_cache.latest_notif) {
>   avc_cache.latest_notif = seqno;
> + policy_seqno = seqno;
> + }

I would have just provided an avc interface for obtaining the seqno,
e.g.
u32 avc_policy_seqno(void)
{
return avc_cache.latest_notif;
}

>   }
>   spin_unlock_irqrestore(_lock, flag);
>  
> diff -purN -X linux-2.6.22/Documentation/dontdiff 
> linux-2.6.22.orig/security/selinux/hooks.c 
> linux-2.6.22/security/selinux/hooks.c
> --- linux-2.6.22.orig/security/selinux/hooks.c2007-07-09 
> 08:32:17.0 +0900
> +++ linux-2.6.22/security/selinux/hooks.c 2007-09-06 16:08:36.0 
> +0900
> @@ -84,6 +84,7 @@
>  extern unsigned int policydb_loaded_version;
>  extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
>  extern int selinux_compat_net;
> +extern u32 policy_seqno;

I think that they frown upon extern declarations in .c files (versus
in .h files), so we don't want to add more - we ultimately should clean
up what we presently have.

>  
>  #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
>  int selinux_enforcing = 0;
> @@ -220,6 +221,8 @@ static int file_alloc_security(struct fi
>  
>   fsec->file = file;
>   fsec->sid = tsec->sid;
> + fsec->tsid = tsec->sid;

I'm not sure why we need the separate field here, as 

[RFC]selinux: Improving SELinux read/write performance

2007-09-06 Thread Yuichi Nakamura
Hello.

As I posted before in selinux list,
I found big overhead of SELinux in read/write on some CPUs,
and trying tuning.
There were discussion in previous threads.
Part 1:
http://marc.info/?t=11884534341=1=2
Part 2:
http://marc.info/?t=11888074984=1=2

I would like to RFC again about this topic.

1. Background
Look at benchmark result below.
lmbench simple read/write.
Big overhead exists especially on SH(SuperH) arch.

1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
Base  SELinux  Overhead(%)
Simple read 1.10  1.24 12.3
Simple write1.00  1.14 14.0
* Base: kernel compiled without SELinux support

2) Result for SH(SH4, SH7751R), kernel 2.6.22
BaseSELinux   Overhead(%)
Simple read 2.395.49  130.5
Simple write2.075.10  146.6
# This result is a little different from previous threads, 
# because I changed some kernel configs.

Overhead more than 100%
I also found about 70-90% overhead in ARM.

2. About patch
I found a overhead in selinux_file_permission function.
This is a function that is called in read/write calls, 
and does SELinux permission check.
SELinux checks permission both in open and read/write time.
Stephen Smalley sugessted that we can usually skip permission check 
in selinux_file_permission.
By this patch, 
permission check in selinux_file_permssion is done only when
- sid of task has changed after file open
- sid of inode has changed after file open
- policy load or boolean change happen after file open

To detect these changes,
I added entries in file_security struct and saving these values at file open.

And to save sid of inode at the time of file open,
I had to add new LSM hook in __dentry_open function.

3. Benchmark after applying this patch
1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
Base  SELinux  Overhead(%)
Simple read 1.10  1.12 1.6(Before 12.3)
Simple write1.00  1.03 3.6(Before 14.0)

2) Result for SH(SH4, SH7751R), kernel 2.6.22
BaseSELinux   Overhead(%)
Simple read 2.392.65  11.1(Before 130.5)
Simple write2.072.28  10.5(Before 146.6)

Performance has improved a lot.
I want comments from community.

Signed-off-by: Yuichi Nakamura<[EMAIL PROTECTED]>
---
 fs/open.c |5 +++
 include/linux/security.h  |   11 +++
 security/selinux/avc.c|5 ++-
 security/selinux/hooks.c  |   54 +-
 security/selinux/include/objsec.h |3 ++
 5 files changed, 76 insertions(+), 2 deletions(-)
diff -purN -X linux-2.6.22/Documentation/dontdiff 
linux-2.6.22.orig/security/selinux/avc.c linux-2.6.22/security/selinux/avc.c
--- linux-2.6.22.orig/security/selinux/avc.c2007-07-09 08:32:17.0 
+0900
+++ linux-2.6.22/security/selinux/avc.c 2007-09-06 14:33:35.0 +0900
@@ -123,6 +123,7 @@ DEFINE_PER_CPU(struct avc_cache_stats, a
 #endif
 
 static struct avc_cache avc_cache;
+u32 policy_seqno = 0;
 static struct avc_callback_node *avc_callbacks;
 static struct kmem_cache *avc_node_cachep;
 
@@ -431,8 +432,10 @@ static int avc_latest_notif_update(int s
ret = -EAGAIN;
}
} else {
-   if (seqno > avc_cache.latest_notif)
+   if (seqno > avc_cache.latest_notif) {
avc_cache.latest_notif = seqno;
+   policy_seqno = seqno;
+   }
}
spin_unlock_irqrestore(_lock, flag);
 
diff -purN -X linux-2.6.22/Documentation/dontdiff 
linux-2.6.22.orig/security/selinux/hooks.c linux-2.6.22/security/selinux/hooks.c
--- linux-2.6.22.orig/security/selinux/hooks.c  2007-07-09 08:32:17.0 
+0900
+++ linux-2.6.22/security/selinux/hooks.c   2007-09-06 16:08:36.0 
+0900
@@ -84,6 +84,7 @@
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
 extern int selinux_compat_net;
+extern u32 policy_seqno;
 
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 int selinux_enforcing = 0;
@@ -220,6 +221,8 @@ static int file_alloc_security(struct fi
 
fsec->file = file;
fsec->sid = tsec->sid;
+   fsec->tsid = tsec->sid;
+   fsec->pseqno = policy_seqno;
fsec->fown_sid = tsec->sid;
file->f_security = fsec;
 
@@ -2458,7 +2461,7 @@ static int selinux_inode_listsecurity(st
 
 /* file security operations */
 
-static int selinux_file_permission(struct file *file, int mask)
+static int do_selinux_file_permission(struct file *file, int mask)
 {
int rc;
struct inode *inode = file->f_path.dentry->d_inode;
@@ -2480,6 +2483,43 @@ static int selinux_file_permission(struc
return selinux_netlbl_inode_permission(inode, mask);
 }
 
+static int selinux_file_permission(struct file *file, int mask)
+{
+   struct inode *inode = file->f_path.dentry->d_inode;
+   struct task_security_struct *tsec = current->security;
+  

Re: [RFC]selinux: Improving SELinux read/write performance

2007-09-06 Thread Stephen Smalley
On Thu, 2007-09-06 at 16:27 +0900, Yuichi Nakamura wrote:
 Hello.
 
 As I posted before in selinux list,
 I found big overhead of SELinux in read/write on some CPUs,
 and trying tuning.
 There were discussion in previous threads.
 Part 1:
 http://marc.info/?t=11884534341r=1w=2
 Part 2:
 http://marc.info/?t=11888074984r=1w=2
 
 I would like to RFC again about this topic.

Thanks for your work on this, as this is clearly an important area to
improve.

 1. Background
 Look at benchmark result below.
 lmbench simple read/write.
 Big overhead exists especially on SH(SuperH) arch.
 
 1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
 Base  SELinux  Overhead(%)
 Simple read 1.10  1.24 12.3
 Simple write1.00  1.14 14.0
 * Base: kernel compiled without SELinux support
 
 2) Result for SH(SH4, SH7751R), kernel 2.6.22
 BaseSELinux   Overhead(%)
 Simple read 2.395.49  130.5
 Simple write2.075.10  146.6
 # This result is a little different from previous threads, 
 # because I changed some kernel configs.
 
 Overhead more than 100%
 I also found about 70-90% overhead in ARM.
 
 2. About patch
 I found a overhead in selinux_file_permission function.
 This is a function that is called in read/write calls, 
 and does SELinux permission check.
 SELinux checks permission both in open and read/write time.
 Stephen Smalley sugessted that we can usually skip permission check 
 in selinux_file_permission.
 By this patch, 
 permission check in selinux_file_permssion is done only when
 - sid of task has changed after file open
 - sid of inode has changed after file open
 - policy load or boolean change happen after file open
 
 To detect these changes,
 I added entries in file_security struct and saving these values at file open.
 
 And to save sid of inode at the time of file open,
 I had to add new LSM hook in __dentry_open function.
 
 3. Benchmark after applying this patch
 1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
 Base  SELinux  Overhead(%)
 Simple read 1.10  1.12 1.6(Before 12.3)
 Simple write1.00  1.03 3.6(Before 14.0)
 
 2) Result for SH(SH4, SH7751R), kernel 2.6.22
 BaseSELinux   Overhead(%)
 Simple read 2.392.65  11.1(Before 130.5)
 Simple write2.072.28  10.5(Before 146.6)
 
 Performance has improved a lot.
 I want comments from community.
 
 Signed-off-by: Yuichi Nakamura[EMAIL PROTECTED]
 ---
  fs/open.c |5 +++
  include/linux/security.h  |   11 +++
  security/selinux/avc.c|5 ++-
  security/selinux/hooks.c  |   54 
 +-
  security/selinux/include/objsec.h |3 ++
  5 files changed, 76 insertions(+), 2 deletions(-)
 diff -purN -X linux-2.6.22/Documentation/dontdiff 
 linux-2.6.22.orig/security/selinux/avc.c linux-2.6.22/security/selinux/avc.c
 --- linux-2.6.22.orig/security/selinux/avc.c  2007-07-09 08:32:17.0 
 +0900
 +++ linux-2.6.22/security/selinux/avc.c   2007-09-06 14:33:35.0 
 +0900
 @@ -123,6 +123,7 @@ DEFINE_PER_CPU(struct avc_cache_stats, a
  #endif
  
  static struct avc_cache avc_cache;
 +u32 policy_seqno = 0;
  static struct avc_callback_node *avc_callbacks;
  static struct kmem_cache *avc_node_cachep;
  
 @@ -431,8 +432,10 @@ static int avc_latest_notif_update(int s
   ret = -EAGAIN;
   }
   } else {
 - if (seqno  avc_cache.latest_notif)
 + if (seqno  avc_cache.latest_notif) {
   avc_cache.latest_notif = seqno;
 + policy_seqno = seqno;
 + }

I would have just provided an avc interface for obtaining the seqno,
e.g.
u32 avc_policy_seqno(void)
{
return avc_cache.latest_notif;
}

   }
   spin_unlock_irqrestore(notif_lock, flag);
  
 diff -purN -X linux-2.6.22/Documentation/dontdiff 
 linux-2.6.22.orig/security/selinux/hooks.c 
 linux-2.6.22/security/selinux/hooks.c
 --- linux-2.6.22.orig/security/selinux/hooks.c2007-07-09 
 08:32:17.0 +0900
 +++ linux-2.6.22/security/selinux/hooks.c 2007-09-06 16:08:36.0 
 +0900
 @@ -84,6 +84,7 @@
  extern unsigned int policydb_loaded_version;
  extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
  extern int selinux_compat_net;
 +extern u32 policy_seqno;

I think that they frown upon extern declarations in .c files (versus
in .h files), so we don't want to add more - we ultimately should clean
up what we presently have.

  
  #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
  int selinux_enforcing = 0;
 @@ -220,6 +221,8 @@ static int file_alloc_security(struct fi
  
   fsec-file = file;
   fsec-sid = tsec-sid;
 + fsec-tsid = tsec-sid;

I'm not sure why we need the separate field here, as fsec-sid already
holds the allocating task SID and doesn't change.

 + fsec-pseqno = policy_seqno;

Not sure that you want