Add overlayfs selinux fixes

Overlayfs currently has no good support for selinux. Backport some
patches being worked on upstream in order to make things work in a more
reasonable way.
This commit is contained in:
Matthew Garrett 2015-09-14 16:31:28 -07:00
parent d6e00b8bb6
commit 0f02032b14
6 changed files with 430 additions and 0 deletions

View File

@ -27,4 +27,9 @@ ${PATCH_DIR}/10-Add-option-to-automatically-enforce-module-signature.patch \
${PATCH_DIR}/12-efi-Make-EFI_SECURE_BOOT_SIG_ENFORCE-depend-on-EFI.patch \
${PATCH_DIR}/13-efi-Add-EFI_SECURE_BOOT-bit.patch \
${PATCH_DIR}/14-hibernate-Disable-in-a-signed-modules-environment.patch \
${PATCH_DIR}/overlayfs/0001-Security-Provide-copy-up-security-hooks-for-unioned-.patch \
${PATCH_DIR}/overlayfs/0002-Overlayfs-Use-copy-up-security-hooks.patch \
${PATCH_DIR}/overlayfs/0003-SELinux-Stub-in-copy-up-handling.patch \
${PATCH_DIR}/overlayfs/0004-SELinux-Handle-opening-of-a-unioned-file.patch \
${PATCH_DIR}/overlayfs/0005-SELinux-Check-against-union-label-for-file-operation.patch \
${PATCH_DIR}/net-wireless-wl18xx-Add-missing-MODULE_FIRMWARE.patch"

View File

