Merge "libtar: store SELinux file context in tar archives" into twrp2.7
This commit is contained in:
@@ -11,5 +11,11 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH) \
|
||||
external/zlib
|
||||
LOCAL_SHARED_LIBRARIES += libz libc
|
||||
|
||||
ifneq ($(wildcard external/libselinux/Android.mk),)
|
||||
LOCAL_C_INCLUDES += external/libselinux/include
|
||||
LOCAL_SHARED_LIBRARIES += libselinux
|
||||
LOCAL_CFLAGS += -DHAVE_SELINUX
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
@@ -90,6 +90,31 @@ tar_append_file(TAR *t, char *realname, char *savename)
|
||||
#endif
|
||||
th_set_path(t, (savename ? savename : realname));
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
/* get selinux context */
|
||||
if(t->options & TAR_STORE_SELINUX)
|
||||
{
|
||||
if(t->th_buf.selinux_context != NULL)
|
||||
{
|
||||
free(t->th_buf.selinux_context);
|
||||
t->th_buf.selinux_context = NULL;
|
||||
}
|
||||
|
||||
security_context_t selinux_context = NULL;
|
||||
if(getfilecon(realname, &selinux_context) >= 0)
|
||||
{
|
||||
t->th_buf.selinux_context = strdup(selinux_context);
|
||||
freecon(selinux_context);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
perror("Failed to get selinux context");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check if it's a hardlink */
|
||||
#ifdef DEBUG
|
||||
puts(" tar_append_file(): checking inode cache for hardlink...");
|
||||
|
||||
+113
@@ -21,6 +21,10 @@
|
||||
|
||||
#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
|
||||
|
||||
// Used to identify selinux_context in extended ('x')
|
||||
// metadata. From RedHat implementation.
|
||||
#define SELINUX_TAG "RHT.security.selinux="
|
||||
#define SELINUX_TAG_LEN 21
|
||||
|
||||
/* read a header block */
|
||||
int
|
||||
@@ -101,6 +105,11 @@ th_read(TAR *t)
|
||||
free(t->th_buf.gnu_longname);
|
||||
if (t->th_buf.gnu_longlink != NULL)
|
||||
free(t->th_buf.gnu_longlink);
|
||||
#ifdef HAVE_SELINUX
|
||||
if (t->th_buf.selinux_context != NULL)
|
||||
free(t->th_buf.selinux_context);
|
||||
#endif
|
||||
|
||||
memset(&(t->th_buf), 0, sizeof(struct tar_header));
|
||||
|
||||
i = th_read_internal(t);
|
||||
@@ -203,6 +212,57 @@ th_read(TAR *t)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if(TH_ISEXTHEADER(t))
|
||||
{
|
||||
sz = th_get_size(t);
|
||||
|
||||
if(sz >= T_BLOCKSIZE) // Not supported
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf(" th_read(): Extended header is too long!\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[T_BLOCKSIZE];
|
||||
i = tar_block_read(t, buf);
|
||||
if (i != T_BLOCKSIZE)
|
||||
{
|
||||
if (i != -1)
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// To be sure
|
||||
buf[T_BLOCKSIZE-1] = 0;
|
||||
|
||||
int len = strlen(buf);
|
||||
char *start = strstr(buf, SELINUX_TAG);
|
||||
if(start && start+SELINUX_TAG_LEN < buf+len)
|
||||
{
|
||||
start += SELINUX_TAG_LEN;
|
||||
char *end = strchr(start, '\n');
|
||||
if(end)
|
||||
{
|
||||
t->th_buf.selinux_context = strndup(start, end-start);
|
||||
#ifdef DEBUG
|
||||
printf(" th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = th_read_internal(t);
|
||||
if (i != T_BLOCKSIZE)
|
||||
{
|
||||
if (i != -1)
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
** work-around for old archive files with broken typeflag fields
|
||||
@@ -359,6 +419,59 @@ th_write(TAR *t)
|
||||
th_set_size(t, sz2);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("th_write(): using selinux_context (\"%s\")\n",
|
||||
t->th_buf.selinux_context);
|
||||
#endif
|
||||
/* save old size and type */
|
||||
type2 = t->th_buf.typeflag;
|
||||
sz2 = th_get_size(t);
|
||||
|
||||
/* write out initial header block with fake size and type */
|
||||
t->th_buf.typeflag = TH_EXT_TYPE;
|
||||
|
||||
/* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
|
||||
// size newline
|
||||
sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
|
||||
|
||||
if(sz >= 100) // another ascci digit for size
|
||||
++sz;
|
||||
|
||||
if(sz >= T_BLOCKSIZE) // impossible
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
th_set_size(t, sz);
|
||||
th_finish(t);
|
||||
i = tar_block_write(t, &(t->th_buf));
|
||||
if (i != T_BLOCKSIZE)
|
||||
{
|
||||
if (i != -1)
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0, T_BLOCKSIZE);
|
||||
snprintf(buf, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", sz, t->th_buf.selinux_context);
|
||||
i = tar_block_write(t, &buf);
|
||||
if (i != T_BLOCKSIZE)
|
||||
{
|
||||
if (i != -1)
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* reset type and size to original values */
|
||||
t->th_buf.typeflag = type2;
|
||||
th_set_size(t, sz2);
|
||||
}
|
||||
#endif
|
||||
|
||||
th_finish(t);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
# include <libgen.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include "selinux/selinux.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(NEED_BASENAME) && !defined(HAVE_BASENAME)
|
||||
|
||||
|
||||
@@ -154,6 +154,18 @@ tar_extract_file(TAR *t, char *realname, char *prefix)
|
||||
printf("FAILED SETTING PERMS: %d\n", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf(" Restoring SELinux context %s to file %s\n", t->th_buf.selinux_context, realname);
|
||||
#endif
|
||||
if(setfilecon(realname, t->th_buf.selinux_context) < 0)
|
||||
fprintf(stderr, "Failed to restore SELinux context %s!\n", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
pathname_len = strlen(th_get_pathname(t)) + 1;
|
||||
realname_len = strlen(realname) + 1;
|
||||
|
||||
@@ -35,6 +35,9 @@ extern "C"
|
||||
#define GNU_LONGNAME_TYPE 'L'
|
||||
#define GNU_LONGLINK_TYPE 'K'
|
||||
|
||||
/* extended metadata for next file - used to store selinux_context */
|
||||
#define TH_EXT_TYPE 'x'
|
||||
|
||||
/* our version of the tar header structure */
|
||||
struct tar_header
|
||||
{
|
||||
@@ -57,6 +60,9 @@ struct tar_header
|
||||
char padding[12];
|
||||
char *gnu_longname;
|
||||
char *gnu_longlink;
|
||||
#ifdef HAVE_SELINUX
|
||||
char *selinux_context;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -96,6 +102,7 @@ TAR;
|
||||
#define TAR_CHECK_MAGIC 16 /* check magic in file header */
|
||||
#define TAR_CHECK_VERSION 32 /* check version in file header */
|
||||
#define TAR_IGNORE_CRC 64 /* ignore CRC in file header */
|
||||
#define TAR_STORE_SELINUX 128 /* store selinux context */
|
||||
|
||||
/* this is obsolete - it's here for backwards-compatibility only */
|
||||
#define TAR_IGNORE_MAGIC 0
|
||||
@@ -177,6 +184,7 @@ int th_write(TAR *t);
|
||||
|| S_ISFIFO((mode_t)oct_to_int((t)->th_buf.mode)))
|
||||
#define TH_ISLONGNAME(t) ((t)->th_buf.typeflag == GNU_LONGNAME_TYPE)
|
||||
#define TH_ISLONGLINK(t) ((t)->th_buf.typeflag == GNU_LONGLINK_TYPE)
|
||||
#define TH_ISEXTHEADER(t) ((t)->th_buf.typeflag == TH_EXT_TYPE)
|
||||
|
||||
/* decode tar header info */
|
||||
#define th_get_crc(t) oct_to_int((t)->th_buf.chksum)
|
||||
|
||||
+10
-10
@@ -860,10 +860,10 @@ void* twrpTar::extractMulti(void *cookie) {
|
||||
int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
|
||||
char* charTarFile = (char*) fn.c_str();
|
||||
|
||||
if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) == -1)
|
||||
if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1)
|
||||
return -1;
|
||||
removeEOT(charTarFile);
|
||||
if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) == -1)
|
||||
if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1)
|
||||
return -1;
|
||||
for (unsigned int i = 0; i < files.size(); ++i) {
|
||||
char* file = (char*) files.at(i).c_str();
|
||||
@@ -956,7 +956,7 @@ int twrpTar::createTar() {
|
||||
close(pipes[2]);
|
||||
close(pipes[3]);
|
||||
fd = pipes[1];
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) != 0) {
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
|
||||
close(fd);
|
||||
LOGERR("tar_fdopen failed\n");
|
||||
return -1;
|
||||
@@ -1002,7 +1002,7 @@ int twrpTar::createTar() {
|
||||
// Parent
|
||||
close(pigzfd[0]); // close parent input
|
||||
fd = pigzfd[1]; // copy parent output
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) != 0) {
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
|
||||
close(fd);
|
||||
LOGERR("tar_fdopen failed\n");
|
||||
return -1;
|
||||
@@ -1042,7 +1042,7 @@ int twrpTar::createTar() {
|
||||
// Parent
|
||||
close(oaesfd[0]); // close parent input
|
||||
fd = oaesfd[1]; // copy parent output
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) != 0) {
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
|
||||
close(fd);
|
||||
LOGERR("tar_fdopen failed\n");
|
||||
return -1;
|
||||
@@ -1052,7 +1052,7 @@ int twrpTar::createTar() {
|
||||
} else {
|
||||
// Not compressed or encrypted
|
||||
init_libtar_buffer(0);
|
||||
if (tar_open(&t, charTarFile, &type, O_WRONLY | O_CREAT | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) == -1) {
|
||||
if (tar_open(&t, charTarFile, &type, O_WRONLY | O_CREAT | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1) {
|
||||
LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
|
||||
return -1;
|
||||
}
|
||||
@@ -1135,7 +1135,7 @@ int twrpTar::openTar() {
|
||||
close(pipes[1]);
|
||||
close(pipes[3]);
|
||||
fd = pipes[2];
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) != 0) {
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
|
||||
close(fd);
|
||||
LOGERR("tar_fdopen failed\n");
|
||||
return -1;
|
||||
@@ -1176,7 +1176,7 @@ int twrpTar::openTar() {
|
||||
// Parent
|
||||
close(oaesfd[1]); // close parent output
|
||||
fd = oaesfd[0]; // copy parent input
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) != 0) {
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
|
||||
close(fd);
|
||||
LOGERR("tar_fdopen failed\n");
|
||||
return -1;
|
||||
@@ -1213,13 +1213,13 @@ int twrpTar::openTar() {
|
||||
// Parent
|
||||
close(pigzfd[1]); // close parent output
|
||||
fd = pigzfd[0]; // copy parent input
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) != 0) {
|
||||
if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
|
||||
close(fd);
|
||||
LOGERR("tar_fdopen failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) != 0) {
|
||||
} else if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
|
||||
LOGERR("Unable to open tar archive '%s'\n", charTarFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user