Hi Craig,
On Thu, Mar 31, 2005 at 09:19:56PM -0500, Craig Rodrigues wrote:
> In terms of documentation/code samples, the best source is
> the extattr(2) and extattr(9) man pages:
>
> http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/sys/extattr_get_file.2
> http://www.freebsd.org/cgi/cvsweb.cgi/src/share/man/man9/extattr.9
>
> Basically I am trying to implement the following system call:
>
> ssize_t extattr_list_file(const char *path, int attrnamespace, void *data,
> size_t nbytes);
>
> Currently on FreeBSD, for attrnamespace,
> "user" attr namespace == 1
> "system" attr namespace == 2
>
> These are the only namespaces implemented so far, but could be
> extended for other file systems
>
>
> On Fri, Apr 01, 2005 at 11:35:31AM +1000, Tim Shimmin wrote:
> > Hi Craig,
> > From xfs_attr.h:
> > #define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value
> > */
> > #define ATTR_KERNAMELS 0x4000 /* [kernel] list attr names (simple list)
> > */
> >
> > #define ATTR_KERNORMALS 0x0800 /* [kernel] normal attr list: user+secure
> > */
> > #define ATTR_KERNROOTLS 0x8000 /* [kernel] include root in the attr list
> > */
> > #define ATTR_KERNFULLS (ATTR_KERNORMALS|ATTR_KERNROOTLS)
> >
> > So back to the question.
> > The linux interface of listing attributes will always list _all_ of
> > the EAs for all the namespaces.
> > The lower level xfs listing code (VOP_ATTR_LIST or xfs_attr_list)
> > can handle listing of EAs for a particular namespace (by specifying
> > the namespace bit in the passed in xflags).
> >
> > --Tim
>
>
> Tim, thanks for your detailed response, it was VERY helpful.
> So if I understand things correctly, if I take extattr_list_file()'s
> attrnamespace flag, and map it to an ATTR_* flag for xfs_attr_list(),
> I might be able to get things to work correctly. Any advice how
> to do this? Something like:
>
> attrnamespace = 1 (user) = xfs_attr_list() flag ATTR_KERNORMALS
> attrnamespace = 2 (system) = xfs_attr_list() flag ATTR_KERNROOTLS
>
> Hmmm...
>
Not quite.
I find the changes that were made for linux a little confusing :)
Basically they've added flags to stop doing namespace matches between
the request and what is on disk.
It has also got complicated because on IRIX we only had a ROOT bit
which when 0 meant USER but since then we've added another namespace.
The code in list says:
if (((context->flags & ATTR_SECURE) != 0) !=
((sfe->flags & XFS_ATTR_SECURE) != 0) &&
!(context->flags & ATTR_KERNORMALS)) {
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
continue;
}
if (((context->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0) &&
!(context->flags & ATTR_KERNROOTLS)) {
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
continue;
}
i.e.
if (we do NOT have the same namespace bits matching for secure AND
we are not overriding with ATTR_KERNORMALS)
then we don't have a match and look at other EAs
if (we do NOT have the same namespace bits for root AND
we are not overriding with ATTR_KERNROOTLS)
then we don't have a match and look at other EAs
In linvfs_listxattr() we set:
xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS;
> > #define ATTR_KERNFULLS (ATTR_KERNORMALS|ATTR_KERNROOTLS)
So if we have CAP_SYS_ADMIN then we don't do the 1st check or the 2nd check as
we have both overrides on and so we list all.
If we do _not_ have CAP_SYS_ADMIN then:
(1) as the override is on for secure, we don't test the secure bit
(2) as the override is off for root and we don't have ATTR_ROOT set,
we will never get the ROOT ones
=> we get all non-root EAs
You want user and system for your xfs_attr_list().
You might map like this:
(a)
user = user
system = root (trusted)
OR
(b)
user = user + secure
system = root (trusted)
If you do the first one (a), then you basically want what we have on IRIX.
For that you could just use 0 for user and ATTR_ROOT for system.
If you want the second one (b), which maps user+secure to user, then
you need to use an overriding macro. (If we had had the USER namespace
as a bit in its own right then we could have done ATTR_USER | ATTR_ROOT
which would have been much clearer - but we don't - bummer).
For this you could use ATTR_KERNORMALS for user (no secure checks and no root
namespace)
and ATTR_ROOT for system.
i.e.
(a)
> attrnamespace = 1 (user) = xfs_attr_list() flag 0
> attrnamespace = 2 (system) = xfs_attr_list() flag ATTR_ROOT
(b)
> attrnamespace = 1 (user) = xfs_attr_list() flag ATTR_KERNORMALS
> attrnamespace = 2 (system) = xfs_attr_list() flag ATTR_ROOT
You need the ATTR_KERN* macros if you want multiple namespaces.
And they work by cancelling out one of the namespace checks.
If you ever add attrnamespace = 3 (secure) then just use
0 (user), ATTR_SECURE (secure), ATTR_ROOT (system).
I think that makes sense :)
--Tim
|