FBE for Pixel 2

Includes various minor fixes for building in Android 8 trees with r23+ tag

Update FBE extended header in libtar to version 2 and include the entire
ext4_encryption_policy structure now after translating the policy.

See this post for more details:
https://plus.google.com/u/1/+DeesTroy/posts/i33ygUi7tiu

Change-Id: I2af981e51f459b17fcd895fb8c2d3f6c8200e24b
diff --git a/libtar/append.c b/libtar/append.c
index 8896764..66e3aa1 100644
--- a/libtar/append.c
+++ b/libtar/append.c
@@ -131,27 +131,39 @@
 #ifdef HAVE_EXT4_CRYPT
 	if (TH_ISDIR(t) && t->options & TAR_STORE_EXT4_POL)
 	{
-		if (t->th_buf.e4crypt_policy != NULL)
+		if (t->th_buf.eep != NULL)
 		{
-			free(t->th_buf.e4crypt_policy);
-			t->th_buf.e4crypt_policy = NULL;
+			free(t->th_buf.eep);
+			t->th_buf.eep = NULL;
 		}
 
-		char e4crypt_policy[EXT4_KEY_DESCRIPTOR_SIZE];
-		if (e4crypt_policy_get(realname, e4crypt_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
+		t->th_buf.eep = (struct ext4_encryption_policy*)malloc(sizeof(struct ext4_encryption_policy));
+		if (!t->th_buf.eep) {
+			printf("malloc ext4_encryption_policy\n");
+			return -1;
+		}
+		if (e4crypt_policy_get_struct(realname, t->th_buf.eep))
 		{
 			char tar_policy[EXT4_KEY_DESCRIPTOR_SIZE];
 			memset(tar_policy, 0, sizeof(tar_policy));
-			char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
-			policy_to_hex(e4crypt_policy, policy_hex);
-			if (lookup_ref_key(e4crypt_policy, &tar_policy)) {
+			char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+			policy_to_hex(t->th_buf.eep->master_key_descriptor, policy_hex);
+			if (lookup_ref_key(t->th_buf.eep->master_key_descriptor, &tar_policy[0])) {
 				printf("found policy '%s' - '%s' - '%s'\n", realname, tar_policy, policy_hex);
-				t->th_buf.e4crypt_policy = strdup(tar_policy);
+				memcpy(t->th_buf.eep->master_key_descriptor, tar_policy, EXT4_KEY_DESCRIPTOR_SIZE);
 			} else {
 				printf("failed to lookup tar policy for '%s' - '%s'\n", realname, policy_hex);
+				free(t->th_buf.eep);
+				t->th_buf.eep = NULL;
 				return -1;
 			}
-		} // else no policy found, but this is not an error as not all dirs will have a policy
+		}
+		else
+		{
+			// no policy found, but this is not an error as not all dirs will have a policy
+			free(t->th_buf.eep);
+			t->th_buf.eep = NULL;
+		}
 	}
 #endif
 
diff --git a/libtar/block.c b/libtar/block.c
index 8b22059..d0adb2b 100644
--- a/libtar/block.c
+++ b/libtar/block.c
@@ -18,6 +18,10 @@
 # include <stdlib.h>
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+# include "ext4crypt_tar.h"
+#endif
+
 #define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
 
 // Used to identify selinux_context in extended ('x')
@@ -138,9 +142,8 @@
 	if (t->th_buf.selinux_context != NULL)
 		free(t->th_buf.selinux_context);
 #ifdef HAVE_EXT4_CRYPT
-	if (t->th_buf.e4crypt_policy != NULL) {
-		free(t->th_buf.e4crypt_policy);
-	}
+	if (t->th_buf.eep != NULL)
+		free(t->th_buf.eep);
 #endif
 	if (t->th_buf.has_cap_data)
 	{
@@ -345,17 +348,41 @@
 			start = strstr(buf, E4CRYPT_TAG);
 			if (start && start+E4CRYPT_TAG_LEN < buf+len)
 			{
+				t->th_buf.eep = (struct ext4_encryption_policy*)malloc(sizeof(struct ext4_encryption_policy));
+				if (!t->th_buf.eep) {
+					printf("malloc ext4_encryption_policy\n");
+					return -1;
+				}
 				start += E4CRYPT_TAG_LEN;
-				char *end = strchr(start, '\n');
-				if(!end)
-					end = strchr(start, '\0');
-				if(end)
+				if (*start == '2')
 				{
-					t->th_buf.e4crypt_policy = strndup(start, end-start);
+					start++;
+					if (start + sizeof(struct ext4_encryption_policy) != '\n')
+						printf("did not find newline char in expected location, continuing anyway...\n");
+					memcpy(t->th_buf.eep, start, sizeof(struct ext4_encryption_policy));
 #ifdef DEBUG
-					printf("    th_read(): E4Crypt policy detected: %s\n", t->th_buf.e4crypt_policy);
+					printf("    th_read(): E4Crypt policy v2 detected: %i %i %i %i %s\n",
+						(int)t->th_buf.eep->version,
+						(int)t->th_buf.eep->contents_encryption_mode,
+						(int)t->th_buf.eep->filenames_encryption_mode,
+						(int)t->th_buf.eep->flags,
+						t->th_buf.eep->master_key_descriptor);
 #endif
 				}
+				else
+				{
+					e4crypt_policy_fill_default_struct(t->th_buf.eep);
+					char *end = strchr(start, '\n');
+					if(!end)
+						end = strchr(start, '\0');
+					if(end)
+					{
+						strncpy(t->th_buf.eep->master_key_descriptor, start, end-start);
+#ifdef DEBUG
+						printf("    th_read(): E4Crypt policy v1 detected: %s\n", t->th_buf.eep->master_key_descriptor);
+#endif
+					}
+				}
 			}
 #endif // HAVE_EXT4_CRYPT
 		}
@@ -557,22 +584,22 @@
 	}
 
 #ifdef HAVE_EXT4_CRYPT
-	if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.e4crypt_policy != NULL)
+	if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.eep != NULL)
 	{
 #ifdef DEBUG
 		printf("th_write(): using e4crypt_policy %s\n",
-		       t->th_buf.e4crypt_policy);
+		       t->th_buf.eep->master_key_descriptor);
 #endif
