Skip to content

Latest commit

 

History

History
193 lines (148 loc) · 7.65 KB

xattr-mapping.md

File metadata and controls

193 lines (148 loc) · 7.65 KB

Extended attribute (xattr) mapping

By default, the name of xattrs used by the client are passed through to the server file system. This can be a problem where either those xattr names are used by something on the server (e.g. selinux client/server confusion) or if the virtiofsd is running in a container with restricted privileges where it cannot access some attributes.

Mapping syntax

A mapping of xattr names can be made using --xattrmap=<mapping> where the <mapping> string consists of a series of rules.

When looking for a mapping, the first matching rule applies. There must be a mapping for every xattr name in the list of rules, for example by making the final rule a catch-all rule to match any remaining attributes.

Each rule consists of a number of fields separated with a separator that is the first non-white space character in the rule. This separator must then be used for the whole rule. White space may be added before and after each rule.

Using : as the separator a rule is of the form:

:type:scope:key:prepend:

scope is one of:

  • client: Match key against an xattr name from the client for setxattr/getxattr/removexattr
  • server: Match prepend against an xattr name from the server for listxattr
  • all: Can be used to make a single rule where both the server and client matches are triggered.

type is one of:

  • prefix: Is designed to prepend and strip a prefix; the modified attributes then being passed on to the client/server.

  • ok: Causes the rule set to be terminated when a match is found while allowing matching xattrs through unchanged. It is intended both as a way of explicitly terminating the list of rules, and to allow some xattrs to skip following rules.

  • bad: If a client tries to use a name matching key it's denied using EPERM; when the server passes an attribute name matching prepend it's hidden. In many ways its use is very like the ok type as either an explicit terminator or for special handling of certain patterns.

  • unsupported: If a client tries to use a name matching key it's denied using ENOTSUP; when the server passes an attribute name matching prepend it's hidden. In many ways its use is very like the ok type as either an explicit terminator or for special handling of certain patterns.

key is a string tested as a prefix on an attribute name originating on the client. It may be empty in which case a client scoped rule will always match on client names.

prepend is a string tested as a prefix on an attribute name originating on the server, and used as a new prefix. It may be empty in which case a server scoped rule will always match on all names from the server.

e.g.:

Mapping rule Description
:prefix:client:trusted.:user.virtiofs.: will match trusted.* attributes in client calls and prefix them before passing them to the server.
:prefix:server::user.virtiofs.: will strip user.virtiofs. from all server replies.
:prefix:all:trusted.:user.virtiofs.: combines the previous two cases into a single rule.
:ok:client:user.:: will allow get/set xattr for user. xattrs.
:ok:server::security.: will pass security. xattrs in listxattr from the server.
:ok:all::: will terminate the rule search passing any remaining attributes in both directions.
:bad:server::security.: would hide security. xattrs in listxattr from the server.

A simpler map type provides a shorter syntax for the common case:

:map:key:prepend:

The map type adds a number of separate rules to add prepend as a prefix to the matched key (or all attributes if key is empty). There may be at most one map rule, and it must be the last rule in the set.

Please note that when the security.capability xattr is remapped, the daemon has to do extra work to remove it during many operations, which the host kernel normally does itself.

Security considerations

Operating systems typically partition the xattr namespace using well-defined name prefixes. Each partition may have different access controls applied. For example, on Linux there are multiple partitions

  • system.*: access varies depending on attribute and filesystem
  • security.*: only processes with CAP_SYS_ADMIN
  • trusted.*: only processes with CAP_SYS_ADMIN
  • user.*: any process granted by file permissions / ownership

While other OS such as FreeBSD have different name prefixes and access control rules.

When remapping attributes on the host, it is important to ensure that the remapping does not allow a guest user to evade the guest access control rules.

Consider if trusted.* from the guest was remapped to user.virtiofs.trusted.* in the host. An unprivileged user in a Linux guest has the ability to write to xattrs under user.*. Thus the user can evade the access control restriction on trusted.* by instead writing to user.virtiofs.trusted.*.

As noted above, the partitions used and access controls applied, will vary across guest OS, so it is not wise to try to predict what the guest OS will use.

The simplest way to avoid an insecure configuration is to remap all xattrs at once, to a given fixed prefix. This is shown in example (1) below.

If selectively mapping only a subset of xattr prefixes, then rules must be added to explicitly block direct access to the target of the remapping. This is shown in example (2) below.

Mapping examples

  1. Prefix all attributes with user.virtiofs.
--xattrmap=":prefix:all::user.virtiofs.::bad:all:::"

This uses two rules, using : as the field separator; the first rule prefixes and strips user.virtiofs., the second rule hides any non-prefixed attributes that the host set.

This is equivalent to the map rule:

--xattrmap=":map::user.virtiofs.:"
  1. Prefix trusted. attributes, allow others through
--xattrmap="/prefix/all/trusted./user.virtiofs./
            /bad/server//trusted./
            /bad/client/user.virtiofs.//
            /ok/all///"

(each rule is on a single line just for the sake of clarity)

Here there are four rules, using / as the field separator, and also demonstrating that new lines can be included between rules. The first rule is the prefixing of trusted. and stripping of user.virtiofs.. The second rule hides unprefixed trusted. attributes on the host. The third rule stops a guest from explicitly setting the user.virtiofs. path directly to prevent access control bypass on the target of the earlier prefix remapping. Finally, the fourth rule lets all remaining attributes through.

This is equivalent to the map rule:

--xattrmap="/map/trusted./user.virtiofs./"
  1. Hide security. attributes, and allow everything else
--xattrmap="/bad/all/security./security./
            /ok/all///"

The first rule combines what could be separate client and server rules into a single all rule, matching security. in either client arguments or lists returned from the host. This prevents the client from seeing and/or setting any security. attributes on the server.