summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2005-09-10 00:01:35 +0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-10 00:57:27 +0400
commit5e41ff9e0650f327a6c819841fa412da95d57319 (patch)
treea525df8bda34c2aa52f30326f94cd15109bb58b3 /security
parentf5ee56cc184e0944ebc9ff1691985219959596f6 (diff)
downloadlinux-5e41ff9e0650f327a6c819841fa412da95d57319.tar.xz
[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')
-rw-r--r--security/dummy.c7
-rw-r--r--security/selinux/hooks.c59
-rw-r--r--security/selinux/include/objsec.h1
3 files changed, 67 insertions, 0 deletions
diff --git a/security/dummy.c b/security/dummy.c
index 6ff887586479..e8a00fa80469 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -258,6 +258,12 @@ static void dummy_inode_free_security (struct inode *inode)
return;
}
+static int dummy_inode_init_security (struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len)
+{
+ return -EOPNOTSUPP;
+}
+
static int dummy_inode_create (struct inode *inode, struct dentry *dentry,
int mask)
{
@@ -886,6 +892,7 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, sb_post_pivotroot);
set_to_dummy_if_null(ops, inode_alloc_security);
set_to_dummy_if_null(ops, inode_free_security);
+ set_to_dummy_if_null(ops, inode_init_security);
set_to_dummy_if_null(ops, inode_create);
set_to_dummy_if_null(ops, inode_post_create);
set_to_dummy_if_null(ops, inode_link);
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,
struct inode *inode;
struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
+ struct inode_security_struct *isec;
u32 newsid;
char *context;
unsigned int len;
@@ -1293,6 +1294,11 @@ static int post_create(struct inode *dir,
return 0;
}
+ isec = inode->i_security;
+
+ if (isec->security_attr_init)
+ return 0;
+
if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
newsid = tsec->create_sid;
} else {
@@ -2018,6 +2024,58 @@ static void selinux_inode_free_security(struct inode *inode)
inode_free_security(inode);
}
+static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
+ char **name, void **value,
+ size_t *len)
+{
+ struct task_security_struct *tsec;
+ struct inode_security_struct *dsec;
+ struct superblock_security_struct *sbsec;
+ struct inode_security_struct *isec;
+ u32 newsid;
+ int rc;
+ char *namep, *context;
+
+ tsec = current->security;
+ dsec = dir->i_security;
+ sbsec = dir->i_sb->s_security;
+ isec = inode->i_security;
+
+ if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
+ newsid = tsec->create_sid;
+ } else {
+ rc = security_transition_sid(tsec->sid, dsec->sid,
+ inode_mode_to_security_class(inode->i_mode),
+ &newsid);
+ if (rc) {
+ printk(KERN_WARNING "%s: "
+ "security_transition_sid failed, rc=%d (dev=%s "
+ "ino=%ld)\n",
+ __FUNCTION__,
+ -rc, inode->i_sb->s_id, inode->i_ino);
+ return rc;
+ }
+ }
+
+ inode_security_set_sid(inode, newsid);
+
+ namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL);
+ if (!namep)
+ return -ENOMEM;
+ *name = namep;
+
+ rc = security_sid_to_context(newsid, &context, len);
+ if (rc) {
+ kfree(namep);
+ return rc;
+ }
+ *value = context;
+
+ isec->security_attr_init = 1;
+
+ return 0;
+}
+
static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
{
return may_create(dir, dentry, SECCLASS_FILE);
@@ -4298,6 +4356,7 @@ static struct security_operations selinux_ops = {
.inode_alloc_security = selinux_inode_alloc_security,
.inode_free_security = selinux_inode_free_security,
+ .inode_init_security = selinux_inode_init_security,
.inode_create = selinux_inode_create,
.inode_post_create = selinux_inode_post_create,
.inode_link = selinux_inode_link,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 887937c8134a..c515bc0b58a1 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -46,6 +46,7 @@ struct inode_security_struct {
unsigned char initialized; /* initialization flag */
struct semaphore sem;
unsigned char inherit; /* inherit SID from parent entry */
+ unsigned char security_attr_init; /* security attributes init flag */
};
struct file_security_struct {