restore(8): Handle extended attribute names correctly

UFS2 extended attribute names are not NUL-terminated.  Handle
appropriately.

Correct the EXTATTR_BASE_LENGTH() macro, which handled ea_namelength ==
one (mod eight) extended attributes incorrectly.

PR:		216127
Reported by:	dewayne at heuristicsystems.com.au
Reviewed by:	kib@
Sponsored by:	Dell EMC Isilon
Differential Revision:	https://reviews.freebsd.org/D9208
This commit is contained in:
Conrad Meyer 2017-01-18 18:16:57 +00:00
parent 4a42ab7dda
commit c9bf814804
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=312393
5 changed files with 72 additions and 145 deletions

View File

@ -645,7 +645,7 @@ setdirmodes(int flags)
if (!Nflag) {
if (node.extsize > 0) {
if (bufsize >= node.extsize) {
set_extattr_file(cp, buf, node.extsize);
set_extattr(-1, cp, buf, node.extsize, SXA_FILE);
} else {
fprintf(stderr, "Cannot restore %s%s\n",
"extended attributes for ", cp);

View File

@ -87,7 +87,12 @@ struct direct *rst_readdir(RST_DIR *);
void rst_closedir(void *);
void runcmdshell(void);
char *savename(char *);
void set_extattr_file(char *, void *, int);
enum set_extattr_mode {
SXA_FILE,
SXA_LINK,
SXA_FD,
};
void set_extattr(int, char *, void *, int, enum set_extattr_mode);
void setdirmodes(int);
void setinput(char *, int);
void setup(void);

View File

@ -105,8 +105,6 @@ static void findinode(struct s_spcl *);
static void findtapeblksize(void);
static char *setupextattr(int);
static void xtrattr(char *, size_t);
static void set_extattr_link(char *, void *, int);
static void set_extattr_fd(int, char *, void *, int);
static void skiphole(void (*)(char *, size_t), size_t *);
static int gethead(struct s_spcl *);
static void readtape(char *);
@ -627,7 +625,7 @@ extractfile(char *name)
}
if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
if (extsize > 0)
set_extattr_link(name, buf, extsize);
set_extattr(-1, name, buf, extsize, SXA_LINK);
(void) lchown(name, uid, gid);
(void) lchmod(name, mode);
(void) utimensat(AT_FDCWD, name, ctimep,
@ -658,7 +656,7 @@ extractfile(char *name)
} else {
buf = setupextattr(extsize);
getfile(xtrnull, xtrattr, xtrnull);
set_extattr_file(name, buf, extsize);
set_extattr(-1, name, buf, extsize, SXA_FILE);
}
(void) chown(name, uid, gid);
(void) chmod(name, mode);
@ -688,7 +686,7 @@ extractfile(char *name)
} else {
buf = setupextattr(extsize);
getfile(xtrnull, xtrattr, xtrnull);
set_extattr_file(name, buf, extsize);
set_extattr(-1, name, buf, extsize, SXA_FILE);
}
(void) chown(name, uid, gid);
(void) chmod(name, mode);
@ -715,7 +713,7 @@ extractfile(char *name)
buf = setupextattr(extsize);
getfile(xtrfile, xtrattr, xtrskip);
if (extsize > 0)
set_extattr_fd(ofile, name, buf, extsize);
set_extattr(ofile, name, buf, extsize, SXA_FD);
(void) fchown(ofile, uid, gid);
(void) fchmod(ofile, mode);
(void) futimens(ofile, ctimep);
@ -728,12 +726,16 @@ extractfile(char *name)
}
/*
* Set attributes for a file.
* Set attributes on a file descriptor, link, or file.
*/
void
set_extattr_file(char *name, void *buf, int size)
set_extattr(int fd, char *name, void *buf, int size, enum set_extattr_mode mode)
{
struct extattr *eap, *eaend;
const char *method;
ssize_t res;
int error;
char eaname[EXTATTR_MAXNAMELEN + 1];
vprintf(stdout, "Set attributes for %s:", name);
eaend = buf + size;
@ -748,17 +750,34 @@ set_extattr_file(char *name, void *buf, int size)
}
if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
continue;
vprintf(stdout, "\n\t%s, (%d bytes), %*s",
snprintf(eaname, sizeof(eaname), "%.*s",
(int)eap->ea_namelength, eap->ea_name);
vprintf(stdout, "\n\t%s, (%d bytes), %s",
namespace_names[eap->ea_namespace], eap->ea_length,
eap->ea_namelength, eap->ea_name);
eaname);
/*
* First we try the general attribute setting interface.
* However, some attributes can only be set by root or
* by using special interfaces (for example, ACLs).
*/
if (extattr_set_file(name, eap->ea_namespace, eap->ea_name,
EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
dprintf(stdout, " (set using extattr_set_file)");
if (mode == SXA_FD) {
res = extattr_set_fd(fd, eap->ea_namespace,
eaname, EXTATTR_CONTENT(eap),
EXTATTR_CONTENT_SIZE(eap));
method = "extattr_set_fd";
} else if (mode == SXA_LINK) {
res = extattr_set_link(name, eap->ea_namespace,
eaname, EXTATTR_CONTENT(eap),
EXTATTR_CONTENT_SIZE(eap));
method = "extattr_set_link";
} else if (mode == SXA_FILE) {
res = extattr_set_file(name, eap->ea_namespace,
eaname, EXTATTR_CONTENT(eap),
EXTATTR_CONTENT_SIZE(eap));
method = "extattr_set_file";
}
if (res != -1) {
dprintf(stdout, " (set using %s)", method);
continue;
}
/*
@ -767,137 +786,37 @@ set_extattr_file(char *name, void *buf, int size)
* know about.
*/
if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
!strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
if (acl_set_file(name, ACL_TYPE_ACCESS,
EXTATTR_CONTENT(eap)) != -1) {
dprintf(stdout, " (set using acl_set_file)");
strcmp(eaname, POSIX1E_ACL_ACCESS_EXTATTR_NAME) == 0) {
if (mode == SXA_FD) {
error = acl_set_fd(fd, EXTATTR_CONTENT(eap));
method = "acl_set_fd";
} else if (mode == SXA_LINK) {
error = acl_set_link_np(name, ACL_TYPE_ACCESS,
EXTATTR_CONTENT(eap));
method = "acl_set_link_np";
} else if (mode == SXA_FILE) {
error = acl_set_file(name, ACL_TYPE_ACCESS,
EXTATTR_CONTENT(eap));
method = "acl_set_file";
}
if (error != -1) {
dprintf(stdout, " (set using %s)", method);
continue;
}
}
if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
!strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
if (acl_set_file(name, ACL_TYPE_DEFAULT,
EXTATTR_CONTENT(eap)) != -1) {
dprintf(stdout, " (set using acl_set_file)");
continue;
strcmp(eaname, POSIX1E_ACL_DEFAULT_EXTATTR_NAME) == 0) {
if (mode == SXA_LINK) {
error = acl_set_link_np(name, ACL_TYPE_DEFAULT,
EXTATTR_CONTENT(eap));
method = "acl_set_link_np";
} else {
error = acl_set_file(name, ACL_TYPE_DEFAULT,
EXTATTR_CONTENT(eap));
method = "acl_set_file";
}
}
vprintf(stdout, " (unable to set)");
}
vprintf(stdout, "\n");
}
/*
* Set attributes for a symbolic link.
*/
static void
set_extattr_link(char *name, void *buf, int size)
{
struct extattr *eap, *eaend;
vprintf(stdout, "Set attributes for %s:", name);
eaend = buf + size;
for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
/*
* Make sure this entry is complete.
*/
if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
dprintf(stdout, "\n\t%scorrupted",
eap == buf ? "" : "remainder ");
break;
}
if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
continue;
vprintf(stdout, "\n\t%s, (%d bytes), %*s",
namespace_names[eap->ea_namespace], eap->ea_length,
eap->ea_namelength, eap->ea_name);
/*
* First we try the general attribute setting interface.
* However, some attributes can only be set by root or
* by using special interfaces (for example, ACLs).
*/
if (extattr_set_link(name, eap->ea_namespace, eap->ea_name,
EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
dprintf(stdout, " (set using extattr_set_link)");
continue;
}
/*
* If the general interface refuses to set the attribute,
* then we try all the specialized interfaces that we
* know about.
*/
if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
!strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
if (acl_set_link_np(name, ACL_TYPE_ACCESS,
EXTATTR_CONTENT(eap)) != -1) {
dprintf(stdout, " (set using acl_set_link_np)");
continue;
}
}
if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
!strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
if (acl_set_link_np(name, ACL_TYPE_DEFAULT,
EXTATTR_CONTENT(eap)) != -1) {
dprintf(stdout, " (set using acl_set_link_np)");
continue;
}
}
vprintf(stdout, " (unable to set)");
}
vprintf(stdout, "\n");
}
/*
* Set attributes on a file descriptor.
*/
static void
set_extattr_fd(int fd, char *name, void *buf, int size)
{
struct extattr *eap, *eaend;
vprintf(stdout, "Set attributes for %s:", name);
eaend = buf + size;
for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
/*
* Make sure this entry is complete.
*/
if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
dprintf(stdout, "\n\t%scorrupted",
eap == buf ? "" : "remainder ");
break;
}
if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
continue;
vprintf(stdout, "\n\t%s, (%d bytes), %*s",
namespace_names[eap->ea_namespace], eap->ea_length,
eap->ea_namelength, eap->ea_name);
/*
* First we try the general attribute setting interface.
* However, some attributes can only be set by root or
* by using special interfaces (for example, ACLs).
*/
if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name,
EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
dprintf(stdout, " (set using extattr_set_fd)");
continue;
}
/*
* If the general interface refuses to set the attribute,
* then we try all the specialized interfaces that we
* know about.
*/
if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
!strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) {
dprintf(stdout, " (set using acl_set_fd)");
continue;
}
}
if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
!strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
if (acl_set_file(name, ACL_TYPE_DEFAULT,
EXTATTR_CONTENT(eap)) != -1) {
dprintf(stdout, " (set using acl_set_file)");
if (error != -1) {
dprintf(stdout, " (set using %s)", method);
continue;
}
}

