Skip to content

Commit

Permalink
lib/replace: validate xattr namespace prefix on FreeBSD
Browse files Browse the repository at this point in the history
We should validate the xattr name string ensuring it either begins with
"sytem." or "user.". If it doesn't, we should fail the request with
EINVAL.

The FreeBSD xattr API uses namespaces but doesn't put the namespace name
as a string prefix at the beginning of the xattr name. It gets passed as
an additional int arg instead.

On the other hand, our libreplace xattr API expects the caller to put a
namespace prefix into the xattr name.

Unfortunately the conversion and stripping of the namespace string prefix
from the xattr name gives the following unexpected result on FreeBSD:

rep_setxattr("foo.bar", ...) => xattr with name "bar"

The code checks if the name begins with "system.", if it doesn't find
it, it defaults to the user namespace and then does a strchr(name, '.')
which skips *any* leading string before the first dot.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=12490

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
  • Loading branch information
slowfranklin authored and jrasamba committed Feb 10, 2017
1 parent e4d1f83 commit 738797d
Showing 1 changed file with 81 additions and 24 deletions.
105 changes: 81 additions & 24 deletions lib/replace/xattr.c
Expand Up @@ -61,11 +61,21 @@ ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t si
#elif defined(HAVE_GETEA)
return getea(path, name, value, size);
#elif defined(HAVE_EXTATTR_GET_FILE)
char *s;
ssize_t retval;
int attrnamespace = (strncmp(name, "system", 6) == 0) ?
EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
int attrnamespace;
const char *attrname;

if (strncmp(name, "system.", 7) == 0) {
attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
attrname = name + 7;
} else if (strncmp(name, "user.", 5) == 0) {
attrnamespace = EXTATTR_NAMESPACE_USER;
attrname = name + 5;
} else {
errno = EINVAL;
return -1;
}

/*
* The BSD implementation has a nasty habit of silently truncating
* the returned value to the size of the buffer, so we have to check
Expand Down Expand Up @@ -125,11 +135,20 @@ ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
#elif defined(HAVE_FGETEA)
return fgetea(filedes, name, value, size);
#elif defined(HAVE_EXTATTR_GET_FD)
char *s;
ssize_t retval;
int attrnamespace = (strncmp(name, "system", 6) == 0) ?
EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
int attrnamespace;
const char *attrname;

if (strncmp(name, "system.", 7) == 0) {
attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
attrname = name + 7;
} else if (strncmp(name, "user.", 5) == 0) {
attrnamespace = EXTATTR_NAMESPACE_USER;
attrname = name + 5;
} else {
errno = EINVAL;
return -1;
}

if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
if (size == 0) {
Expand Down Expand Up @@ -414,10 +433,19 @@ int rep_removexattr (const char *path, const char *name)
#elif defined(HAVE_REMOVEEA)
return removeea(path, name);
#elif defined(HAVE_EXTATTR_DELETE_FILE)
char *s;
int attrnamespace = (strncmp(name, "system", 6) == 0) ?
EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
int attrnamespace;
const char *attrname;

if (strncmp(name, "system.", 7) == 0) {
attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
attrname = name + 7;
} else if (strncmp(name, "user.", 5) == 0) {
attrnamespace = EXTATTR_NAMESPACE_USER;
attrname = name + 5;
} else {
errno = EINVAL;
return -1;
}

return extattr_delete_file(path, attrnamespace, attrname);
#elif defined(HAVE_ATTR_REMOVE)
Expand Down Expand Up @@ -455,10 +483,19 @@ int rep_fremovexattr (int filedes, const char *name)
#elif defined(HAVE_FREMOVEEA)
return fremoveea(filedes, name);
#elif defined(HAVE_EXTATTR_DELETE_FD)
char *s;
int attrnamespace = (strncmp(name, "system", 6) == 0) ?
EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
int attrnamespace;
const char *attrname;

if (strncmp(name, "system.", 7) == 0) {
attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
attrname = name + 7;
} else if (strncmp(name, "user.", 5) == 0) {
attrnamespace = EXTATTR_NAMESPACE_USER;
attrname = name + 5;
} else {
errno = EINVAL;
return -1;
}

return extattr_delete_fd(filedes, attrnamespace, attrname);
#elif defined(HAVE_ATTR_REMOVEF)
Expand Down Expand Up @@ -496,11 +533,21 @@ int rep_setxattr (const char *path, const char *name, const void *value, size_t
#elif defined(HAVE_SETEA)
return setea(path, name, value, size, flags);
#elif defined(HAVE_EXTATTR_SET_FILE)
char *s;
int retval = 0;
int attrnamespace = (strncmp(name, "system", 6) == 0) ?
EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
int attrnamespace;
const char *attrname;

if (strncmp(name, "system.", 7) == 0) {
attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
attrname = name + 7;
} else if (strncmp(name, "user.", 5) == 0) {
attrnamespace = EXTATTR_NAMESPACE_USER;
attrname = name + 5;
} else {
errno = EINVAL;
return -1;
}

if (flags) {
/* Check attribute existence */
retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
Expand Down Expand Up @@ -563,11 +610,21 @@ int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size
#elif defined(HAVE_FSETEA)
return fsetea(filedes, name, value, size, flags);
#elif defined(HAVE_EXTATTR_SET_FD)
char *s;
int retval = 0;
int attrnamespace = (strncmp(name, "system", 6) == 0) ?
EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
int attrnamespace;
const char *attrname;

if (strncmp(name, "system.", 7) == 0) {
attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
attrname = name + 7;
} else if (strncmp(name, "user.", 5) == 0) {
attrnamespace = EXTATTR_NAMESPACE_USER;
attrname = name + 5;
} else {
errno = EINVAL;
return -1;
}

if (flags) {
/* Check attribute existence */
retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
Expand Down

0 comments on commit 738797d

Please sign in to comment.