aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/security.h41
-rw-r--r--security/dummy.c7
-rw-r--r--security/selinux/hooks.c59
-rw-r--r--security/selinux/include/objsec.h1
4 files changed, 108 insertions, 0 deletions
diff --git a/include/linux/security.h b/include/linux/security.h
index 7aab6ab7c57f..d4f3b7a94ea6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -250,6 +250,25 @@ struct swap_info_struct;
250 * @inode contains the inode structure. 250 * @inode contains the inode structure.
251 * Deallocate the inode security structure and set @inode->i_security to 251 * Deallocate the inode security structure and set @inode->i_security to
252 * NULL. 252 * NULL.
253 * @inode_init_security:
254 * Obtain the security attribute name suffix and value to set on a newly
255 * created inode and set up the incore security field for the new inode.
256 * This hook is called by the fs code as part of the inode creation
257 * transaction and provides for atomic labeling of the inode, unlike
258 * the post_create/mkdir/... hooks called by the VFS. The hook function
259 * is expected to allocate the name and value via kmalloc, with the caller
260 * being responsible for calling kfree after using them.
261 * If the security module does not use security attributes or does
262 * not wish to put a security attribute on this particular inode,
263 * then it should return -EOPNOTSUPP to skip this processing.
264 * @inode contains the inode structure of the newly created inode.
265 * @dir contains the inode structure of the parent directory.
266 * @name will be set to the allocated name suffix (e.g. selinux).
267 * @value will be set to the allocated attribute value.
268 * @len will be set to the length of the value.
269 * Returns 0 if @name and @value have been successfully set,
270 * -EOPNOTSUPP if no security attribute is needed, or
271 * -ENOMEM on memory allocation failure.
253 * @inode_create: 272 * @inode_create:
254 * Check permission to create a regular file. 273 * Check permission to create a regular file.
255 * @dir contains inode structure of the parent of the new file. 274 * @dir contains inode structure of the parent of the new file.
@@ -1080,6 +1099,8 @@ struct security_operations {
1080 1099
1081 int (*inode_alloc_security) (struct inode *inode); 1100 int (*inode_alloc_security) (struct inode *inode);
1082 void (*inode_free_security) (struct inode *inode); 1101 void (*inode_free_security) (struct inode *inode);
1102 int (*inode_init_security) (struct inode *inode, struct inode *dir,
1103 char **name, void **value, size_t *len);
1083 int (*inode_create) (struct inode *dir, 1104 int (*inode_create) (struct inode *dir,
1084 struct dentry *dentry, int mode); 1105 struct dentry *dentry, int mode);
1085 void (*inode_post_create) (struct inode *dir, 1106 void (*inode_post_create) (struct inode *dir,
@@ -1442,6 +1463,17 @@ static inline void security_inode_free (struct inode *inode)
1442 return; 1463 return;
1443 security_ops->inode_free_security (inode); 1464 security_ops->inode_free_security (inode);
1444} 1465}
1466
1467static inline int security_inode_init_security (struct inode *inode,
1468 struct inode *dir,
1469 char **name,
1470 void **value,
1471 size_t *len)
1472{
1473 if (unlikely (IS_PRIVATE (inode)))
1474 return -EOPNOTSUPP;
1475 return security_ops->inode_init_security (inode, dir, name, value, len);
1476}
1445 1477
1446static inline int security_inode_create (struct inode *dir, 1478static inline int security_inode_create (struct inode *dir,
1447 struct dentry *dentry, 1479 struct dentry *dentry,
@@ -2171,6 +2203,15 @@ static inline int security_inode_alloc (struct inode *inode)
2171 2203
2172static inline void security_inode_free (struct inode *inode) 2204static inline void security_inode_free (struct inode *inode)
2173{ } 2205{ }
2206
2207static inline int security_inode_init_security (struct inode *inode,
2208 struct inode *dir,
2209 char **name,
2210 void **value,
2211 size_t *len)
2212{
2213 return -EOPNOTSUPP;
2214}
2174 2215
2175static inline int security_inode_create (struct inode *dir, 2216static inline int security_inode_create (struct inode *dir,
2176 struct dentry *dentry, 2217 struct dentry *dentry,
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)
258 return; 258 return;
259} 259}
260 260
261static int dummy_inode_init_security (struct inode *inode, struct inode *dir,
262 char **name, void **value, size_t *len)
263{
264 return -EOPNOTSUPP;
265}
266
261static int dummy_inode_create (struct inode *inode, struct dentry *dentry, 267static int dummy_inode_create (struct inode *inode, struct dentry *dentry,
262 int mask) 268 int mask)
263{ 269{
@@ -886,6 +892,7 @@ void security_fixup_ops (struct security_operations *ops)
886 set_to_dummy_if_null(ops, sb_post_pivotroot); 892 set_to_dummy_if_null(ops, sb_post_pivotroot);
887 set_to_dummy_if_null(ops, inode_alloc_security); 893 set_to_dummy_if_null(ops, inode_alloc_security);
888 set_to_dummy_if_null(ops, inode_free_security); 894 set_to_dummy_if_null(ops, inode_free_security);
895 set_to_dummy_if_null(ops, inode_init_security);
889 set_to_dummy_if_null(ops, inode_create); 896 set_to_dummy_if_null(ops, inode_create);
890 set_to_dummy_if_null(ops, inode_post_create); 897 set_to_dummy_if_null(ops, inode_post_create);
891 set_to_dummy_if_null(ops, inode_link); 898 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,
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,
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 {
46 unsigned char initialized; /* initialization flag */ 46 unsigned char initialized; /* initialization flag */
47 struct semaphore sem; 47 struct semaphore sem;
48 unsigned char inherit; /* inherit SID from parent entry */ 48 unsigned char inherit; /* inherit SID from parent entry */
49 unsigned char security_attr_init; /* security attributes init flag */
49}; 50};
50 51
51struct file_security_struct { 52struct file_security_struct {