Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreeBSD MAC label support (initial version) #42

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Expand Up @@ -1361,6 +1361,8 @@ IF(ENABLE_XATTR)
LA_CHECK_INCLUDE_FILE(attr/xattr.h HAVE_ATTR_XATTR_H)
LA_CHECK_INCLUDE_FILE(sys/xattr.h HAVE_SYS_XATTR_H)
LA_CHECK_INCLUDE_FILE(sys/extattr.h HAVE_SYS_EXTATTR_H)
LA_CHECK_INCLUDE_FILE(sys/mac.h HAVE_SYS_MAC_H)
LA_CHECK_INCLUDE_FILE(sys/sysctl.h HAVE_SYS_SYSCTL_H)
CHECK_LIBRARY_EXISTS(attr "setxattr" "" HAVE_LIBATTR)
IF(HAVE_LIBATTR)
SET(CMAKE_REQUIRED_LIBRARIES "attr")
Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Expand Up @@ -354,6 +354,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_fuzz.c \
libarchive/test/test_gnutar_filename_encoding.c \
libarchive/test/test_link_resolver.c \
libarchive/test/test_maclabel_freebsd.c \
libarchive/test/test_open_failure.c \
libarchive/test/test_open_fd.c \
libarchive/test/test_open_file.c \
Expand Down
2 changes: 2 additions & 0 deletions configure.ac
Expand Up @@ -568,6 +568,8 @@ AC_ARG_ENABLE([xattr],
if test "x$enable_xattr" != "xno"; then
AC_CHECK_HEADERS([attr/xattr.h])
AC_CHECK_HEADERS([sys/xattr.h sys/ea.h])
AC_CHECK_HEADERS([sys/mac.h])
AC_CHECK_HEADERS([sys/sysctl.h])
AC_CHECK_LIB(attr,setxattr)
AC_CHECK_FUNCS([extattr_get_file extattr_list_file])
AC_CHECK_FUNCS([extattr_set_fd extattr_set_file])
Expand Down
137 changes: 102 additions & 35 deletions libarchive/archive_read_disk_entry_from_file.c
Expand Up @@ -81,6 +81,12 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h>
#endif
#ifdef HAVE_SYS_MAC_H
#include <sys/mac.h>
#endif
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
/*
* Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
* As the include guards don't agree, the order of include is important.
Expand Down Expand Up @@ -911,10 +917,15 @@ setup_xattrs(struct archive_read_disk *a,
struct archive_entry *entry, int *fd)
{
char buff[512];
char *list, *p;
ssize_t list_size;
const char *path;
int namespace = EXTATTR_NAMESPACE_USER;
int ret;
#if defined (HAVE_SYS_MAC_H) && defined (HAVE_SYS_SYSCTL_H) && \
defined (__FreeBSD__)
uint64_t mac_labeled = 0;
size_t ml_len = sizeof(uint64_t);
#endif

path = archive_entry_sourcepath(entry);
if (path == NULL)
Expand All @@ -941,51 +952,107 @@ setup_xattrs(struct archive_read_disk *a,
else
list_size = extattr_list_file(path, namespace, NULL, 0);

if (list_size == -1 && errno == EOPNOTSUPP)
return (ARCHIVE_OK);
if (list_size == -1) {
ret = ARCHIVE_OK;
if (list_size == -1 && errno != EOPNOTSUPP) {
archive_set_error(&a->archive, errno,
"Couldn't list extended attributes");
return (ARCHIVE_WARN);
ret = ARCHIVE_WARN;
}

if (list_size == 0)
return (ARCHIVE_OK);
if (list_size > 0) {
char *list, *p;

if ((list = malloc(list_size)) == NULL) {
archive_set_error(&a->archive, errno, "Out of memory");
return (ARCHIVE_FATAL);
}
if ((list = malloc(list_size)) == NULL) {
archive_set_error(&a->archive, errno, "Out of memory");
return (ARCHIVE_FATAL);
}

if (*fd >= 0)
list_size = extattr_list_fd(*fd, namespace, list, list_size);
else if (!a->follow_symlinks)
list_size = extattr_list_link(path, namespace, list, list_size);
else
list_size = extattr_list_file(path, namespace, list, list_size);
if (*fd >= 0)
list_size = extattr_list_fd(*fd,
namespace, list, list_size);
else if (!a->follow_symlinks)
list_size = extattr_list_link(path,
namespace, list, list_size);
else
list_size = extattr_list_file(path,
namespace, list, list_size);

if (list_size == -1) {
archive_set_error(&a->archive, errno,
"Couldn't retrieve extended attributes");
free(list);
ret = ARCHIVE_WARN;
} else {

p = list;
while ((p - list) < list_size) {
size_t len = 255 & (int)*p;
char *name;

strcpy(buff, "user.");
name = buff + strlen(buff);
memcpy(name, p + 1, len);
name[len] = '\0';
setup_xattr(a, entry, namespace,
name, buff, *fd);
p += 1 + len;
}
}

if (list_size == -1) {
archive_set_error(&a->archive, errno,
"Couldn't retrieve extended attributes");
free(list);
return (ARCHIVE_WARN);
}

p = list;
while ((p - list) < list_size) {
size_t len = 255 & (int)*p;
char *name;

strcpy(buff, "user.");
name = buff + strlen(buff);
memcpy(name, p + 1, len);
name[len] = '\0';
setup_xattr(a, entry, namespace, name, buff, *fd);
p += 1 + len;
}
#if defined (HAVE_SYS_MAC_H) && defined (HAVE_SYS_SYSCTL_H) && \
defined (__FreeBSD__)
/* Handle FreeBSD MAC labels. This is a simplified hack that
* stores the label in textual representation as an xattr
* with the name "system.mac". There is no name clash under
* FreeBSD, as only the user namespace is otherwise touched;
* extracting archives that contain this data on other, xattr
* capable systems may potentially break.
*/
/* if (mac_is_present(NULL) == 1) { */
if (!sysctlbyname("security.mac.labeled",
&mac_labeled, &ml_len, NULL, 0) && \
mac_labeled != 0) {
mac_t mac;
char *labeltext;

if (mac_prepare_file_label(&mac)) {
archive_set_error(&a->archive, errno,
"Failed to prepare MAC label");
return (ARCHIVE_FATAL);
} else {
int err = 0;
if (*fd >= 0)
err = mac_get_fd(*fd, mac);
else if (!a->follow_symlinks)
err = mac_get_link(path, mac);
else
err = mac_get_file(path, mac);
if (err) {
archive_set_error(&a->archive, errno,
"Couldn't read MAC label");
mac_free(mac);
return (ARCHIVE_WARN);
}

free(list);
return (ARCHIVE_OK);
if (mac_to_text(mac, &labeltext)) {
archive_set_error(&a->archive, errno,
"Couldn't convert MAC label");
mac_free(mac);
return (ARCHIVE_FATAL);
} else {
archive_entry_xattr_add_entry(entry,
"system.mac",
labeltext, strlen(labeltext));
free(labeltext);
}
mac_free(mac);
}
}
#endif
return (ret);
}