@ -0,0 +1,140 @@
From bf7f29c3ce247f0074b9cec78e948f779d19dab6 Mon Sep 17 00:00:00 2001
From: David Howells <dhowells@redhat.com>
Date: Tue, 16 Jun 2015 14:14:31 +0100
Subject: [PATCH 1/5] Security: Provide copy-up security hooks for unioned
files
Provide two new security hooks for use with security files that are used when
a file is copied up between layers:
(1) security_inode_copy_up(). This is called so that the security label on
the destination file can be set appropriately.
(2) security_inode_copy_up_xattr(). This is called so that each xattr being
copied up can be vetted - including modification and discard.
Signed-off-by: David Howells <dhowells@redhat.com>
---
include/linux/lsm_hooks.h | 23 +++++++++++++++++++++++
include/linux/security.h | 14 ++++++++++++++
security/security.c | 17 +++++++++++++++++
3 files changed, 54 insertions(+)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 9429f05..1c38ceb 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -401,6 +401,24 @@
* @inode contains a pointer to the inode.
* @secid contains a pointer to the location where result will be saved.
* In case of failure, @secid will be set to zero.
+ * @inode_copy_up:
+ * Appropriately label the destination inode when a unioned file is copied
+ * up from a lower layer to the union/overlay layer.
+ * @src indicates the file that is being copied up.
+ * @dst indicates the file that has being created by the copy up.
+ * Returns 0 on success or a negative error code on error.
+ * @inode_copy_up_xattr:
+ * Filter/modify the xattrs being copied up when a unioned file is copied
+ * up from a lower layer to the union/overlay layer.
+ * @src indicates the file that is being copied up.
+ * @dst indicates the file that has being created by the copy up.
+ * @name indicates the name of the xattr.
+ * @value, *@size indicate the payload of the xattr.
+ * Returns 0 to accept the xattr, 1 to discard the xattr or a negative
+ * error code to abort the copy up. The xattr buffer must be at least
+ * XATTR_SIZE_MAX in capacity and the contents may be modified and *@size
+ * changed appropriately. Note that the caller is responsible for reading
+ * and writing the xattrs as this hook is merely a filter.
*
* Security hooks for file operations
*
@@ -1421,6 +1439,9 @@ union security_list_options {
int (*inode_listsecurity)(struct inode *inode, char *buffer,
size_t buffer_size);
void (*inode_getsecid)(const struct inode *inode, u32 *secid);
+ int (*inode_copy_up) (struct dentry *src, struct dentry *dst);
+ int (*inode_copy_up_xattr) (struct dentry *src, struct dentry *dst,
+ const char *name, void *value, size_t *size);
int (*file_permission)(struct file *file, int mask);
int (*file_alloc_security)(struct file *file);
@@ -1689,6 +1710,8 @@ struct security_hook_heads {
struct list_head inode_setsecurity;
struct list_head inode_listsecurity;
struct list_head inode_getsecid;
+ struct list_head inode_copy_up;
+ struct list_head inode_copy_up_xattr;
struct list_head file_permission;
struct list_head file_alloc_security;
struct list_head file_free_security;
diff --git a/include/linux/security.h b/include/linux/security.h
index 79d85dd..10d3211 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -274,6 +274,10 @@ int security_inode_getsecurity(const struct inode *inode, const char *name, void
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
void security_inode_getsecid(const struct inode *inode, u32 *secid);
+int security_inode_copy_up(struct dentry *src, struct dentry *dst);
+int security_inode_copy_up_xattr(struct dentry *src, struct dentry *dst,
+ const char *name, void *value, size_t *size);
+
int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
void security_file_free(struct file *file);
@@ -739,6 +743,16 @@ static inline void security_inode_getsecid(const struct inode *inode, u32 *secid
*secid = 0;
}
+static inline int security_inode_copy_up(struct dentry *src, struct dentry *dst)
+{
+ return 0;
+}
+static inline int security_inode_copy_up_xattr(struct dentry *src, struct dentry *dst,
+ const char *name, const void *value, size_t *size)
+{
+ return 0;
+}
+
static inline int security_file_permission(struct file *file, int mask)
{
return 0;
diff --git a/security/security.c b/security/security.c
index 9942836..976e7114 100644
--- a/security/security.c
+++ b/security/security.c
@@ -731,6 +731,19 @@ void security_inode_getsecid(const struct inode *inode, u32 *secid)
call_void_hook(inode_getsecid, inode, secid);
}
+int security_inode_copy_up(struct dentry *src, struct dentry *dst)
+{
+ return call_int_hook(inode_copy_up, 0, src, dst);
+}
+EXPORT_SYMBOL(security_inode_copy_up);
+
+int security_inode_copy_up_xattr(struct dentry *src, struct dentry *dst,
+ const char *name, void *value, size_t *size)
+{
+ return call_int_hook(inode_copy_up_xattr, 0, src, dst, name, value, size);
+}
+EXPORT_SYMBOL(security_inode_copy_up_xattr);
+
int security_file_permission(struct file *file, int mask)
{
int ret;
@@ -1659,6 +1672,10 @@ struct security_hook_heads security_hook_heads = {
LIST_HEAD_INIT(security_hook_heads.inode_listsecurity),
.inode_getsecid =
LIST_HEAD_INIT(security_hook_heads.inode_getsecid),
+ .inode_copy_up =
+ LIST_HEAD_INIT(security_hook_heads.inode_copy_up),
+ .inode_copy_up_xattr =
+ LIST_HEAD_INIT(security_hook_heads.inode_copy_up_xattr),
.file_permission =
LIST_HEAD_INIT(security_hook_heads.file_permission),
.file_alloc_security =
--
2.4.3

View File

@ -0,0 +1,47 @@
From f7232b5105b54e8605810a4a22407625ef626cfd Mon Sep 17 00:00:00 2001
From: David Howells <dhowells@redhat.com>
Date: Tue, 16 Jun 2015 14:14:31 +0100
Subject: [PATCH 2/5] Overlayfs: Use copy-up security hooks
Use the copy-up security hooks previously provided to allow an LSM to adjust
the security on a newly created copy and to filter the xattrs copied to that
file copy.
Signed-off-by: David Howells <dhowells@redhat.com>
---
fs/overlayfs/copy_up.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 84d693d..8f66b39 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -58,6 +58,14 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
error = size;
goto out_free_value;
}
+ error = security_inode_copy_up_xattr(old, new,
+ name, value, &size);
+ if (error < 0)
+ goto out_free_value;
+ if (error == 1) {
+ error = 0;
+ continue; /* Discard */
+ }
error = vfs_setxattr(new, name, value, size, 0);
if (error)
goto out_free_value;
@@ -223,6 +231,10 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
if (err)
goto out2;
+ err = security_inode_copy_up(lowerpath->dentry, newdentry);
+ if (err < 0)
+ goto out_cleanup;
+
if (S_ISREG(stat->mode)) {
struct path upperpath;
ovl_path_upper(dentry, &upperpath);
--
2.4.3

View File

@ -0,0 +1,55 @@
From c86855ff554866751bbaf3f710081222448ae2cc Mon Sep 17 00:00:00 2001
From: David Howells <dhowells@redhat.com>
Date: Tue, 16 Jun 2015 14:14:32 +0100
Subject: [PATCH 3/5] SELinux: Stub in copy-up handling
Provide stubs for union/overlay copy-up handling. The xattr copy up stub
discards lower SELinux xattrs rather than letting them be copied up so that
the security label on the copy doesn't get corrupted.
Signed-off-by: David Howells <dhowells@redhat.com>
---
security/selinux/hooks.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 564079c..5b5864f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3184,6 +3184,24 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
*secid = isec->sid;
}
+static int selinux_inode_copy_up(struct dentry *src, struct dentry *dst)
+{
+ return 0;
+}
+
+static int selinux_inode_copy_up_xattr(struct dentry *src, struct dentry *dst,
+ const char *name, void *value,
+ size_t *size)
+{
+ /* The copy_up hook above sets the initial context on an inode, but we
+ * don't then want to overwrite it by blindly copying all the lower
+ * xattrs up. Instead, we have to filter out SELinux-related xattrs.
+ */
+ if (strcmp(name, XATTR_NAME_SELINUX) == 0)
+ return 1; /* Discard */
+ return 0;
+}
+
/* file security operations */
static int selinux_revalidate_file_permission(struct file *file, int mask)
@@ -5872,6 +5890,8 @@ static struct security_hook_list selinux_hooks[] = {
LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
+ LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
+ LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
--
2.4.3

View File

@ -0,0 +1,133 @@
From 960b4a846a973eab6caf342af7b19e4e1cf7cdd3 Mon Sep 17 00:00:00 2001
From: David Howells <dhowells@redhat.com>
Date: Tue, 16 Jun 2015 14:14:32 +0100
Subject: [PATCH 4/5] SELinux: Handle opening of a unioned file
Handle the opening of a unioned file by trying to derive the label that would
be attached to the union-layer inode if it doesn't exist.
If the union-layer inode does exist (as it necessarily does in overlayfs, but
not in unionmount), we assume that it has the right label and use that.
Otherwise we try to get it from the superblock.
If the superblock has a globally-applied label, we use that, otherwise we try
to transition to an appropriate label. This union label is then stored in the
file_security_struct.
We then perform an additional check to make sure that the calling task is
granted permission by the union-layer inode label to open the file in addition
to a check to make sure that the task is granted permission to open the lower
file with the lower inode label.
Signed-off-by: David Howells <dhowells@redhat.com>
---
security/selinux/hooks.c | 69 +++++++++++++++++++++++++++++++++++++++
security/selinux/include/objsec.h | 1 +
2 files changed, 70 insertions(+)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5b5864f..1b5a338 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3474,10 +3474,72 @@ static int selinux_file_receive(struct file *file)
return file_has_perm(cred, file, file_to_av(file));
}
+/*
+ * We have a file opened on a unioned file system that falls through to a file
+ * on a lower layer. If there is a union inode, we try to get the label from
+ * that, otherwise we need to get it from the superblock.
+ *
+ * file->f_path points to the union layer and file->f_inode points to the lower
+ * layer.
+ */
+static int selinux_file_open_union(struct file *file,
+ struct file_security_struct *fsec,
+ const struct cred *cred)
+{
+ const struct superblock_security_struct *sbsec;
+ const struct inode_security_struct *isec, *dsec, *fisec;
+ const struct task_security_struct *tsec = current_security();
+ struct common_audit_data ad;
+ struct dentry *union_dentry = file->f_path.dentry;
+ const struct inode *union_inode = d_inode(union_dentry);
+ const struct inode *lower_inode = file_inode(file);
+ struct dentry *dir;
+ int rc;
+
+ sbsec = union_dentry->d_sb->s_security;
+
+ if (union_inode) {
+ isec = union_inode->i_security;
+ fsec->union_isid = isec->sid;
+ } else if ((sbsec->flags & SE_SBINITIALIZED) &&
+ (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) {
+ fsec->union_isid = sbsec->mntpoint_sid;
+ } else {
+ dir = dget_parent(union_dentry);
+ dsec = d_inode(dir)->i_security;
+
+ rc = security_transition_sid(
+ tsec->sid, dsec->sid,
+ inode_mode_to_security_class(lower_inode->i_mode),
+ &union_dentry->d_name,
+ &fsec->union_isid);
+ dput(dir);
+ if (rc) {
+ pr_warn("%s: security_transition_sid failed, rc=%d (name=%pD)\n",
+ __func__, -rc, file);
+ return rc;
+ }
+ }
+
+ /* We need to check that the union file is allowed to be opened as well
+ * as checking that the lower file is allowed to be opened.
+ */
+ if (unlikely(IS_PRIVATE(lower_inode)))
+ return 0;
+
+ ad.type = LSM_AUDIT_DATA_PATH;
+ ad.u.path = file->f_path;
+
+ fisec = lower_inode->i_security;
+ return avc_has_perm(cred_sid(cred), fsec->union_isid, fisec->sclass,
+ open_file_to_av(file), &ad);
+}
+
static int selinux_file_open(struct file *file, const struct cred *cred)
{
struct file_security_struct *fsec;
struct inode_security_struct *isec;
+ int rc;
fsec = file->f_security;
isec = file_inode(file)->i_security;
@@ -3498,6 +3560,13 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
* new inode label or new policy.
* This check is not redundant - do not remove.
*/
+
+ if (d_inode(file->f_path.dentry) != file->f_inode) {
+ rc = selinux_file_open_union(file, fsec, cred);
+ if (rc < 0)
+ return rc;
+ }
+
return file_path_has_perm(cred, file, open_file_to_av(file));
}
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 81fa718..f088c08 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -54,6 +54,7 @@ struct file_security_struct {
u32 sid; /* SID of open file description */
u32 fown_sid; /* SID of file owner (for SIGIO) */
u32 isid; /* SID of inode at the time of file open */
+ u32 union_isid; /* SID of would-be inodes in union top (or 0) */
u32 pseqno; /* Policy seqno at the time of file open */
};
--
2.4.3

View File

@ -0,0 +1,50 @@
From 8801593b646aa444732e4c7431442d453d1b08cf Mon Sep 17 00:00:00 2001
From: David Howells <dhowells@redhat.com>
Date: Tue, 16 Jun 2015 14:14:32 +0100
Subject: [PATCH 5/5] SELinux: Check against union label for file operations
File operations (eg. read, write) issued against a file that is attached to
the lower layer of a union file needs to be checked against the union-layer
label not the lower layer label.
The union label is stored in the file_security_struct rather than being
retrieved from one of the inodes.
Signed-off-by: David Howells <dhowells@redhat.com>
---
security/selinux/hooks.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1b5a338..b33cbbb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1671,6 +1671,7 @@ static int file_has_perm(const struct cred *cred,
struct file *file,
u32 av)
{
+ struct inode_security_struct *isec;
struct file_security_struct *fsec = file->f_security;
struct inode *inode = file_inode(file);
struct common_audit_data ad;
@@ -1691,8 +1692,15 @@ static int file_has_perm(const struct cred *cred,
/* av is zero if only checking access to the descriptor. */
rc = 0;
- if (av)
- rc = inode_has_perm(cred, inode, av, &ad);
+ if (av && likely(!IS_PRIVATE(inode))) {
+ if (fsec->union_isid) {
+ isec = inode->i_security;
+ rc = avc_has_perm(sid, fsec->union_isid, isec->sclass,
+ av, &ad);
+ }
+ if (!rc)
+ rc = inode_has_perm(cred, inode, av, &ad);
+ }
out:
return rc;
--
2.4.3