[21/21] hfsplus: remove can_set_xattr
diff mbox

Message ID 20131220132524.900291394@bombadil.infradead.org
State Not Applicable
Headers show

Commit Message

Christoph Hellwig Dec. 20, 2013, 1:16 p.m. UTC
When using the per-superblock xattr handlers permission checking is
done by the generic code.  hfsplus just needs to check for the magic
osx attribute not to leak into protected namespaces.

Also given that the code was obviously copied from JFS the proper
attribution was missing.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/hfsplus/xattr.c |   87 ++--------------------------------------------------
 1 file changed, 3 insertions(+), 84 deletions(-)

Comments

Viacheslav Dubeyko Dec. 21, 2013, 5:07 p.m. UTC | #1
On Dec 20, 2013, at 4:16 PM, Christoph Hellwig wrote:

> When using the per-superblock xattr handlers permission checking is
> done by the generic code.  hfsplus just needs to check for the magic
> osx attribute not to leak into protected namespaces.
> 
> Also given that the code was obviously copied from JFS the proper
> attribution was missing.
> 

I don't think that this code changing is correct. Current modification
breaks logic. Please, see my comments below.

> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/hfsplus/xattr.c |   87 ++--------------------------------------------------
> 1 file changed, 3 insertions(+), 84 deletions(-)
> 
> diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
> index bf88baa..0b4a5c9 100644
> --- a/fs/hfsplus/xattr.c
> +++ b/fs/hfsplus/xattr.c
> @@ -52,82 +52,6 @@ static inline int is_known_namespace(const char *name)
> 	return true;
> }
> 
> -static int can_set_system_xattr(struct inode *inode, const char *name,
> -				const void *value, size_t size)

I agree that it makes sense to remove this code if permission checking
is done by generic code.

> -{
> -#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
> -	struct posix_acl *acl;
> -	int err;
> -
> -	if (!inode_owner_or_capable(inode))
> -		return -EPERM;
> -
> -	/*
> -	 * POSIX_ACL_XATTR_ACCESS is tied to i_mode
> -	 */
> -	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {
> -		acl = posix_acl_from_xattr(&init_user_ns, value, size);
> -		if (IS_ERR(acl))
> -			return PTR_ERR(acl);
> -		if (acl) {
> -			err = posix_acl_equiv_mode(acl, &inode->i_mode);
> -			posix_acl_release(acl);
> -			if (err < 0)
> -				return err;
> -			mark_inode_dirty(inode);
> -		}
> -		/*
> -		 * We're changing the ACL.  Get rid of the cached one
> -		 */
> -		forget_cached_acl(inode, ACL_TYPE_ACCESS);
> -
> -		return 0;
> -	} else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
> -		acl = posix_acl_from_xattr(&init_user_ns, value, size);
> -		if (IS_ERR(acl))
> -			return PTR_ERR(acl);
> -		posix_acl_release(acl);
> -
> -		/*
> -		 * We're changing the default ACL.  Get rid of the cached one
> -		 */
> -		forget_cached_acl(inode, ACL_TYPE_DEFAULT);
> -
> -		return 0;
> -	}
> -#endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */
> -	return -EOPNOTSUPP;
> -}
> -
> -static int can_set_xattr(struct inode *inode, const char *name,
> -				const void *value, size_t value_len)

This function works for all handlers. So, I don't think that it makes sense
to delete it.

> -{
> -	if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
> -		return can_set_system_xattr(inode, name, value, value_len);
> -

I agree that it needs to remove this check for XATTR_SYSTEM_PREFIX case.

> -	if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
> -		/*
> -		 * This makes sure that we aren't trying to set an
> -		 * attribute in a different namespace by prefixing it
> -		 * with "osx."
> -		 */
> -		if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN))
> -			return -EOPNOTSUPP;

I think that this check is important. It forbids such combinations as "osx.system.*" or
"osx.trusted.*", for example. Because "osx.*" is virtual namespace for xattrs that
it can be under Mac OS X. If you want to set xattr from "system.*" namespace, for example,
then you need to use another handler. And such namespace should be without
addition of "osx." prefix.

> -
> -		return 0;
> -	}
> -
> -	/*
> -	 * Don't allow setting an attribute in an unknown namespace.
> -	 */
> -	if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) &&
> -	    strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
> -	    strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
> -		return -EOPNOTSUPP;
> -
> -	return 0;
> -}
> -
> static void hfsplus_init_header_node(struct inode *attr_file,
> 					u32 clump_size,
> 					char *buf, u16 node_size)
> @@ -350,10 +274,6 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
> 				HFSPLUS_IS_RSRC(inode))
> 		return -EOPNOTSUPP;
> 
> -	err = can_set_xattr(inode, name, value, size);

The __hfsplus_setxattr() is common method for all handlers. So, removing
this call means that we don't check validity of namespace. I don't think
that such modification is a right way.

> -	if (err)
> -		return err;
> -
> 	if (strncmp(name, XATTR_MAC_OSX_PREFIX,
> 				XATTR_MAC_OSX_PREFIX_LEN) == 0)
> 		name += XATTR_MAC_OSX_PREFIX_LEN;
> @@ -841,10 +761,6 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name)
> 	if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
> 		return -EOPNOTSUPP;
> 
> -	err = can_set_xattr(inode, name, NULL, 0);