View File

@ -57,10 +57,11 @@
EXTATTR_NAMESPACE_USER_STRING, \
EXTATTR_NAMESPACE_SYSTEM_STRING }
#define EXTATTR_MAXNAMELEN NAME_MAX
#ifdef _KERNEL
#include <sys/types.h>
#define EXTATTR_MAXNAMELEN NAME_MAX
struct thread;
struct ucred;
struct vnode;

View File

@ -93,12 +93,14 @@ struct extattr {
* content referenced by eap.
*/
#define EXTATTR_NEXT(eap) \
((struct extattr *)(((void *)(eap)) + (eap)->ea_length))
#define EXTATTR_CONTENT(eap) (((void *)(eap)) + EXTATTR_BASE_LENGTH(eap))
((struct extattr *)(((u_char *)(eap)) + (eap)->ea_length))
#define EXTATTR_CONTENT(eap) \
(void *)(((u_char *)(eap)) + EXTATTR_BASE_LENGTH(eap))
#define EXTATTR_CONTENT_SIZE(eap) \
((eap)->ea_length - EXTATTR_BASE_LENGTH(eap) - (eap)->ea_contentpadlen)
/* -1 below compensates for ea_name[1] */
#define EXTATTR_BASE_LENGTH(eap) \
((sizeof(struct extattr) + (eap)->ea_namelength + 7) & ~7)
roundup2((sizeof(struct extattr) - 1 + (eap)->ea_namelength), 8)
#ifdef _KERNEL