aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Morris <jmorris@namei.org>2005-10-30 17:59:22 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-30 20:37:11 -0500
commitd381d8a9a08cac9824096213069159be17fd2e2f (patch)
tree0c19722b8f67c29b7c08c6ab8776a9c146395d03
parent89d155ef62e5e0c10e4b37aaa5056f0beafe10e6 (diff)
[PATCH] SELinux: canonicalize getxattr()
This patch allows SELinux to canonicalize the value returned from getxattr() via the security_inode_getsecurity() hook, which is called after the fs level getxattr() function. The purpose of this is to allow the in-core security context for an inode to override the on-disk value. This could happen in cases such as upgrading a system to a different labeling form (e.g. standard SELinux to MLS) without needing to do a full relabel of the filesystem. In such cases, we want getxattr() to return the canonical security context that the kernel is using rather than what is stored on disk. The implementation hooks into the inode_getsecurity(), adding another parameter to indicate the result of the preceding fs-level getxattr() call, so that SELinux knows whether to compare a value obtained from disk with the kernel value. We also now allow getxattr() to work for mountpoint labeled filesystems (i.e. mount with option context=foo_t), as we are able to return the kernel value to the user. Signed-off-by: James Morris <jmorris@namei.org> 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--fs/xattr.c14
-rw-r--r--include/linux/security.h11
-rw-r--r--security/dummy.c2
-rw-r--r--security/selinux/hooks.c46
4 files changed, 49 insertions, 24 deletions
diff --git a/fs/xattr.c b/fs/xattr.c
index 3f9c64bea151..f6e00c0e114f 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -143,7 +143,7 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
143 if (size) { 143 if (size) {
144 if (size > XATTR_SIZE_MAX) 144 if (size > XATTR_SIZE_MAX)
145 size = XATTR_SIZE_MAX; 145 size = XATTR_SIZE_MAX;
146 kvalue = kmalloc(size, GFP_KERNEL); 146 kvalue = kzalloc(size, GFP_KERNEL);
147 if (!kvalue) 147 if (!kvalue)
148 return -ENOMEM; 148 return -ENOMEM;
149 } 149 }
@@ -154,11 +154,15 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
154 error = -EOPNOTSUPP; 154 error = -EOPNOTSUPP;
155 if (d->d_inode->i_op && d->d_inode->i_op->getxattr) 155 if (d->d_inode->i_op && d->d_inode->i_op->getxattr)
156 error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); 156 error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
157 else if (!strncmp(kname, XATTR_SECURITY_PREFIX, 157
158 sizeof XATTR_SECURITY_PREFIX - 1)) { 158 if (!strncmp(kname, XATTR_SECURITY_PREFIX,
159 sizeof XATTR_SECURITY_PREFIX - 1)) {
159 const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1; 160 const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
160 error = security_inode_getsecurity(d->d_inode, suffix, kvalue, 161 int rv = security_inode_getsecurity(d->d_inode, suffix, kvalue,
161 size); 162 size, error);
163 /* Security module active: overwrite error value */
164 if (rv != -EOPNOTSUPP)
165 error = rv;
162 } 166 }
163 if (error > 0) { 167 if (error > 0) {
164 if (size && copy_to_user(value, kvalue, error)) 168 if (size && copy_to_user(value, kvalue, error))
diff --git a/include/linux/security.h b/include/linux/security.h
index dac956ed98f0..607ee209ea3b 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -385,6 +385,9 @@ struct swap_info_struct;
385 * NULL to request the size of the buffer required. @size indicates 385 * NULL to request the size of the buffer required. @size indicates
386 * the size of @buffer in bytes. Note that @name is the remainder 386 * the size of @buffer in bytes. Note that @name is the remainder
387 * of the attribute name after the security. prefix has been removed. 387 * of the attribute name after the security. prefix has been removed.
388 * @err is the return value from the preceding fs getxattr call,
389 * and can be used by the security module to determine whether it
390 * should try and canonicalize the attribute value.
388 * Return number of bytes used/required on success. 391 * Return number of bytes used/required on success.
389 * @inode_setsecurity: 392 * @inode_setsecurity:
390 * Set the security label associated with @name for @inode from the 393 * Set the security label associated with @name for @inode from the
@@ -1091,7 +1094,7 @@ struct security_operations {
1091 int (*inode_getxattr) (struct dentry *dentry, char *name); 1094 int (*inode_getxattr) (struct dentry *dentry, char *name);
1092 int (*inode_listxattr) (struct dentry *dentry); 1095 int (*inode_listxattr) (struct dentry *dentry);
1093 int (*inode_removexattr) (struct dentry *dentry, char *name); 1096 int (*inode_removexattr) (struct dentry *dentry, char *name);
1094 int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size); 1097 int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size, int err);
1095 int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags); 1098 int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
1096 int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size); 1099 int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
1097 1100
@@ -1580,11 +1583,11 @@ static inline int security_inode_removexattr (struct dentry *dentry, char *name)
1580 return security_ops->inode_removexattr (dentry, name); 1583 return security_ops->inode_removexattr (dentry, name);
1581} 1584}
1582 1585
1583static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size) 1586static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
1584{ 1587{
1585 if (unlikely (IS_PRIVATE (inode))) 1588 if (unlikely (IS_PRIVATE (inode)))
1586 return 0; 1589 return 0;
1587 return security_ops->inode_getsecurity(inode, name, buffer, size); 1590 return security_ops->inode_getsecurity(inode, name, buffer, size, err);
1588} 1591}
1589 1592
1590static inline int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) 1593static inline int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
@@ -2222,7 +2225,7 @@ static inline int security_inode_removexattr (struct dentry *dentry, char *name)
2222 return cap_inode_removexattr(dentry, name); 2225 return cap_inode_removexattr(dentry, name);
2223} 2226}
2224 2227
2225static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size) 2228static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
2226{ 2229{
2227 return -EOPNOTSUPP; 2230 return -EOPNOTSUPP;
2228} 2231}
diff --git a/security/dummy.c b/security/dummy.c
index 3d34f3de7e82..2a0337a52d32 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -377,7 +377,7 @@ static int dummy_inode_removexattr (struct dentry *dentry, char *name)
377 return 0; 377 return 0;
378} 378}
379 379
380static int dummy_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size) 380static int dummy_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
381{ 381{
382 return -EOPNOTSUPP; 382 return -EOPNOTSUPP;
383} 383}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8cd33b2cd865..d9ec85292e1c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2208,9 +2208,6 @@ static int selinux_inode_getxattr (struct dentry *dentry, char *name)
2208 struct inode *inode = dentry->d_inode; 2208 struct inode *inode = dentry->d_inode;
2209 struct superblock_security_struct *sbsec = inode->i_sb->s_security; 2209 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
2210 2210
2211 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
2212 return -EOPNOTSUPP;
2213
2214 return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); 2211 return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
2215} 2212}
2216 2213
@@ -2241,33 +2238,54 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
2241 return -EACCES; 2238 return -EACCES;
2242} 2239}
2243 2240
2244static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size) 2241/*
2242 * Copy the in-core inode security context value to the user. If the
2243 * getxattr() prior to this succeeded, check to see if we need to
2244 * canonicalize the value to be finally returned to the user.
2245 *
2246 * Permission check is handled by selinux_inode_getxattr hook.
2247 */
2248static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
2245{ 2249{
2246 struct inode_security_struct *isec = inode->i_security; 2250 struct inode_security_struct *isec = inode->i_security;
2247 char *context; 2251 char *context;
2248 unsigned len; 2252 unsigned len;
2249 int rc; 2253 int rc;
2250 2254
2251 /* Permission check handled by selinux_inode_getxattr hook.*/ 2255 if (strcmp(name, XATTR_SELINUX_SUFFIX)) {
2252 2256 rc = -EOPNOTSUPP;
2253 if (strcmp(name, XATTR_SELINUX_SUFFIX)) 2257 goto out;
2254 return -EOPNOTSUPP; 2258 }
2255 2259
2256 rc = security_sid_to_context(isec->sid, &context, &len); 2260 rc = security_sid_to_context(isec->sid, &context, &len);
2257 if (rc) 2261 if (rc)
2258 return rc; 2262 goto out;
2259 2263
2264 /* Probe for required buffer size */
2260 if (!buffer || !size) { 2265 if (!buffer || !size) {
2261 kfree(context); 2266 rc = len;
2262 return len; 2267 goto out_free;
2263 } 2268 }
2269
2264 if (size < len) { 2270 if (size < len) {
2265 kfree(context); 2271 rc = -ERANGE;
2266 return -ERANGE; 2272 goto out_free;
2273 }
2274
2275 if (err > 0) {
2276 if ((len == err) && !(memcmp(context, buffer, len))) {
2277 /* Don't need to canonicalize value */
2278 rc = err;
2279 goto out_free;
2280 }
2281 memset(buffer, 0, size);
2267 } 2282 }
2268 memcpy(buffer, context, len); 2283 memcpy(buffer, context, len);
2284 rc = len;
2285out_free:
2269 kfree(context); 2286 kfree(context);
2270 return len; 2287out:
2288 return rc;
2271} 2289}
2272 2290
2273static int selinux_inode_setsecurity(struct inode *inode, const char *name, 2291static int selinux_inode_setsecurity(struct inode *inode, const char *name,