aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,