aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2005-09-09 16:01:35 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 16:57:27 -0400
commit5e41ff9e0650f327a6c819841fa412da95d57319 (patch)
treea525df8bda34c2aa52f30326f94cd15109bb58b3 /security/selinux/hooks.c
parentf5ee56cc184e0944ebc9ff1691985219959596f6 (diff)
[PATCH] security: enable atomic inode security labeling
The following patch set enables atomic security labeling of newly created inodes by altering the fs code to invoke a new LSM hook to obtain the security attribute to apply to a newly created inode and to set up the incore inode security state during the inode creation transaction. This parallels the existing processing for setting ACLs on newly created inodes. Otherwise, it is possible for new inodes to be accessed by another thread via the dcache prior to complete security setup (presently handled by the post_create/mkdir/... LSM hooks in the VFS) and a newly created inode may be left unlabeled on the disk in the event of a crash. SELinux presently works around the issue by ensuring that the incore inode security label is initialized to a special SID that is inaccessible to unprivileged processes (in accordance with policy), thereby preventing inappropriate access but potentially causing false denials on legitimate accesses. A simple test program demonstrates such false denials on SELinux, and the patch solves the problem. Similar such false denials have been encountered in real applications. This patch defines a new inode_init_security LSM hook to obtain the security attribute to apply to a newly created inode and to set up the incore inode security state for it, and adds a corresponding hook function implementation to SELinux. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8641f8894b4c..63701fe0e1ad 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1274,6 +1274,7 @@ static int post_create(struct inode *dir,
1274 struct inode *inode; 1274 struct inode *inode;
1275 struct inode_security_struct *dsec; 1275 struct inode_security_struct *dsec;
1276 struct superblock_security_struct *sbsec; 1276 struct superblock_security_struct *sbsec;
1277 struct inode_security_struct *isec;
1277 u32 newsid; 1278 u32 newsid;
1278 char *context; 1279 char *context;
1279 unsigned int len; 1280 unsigned int len;
@@ -1293,6 +1294,11 @@ static int post_create(struct inode *dir,
1293 return 0; 1294 return 0;
1294 } 1295 }
1295 1296
1297 isec = inode->i_security;
1298
1299 if (isec->security_attr_init)
1300 return 0;
1301
1296 if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { 1302 if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
1297 newsid = tsec->create_sid; 1303 newsid = tsec->create_sid;
1298 } else { 1304 } else {
@@ -2018,6 +2024,58 @@ static void selinux_inode_free_security(struct inode *inode)
2018 inode_free_security(inode); 2024 inode_free_security(inode);
2019} 2025}
2020 2026
2027static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2028 char **name, void **value,
2029 size_t *len)
2030{
2031 struct task_security_struct *tsec;
2032 struct inode_security_struct *dsec;
2033 struct superblock_security_struct *sbsec;
2034 struct inode_security_struct *isec;
2035 u32 newsid;
2036 int rc;
2037 char *namep, *context;
2038
2039 tsec = current->security;
2040 dsec = dir->i_security;
2041 sbsec = dir->i_sb->s_security;
2042 isec = inode->i_security;
2043
2044 if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
2045 newsid = tsec->create_sid;
2046 } else {
2047 rc = security_transition_sid(tsec->sid, dsec->sid,
2048 inode_mode_to_security_class(inode->i_mode),
2049 &newsid);
2050 if (rc) {
2051 printk(KERN_WARNING "%s: "
2052 "security_transition_sid failed, rc=%d (dev=%s "
2053 "ino=%ld)\n",
2054 __FUNCTION__,
2055 -rc, inode->i_sb->s_id, inode->i_ino);
2056 return rc;
2057 }
2058 }
2059
2060 inode_security_set_sid(inode, newsid);
2061
2062 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL);
2063 if (!namep)
2064 return -ENOMEM;
2065 *name = namep;
2066
2067 rc = security_sid_to_context(newsid, &context, len);
2068 if (rc) {
2069 kfree(namep);
2070 return rc;
2071 }
2072 *value = context;
2073
2074 isec->security_attr_init = 1;
2075
2076 return 0;
2077}
2078
2021static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask) 2079static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2022{ 2080{
2023 return may_create(dir, dentry, SECCLASS_FILE); 2081 return may_create(dir, dentry, SECCLASS_FILE);
@@ -4298,6 +4356,7 @@ static struct security_operations selinux_ops = {
4298 4356
4299 .inode_alloc_security = selinux_inode_alloc_security, 4357 .inode_alloc_security = selinux_inode_alloc_security,
4300 .inode_free_security = selinux_inode_free_security, 4358 .inode_free_security = selinux_inode_free_security,
4359 .inode_init_security = selinux_inode_init_security,
4301 .inode_create = selinux_inode_create, 4360 .inode_create = selinux_inode_create,
4302 .inode_post_create = selinux_inode_post_create, 4361 .inode_post_create = selinux_inode_post_create,
4303 .inode_link = selinux_inode_link, 4362 .inode_link = selinux_inode_link,