#else
Expand Down
67 changes: 67 additions & 0 deletions libarchive/archive_write_disk_posix.c
Expand Up @@ -77,6 +77,12 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h> /* for Linux file flags */
#endif
#ifdef HAVE_SYS_MAC_H
#include <sys/mac.h>
#endif
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
/*
* Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
* As the include guards don't agree, the order of include is important.
Expand Down Expand Up @@ -3690,6 +3696,59 @@ set_xattrs(struct archive_write_disk *a)
return (ret);
}
#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER

#if defined (HAVE_SYS_MAC_H) && defined (HAVE_SYS_SYSCTL_H) && \
defined (__FreeBSD__)
/*
* Set FreeBSD MAC labels.
* Converts a text representation to a label and applies it.
*/
static int
set_maclabel(struct archive_write_disk *a, const char *labeltext, size_t size)
{
int ret = ARCHIVE_OK;
uint64_t mac_labeled = 0;
size_t ml_len = sizeof(uint64_t);

/* if (mac_is_present(NULL) == 1) { */
if (!sysctlbyname("security.mac.labeled",
&mac_labeled, &ml_len, NULL, 0) && \
mac_labeled != 0) {
mac_t mac;
char buff[512];

if (size > 511)
size = 511;
memcpy(buff, labeltext, size);
buff[size] = '\0';

if (mac_from_text(&mac, buff)) {
archive_set_error(&a->archive, errno,
"Couldn't convert MAC label");
return (ARCHIVE_WARN);
} else {
int err = 0;

if (a->fd >= 0)
err = mac_set_fd(a->fd, mac);
else
err = mac_set_link(
archive_entry_pathname(a->entry),
mac);

if (err) {
archive_set_error(&a->archive, errno,
"Couldn't set MAC label");
ret = ARCHIVE_WARN;
}
mac_free(mac);
}
}

return (ret);
}
#endif

/*
* Restore extended attributes - FreeBSD implementation
*/
Expand All @@ -3714,6 +3773,14 @@ set_xattrs(struct archive_write_disk *a)
/* "user." attributes go to user namespace */
name += 5;
namespace = EXTATTR_NAMESPACE_USER;
#if defined (HAVE_SYS_MAC_H) && defined (HAVE_SYS_SYSCTL_H) && \
defined (__FreeBSD__)
} else if (strncmp(name, "system.mac", 10) == 0) {
int r1 = set_maclabel(a, value, size);
if (r1 < ret)
ret = r1;
continue;
#endif
} else {
/* Warn about other extended attributes. */
archive_set_error(&a->archive,
Expand Down
2 changes: 2 additions & 0 deletions libarchive/config_freebsd.h
Expand Up @@ -41,6 +41,8 @@
#define HAVE_EXTATTR_SET_FILE 1
#define HAVE_SYS_ACL_H 1
#define HAVE_SYS_EXTATTR_H 1
#define HAVE_SYS_MAC_H 1
#define HAVE_SYS_SYSCTL_H 1
#endif

#ifdef WITH_OPENSSL
Expand Down
15 changes: 12 additions & 3 deletions libarchive/test/test_extattr_freebsd.c
Expand Up @@ -160,9 +160,18 @@ DEFINE_TEST(test_extattr_freebsd)
archive_entry_set_pathname(ae, "test0");
assertEqualInt(ARCHIVE_OK,
archive_read_disk_entry_from_file(a, ae, -1, NULL));
assertEqualInt(1, archive_entry_xattr_reset(ae));
assertEqualInt(ARCHIVE_OK,
archive_entry_xattr_next(ae, &xname, &xval, &xsize));
/* If the system has MAC enabled, unexpected xattrs can
* appear here; skip them.
*/
n = archive_entry_xattr_reset(ae);
while (n--) {
assertEqualInt(ARCHIVE_OK,
archive_entry_xattr_next(ae, &xname, &xval, &xsize));
if (xname != NULL) {
if (strncmp(xname, "user.foo", 8) == 0)
break;
}
}
assertEqualString(xname, "user.foo");
assertEqualInt(xsize, 5);
assertEqualMem(xval, "12345", xsize);
Expand Down