-		/* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
+		/* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *version code* *content* *newline* */
 		//                                                       size   newline
-		sz = E4CRYPT_TAG_LEN + strlen(t->th_buf.e4crypt_policy) + 3  +    1;
+		sz = E4CRYPT_TAG_LEN + sizeof(struct ext4_encryption_policy) + 1 + 3  +    1;
 
 		if(sz >= 100) // another ascci digit for size
 			++sz;
 
 		if (total_sz + sz >= T_BLOCKSIZE)
 		{
-			if (th_write_extended(t, &buf, total_sz))
+			if (th_write_extended(t, &buf[0], total_sz))
 				return -1;
 			ptr = buf;
 			total_sz = sz;
@@ -580,7 +607,8 @@
 		else
 			total_sz += sz;
 
-		snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"%s", (int)sz, t->th_buf.e4crypt_policy);
+		snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"2", (int)sz);
+		memcpy(ptr + sz - sizeof(struct ext4_encryption_policy) - 1, t->th_buf.eep, sizeof(struct ext4_encryption_policy));
 		char *nlptr = ptr + sz - 1;
 		*nlptr = '\n';
 		ptr += sz;
@@ -599,7 +627,7 @@
 
 		if (total_sz + sz >= T_BLOCKSIZE)
 		{
-			if (th_write_extended(t, &buf, total_sz))
+			if (th_write_extended(t, &buf[0], total_sz))
 				return -1;
 			ptr = buf;
 			total_sz = sz;
@@ -623,7 +651,7 @@
 
 			if (total_sz + sz >= T_BLOCKSIZE)
 			{
-				if (th_write_extended(t, &buf, total_sz))
+				if (th_write_extended(t, &buf[0], total_sz))
 					return -1;
 				ptr = buf;
 				total_sz = sz;
@@ -644,7 +672,7 @@
 
 			if (total_sz + sz >= T_BLOCKSIZE)
 			{
-				if (th_write_extended(t, &buf, total_sz))
+				if (th_write_extended(t, &buf[0], total_sz))
 					return -1;
 				ptr = buf;
 				total_sz = sz;
@@ -665,7 +693,7 @@
 
 			if (total_sz + sz >= T_BLOCKSIZE)
 			{
-				if (th_write_extended(t, &buf, total_sz))
+				if (th_write_extended(t, &buf[0], total_sz))
 					return -1;
 				ptr = buf;
 				total_sz = sz;
@@ -679,7 +707,7 @@
 			ptr += sz;
 		}
 	}
-	if (total_sz > 0 && th_write_extended(t, &buf, total_sz)) // write any outstanding tar extended header
+	if (total_sz > 0 && th_write_extended(t, &buf[0], total_sz)) // write any outstanding tar extended header
 		return -1;
 
 	th_finish(t);
diff --git a/libtar/compat.h b/libtar/compat.h
index 70ac2f4..16b3c3b 100644
--- a/libtar/compat.h
+++ b/libtar/compat.h
@@ -4,6 +4,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 
 #include <stdarg.h>
 #include <stddef.h>
diff --git a/libtar/encode.c b/libtar/encode.c
index c937152..1e679d8 100644
--- a/libtar/encode.c
+++ b/libtar/encode.c
@@ -16,6 +16,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <sys/types.h>
+#include <sys/sysmacros.h>
 
 #ifdef STDC_HEADERS
 # include <string.h>
diff --git a/libtar/extract.c b/libtar/extract.c
index 82ed766..fcd403a 100644
--- a/libtar/extract.c
+++ b/libtar/extract.c
@@ -549,22 +549,23 @@
 	}
 
 #ifdef HAVE_EXT4_CRYPT
-	if(t->th_buf.e4crypt_policy != NULL)
+	if(t->th_buf.eep != NULL)
 	{
 #ifdef DEBUG
-		printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.e4crypt_policy, realname);
+		printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.eep->master_key_descriptor, realname);
 #endif
 		char binary_policy[EXT4_KEY_DESCRIPTOR_SIZE];