Ditto. Moreover, it is used namely hfsplus_removexattr() and not
__hfsplus_setxattr() for removing xattrs in hfsplus driver. So, removing
this check is not good way.

> -	if (err)
> -		return err;
> -
> 	if (strncmp(name, XATTR_MAC_OSX_PREFIX,
> 				XATTR_MAC_OSX_PREFIX_LEN) == 0)
> 		name += XATTR_MAC_OSX_PREFIX_LEN;
> @@ -941,6 +857,9 @@ static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
> 	if (len > HFSPLUS_ATTR_MAX_STRLEN)
> 		return -EOPNOTSUPP;
> 
> +	if (is_known_namespace(name))
> +		return -EOPNOTSUPP;

If common check in __hfsplus_setxattr() will be on the same place then
this addition doesn't make sense.

Thanks,
Vyacheslav Dubeyko.

> +
> 	strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
> 	strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
> 
> -- 
> 1.7.10.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Hellwig Dec. 22, 2013, 7:28 p.m. UTC | #2
On Sat, Dec 21, 2013 at 08:07:51PM +0300, Vyacheslav Dubeyko wrote:
> > -static int can_set_xattr(struct inode *inode, const char *name,
> > -				const void *value, size_t value_len)
> 
> This function works for all handlers. So, I don't think that it makes sense
> to delete it.

It "works" in a minimal sense that it won't crash or actively cause
harm.  But it also is useless except for the check that we can abuse
the osx namespace to set an attribute in another namespace, which we
still do in the proper way after my patch.

> > -	if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
> > -		/*
> > -		 * This makes sure that we aren't trying to set an
> > -		 * attribute in a different namespace by prefixing it
> > -		 * with "osx."
> > -		 */
> > -		if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN))
> > -			return -EOPNOTSUPP;
> 
> I think that this check is important. It forbids such combinations as "osx.system.*" or
> "osx.trusted.*", for example. Because "osx.*" is virtual namespace for xattrs that
> it can be under Mac OS X. If you want to set xattr from "system.*" namespace, for example,
> then you need to use another handler. And such namespace should be without
> addition of "osx." prefix.

Right, and we keep exactly the check, just in a different place.

> The __hfsplus_setxattr() is common method for all handlers. So, removing
> this call means that we don't check validity of namespace. I don't think
> that such modification is a right way.

The generic code already checks for the validity of the namespace for
you. xattr_resolve_name in fs/xattr.c makes sure only attributes for a
namespace that the filesystem registered can be set or modified.

> > @@ -841,10 +761,6 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name)
> > 	if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
> > 		return -EOPNOTSUPP;
> > 
> > -	err = can_set_xattr(inode, name, NULL, 0);
> 
> Ditto. Moreover, it is used namely hfsplus_removexattr() and not
> __hfsplus_setxattr() for removing xattrs in hfsplus driver. So, removing
> this check is not good way.

Oh, I just noticed that hfsplus does not use the xattr handlers for
removing, while it does for getting and setting xattrs.  That's a really
bad a confusing design, and we'll indeed need to fix that as well.

> > 	if (len > HFSPLUS_ATTR_MAX_STRLEN)
> > 		return -EOPNOTSUPP;
> > 
> > +	if (is_known_namespace(name))
> > +		return -EOPNOTSUPP;
> 
> If common check in __hfsplus_setxattr() will be on the same place then
> this addition doesn't make sense.

Having both does indeed not make sense, but this is the better place to
have it.

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Viacheslav Dubeyko Dec. 23, 2013, 6:40 a.m. UTC | #3
On Sun, 2013-12-22 at 11:28 -0800, Christoph Hellwig wrote:

> 
> > > -	if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
> > > -		/*
> > > -		 * This makes sure that we aren't trying to set an
> > > -		 * attribute in a different namespace by prefixing it
> > > -		 * with "osx."
> > > -		 */
> > > -		if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN))
> > > -			return -EOPNOTSUPP;
> > 
> > I think that this check is important. It forbids such combinations as "osx.system.*" or
> > "osx.trusted.*", for example. Because "osx.*" is virtual namespace for xattrs that
> > it can be under Mac OS X. If you want to set xattr from "system.*" namespace, for example,
> > then you need to use another handler. And such namespace should be without
> > addition of "osx." prefix.
> 
> Right, and we keep exactly the check, just in a different place.
> 

Maybe I missed something, but I can see that this check is removed only.
Could you point out the code in your patch that it checks and forbids
such combination as "osx.security.*", "osx.trusted.*" and so on?

I can see that is_known_namespace() is called for
hfsplus_xattr_osx_handler only. But this method doesn't contain
above-mentioned check. Moreover, hfsplus_xattr_user_handler,
hfsplus_xattr_trusted_handler, hfsplus_xattr_security_handler will be
without is_know_namespace() check. What about it?

