libtar: support backing up and restoring new Android user.* xattr
Support for backing up and restoring user.default, user.inode_cache, and user.inode_code_cache xattrs introduced in Android 7.x Change-Id: I6e0aa7fc9cd30ed004ef28ebb58d60a82e518123
This commit is contained in:
+2
-2
@@ -5,7 +5,7 @@ include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libtar
|
||||
LOCAL_MODULE_TAGS := eng optional
|
||||
LOCAL_SRC_FILES := append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c
|
||||
LOCAL_SRC_FILES := append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c android_utils.c
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH) \
|
||||
external/zlib
|
||||
LOCAL_SHARED_LIBRARIES += libz libc
|
||||
@@ -26,7 +26,7 @@ include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libtar_static
|
||||
LOCAL_MODULE_TAGS := eng optional
|
||||
LOCAL_SRC_FILES := append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c
|
||||
LOCAL_SRC_FILES := append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c android_utils.c
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH) \
|
||||
external/zlib
|
||||
LOCAL_STATIC_LIBRARIES += libz libc
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
** Copyright 2008, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <string.h>
|
||||
#include <linux/limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "libtar.h"
|
||||
#include "android_utils.h"
|
||||
|
||||
/* This code may come in handy later if we ever need to extend to storing more user.inode_* xattrs
|
||||
#define USER_INODE_SEPARATOR "\0"
|
||||
#define ANDROID_USER_INODE_XATTR_PREFIX "user.inode_"
|
||||
#define ANDROID_USER_INODE_XATTR_PREFIX_LEN strlen(ANDROID_USER_INODE_XATTR_PREFIX)
|
||||
|
||||
char* scan_xattrs_for_user_inode (const char *realname, size_t *return_size)
|
||||
{
|
||||
ssize_t size;
|
||||
char xattr_list[PATH_MAX];
|
||||
size = listxattr(realname, xattr_list, sizeof(xattr_list));
|
||||
if (size < 0) {
|
||||
return NULL;
|
||||
}
|
||||
char xattr[T_BLOCKSIZE];
|
||||
char *xattr_ptr;
|
||||
int first = 1;
|
||||
*return_size = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (xattr_list[i]) {
|
||||
xattr_ptr = xattr_list + i;
|
||||
if (strncmp(xattr_ptr, ANDROID_USER_INODE_XATTR_PREFIX, ANDROID_USER_INODE_XATTR_PREFIX_LEN) == 0) {
|
||||
// found a user.inode xattr
|
||||
if (first) {
|
||||
first = 0;
|
||||
strcpy(xattr, xattr_ptr);
|
||||
*return_size = strlen(xattr_ptr);
|
||||
} else {
|
||||
char *ptr = xattr + *return_size;
|
||||
snprintf(ptr, T_BLOCKSIZE - *return_size, "%s", xattr_ptr);
|
||||
*return_size += strlen(xattr_ptr) + 1; // + 1 for null separator
|
||||
if (*return_size >= T_BLOCKSIZE) {
|
||||
*return_size = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += strlen(xattr_ptr);
|
||||
}
|
||||
}
|
||||
if (first)
|
||||
return NULL;
|
||||
return strdup(xattr);
|
||||
}*/
|
||||
|
||||
/*
|
||||
* get_path_inode and write_path_inode were taken from frameworks/native/cmds/installd/utils.cpp
|
||||
*/
|
||||
|
||||
static int get_path_inode(const char* path, ino_t *inode) {
|
||||
struct stat buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
if (stat(path, &buf) != 0) {
|
||||
printf("failed to stat %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
*inode = buf.st_ino;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the inode of a specific child file into the given xattr on the
|
||||
* parent directory. This allows you to find the child later, even if its
|
||||
* name is encrypted.
|
||||
*/
|
||||
int write_path_inode(const char* parent, const char* name, const char* inode_xattr) {
|
||||
ino_t inode = 0;
|
||||
uint64_t inode_raw = 0;
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, PATH_MAX, "%s/%s", parent, name);
|
||||
|
||||
if (mkdirhier(path) == -1) {
|
||||
printf("failed to mkdirhier for %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_path_inode(path, &inode) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check to see if already set correctly
|
||||
if (getxattr(parent, inode_xattr, &inode_raw, sizeof(inode_raw)) == sizeof(inode_raw)) {
|
||||
if (inode_raw == inode) {
|
||||
// Already set correctly; skip writing
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inode_raw = inode;
|
||||
printf("setting %s on %s pointing to %s\n", inode_xattr, parent, path);
|
||||
if (setxattr(parent, inode_xattr, &inode_raw, sizeof(inode_raw), 0) != 0 && errno != EOPNOTSUPP) {
|
||||
printf("Failed to write xattr %s at %s (%s)\n", inode_xattr, parent, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
** Copyright 2008, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef LIBTAR_ANDROID_UTILS_H
|
||||
#define LIBTAR_ANDROID_UTILS_H
|
||||
|
||||
int write_path_inode(const char* parent, const char* name, const char* inode_xattr);
|
||||
|
||||
#endif
|
||||
@@ -40,6 +40,7 @@
|
||||
#ifdef HAVE_EXT4_CRYPT
|
||||
# include "ext4crypt_tar.h"
|
||||
#endif
|
||||
#include "android_utils.h"
|
||||
|
||||
struct tar_dev
|
||||
{
|
||||
@@ -172,6 +173,32 @@ tar_append_file(TAR *t, const char *realname, const char *savename)
|
||||
}
|
||||
}
|
||||
|
||||
/* get android user.default xattr */
|
||||
if (TH_ISDIR(t) && t->options & TAR_STORE_ANDROID_USER_XATTR)
|
||||
{
|
||||
if (getxattr(realname, "user.default", NULL, 0) >= 0)
|
||||
{
|
||||
t->th_buf.has_user_default = 1;
|
||||
#if 1 //def DEBUG
|
||||
printf("storing xattr user.default\n");
|
||||
#endif
|
||||
}
|
||||
if (getxattr(realname, "user.inode_cache", NULL, 0) >= 0)
|
||||
{
|
||||
t->th_buf.has_user_cache = 1;
|
||||
#if 1 //def DEBUG
|
||||
printf("storing xattr user.inode_cache\n");
|
||||
#endif
|
||||
}
|
||||
if (getxattr(realname, "user.inode_code_cache", NULL, 0) >= 0)
|
||||
{
|
||||
t->th_buf.has_user_code_cache = 1;
|
||||
#if 1 //def DEBUG
|
||||
printf("storing xattr user.inode_code_cache\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* check if it's a hardlink */
|
||||
#ifdef DEBUG
|
||||
puts("tar_append_file(): checking inode cache for hardlink...");
|
||||
|
||||
+114
-6
@@ -23,15 +23,27 @@
|
||||
// Used to identify selinux_context in extended ('x')
|
||||
// metadata. From RedHat implementation.
|
||||
#define SELINUX_TAG "RHT.security.selinux="
|
||||
#define SELINUX_TAG_LEN 21
|
||||
#define SELINUX_TAG_LEN strlen(SELINUX_TAG)
|
||||
|
||||
// Used to identify e4crypt_policy in extended ('x')
|
||||
#define E4CRYPT_TAG "TWRP.security.e4crypt="
|
||||
#define E4CRYPT_TAG_LEN 22
|
||||
#define E4CRYPT_TAG_LEN strlen(E4CRYPT_TAG)
|
||||
|
||||
// Used to identify Posix capabilities in extended ('x')
|
||||
#define CAPABILITIES_TAG "SCHILY.xattr.security.capability="
|
||||
#define CAPABILITIES_TAG_LEN 33
|
||||
#define CAPABILITIES_TAG_LEN strlen(CAPABILITIES_TAG)
|
||||
|
||||
// Used to identify Android user.default xattr in extended ('x')
|
||||
#define ANDROID_USER_DEFAULT_TAG "ANDROID.user.default"
|
||||
#define ANDROID_USER_DEFAULT_TAG_LEN strlen(ANDROID_USER_DEFAULT_TAG)
|
||||
|
||||
// Used to identify Android user.inode_cache xattr in extended ('x')
|
||||
#define ANDROID_USER_CACHE_TAG "ANDROID.user.inode_cache"
|
||||
#define ANDROID_USER_CACHE_TAG_LEN strlen(ANDROID_USER_CACHE_TAG)
|
||||
|
||||
// Used to identify Android user.inode_code_cache xattr in extended ('x')
|
||||
#define ANDROID_USER_CODE_CACHE_TAG "ANDROID.user.inode_code_cache"
|
||||
#define ANDROID_USER_CODE_CACHE_TAG_LEN strlen(ANDROID_USER_CODE_CACHE_TAG)
|
||||
|
||||
/* read a header block */
|
||||
/* FIXME: the return value of this function should match the return value
|
||||
@@ -135,6 +147,9 @@ th_read(TAR *t)
|
||||
memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
|
||||
t->th_buf.has_cap_data = 0;
|
||||
}
|
||||
t->th_buf.has_user_default = 0;
|
||||
t->th_buf.has_user_cache = 0;
|
||||
t->th_buf.has_user_code_cache = 0;
|
||||
|
||||
memset(&(t->th_buf), 0, sizeof(struct tar_header));
|
||||
|
||||
@@ -276,7 +291,7 @@ th_read(TAR *t)
|
||||
int len = strlen(buf);
|
||||
// posix capabilities
|
||||
char *start = strstr(buf, CAPABILITIES_TAG);
|
||||
if(start && start+CAPABILITIES_TAG_LEN < buf+len)
|
||||
if (start && start+CAPABILITIES_TAG_LEN < buf+len)
|
||||
{
|
||||
start += CAPABILITIES_TAG_LEN;
|
||||
memcpy(&t->th_buf.cap_data, start, sizeof(struct vfs_cap_data));
|
||||
@@ -287,7 +302,7 @@ th_read(TAR *t)
|
||||
} // end posix capabilities
|
||||
// selinux contexts
|
||||
start = strstr(buf, SELINUX_TAG);
|
||||
if(start && start+SELINUX_TAG_LEN < buf+len)
|
||||
if (start && start+SELINUX_TAG_LEN < buf+len)
|
||||
{
|
||||
start += SELINUX_TAG_LEN;
|
||||
char *end = strchr(start, '\n');
|
||||
@@ -299,9 +314,36 @@ th_read(TAR *t)
|
||||
#endif
|
||||
}
|
||||
} // end selinux contexts
|
||||
// android user.default xattr
|
||||
start = strstr(buf, ANDROID_USER_DEFAULT_TAG);
|
||||
if (start)
|
||||
{
|
||||
t->th_buf.has_user_default = 1;
|
||||
#ifdef DEBUG
|
||||
printf(" th_read(): android user.default xattr detected\n");
|
||||
#endif
|
||||
} // end android user.default xattr
|
||||
// android user.inode_cache xattr
|
||||
start = strstr(buf, ANDROID_USER_CACHE_TAG);
|
||||
if (start)
|
||||
{
|
||||
t->th_buf.has_user_cache = 1;
|
||||
#ifdef DEBUG
|
||||
printf(" th_read(): android user.inode_cache xattr detected\n");
|
||||
#endif
|
||||
} // end android user.inode_cache xattr
|
||||
// android user.inode_code_cache xattr
|
||||
start = strstr(buf, ANDROID_USER_CODE_CACHE_TAG);
|
||||
if (start)
|
||||
{
|
||||
t->th_buf.has_user_code_cache = 1;
|
||||
#ifdef DEBUG
|
||||
printf(" th_read(): android user.inode_code_cache xattr detected\n");
|
||||
#endif
|
||||
} // end android user.inode_code_cache xattr
|
||||
#ifdef HAVE_EXT4_CRYPT
|
||||
start = strstr(buf, E4CRYPT_TAG);
|
||||
if(start && start+E4CRYPT_TAG_LEN < buf+len)
|
||||
if (start && start+E4CRYPT_TAG_LEN < buf+len)
|
||||
{
|
||||
start += E4CRYPT_TAG_LEN;
|
||||
char *end = strchr(start, '\n');
|
||||
@@ -569,6 +611,72 @@ th_write(TAR *t)
|
||||
*nlptr = '\n';
|
||||
ptr += sz;
|
||||
}
|
||||
if (t->options & TAR_STORE_ANDROID_USER_XATTR)
|
||||
{
|
||||
if (t->th_buf.has_user_default) {
|
||||
#ifdef DEBUG
|
||||
printf("th_write(): has android user.default xattr\n");
|
||||
#endif
|
||||
sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
|
||||
|
||||
if (total_sz + sz >= T_BLOCKSIZE)
|
||||
{
|
||||
if (th_write_extended(t, &buf, total_sz))
|
||||
return -1;
|
||||
ptr = buf;
|
||||
total_sz = sz;
|
||||
}
|
||||
else
|
||||
total_sz += sz;
|
||||
|
||||
snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
|
||||
char *nlptr = ptr + sz - 1;
|
||||
*nlptr = '\n';
|
||||
ptr += sz;
|
||||
}
|
||||
if (t->th_buf.has_user_cache) {
|
||||
#ifdef DEBUG
|
||||
printf("th_write(): has android user.inode_cache xattr\n");
|
||||
#endif
|
||||
sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
|
||||
|
||||
if (total_sz + sz >= T_BLOCKSIZE)
|
||||
{
|
||||
if (th_write_extended(t, &buf, total_sz))
|
||||
return -1;
|
||||
ptr = buf;
|
||||
total_sz = sz;
|
||||
}
|
||||
else
|
||||
total_sz += sz;
|
||||
|
||||
snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
|
||||
char *nlptr = ptr + sz - 1;
|
||||
*nlptr = '\n';
|
||||
ptr += sz;
|
||||
}
|
||||
if (t->th_buf.has_user_code_cache) {
|
||||
#ifdef DEBUG
|
||||
printf("th_write(): has android user.inode_code_cache xattr\n");
|
||||
#endif
|
||||
sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
|
||||
|
||||
if (total_sz + sz >= T_BLOCKSIZE)
|
||||
{
|
||||
if (th_write_extended(t, &buf, total_sz))
|
||||
return -1;
|
||||
ptr = buf;
|
||||
total_sz = sz;
|
||||
}
|
||||
else
|
||||
total_sz += sz;
|
||||
|
||||
snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
|
||||
char *nlptr = ptr + sz - 1;
|
||||
*nlptr = '\n';
|
||||
ptr += sz;
|
||||
}
|
||||
}
|
||||
if (total_sz > 0 && th_write_extended(t, &buf, total_sz)) // write any outstanding tar extended header
|
||||
return -1;
|
||||
|
||||
|
||||
+28
-1
@@ -37,6 +37,7 @@
|
||||
#ifdef HAVE_EXT4_CRYPT
|
||||
# include "ext4crypt_tar.h"
|
||||
#endif
|
||||
#include "android_utils.h"
|
||||
|
||||
const unsigned long long progress_size = (unsigned long long)(T_BLOCKSIZE);
|
||||
|
||||
@@ -469,7 +470,6 @@ tar_extract_blockdev(TAR *t, const char *realname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* directory */
|
||||
int
|
||||
tar_extract_dir(TAR *t, const char *realname)
|
||||
@@ -521,6 +521,33 @@ tar_extract_dir(TAR *t, const char *realname)
|
||||
}
|
||||
}
|
||||
|
||||
if (t->options & TAR_STORE_ANDROID_USER_XATTR)
|
||||
{
|
||||
if (t->th_buf.has_user_default) {
|
||||
#if 1 //def DEBUG
|
||||
printf("tar_extract_file(): restoring android user.default xattr to %s\n", realname);
|
||||
#endif
|
||||
if (setxattr(realname, "user.default", NULL, 0, 0) < 0) {
|
||||
fprintf(stderr, "tar_extract_file(): failed to restore android user.default to file %s !!!\n", realname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (t->th_buf.has_user_cache) {
|
||||
#if 1 //def DEBUG
|
||||
printf("tar_extract_file(): restoring android user.inode_cache xattr to %s\n", realname);
|
||||
#endif
|
||||
if (write_path_inode(realname, "cache", "user.inode_cache"))
|
||||
return -1;
|
||||
}
|
||||
if (t->th_buf.has_user_code_cache) {
|
||||
#if 1 //def DEBUG
|
||||
printf("tar_extract_file(): restoring android user.inode_code_cache xattr to %s\n", realname);
|
||||
#endif
|
||||
if (write_path_inode(realname, "code_cache", "user.inode_code_cache"))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXT4_CRYPT
|
||||
if(t->th_buf.e4crypt_policy != NULL)
|
||||
{
|
||||
|
||||
@@ -74,6 +74,9 @@ struct tar_header
|
||||
#endif
|
||||
int has_cap_data;
|
||||
struct vfs_cap_data cap_data;
|
||||
int has_user_default;
|
||||
int has_user_cache;
|
||||
int has_user_code_cache;
|
||||
};
|
||||
|
||||
|
||||
@@ -120,6 +123,7 @@ TAR;
|
||||
#define TAR_USE_NUMERIC_ID 256 /* favor numeric owner over names */
|
||||
#define TAR_STORE_EXT4_POL 512 /* store ext4 crypto policy */
|
||||
#define TAR_STORE_POSIX_CAP 1024 /* store posix file capabilities */
|
||||
#define TAR_STORE_ANDROID_USER_XATTR 2048 /* store android user.* xattr */
|
||||
|
||||
/* this is obsolete - it's here for backwards-compatibility only */
|
||||
#define TAR_IGNORE_MAGIC 0
|
||||
|
||||
+2
-2
@@ -55,9 +55,9 @@ extern "C" {
|
||||
|
||||
#ifdef TW_INCLUDE_FBE
|
||||
#include "crypto/ext4crypt/ext4crypt_tar.h"
|
||||
#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX | TAR_STORE_POSIX_CAP |TAR_STORE_EXT4_POL
|
||||
#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX | TAR_STORE_POSIX_CAP | TAR_STORE_ANDROID_USER_XATTR |TAR_STORE_EXT4_POL
|
||||
#else
|
||||
#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX | TAR_STORE_POSIX_CAP
|
||||
#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX | TAR_STORE_POSIX_CAP | TAR_STORE_ANDROID_USER_XATTR
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
Reference in New Issue
Block a user