blob: 9dd99d38c22d8969718f4ba049b6b75dd803db2e [file] [log] [blame]
From 204527c73663a2b78cede04f6328ed14a4bdffa5 Mon Sep 17 00:00:00 2001
From: Gwendal Grignou <gwendal@google.com>
Date: Fri, 30 Apr 2021 13:34:23 -0700
Subject: [PATCH] squashfs-tools: Allow setting selinux xattrs through
file_context
Add a context-file flag that allows passing an selinux security context
file to set security.selinux xattrs rather than reading xattrs from
filesystem's source directory.
Based on the original change to allow the use of SELinux file_contexts
directly from the source file which was committed to Android's copy
of squashfs-tools and written by Mohamad Ayyash <mkayyash@google.com>
---
---
squashfs-tools/Makefile | 26 ++++++-
squashfs-tools/mksquashfs.c | 34 ++++++++-
squashfs-tools/selinux.c | 62 ++++++++++++++++
squashfs-tools/selinux.h | 27 +++++++
squashfs-tools/xattr.c | 140 ++++++++++++++++++++++++++----------
squashfs-tools/xattr.h | 10 ++-
6 files changed, 258 insertions(+), 41 deletions(-)
create mode 100644 squashfs-tools/selinux.c
create mode 100644 squashfs-tools/selinux.h
diff --git a/squashfs-tools/Makefile b/squashfs-tools/Makefile
index 9aa4381..4cf2425 100755
--- a/squashfs-tools/Makefile
+++ b/squashfs-tools/Makefile
@@ -114,6 +114,22 @@ XATTR_SUPPORT = 1
# default. Users can enable xattrs by using the -xattrs option.
XATTR_DEFAULT = 1
+###############################################
+# SELinux labelling support build options #
+###############################################
+#
+# Building SELinux labelling support for Mksquashfs. This provides an
+# alternative to reading SELinux labels from the filesystem with XATTR
+# support. It is possible to label the files in the Squashfs filesystem
+# differently than the source filesystem with this option.
+#
+# Note that SELinux labelling support requries that XATTR is also
+# supported.
+#
+# If your build/target environment does not have support for SELinux then
+# comment out the next line to build Mksquashfs without SELinux labelling
+# support.
+SELINUX_SUPPORT = 1
###############################################
# Reproducible Image options #
@@ -214,7 +230,7 @@ UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
unsquash-4.o unsquash-123.o unsquash-34.o unsquash-1234.o unsquash-12.o \
swap.o compressor.o unsquashfs_info.o date.o
-CFLAGS ?= -O2
+CFLAGS ?= -O2 -ggdb
CFLAGS += $(EXTRA_CFLAGS) $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 \
-D_LARGEFILE_SOURCE -D_GNU_SOURCE -DCOMP_DEFAULT=\"$(COMP_DEFAULT)\" \
-Wall
@@ -286,6 +302,14 @@ CFLAGS += -DXATTR_SUPPORT
endif
MKSQUASHFS_OBJS += xattr.o read_xattrs.o tar_xattr.o pseudo_xattr.o
UNSQUASHFS_OBJS += read_xattrs.o unsquashfs_xattr.o
+
+# SELinux support is only available if XATTR support is available
+ifeq ($(SELINUX_SUPPORT),1)
+CFLAGS += -DSELINUX_SUPPORT
+MKSQUASHFS_OBJS += selinux.o
+LIBS += -lselinux
+endif
+
endif
ifeq ($(REPRODUCIBLE_DEFAULT),1)
diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c
index a6f3bcb..985eb26 100644
--- a/squashfs-tools/mksquashfs.c
+++ b/squashfs-tools/mksquashfs.c
@@ -75,6 +75,7 @@
#include "fnmatch_compat.h"
#include "tar.h"
#include "merge_sort.h"
+#include "selinux.h"
/* Compression options */
int noF = FALSE;
@@ -352,6 +353,11 @@ char *sqfstar_option_table[] = { "comp", "b", "mkfs-time", "fstime", "all-time",
"default-mode", "default-uid", "default-gid", "mem-percent", NULL
};
+/* selinux label */
+squashfs_selinux_handle *sehnd = NULL;
+char *context_file = NULL;
+char *mount_point = NULL;
+
static char *read_from_disk(long long start, unsigned int avail_bytes);
static void add_old_root_entry(char *name, squashfs_inode inode,
unsigned int inode_number, int type);
@@ -6171,6 +6177,9 @@ static void print_options(FILE *stream, char *name, int total_mem)
fprintf(stream, "-comp <comp>\t\tselect <comp> compression\n");
fprintf(stream, "\t\t\tCompressors available:\n");
display_compressors(stream, "\t\t\t", COMP_DEFAULT);
+ fprintf(stream, "-context-file <file>\tApply SELinux context ");
+ fprintf(stream, "xattr from <file> instead\n\t\t\t");
+ fprintf(stream, "of reading xattr from filesystem\n");
fprintf(stream, "-noI\t\t\tdo not compress inode table\n");
fprintf(stream, "-noId\t\t\tdo not compress the uid/gid table (implied by ");
fprintf(stream, "-noI)\n");
@@ -6249,6 +6258,9 @@ static void print_options(FILE *stream, char *name, int total_mem)
fprintf(stream, "create a root\n");
fprintf(stream, "\t\t\tdirectory containing that directory, rather than the\n");
fprintf(stream, "\t\t\tcontents of the directory\n");
+ fprintf(stream, "-mount-point <name>\tWhen applying attributes such ");
+ fprintf(stream, "as SELinux context, treat\n\t\t\t");
+ fprintf(stream, "the filesystem as mounted at <name>\n");
fprintf(stream, "-4k-align\t\tenables 4k alignment of all files\n");
fprintf(stream, "\nFilesystem filter options:\n");
fprintf(stream, "-p <pseudo-definition>\tadd pseudo file ");
@@ -6460,6 +6472,9 @@ static void print_sqfstar_options(FILE *stream, char *name, int total_mem)
fprintf(stream, "-comp <comp>\t\tselect <comp> compression\n");
fprintf(stream, "\t\t\tCompressors available:\n");
display_compressors(stream, "\t\t\t", COMP_DEFAULT);
+ fprintf(stream, "-context-file <file>\tApply SELinux context ");
+ fprintf(stream, "xattr from <file> instead\n\t\t\t");
+ fprintf(stream, "of reading xattr from filesystem\n");
fprintf(stream, "-noI\t\t\tdo not compress inode table\n");
fprintf(stream, "-noId\t\t\tdo not compress the uid/gid table (implied by ");
fprintf(stream, "-noI)\n");
@@ -8392,7 +8407,15 @@ print_compressor_options:
xattrs_add(argv[i]);
no_xattrs = FALSE;
}
- } else if(strcmp(argv[i], "-nopad") == 0)
+ } else if(strcmp(argv[i], "-context-file") == 0) {
+ if(++i == argc) {
+ ERROR("%s: -context-file: missing filename\n",
+ argv[0]);
+ exit(1);
+ }
+ context_file = argv[i];
+ }
+ else if(strcmp(argv[i], "-nopad") == 0)
nopad = TRUE;
else if(strcmp(argv[i], "-info") == 0)
@@ -8410,6 +8433,15 @@ print_compressor_options:
else if(strcmp(argv[i], "-keep-as-directory") == 0)
keep_as_directory = TRUE;
+ else if(strcmp(argv[i], "-mount-point") == 0) {
+ if(++i == argc) {
+ ERROR("%s: -mount-point: missing mount point name\n",
+ argv[0]);
+ exit(1);
+ }
+ mount_point = argv[i];
+ }
+
else if(strcmp(argv[i], "-exit-on-error") == 0)
exit_on_error = TRUE;
diff --git a/squashfs-tools/selinux.c b/squashfs-tools/selinux.c
new file mode 100644
index 0000000..e28c44c
--- /dev/null
+++ b/squashfs-tools/selinux.c
@@ -0,0 +1,62 @@
+/* Copyright 2015 The Android Open Source Project */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <selinux/label.h>
+
+#include "error.h"
+#include "mksquashfs_error.h"
+#include "selinux.h"
+#include "xattr.h"
+
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+
+squashfs_selinux_handle *get_sehnd(const char *context_file) {
+ struct selinux_opt seopts[] = {
+ {
+ .type = SELABEL_OPT_PATH,
+ .value = context_file
+ }
+ };
+ struct selabel_handle *sehnd =
+ selabel_open(SELABEL_CTX_FILE, seopts, ARRAY_SIZE(seopts));
+
+ if(sehnd == NULL)
+ BAD_ERROR("Failure calling selabel_open: %s\n", strerror(errno));
+
+ return sehnd;
+}
+
+static char *set_selabel(const char *path, unsigned int mode, struct selabel_handle *sehnd) {
+ char *secontext;
+ if(sehnd == NULL)
+ BAD_ERROR("selabel handle is NULL\n");
+
+ int full_name_size = strlen(path) + 2;
+ char* full_name = (char*) malloc(full_name_size);
+ if(full_name == NULL)
+ MEM_ERROR();
+
+ full_name[0] = '/';
+ strncpy(full_name + 1, path, full_name_size - 1);
+
+ if(selabel_lookup(sehnd, &secontext, full_name, mode))
+ secontext = strdup("u:object_r:unlabeled:s0");
+
+ free(full_name);
+ return secontext;
+}
+
+void read_selinux_xattr_from_context_file(char *filename, int mode,
+ squashfs_selinux_handle *sehnd, struct xattr_list *xattrs) {
+ char *attr_val;
+
+ xattrs->type = xattr_get_prefix(xattrs, "security.selinux");
+ attr_val = set_selabel(filename, mode, sehnd);
+ xattrs->value = (void *)attr_val;
+ xattrs->vsize = strlen(attr_val);
+}
+
diff --git a/squashfs-tools/selinux.h b/squashfs-tools/selinux.h
new file mode 100644
index 0000000..f29b679
--- /dev/null
+++ b/squashfs-tools/selinux.h
@@ -0,0 +1,27 @@
+/* Copyright 2015 The Android Open Source Project */
+
+#ifndef SELINUX_H
+#define SELINUX_H
+
+#include "xattr.h"
+
+#ifdef SELINUX_SUPPORT
+typedef struct selabel_handle squashfs_selinux_handle;
+extern squashfs_selinux_handle *get_sehnd(const char *context_file);
+extern void read_selinux_xattr_from_context_file(char *filename, int mode,
+ struct selabel_handle *sehnd, struct xattr_list *xattrs);
+#else
+typedef void squashfs_selinux_handle;
+
+
+static squashfs_selinux_handle *get_sehnd(const char *context_file) {
+ return NULL;
+}
+
+
+static void read_selinux_xattr_from_context_file(char *filename, int mode,
+ squashfs_selinux_handle *sehnd, struct xattr_list *xattrs) {
+}
+#endif
+
+#endif
diff --git a/squashfs-tools/xattr.c b/squashfs-tools/xattr.c
index f9f4cc3..5b46942 100644
--- a/squashfs-tools/xattr.c
+++ b/squashfs-tools/xattr.c
@@ -35,6 +35,7 @@
#include <errno.h>
#include <dirent.h>
#include <string.h>
+#include <stdint.h>
#include <stdlib.h>
#include <sys/xattr.h>
#include <regex.h>
@@ -43,6 +44,7 @@
#include "squashfs_swap.h"
#include "mksquashfs.h"
#include "xattr.h"
+#include "selinux.h"
#include "mksquashfs_error.h"
#include "progressbar.h"
#include "pseudo.h"
@@ -60,6 +62,8 @@
/* compressed xattr table */
static char *xattr_table = NULL;
static unsigned int xattr_size = 0;
+extern char *context_file;
+extern char *mount_point;
/* cached uncompressed xattr data */
static char *data_cache = NULL;
@@ -103,12 +107,71 @@ extern void write_destination(int, long long, long long, void *);
extern long long generic_write_table(long long, void *, int, void *, int);
extern int mangle(char *, char *, int, int, int, int);
extern char *pathname(struct dir_ent *);
+extern char *subpathname(struct dir_ent *);
/* helper functions and definitions from read_xattrs.c */
extern unsigned int read_xattrs_from_disk(int, struct squashfs_super_block *, int, long long *);
extern struct xattr_list *get_xattr(int, unsigned int *, int *);
extern struct prefix prefix_table[];
+/* selinux label */
+extern squashfs_selinux_handle *sehnd;
+
+void alloc_mounted_path(const char *mount_point, const char *subpath, char **new_path) {
+ size_t mount_point_len = strlen(mount_point);
+ size_t subpath_len = strlen(subpath);
+ size_t new_path_len = mount_point_len + subpath_len + 1;
+
+ if(new_path_len < mount_point_len || new_path_len < subpath_len)
+ BAD_ERROR("Cannot allocate mounted path length; it is over %d\n",
+ SIZE_MAX);
+
+ *new_path = malloc(new_path_len);
+ if (*new_path == NULL)
+ MEM_ERROR();
+
+ strcpy(*new_path, mount_point);
+ strcat(*new_path, subpath);
+}
+
+static struct xattr_list *xattr_list_add(int *xattr_count, struct xattr_list **xattrs) {
+ struct xattr_list *x, *next_xattr;
+
+ x = realloc(*xattrs, ++*xattr_count * sizeof(struct xattr_list));
+ if(x == NULL)
+ MEM_ERROR();
+
+ next_xattr = &x[*xattr_count - 1];
+ memset(next_xattr, 0, sizeof(struct xattr_list));
+
+ *xattrs = x;
+ return next_xattr;
+}
+
+static struct xattr_list *xattr_list_trim(int *xattr_count, struct xattr_list **xattrs) {
+ struct xattr_list *x, *last_xattr;
+
+ if (*xattr_count == 0 || *xattrs == NULL)
+ return NULL;
+ x = *xattrs;
+
+ last_xattr = &x[*xattr_count - 1];
+ free(last_xattr->full_name);
+ free(last_xattr->value);
+
+ if (--*xattr_count == 0) {
+ free(*xattrs);
+ *xattrs = NULL;
+ return NULL;
+ }
+
+ x = realloc(*xattrs, *xattr_count * sizeof(struct xattr_list));
+ if(x == NULL)
+ MEM_ERROR();
+
+ *xattrs = x;
+ return &x[*xattr_count - 1];
+}
static int xattr_get_type(char *name)
{
@@ -144,12 +207,10 @@ int xattr_get_prefix(struct xattr_list *xattr, char *name)
static int read_xattrs_from_system(struct dir_ent *dir_ent, char *filename,
- struct xattr_list **xattrs)
+ int* xattr_count, struct xattr_list **xattrs)
{
ssize_t size, vsize;
char *xattr_names, *p;
- int i = 0;
- struct xattr_list *xattr_list = NULL;
struct xattr_data *xattr_exc_list;
struct xattr_data *xattr_inc_list;
@@ -191,7 +252,6 @@ static int read_xattrs_from_system(struct dir_ent *dir_ent, char *filename,
xattr_inc_list = eval_xattr_inc_actions(root_dir, dir_ent);
for(p = xattr_names; p < xattr_names + size;) {
- struct xattr_list *x;
int res;
res = match_xattr_exc_actions(xattr_exc_list, p);
@@ -222,14 +282,10 @@ static int read_xattrs_from_system(struct dir_ent *dir_ent, char *filename,
}
}
- x = realloc(xattr_list, (i + 1) * sizeof(struct xattr_list));
- if(x == NULL)
- MEM_ERROR();
- xattr_list = x;
-
- xattr_list[i].type = xattr_get_prefix(&xattr_list[i], p);
+ struct xattr_list *next_xattr = xattr_list_add(xattr_count, xattrs);
+ next_xattr->type = xattr_get_prefix(next_xattr, p);
- if(xattr_list[i].type == -1) {
+ if(next_xattr->type == -1) {
ERROR("Unrecognised xattr prefix %s\n", p);
p += strlen(p) + 1;
continue;
@@ -238,25 +294,25 @@ static int read_xattrs_from_system(struct dir_ent *dir_ent, char *filename,
p += strlen(p) + 1;
while(1) {
- vsize = lgetxattr(filename, xattr_list[i].full_name,
+ vsize = lgetxattr(filename, next_xattr->full_name,
NULL, 0);
if(vsize < 0) {
ERROR_START("lgetxattr failed for %s in "
"read_attrs, because %s", filename,
strerror(errno));
ERROR_EXIT(". Ignoring\n");
- free(xattr_list[i].full_name);
+ xattr_list_trim(xattr_count, xattrs);
goto failed;
}
- xattr_list[i].value = malloc(vsize);
- if(xattr_list[i].value == NULL)
+ next_xattr->value = malloc(vsize);
+ if(next_xattr->value == NULL)
MEM_ERROR();
- vsize = lgetxattr(filename, xattr_list[i].full_name,
- xattr_list[i].value, vsize);
+ vsize = lgetxattr(filename, next_xattr->full_name,
+ next_xattr->value, vsize);
if(vsize < 0) {
- free(xattr_list[i].value);
+ free(next_xattr->value);
if(errno == ERANGE)
/* xattr grew? Try again */
continue;
@@ -265,7 +321,7 @@ static int read_xattrs_from_system(struct dir_ent *dir_ent, char *filename,
"in read_attrs, because %s",
filename, strerror(errno));
ERROR_EXIT(". Ignoring\n");
- free(xattr_list[i].full_name);
+ xattr_list_trim(xattr_count, xattrs);
goto failed;
}
}
@@ -273,28 +329,18 @@ static int read_xattrs_from_system(struct dir_ent *dir_ent, char *filename,
break;
}
- xattr_list[i].vsize = vsize;
+ next_xattr->vsize = vsize;
TRACE("read_xattrs_from_system: filename %s, xattr name %s,"
- " vsize %d\n", filename, xattr_list[i].full_name,
- xattr_list[i].vsize);
- i++;
+ " vsize %d\n", filename, next_xattr->full_name,
+ next_xattr->vsize);
}
free(xattr_names);
-
- if(i > 0)
- *xattrs = xattr_list;
- else
- free(xattr_list);
- return i;
+ return 1;
failed:
- while(--i >= 0) {
- free(xattr_list[i].full_name);
- free(xattr_list[i].value);
- }
- free(xattr_list);
+ while(xattr_list_trim(xattr_count, xattrs) != NULL);
free(xattr_names);
return 0;
}
@@ -708,7 +754,7 @@ int read_xattrs(void *d, int type)
struct dir_ent *dir_ent = d;
struct inode_info *inode = dir_ent->inode;
char *filename = pathname(dir_ent);
- struct xattr_list *xattr_list = NULL, *head;
+ struct xattr_list *xattr_list = NULL, *head, *next_xattr = NULL;
int count, i = 0, j;
struct xattr_add *l1 = xattr_add_list, *l2 = NULL, *l3 = NULL;
struct xattr_add *action_add_list;
@@ -719,7 +765,24 @@ int read_xattrs(void *d, int type)
if(IS_TARFILE(inode))
i = read_xattrs_from_tarfile(inode, &xattr_list);
else if(!inode->dummy_root_dir && !IS_PSEUDO(inode))
- i = read_xattrs_from_system(dir_ent, filename, &xattr_list);
+ read_xattrs_from_system(dir_ent, filename, &i, &xattr_list);
+
+ if(context_file) {
+ if(sehnd == NULL)
+ sehnd = get_sehnd(context_file);
+ if(mount_point) {
+ char *mounted_path;
+ alloc_mounted_path(mount_point, subpathname(dir_ent), &mounted_path);
+ next_xattr = xattr_list_add(&i, &xattr_list);
+ read_selinux_xattr_from_context_file(mounted_path, inode->buf.st_mode,
+ sehnd, next_xattr);
+ free(mounted_path);
+ } else {
+ next_xattr = xattr_list_add(&i, &xattr_list);
+ read_selinux_xattr_from_context_file(filename, inode->buf.st_mode,
+ sehnd, next_xattr);
+ }
+ }
action_add_list = eval_xattr_add_actions(root_dir, dir_ent, &count);
@@ -838,7 +901,7 @@ int read_xattrs(void *d, int type)
if(i == 0)
return SQUASHFS_INVALID_XATTR;
- else if(i == 1)
+ else if(i == 1 || context_file)
goto skip_dup_check;
/*
@@ -854,10 +917,11 @@ int read_xattrs(void *d, int type)
for(j = 0; j < i - 1; head=head->vnext, j++)
if(strcmp(head->full_name, head->vnext->full_name) == 0)
- BAD_ERROR("Duplicate xattr name %s in file %s\n",
+ BAD_ERROR("Duplicate xattr name %s in file %s\n",
head->full_name, filename);
skip_dup_check:
+
return generate_xattrs(i, xattr_list);
}
diff --git a/squashfs-tools/xattr.h b/squashfs-tools/xattr.h
index 0697f83..ba43d46 100644
--- a/squashfs-tools/xattr.h
+++ b/squashfs-tools/xattr.h
@@ -24,6 +24,8 @@
* xattr.h
*/
+#include "squashfs_fs.h"
+
#define XATTR_VALUE_OOL SQUASHFS_XATTR_VALUE_OOL
#define XATTR_PREFIX_MASK SQUASHFS_XATTR_PREFIX_MASK
@@ -83,6 +85,8 @@ struct xattr_add {
extern int generate_xattrs(int, struct xattr_list *);
#ifdef XATTR_SUPPORT
+#include <regex.h>
+extern int xattr_get_prefix(struct xattr_list *xattr, char *name);
extern int get_xattrs(int, struct squashfs_super_block *);
extern int read_xattrs(void *, int type);
extern long long write_xattrs();
@@ -103,7 +107,11 @@ extern int read_pseudo_xattr(char *orig_def, char *filename, char *name, char *d
extern void print_xattr(char *, unsigned int, int);
extern int has_xattrs(unsigned int);
#else
-#include "squashfs_swap.h"
+
+static inline int xattr_get_prefix(struct xattr_list *xattr, char *name)
+{
+ return -1;
+}
static inline int get_xattrs(int fd, struct squashfs_super_block *sBlk)
{
--
2.43.0.381.gb435a96ce8-goog