> > The __hfsplus_setxattr() is common method for all handlers. So, removing
> > this call means that we don't check validity of namespace. I don't think
> > that such modification is a right way.
> 
> The generic code already checks for the validity of the namespace for
> you. xattr_resolve_name in fs/xattr.c makes sure only attributes for a
> namespace that the filesystem registered can be set or modified.
> 

But generic code doesn't check such names combination that it is treated
as wrong for concrete file systems. For example, "osx.security.*" is
wrong for the case of HFS+. Because it will works
hfsplus_xattr_osx_handler instead of hfsplus_xattr_security_handler.

> > > @@ -841,10 +761,6 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name)
> > > 	if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
> > > 		return -EOPNOTSUPP;
> > > 
> > > -	err = can_set_xattr(inode, name, NULL, 0);
> > 
> > Ditto. Moreover, it is used namely hfsplus_removexattr() and not
> > __hfsplus_setxattr() for removing xattrs in hfsplus driver. So, removing
> > this check is not good way.
> 
> Oh, I just noticed that hfsplus does not use the xattr handlers for
> removing, while it does for getting and setting xattrs.  That's a really
> bad a confusing design, and we'll indeed need to fix that as well.
> 

Why bad design? Do you mean that using .removexattr callback is bad
idea?

So, if it needs to use xattr handler only for removing then it needs to
make some refactoring of using __hfsplus_setxattr() and
hfsplus_removexattr() or merging these two functions into one. And I
think that merging is better idea.

Thanks,
Vyacheslav Dubeyko.


--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
index bf88baa..0b4a5c9 100644
--- a/fs/hfsplus/xattr.c
+++ b/fs/hfsplus/xattr.c
@@ -52,82 +52,6 @@  static inline int is_known_namespace(const char *name)
 	return true;
 }
 
-static int can_set_system_xattr(struct inode *inode, const char *name,
-				const void *value, size_t size)
-{
-#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
-	struct posix_acl *acl;
-	int err;
-
-	if (!inode_owner_or_capable(inode))
-		return -EPERM;
-
-	/*
-	 * POSIX_ACL_XATTR_ACCESS is tied to i_mode
-	 */
-	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {
-		acl = posix_acl_from_xattr(&init_user_ns, value, size);
-		if (IS_ERR(acl))
-			return PTR_ERR(acl);
-		if (acl) {
-			err = posix_acl_equiv_mode(acl, &inode->i_mode);
-			posix_acl_release(acl);
-			if (err < 0)
-				return err;
-			mark_inode_dirty(inode);
-		}
-		/*
-		 * We're changing the ACL.  Get rid of the cached one
-		 */
-		forget_cached_acl(inode, ACL_TYPE_ACCESS);
-
-		return 0;
-	} else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
-		acl = posix_acl_from_xattr(&init_user_ns, value, size);
-		if (IS_ERR(acl))
-			return PTR_ERR(acl);
-		posix_acl_release(acl);
-
-		/*
-		 * We're changing the default ACL.  Get rid of the cached one
-		 */
-		forget_cached_acl(inode, ACL_TYPE_DEFAULT);
-
-		return 0;
-	}
-#endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */
-	return -EOPNOTSUPP;
-}
-
-static int can_set_xattr(struct inode *inode, const char *name,
-				const void *value, size_t value_len)
-{
-	if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-		return can_set_system_xattr(inode, name, value, value_len);
-
-	if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
-		/*
-		 * This makes sure that we aren't trying to set an
-		 * attribute in a different namespace by prefixing it
-		 * with "osx."
-		 */
-		if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN))
-			return -EOPNOTSUPP;
-
-		return 0;
-	}
-
-	/*
-	 * Don't allow setting an attribute in an unknown namespace.
-	 */
-	if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) &&
-	    strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
-	    strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
-		return -EOPNOTSUPP;
-
-	return 0;
-}
-
 static void hfsplus_init_header_node(struct inode *attr_file,
 					u32 clump_size,
 					char *buf, u16 node_size)
@@ -350,10 +274,6 @@  int __hfsplus_setxattr(struct inode *inode, const char *name,
 				HFSPLUS_IS_RSRC(inode))
 		return -EOPNOTSUPP;
 
-	err = can_set_xattr(inode, name, value, size);
-	if (err)
-		return err;
-
 	if (strncmp(name, XATTR_MAC_OSX_PREFIX,
 				XATTR_MAC_OSX_PREFIX_LEN) == 0)
 		name += XATTR_MAC_OSX_PREFIX_LEN;
@@ -841,10 +761,6 @@  int hfsplus_removexattr(struct dentry *dentry, const char *name)
 	if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
 		return -EOPNOTSUPP;
 
-	err = can_set_xattr(inode, name, NULL, 0);
-	if (err)
-		return err;
-
 	if (strncmp(name, XATTR_MAC_OSX_PREFIX,
 				XATTR_MAC_OSX_PREFIX_LEN) == 0)
 		name += XATTR_MAC_OSX_PREFIX_LEN;
@@ -941,6 +857,9 @@  static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
 	if (len > HFSPLUS_ATTR_MAX_STRLEN)
 		return -EOPNOTSUPP;
 
+	if (is_known_namespace(name))
+		return -EOPNOTSUPP;
+
 	strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
 	strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);