-		if (!lookup_ref_tar(t->th_buf.e4crypt_policy, &binary_policy)) {
-			printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.e4crypt_policy);
+		if (!lookup_ref_tar(t->th_buf.eep->master_key_descriptor, &binary_policy[0])) {
+			printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.eep->master_key_descriptor);
 			return -1;
 		}
-		char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
+		char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
 		policy_to_hex(binary_policy, policy_hex);
-		printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.e4crypt_policy, policy_hex, realname);
-		if (!e4crypt_policy_set(realname, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
+		printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.eep->master_key_descriptor, policy_hex, realname);
+		memcpy(&t->th_buf.eep->master_key_descriptor, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE);
+		if (!e4crypt_policy_set_struct(realname, t->th_buf.eep))
 		{
-			printf("tar_extract_file(): failed to restore EXT4 crypt policy %s to dir '%s' '%s'!!!\n", t->th_buf.e4crypt_policy, realname, policy_hex);
+			printf("tar_extract_file(): failed to restore EXT4 crypt policy to dir '%s' '%s'!!!\n", realname, policy_hex);
 			//return -1; // This may not be an error in some cases, so log and ignore
 		}
 	}
diff --git a/libtar/libtar.h b/libtar/libtar.h
index 2d0a3d3..aa637b1 100644
--- a/libtar/libtar.h
+++ b/libtar/libtar.h
@@ -21,8 +21,7 @@
 #include "libtar_listhash.h"
 
 #ifdef HAVE_EXT4_CRYPT
-#define EXT4_KEY_DESCRIPTOR_SIZE 8
-#define EXT4_KEY_DESCRIPTOR_HEX 17
+# include "ext4crypt_tar.h"
 #endif
 
 #ifdef __cplusplus
@@ -70,7 +69,7 @@
 	char *gnu_longlink;
 	char *selinux_context;
 #ifdef HAVE_EXT4_CRYPT
-	char *e4crypt_policy;
+	struct ext4_encryption_policy *eep;
 #endif
 	int has_cap_data;
 	struct vfs_cap_data cap_data;
diff --git a/libtar/output.c b/libtar/output.c
index d2bf8bb..f5431b6 100644
--- a/libtar/output.c
+++ b/libtar/output.c
@@ -24,6 +24,10 @@
 # include <string.h>
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+# include "ext4crypt_tar.h"
+#endif
+
 
 #ifndef _POSIX_LOGIN_NAME_MAX
 # define _POSIX_LOGIN_NAME_MAX	9
@@ -45,8 +49,8 @@
 	printf("  linkname = \"%.100s\"\n", t->th_buf.linkname);
 	printf("  magic    = \"%.6s\"\n", t->th_buf.magic);
 	/*printf("  version  = \"%.2s\"\n", t->th_buf.version); */
-	printf("  version[0] = \'%c\',version[1] = \'%c\'\n",
-	       t->th_buf.version[0], t->th_buf.version[1]);
+	/*printf("  version[0] = \'%c\',version[1] = \'%c\'\n",
+	       t->th_buf.version[0], t->th_buf.version[1]);*/
 	printf("  uname    = \"%.32s\"\n", t->th_buf.uname);
 	printf("  gname    = \"%.32s\"\n", t->th_buf.gname);
 	printf("  devmajor = \"%.8s\"\n", t->th_buf.devmajor);
@@ -57,6 +61,10 @@
 	       (t->th_buf.gnu_longname ? t->th_buf.gnu_longname : "[NULL]"));
 	printf("  gnu_longlink = \"%s\"\n",
 	       (t->th_buf.gnu_longlink ? t->th_buf.gnu_longlink : "[NULL]"));
+#ifdef HAVE_EXT4_CRYPT
+	printf("  eep = \"%s\"\n",
+	       (t->th_buf.eep ? t->th_buf.eep->master_key_descriptor : "[NULL]"));
+#endif
 }