selinux: Improving SELinux read/write performance
Subsystems (3)
RFC 1/1 selinux: Improving SELinux read/write performance
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=118845343400001&r=1&w=2
Part 2:
http://marc.info/?t=118880749800004&r=1&w=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 write 1.00 1.14 14.0
* Base: kernel compiled without SELinux support
2) Result for SH(SH4, SH7751R), kernel 2.6.22
Base SELinux Overhead(%) Simple read 2.39 5.49 130.5 Simple write 2.07 5.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 write 1.00 1.03 3.6(Before 14.0)
2) Result for SH(SH4, SH7751R), kernel 2.6.22
Base SELinux Overhead(%) Simple read 2.39 2.65 11.1(Before 130.5) Simple write 2.07 2.28 10.5(Before 146.6)
Performance has improved a lot.
I want comments from community.
--- 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(-)
security/selinux/avc.c +4 -1
@@ -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 (¬if_lock, flag);
security/selinux/hooks.c +53 -1
90 lines not on this page · raw message
security/selinux/include/objsec.h +3 -0
@@ -53,6 +53,9 @@ struct file_security_struct {struct file *file;/* back pointer to file object */ u32 sid;/* SID of open file description */ u32 fown_sid;/* SID of file owner (for SIGIO) */ +u32 tsid;/* SID of task at the time of file open*/ +u32 isid;/* SID of inode at the time of file open */ +u32 pseqno;/* Policy seqno at the time of file open */ };struct superblock_security_struct {
fs/open.c +5 -0
@@ -698,6 +698,11 @@ static struct file *__dentry_open(structif (!open && f->f_op) open = f->f_op->open; + + error =security_dentry_open (f, flags); +if (error) + goto cleanup_all; +if (open) { error =open (inode, f);if (error)
include/linux/security.h +11 -0
@@ -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. +* * Security hooks for task operations. * * @task_create:
@@ -1253,6 +1258,7 @@ struct security_operations {int (*file_send_sigiotask) (struct task_struct * tsk,struct fown_struct * fown,int sig);int (*file_receive) (struct file * file); +int (*dentry_open) (struct file *file,int flags);int (*task_create) (unsigned long clone_flags);int (*task_alloc_security) (struct task_struct * p);
@@ -1854,6 +1860,11 @@ static inline int security_file_receivereturn security_ops->file_receive (file); } +static inline int security_dentry_open (struct file *file,int flags) +{ +return security_ops->dentry_open (file, flags); +} +static inline int security_task_create (unsigned long clone_flags) {return security_ops->task_create (clone_flags);
Regards,
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 11 lines · 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=118845343400001&r=1&w=2
Part 2:
http://marc.info/?t=118880749800004&r=1&w=2
Quoted 1 line
I would like to RFC again about this topic.
Thanks for your work on this, as this is clearly an important area to improve.
Quoted 74 lines
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 write 1.00 1.14 14.0* Base: kernel compiled without SELinux support
2) Result for
SH(SH4, SH7751R), kernel 2.6.22Base SELinux Overhead(%) Simple read 2.39 5.49 130.5 Simple write 2.07 5.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 inselinux_file_permissionfunction. 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 inselinux_file_permission.
By this patch,
permission check inselinux_file_permssionis 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 openTo detect these changes,
I added entries infile_securitystruct 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_openfunction.3. Benchmark after applying this patch
1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22Base SELinux Overhead(%) Simple read 1.10 1.12 1.6(Before 12.3) Simple write 1.00 1.03 3.6(Before 14.0)2) Result for
SH(SH4, SH7751R), kernel 2.6.22Base SELinux Overhead(%) Simple read 2.39 2.65 11.1(Before 130.5) Simple write 2.07 2.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.clinux-2.6.22/security/selinux/avc.csecurity/selinux/avc.c +1
-0@@ -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;
security/selinux/avc.c static int avc_latest_notif_update(int s · line 438
Quoted 8 lines
security/selinux/avc.c +3
-1@@ -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;
}security/selinux/hooks.c line 87
Quoted 11 lines
security/selinux/avc.c +0
-0}spin_unlock_irqrestore (¬if_lock, flag);diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/hooks.clinux-2.6.22/security/selinux/hooks.csecurity/selinux/hooks.c +1
-0@@ -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.
security/selinux/hooks.c static int file_alloc_security(struct fi · line 224
Quoted 8 lines
security/selinux/hooks.c +1
-0#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.
security/selinux/hooks.c static int file_alloc_security(struct fi · line 225
Quoted 1 line
security/selinux/hooks.c +1
-0+ 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.
security/selinux/hooks.c static int selinux_inode_listsecurity(st · line 2464
Quoted 9 lines
security/selinux/hooks.c +1
-1fsec->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 orselinux_file_permission_slow (slow path) or
something similar.
Quoted 25 lines
security/selinux/hooks.c +18
-0{int rc;struct inode *inode = file->f_path.dentry->d_inode;@@ -2480,6 +2483,43 @@ static int selinux_file_permission(strucreturn 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;
security/selinux/hooks.c static int selinux_file_permission(struc · line 2513
Quoted 10 lines
security/selinux/hooks.c +10
-0+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);
Quoted 4 lines
security/selinux/hooks.c +0
-0static int selinux_file_alloc_security (struct file *file) {return file_alloc_security (file);
security/selinux/hooks.c static int selinux_file_receive(struct f · line 2764
Quoted 10 lines
security/selinux/hooks.c +7
-0@@ -2715,6 +2755,16 @@ static int selinux_file_receive(struct freturn 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 be a small window there.
security/selinux/include/objsec.h struct file_security_struct { · line 58
Quoted 10 lines
diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/include/objsec.hlinux-2.6.22/security/selinux/include/objsec.hsecurity/selinux/include/objsec.h +3
-0@@ -53,6 +53,9 @@ struct file_security_struct {struct file *file;/* back pointer to file object */ u32 sid;/* SID of open file description */ u32 fown_sid;/* SID of file owner (for SIGIO) */ +u32 tsid;/* SID of task at the time of file open*/ +u32 isid;/* SID of inode at the time of file open */ +u32 pseqno;/* Policy seqno at the time of file open */
No need for tsid above I think.
Quoted 25 lines
diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/include/linux/security.hlinux-2.6.22/include/linux/security.hinclude/linux/security.h +6
-0@@ -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. +* * Security hooks for task operations. * * @task_create: @@ -1253,6 +1258,7 @@ struct security_operations {int (*file_send_sigiotask) (struct task_struct * tsk,struct fown_struct * fown,int sig);int (*file_receive) (struct file * file); +int (*dentry_open) (struct file *file,int flags);int (*task_create) (unsigned long clone_flags);int (*task_alloc_security) (struct task_struct * p);@@ -1854,6 +1860,11 @@ static inline int security_file_receivereturn security_ops->file_receive (file);
include/linux/security.h static inline int security_file_receive · line 1870
Quoted 10 lines
include/linux/security.h +5
-0} +static inline int security_dentry_open (struct file *file,int flags) +{ +return security_ops->dentry_open (file, flags); +} +static inline int security_task_create (unsigned long clone_flags) {return security_ops->task_create (clone_flags);
Need to also provide the stub definition in the #else case (SECURITY=n) and a stub function for the dummy security module.
Thanks.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
On Thu, 06 Sep 2007 09:47:15 -0400
Stephen Smalley wrote:
<snip>
Quoted 14 lines
Review static int avc_latest_notif_update(int s · line 438
Quoted 10 lines
(quoted diff) +3
-1@@ -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.
u32avc_policy_seqno(void)
Quoted 3 lines
{
return avc_cache.latest_notif;
}Fixed.
Quoted 4 lines
Quoted 4 lines
(quoted diff) +0
-0} spin_unlock_irqrestore(¬if_lock, flag);
Quoted 12 lines
security/selinux/hooks.c line 87
Quoted 8 lines
diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/hooks.clinux-2.6.22/security/selinux/hooks.csecurity/selinux/hooks.c +1
-0@@ -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.
Quoted 6 lines
Quoted 6 lines
security/selinux/hooks.c +0
-0#ifdef CONFIG_SECURITY_SELINUX_DEVELOP int selinux_enforcing =0 ;@@ -220,6 +221,8 @@ static int file_alloc_security(struct fi
Quoted 6 lines
security/selinux/hooks.c static int file_alloc_security(struct fi · line 224
Quoted 3 lines
security/selinux/hooks.c +1
-0fsec->file = file; fsec->sid = tsec->sid; + fsec->tsid = tsec->sid;I'm not sure why we need the separate field here, as
fsec->sidalready holds the allocating task SID and doesn't change.
I see.
removed fsec->tsid.
Quoted 4 lines
security/selinux/hooks.c static int file_alloc_security(struct fi · line 225
Quoted 1 line
security/selinux/hooks.c +1
-0+ 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.
Quoted 7 lines
Quoted 7 lines
security/selinux/hooks.c +0
-0fsec->fown_sid = tsec->sid; file->f_security = fsec;@@ -2458,7 +2461,7 @@ static int selinux_inode_listsecurity(st/* file security operations */
Quoted 7 lines
security/selinux/hooks.c static int selinux_inode_listsecurity(st · line 2464
Quoted 2 lines
security/selinux/hooks.c +1
-1-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_permissionorselinux_file_permission_slow(slow path) or
something similar.
Renamed to selinux_revalidate_file_permission.
Quoted 40 lines
Quoted 26 lines
security/selinux/hooks.c +18
-0{int rc;struct inode *inode = file->f_path.dentry->d_inode;@@ -2480,6 +2483,43 @@ static int selinux_file_permission(strucreturn 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;security/selinux/hooks.c static int selinux_file_permission(struc · line 2513
Quoted 10 lines
security/selinux/hooks.c +10
-0+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_USEcheck 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:
Quoted 4 lines
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.
Quoted 7 lines
Quoted 7 lines
security/selinux/hooks.c +0
-0static int selinux_file_alloc_security (struct file *file) {return file_alloc_security (file);@@ -2715,6 +2755,16 @@ static int selinux_file_receive(struct freturn file_has_perm (current, file,file_to_av (file)); }
Quoted 11 lines
security/selinux/hooks.c static int selinux_file_receive(struct f · line 2764
Quoted 7 lines
security/selinux/hooks.c +7
-0+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 be a small window there.
Fixed, setting pseqno now.
Quoted 4 lines
Quoted 4 lines
diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/include/objsec.hlinux-2.6.22/security/selinux/include/objsec.hsecurity/selinux/include/objsec.h +0
-0@@ -53,6 +53,9 @@ struct file_security_struct {
Quoted 8 lines
security/selinux/include/objsec.h struct file_security_struct { · line 58
Quoted 6 lines
security/selinux/include/objsec.h +3
-0struct file *file;/* back pointer to file object */ u32 sid;/* SID of open file description */ u32 fown_sid;/* SID of file owner (for SIGIO) */ +u32 tsid;/* SID of task at the time of file open*/ +u32 isid;/* SID of inode at the time of file open */ +u32 pseqno;/* Policy seqno at the time of file open */ No need for tsid above I think.
Removed tsid.
Quoted 27 lines
Quoted 27 lines
diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/include/linux/security.hlinux-2.6.22/include/linux/security.hinclude/linux/security.h +6
-0@@ -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. +* * Security hooks for task operations. * * @task_create: @@ -1253,6 +1258,7 @@ struct security_operations {int (*file_send_sigiotask) (struct task_struct * tsk,struct fown_struct * fown,int sig);int (*file_receive) (struct file * file); +int (*dentry_open) (struct file *file,int flags);int (*task_create) (unsigned long clone_flags);int (*task_alloc_security) (struct task_struct * p);@@ -1854,6 +1860,11 @@ static inline int security_file_receivereturn security_ops->file_receive (file); }
Quoted 11 lines
include/linux/security.h static inline int security_file_receive · line 1870
Quoted 8 lines
include/linux/security.h +5
-0+static inline int security_dentry_open (struct file *file,int flags) +{ +return security_ops->dentry_open (file, flags); +} +static inline int security_task_create (unsigned long clone_flags) {return security_ops->task_create (clone_flags);Need to also provide the stub definition in the #else case (SECURITY=n) and a stub function for the dummy security module.
Fixed.
Quoted 6 lines
Thanks.
Signature · 2 lines
Stephen Smalley National Security Agency
Next is updated patch.
--- 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(-)
security/selinux/avc.c +5 -0
@@ -913,3 +913,8 @@ int avc_has_perm(u32 ssid, u32 tsid, u16avc_audit (ssid, tsid, tclass, requested, &avd, rc, auditdata);return rc; } + +u32 avc_policy_seqno (void ) +{ +return avc_cache.latest_notif; +}
security/selinux/hooks.c +35 -1
@@ -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(strucreturn 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 freturn 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,
security/selinux/include/avc.h +2 -0
@@ -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 2#define AVC_CALLBACK_REVOKE 4
security/selinux/include/objsec.h +2 -0
@@ -53,6 +53,8 @@ struct file_security_struct {struct file *file;/* back pointer to file object */ u32 sid;/* SID of open file description */ u32 fown_sid;/* SID of file owner (for SIGIO) */ +u32 isid;/* SID of inode at the time of file open */ +u32 pseqno;/* Policy seqno at the time of file open */ };struct superblock_security_struct {
fs/open.c +5 -0
@@ -698,6 +698,11 @@ static struct file *__dentry_open(structif (!open && f->f_op) open = f->f_op->open; + + error =security_dentry_open (f, flags); +if (error) + goto cleanup_all; +if (open) { error =open (inode, f);if (error)
include/linux/security.h +16 -0
@@ -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. +* * Security hooks for task operations. * * @task_create:
@@ -1253,6 +1258,7 @@ struct security_operations {int (*file_send_sigiotask) (struct task_struct * tsk,struct fown_struct * fown,int sig);int (*file_receive) (struct file * file); +int (*dentry_open) (struct file *file,int flags);int (*task_create) (unsigned long clone_flags);int (*task_alloc_security) (struct task_struct * p);
@@ -1854,6 +1860,11 @@ static inline int security_file_receivereturn security_ops->file_receive (file); } +static inline int security_dentry_open (struct file *file,int flags) +{ +return security_ops->dentry_open (file, flags); +} +static inline int security_task_create (unsigned long clone_flags) {return security_ops->task_create (clone_flags);
@@ -2529,6 +2540,11 @@ static inline int security_file_receivereturn 0 ; } +static inline int security_dentry_open (struct file *file,int flags) +{ +return 0 ; +} +static inline int security_task_create (unsigned long clone_flags) {return 0 ;
Regards,
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 1 line · Yuichi Nakamura
Next is updated patch.
Thanks.
Please include the short description of the patch though when re-submitting.
Quoted 9 lines
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?
Quoted 174 lines
diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/avc.clinux-2.6.22/security/selinux/avc.csecurity/selinux/avc.c +5
-0@@ -913,3 +913,8 @@ int avc_has_perm(u32 ssid, u32 tsid, u16avc_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.clinux-2.6.22/security/selinux/hooks.csecurity/selinux/hooks.c +35
-1@@ -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(strucreturn 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 freturn 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.hlinux-2.6.22/security/selinux/include/avc.hsecurity/selinux/include/avc.h +2
-0@@ -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 2#define AVC_CALLBACK_REVOKE 4diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/include/objsec.hlinux-2.6.22/security/selinux/include/objsec.hsecurity/selinux/include/objsec.h +2
-0@@ -53,6 +53,8 @@ struct file_security_struct {struct file *file;/* back pointer to file object */ u32 sid;/* SID of open file description */ u32 fown_sid;/* SID of file owner (for SIGIO) */ +u32 isid;/* SID of inode at the time of file open */ +u32 pseqno;/* Policy seqno at the time of file open */ };struct superblock_security_struct {diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/fs/open.clinux-2.6.22/fs/open.cfs/open.c +5
-0@@ -698,6 +698,11 @@ static struct file *__dentry_open(structif (!open && f->f_op) open = f->f_op->open; + + error =security_dentry_open (f, flags); +if (error) + goto cleanup_all; +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.hlinux-2.6.22/include/linux/security.hinclude/linux/security.h +16
-0@@ -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. +* * Security hooks for task operations. * * @task_create: @@ -1253,6 +1258,7 @@ struct security_operations {int (*file_send_sigiotask) (struct task_struct * tsk,struct fown_struct * fown,int sig);int (*file_receive) (struct file * file); +int (*dentry_open) (struct file *file,int flags);int (*task_create) (unsigned long clone_flags);int (*task_alloc_security) (struct task_struct * p);@@ -1854,6 +1860,11 @@ static inline int security_file_receivereturn security_ops->file_receive (file); } +static inline int security_dentry_open (struct file *file,int flags) +{ +return security_ops->dentry_open (file, flags); +} +static inline int security_task_create (unsigned long clone_flags) {return security_ops->task_create (clone_flags);@@ -2529,6 +2540,11 @@ static inline int security_file_receivereturn 0 ; } +static inline int security_dentry_open (struct file *file,int flags) +{ +return 0 ; +} +static inline int security_task_create (unsigned long clone_flags) {return 0 ;Regards,
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Hi.
Stephen Smalley pointed out possibility of race condition in off-list discussion.
Quoted 8 lines · Stephen Smalley
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 write 1.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
Base SELinux Overhead(%) Simple read 2.39 5.49 130.5 Simple write 2.07 5.10 146.6 open/close 32.6 62.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 write 1.02 1.024 0.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
Base SELinux Overhead(%) Simple read 2.39 2.63 10.4(Before 130.5) Simple write 2.07 2.34 13.1(Before 146.6) open/close 32.6 58.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.
--- 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(-)
security/selinux/avc.c +5 -0
@@ -913,3 +913,8 @@ int avc_has_perm(u32 ssid, u32 tsid, u16avc_audit (ssid, tsid, tclass, requested, &avd, rc, auditdata);return rc; } + +u32 avc_policy_seqno (void ) +{ +return avc_cache.latest_notif; +}
security/selinux/hooks.c +42 -1
79 lines not on this page · raw message
security/selinux/include/avc.h +2 -0
@@ -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 2#define AVC_CALLBACK_REVOKE 4
security/selinux/include/objsec.h +2 -0
@@ -53,6 +53,8 @@ struct file_security_struct {struct file *file;/* back pointer to file object */ u32 sid;/* SID of open file description */ u32 fown_sid;/* SID of file owner (for SIGIO) */ +u32 isid;/* SID of inode at the time of file open */ +u32 pseqno;/* Policy seqno at the time of file open */ };struct superblock_security_struct {
fs/open.c +5 -0
@@ -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; +if (open) { error =open (inode, f);if (error)
include/linux/security.h +16 -0
@@ -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. +* * Security hooks for task operations. * * @task_create:
@@ -1253,6 +1258,7 @@ struct security_operations {int (*file_send_sigiotask) (struct task_struct * tsk,struct fown_struct * fown,int sig);int (*file_receive) (struct file * file); +int (*dentry_open) (struct file *file);int (*task_create) (unsigned long clone_flags);int (*task_alloc_security) (struct task_struct * p);
@@ -1854,6 +1860,11 @@ static inline int security_file_receivereturn security_ops->file_receive (file); } +static inline int security_dentry_open (struct file *file) +{ +return security_ops->dentry_open (file); +} +static inline int security_task_create (unsigned long clone_flags) {return security_ops->task_create (clone_flags);
@@ -2529,6 +2540,11 @@ static inline int security_file_receivereturn 0 ; } +static inline int security_dentry_open (struct file *file) +{ +return 0 ; +} +static inline int security_task_create (unsigned long clone_flags) {return 0 ;
security/dummy.c +6 -0
@@ -459,6 +459,11 @@ static int dummy_file_receive (struct fireturn 0 ; } +static int dummy_dentry_open (struct file *file) +{ +return 0 ; +} +static int dummy_task_create (unsigned long clone_flags) {return 0 ;
@@ -1029,6 +1034,7 @@ void security_fixup_ops (struct securityset_to_dummy_if_null (ops, file_set_fowner);set_to_dummy_if_null (ops, file_send_sigiotask);set_to_dummy_if_null (ops, file_receive); +set_to_dummy_if_null (ops, dentry_open);set_to_dummy_if_null (ops, task_create);set_to_dummy_if_null (ops, task_alloc_security);set_to_dummy_if_null (ops, task_free_security);
Regards,
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 45 lines · Yuichi Nakamura
Hi.
Stephen Smalley pointed out possibility of race condition in off-list discussion.
Quoted 8 lines · Stephen Smalley
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.22Base SELinux Overhead(%) Simple read 1.10 1.24 12.3 Simple write 1.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.22Base SELinux Overhead(%) Simple read 2.39 5.49 130.5 Simple write 2.07 5.10 146.6 open/close 32.6 62.8 93.0* After tuning
1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22Base SELinux Overhead(%) Simple read 1.10 1.13 2.3(Before 12.3) Simple write 1.02 1.024 0.6(Before 14.0) open/close 5.97 7.48 25.3(Before 24.9)* Base: kernel compiled without SELinux support
Quoted 7 lines
2) Result for
SH(SH4, SH7751R), kernel 2.6.22Base SELinux Overhead(%) Simple read 2.39 2.63 10.4(Before 130.5) Simple write 2.07 2.34 13.1(Before 146.6) open/close 32.6 58.7 80.2(before 93.0)Next is a patch.
Thanks, a few comments below.
Quoted 7 lines
* Description of patch
This patch improves performance of read/write in SELinux. It improves performance by skipping permission check inselinux_file_permission. Permission is only checked when sid change or policy load is detected after file open. To detect sid change, new LSM hooksecuriy_dentry_openis 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.
Quoted 11 lines
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>
security/selinux/hooks.c line 85
Quoted 8 lines
diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/hooks.clinux-2.6.22/security/selinux/hooks.csecurity/selinux/hooks.c +1
-0@@ -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>
security/selinux/hooks.c static int selinux_file_receive(struct f · line 2747
Quoted 12 lines
security/selinux/hooks.c +8
-0@@ -2715,6 +2737,23 @@ static int selinux_file_receive(struct freturn 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.
*/
security/selinux/hooks.c static int selinux_file_receive(struct f · line 2753
Quoted 6 lines
security/selinux/hooks.c +6
-0+ 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. */
Quoted 11 lines
security/selinux/hooks.c +3
-0+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.clinux-2.6.22/fs/open.c
fs/open.c static struct file *__dentry_open(struct · line 705
Quoted 10 lines
fs/open.c +5
-0@@ -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.
Quoted 7 lines
fs/open.c +0
-0if (open) { error =open (inode, f);if (error)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/include/linux/security.hlinux-2.6.22/include/linux/security.h
include/linux/security.h struct request_sock; · line 510
Quoted 8 lines
include/linux/security.h +5
-0@@ -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 permission checking state for later use upon file_permission, and recheck access if anything has changed since inode_permission."
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 1 line · 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>
Quoted 1 line
Thanks, a few comments below.
Thanks for comments!
Quoted 8 lines
Quoted 7 lines
* Description of patch
This patch improves performance of read/write in SELinux. It improves performance by skipping permission check inselinux_file_permission. Permission is only checked when sid change or policy load is detected after file open. To detect sid change, new LSM hooksecuriy_dentry_openis added.
Quoted 7 lines
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_permissionif 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.
Quoted 17 lines
Quoted 11 lines
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>
Quoted 5 lines
diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/hooks.clinux-2.6.22/security/selinux/hooks.csecurity/selinux/hooks.c +0
-0@@ -80,6 +82,7 @@
Quoted 5 lines
security/selinux/hooks.c line 85
Quoted 3 lines
security/selinux/hooks.c +1
-0#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.
Quoted 15 lines
<snip>
security/selinux/hooks.c static int selinux_file_receive(struct f · line 2747
Quoted 12 lines
security/selinux/hooks.c +8
-0@@ -2715,6 +2737,23 @@ static int selinux_file_receive(struct freturn 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;
Quoted 8 lines
I'd add a comment here, e.g.
/*
* Save inode label and policy sequence number
* at open-time so thatselinux_file_permission
* can determine whether revalidation is necessary.
* Task label is already saved in the file security
* struct as its SID.
*/
Fixed.
Quoted 10 lines
security/selinux/hooks.c static int selinux_file_receive(struct f · line 2753
Quoted 7 lines
security/selinux/hooks.c +6
-0+ 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.
Quoted 8 lines
/*
* Since the inode label or policy seqno may have changed
* between theselinux_inode_permissioncheck 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.
Quoted 15 lines
Quoted 15 lines
security/selinux/hooks.c +3
-0+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.clinux-2.6.22/fs/open.cfs/open.c +0
-0@@ -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);
Quoted 9 lines
fs/open.c static struct file *__dentry_open(struct · line 705
Quoted 7 lines
fs/open.c +5
-0+ 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.
Quoted 12 lines
Quoted 12 lines
fs/open.c +0
-0if (open) { error =open (inode, f);if (error)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/include/linux/security.hlinux-2.6.22/include/linux/security.hinclude/linux/security.h +1
-0@@ -503,6 +503,11 @@ struct request_sock;* @file contains the file structure being received. * Return 0 if permission is granted. * +* Security hook for dentry
Quoted 8 lines
include/linux/security.h struct request_sock; · line 510
Quoted 4 lines
include/linux/security.h +4
-0+* +* @dentry_open +* Check permission or get additional information before opening dentry. +* More precisely, "Save open-time permission checking state for later use upon
file_permission, and recheck access if anything has changed sinceinode_permission."
Fixed.
Quoted 3 lines
Signature · 2 lines
Stephen Smalley National Security Agency
I would like to send patch in next e-mail in new thread.
Regards,
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.