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:
parent
4a42ab7dda
commit
c9bf814804
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user