* [PATCH 06/32] vfs: Add LSM hooks for the new mount API [ver #9]
[not found] <153126248868.14533.9751473662727327569.stgit@warthog.procyon.org.uk>
@ 2018-07-10 22:42 ` David Howells
2018-07-10 22:42 ` [PATCH 07/32] selinux: Implement the new mount API LSM hooks " David Howells
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: David Howells @ 2018-07-10 22:42 UTC (permalink / raw)
To: linux-security-module
Add LSM hooks for use by the new mount API and filesystem context code.
This includes:
(1) Hooks to handle allocation, duplication and freeing of the security
record attached to a filesystem context.
(2) A hook to snoop source specifications. There may be multiple of these
if the filesystem supports it. They will to be local files/devices if
fs_context::source_is_dev is true and will be something else, possibly
remote server specifications, if false.
(3) A hook to snoop superblock configuration options in key[=val] form.
If the LSM decides it wants to handle it, it can suppress the option
being passed to the filesystem. Note that 'val' may include commas
and binary data with the fsopen patch.
(4) A hook to perform validation and allocation after the configuration
has been done but before the superblock is allocated and set up.
(5) A hook to transfer the security from the context to a newly created
superblock.
(6) A hook to rule on whether a path point can be used as a mountpoint.
These are intended to replace:
security_sb_copy_data
security_sb_kern_mount
security_sb_mount
security_sb_set_mnt_opts
security_sb_clone_mnt_opts
security_sb_parse_opts_str
Signed-off-by: David Howells <dhowells@redhat.com>
cc: linux-security-module at vger.kernel.org
---
include/linux/lsm_hooks.h | 70 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/security.h | 49 ++++++++++++++++++++++++++++++++
security/security.c | 46 ++++++++++++++++++++++++++++++
3 files changed, 165 insertions(+)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 926607defd83..43ca087b6454 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -76,6 +76,56 @@
* changes on the process such as clearing out non-inheritable signal
* state. This is called immediately after commit_creds().
*
+ * Security hooks for mount using fs_context.
+ * [See also Documentation/filesystems/mounting.txt]
+ *
+ * @fs_context_alloc:
+ * Allocate and attach a security structure to sc->security. This pointer
+ * is initialised to NULL by the caller.
+ * @fc indicates the new filesystem context.
+ * @reference indicates the source dentry of a submount or start of reconfig.
+ * @fs_context_dup:
+ * Allocate and attach a security structure to sc->security. This pointer
+ * is initialised to NULL by the caller.
+ * @fc indicates the new filesystem context.
+ * @src_fc indicates the original filesystem context.
+ * @fs_context_free:
+ * Clean up a filesystem context.
+ * @fc indicates the filesystem context.
+ * @fs_context_parse_source:
+ * Check a source for the superblock (multiple sources may be provided).
+ * The LSM may reject it with an error; otherwise it should return 0.
+ * @fc indicates the filesystem context.
+ * @src indicates the source name. It is NUL-terminated,
+ * @fs_context_parse_option:
+ * Userspace provided an option to configure a superblock. The LSM may
+ * reject it with an error and may use it for itself, in which case it
+ * should return 1; otherwise it should return 0 to pass it on to the
+ * filesystem.
+ * @fc indicates the filesystem context.
+ * @opt indicates the option in "key[=val]" form. It is NUL-terminated,
+ * but val may be binary data.
+ * @len indicates the size of the option.
+ * @fs_context_validate:
+ * Validate the filesystem context preparatory to applying it. This is
+ * done after all the options have been parsed.
+ * @fc indicates the filesystem context.
+ * @sb_get_tree:
+ * Assign the security to a newly created superblock.
+ * @fc indicates the filesystem context.
+ * @fc->root indicates the root that will be mounted.
+ * @fc->root->d_sb points to the superblock.
+ * @sb_reconfigure:
+ * Apply reconfiguration to the security on a superblock.
+ * @fc indicates the filesystem context.
+ * @fc->root indicates a dentry in the mount.
+ * @fc->root->d_sb points to the superblock.
+ * @sb_mountpoint:
+ * Equivalent of sb_mount, but with an fs_context.
+ * @fc indicates the filesystem context.
+ * @mountpoint indicates the path on which the mount will take place.
+ * @mnt_flags indicates the MNT_* flags specified.
+ *
* Security hooks for filesystem operations.
*
* @sb_alloc_security:
@@ -1459,6 +1509,17 @@ union security_list_options {
void (*bprm_committing_creds)(struct linux_binprm *bprm);
void (*bprm_committed_creds)(struct linux_binprm *bprm);
+ int (*fs_context_alloc)(struct fs_context *fc, struct dentry *reference);
+ int (*fs_context_dup)(struct fs_context *fc, struct fs_context *src_sc);
+ void (*fs_context_free)(struct fs_context *fc);
+ int (*fs_context_parse_source)(struct fs_context *fc, char *src);
+ int (*fs_context_parse_option)(struct fs_context *fc, char *opt, size_t len);
+ int (*fs_context_validate)(struct fs_context *fc);
+ int (*sb_get_tree)(struct fs_context *fc);
+ void (*sb_reconfigure)(struct fs_context *fc);
+ int (*sb_mountpoint)(struct fs_context *fc, struct path *mountpoint,
+ unsigned int mnt_flags);
+
int (*sb_alloc_security)(struct super_block *sb);
void (*sb_free_security)(struct super_block *sb);
int (*sb_copy_data)(char *orig, char *copy);
@@ -1798,6 +1859,15 @@ struct security_hook_heads {
struct hlist_head bprm_check_security;
struct hlist_head bprm_committing_creds;
struct hlist_head bprm_committed_creds;
+ struct hlist_head fs_context_alloc;
+ struct hlist_head fs_context_dup;
+ struct hlist_head fs_context_free;
+ struct hlist_head fs_context_parse_source;
+ struct hlist_head fs_context_parse_option;
+ struct hlist_head fs_context_validate;
+ struct hlist_head sb_get_tree;
+ struct hlist_head sb_reconfigure;
+ struct hlist_head sb_mountpoint;
struct hlist_head sb_alloc_security;
struct hlist_head sb_free_security;
struct hlist_head sb_copy_data;
diff --git a/include/linux/security.h b/include/linux/security.h
index 15d121f156b3..7f093b27169d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -53,6 +53,7 @@ struct msg_msg;
struct xattr;
struct xfrm_sec_ctx;
struct mm_struct;
+struct fs_context;
/* If capable should audit the security request */
#define SECURITY_CAP_NOAUDIT 0
@@ -225,6 +226,16 @@ int security_bprm_set_creds(struct linux_binprm *bprm);
int security_bprm_check(struct linux_binprm *bprm);
void security_bprm_committing_creds(struct linux_binprm *bprm);
void security_bprm_committed_creds(struct linux_binprm *bprm);
+int security_fs_context_alloc(struct fs_context *fc, struct dentry *reference);
+int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc);
+void security_fs_context_free(struct fs_context *fc);
+int security_fs_context_parse_source(struct fs_context *fc, char *src);
+int security_fs_context_parse_option(struct fs_context *fc, char *opt, size_t len);
+int security_fs_context_validate(struct fs_context *fc);
+int security_sb_get_tree(struct fs_context *fc);
+void security_sb_reconfigure(struct fs_context *fc);
+int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint,
+ unsigned int mnt_flags);
int security_sb_alloc(struct super_block *sb);
void security_sb_free(struct super_block *sb);
int security_sb_copy_data(char *orig, char *copy);
@@ -526,6 +537,44 @@ static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
{
}
+static inline int security_fs_context_alloc(struct fs_context *fc,
+ struct dentry *reference)
+{
+ return 0;
+}
+static inline int security_fs_context_dup(struct fs_context *fc,
+ struct fs_context *src_fc)
+{
+ return 0;
+}
+static inline void security_fs_context_free(struct fs_context *fc)
+{
+}
+static inline int security_fs_context_parse_source(struct fs_context *fc, char *src)
+{
+ return 0;
+}
+static inline int security_fs_context_parse_option(struct fs_context *fc, char *opt, size_t len)
+{
+ return 0;
+}
+static inline int security_fs_context_validate(struct fs_context *fc)
+{
+ return 0;
+}
+static inline int security_sb_get_tree(struct fs_context *fc)
+{
+ return 0;
+}
+static inline void security_sb_reconfigure(struct fs_context *fc)
+{
+}
+static inline int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint,
+ unsigned int mnt_flags)
+{
+ return 0;
+}
+
static inline int security_sb_alloc(struct super_block *sb)
{
return 0;
diff --git a/security/security.c b/security/security.c
index c4cbdb7d3a5f..597470fd3727 100644
--- a/security/security.c
+++ b/security/security.c
@@ -358,6 +358,52 @@ void security_bprm_committed_creds(struct linux_binprm *bprm)
call_void_hook(bprm_committed_creds, bprm);
}
+int security_fs_context_alloc(struct fs_context *fc, struct dentry *reference)
+{
+ return call_int_hook(fs_context_alloc, 0, fc, reference);
+}
+
+int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
+{
+ return call_int_hook(fs_context_dup, 0, fc, src_fc);
+}
+
+void security_fs_context_free(struct fs_context *fc)
+{
+ call_void_hook(fs_context_free, fc);
+}
+
+int security_fs_context_parse_source(struct fs_context *fc, char *src)
+{
+ return call_int_hook(fs_context_parse_source, 0, fc, src);
+}
+
+int security_fs_context_parse_option(struct fs_context *fc, char *opt, size_t len)
+{
+ return call_int_hook(fs_context_parse_option, 0, fc, opt, len);
+}
+
+int security_fs_context_validate(struct fs_context *fc)
+{
+ return call_int_hook(fs_context_validate, 0, fc);
+}
+
+int security_sb_get_tree(struct fs_context *fc)
+{
+ return call_int_hook(sb_get_tree, 0, fc);
+}
+
+void security_sb_reconfigure(struct fs_context *fc)
+{
+ call_void_hook(sb_reconfigure, fc);
+}
+
+int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint,
+ unsigned int mnt_flags)
+{
+ return call_int_hook(sb_mountpoint, 0, fc, mountpoint, mnt_flags);
+}
+
int security_sb_alloc(struct super_block *sb)
{
return call_int_hook(sb_alloc_security, 0, sb);
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 07/32] selinux: Implement the new mount API LSM hooks [ver #9]
[not found] <153126248868.14533.9751473662727327569.stgit@warthog.procyon.org.uk>
2018-07-10 22:42 ` [PATCH 06/32] vfs: Add LSM hooks for the new mount API [ver #9] David Howells
@ 2018-07-10 22:42 ` David Howells
2018-07-11 14:08 ` Stephen Smalley
2018-07-10 22:42 ` [PATCH 08/32] smack: Implement filesystem context security " David Howells
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: David Howells @ 2018-07-10 22:42 UTC (permalink / raw)
To: linux-security-module
Implement the new mount API LSM hooks for SELinux. At some point the old
hooks will need to be removed.
Question: Should the ->fs_context_parse_source() hook be implemented to
check the labels on any source devices specified?
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Paul Moore <paul@paul-moore.com>
cc: Stephen Smalley <sds@tycho.nsa.gov>
cc: selinux at tycho.nsa.gov
cc: linux-security-module at vger.kernel.org
---
security/selinux/hooks.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 264 insertions(+)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5bb53edd74cc..bdecae4b7306 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -48,6 +48,7 @@
#include <linux/fdtable.h>
#include <linux/namei.h>
#include <linux/mount.h>
+#include <linux/fs_context.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/tty.h>
@@ -2973,6 +2974,261 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
FILESYSTEM__UNMOUNT, NULL);
}
+/* fsopen mount context operations */
+
+static int selinux_fs_context_alloc(struct fs_context *fc,
+ struct dentry *reference)
+{
+ struct security_mnt_opts *opts;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ fc->security = opts;
+ return 0;
+}
+
+static int selinux_fs_context_dup(struct fs_context *fc,
+ struct fs_context *src_fc)
+{
+ const struct security_mnt_opts *src = src_fc->security;
+ struct security_mnt_opts *opts;
+ int i, n;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+ fc->security = opts;
+
+ if (!src || !src->num_mnt_opts)
+ return 0;
+ n = opts->num_mnt_opts = src->num_mnt_opts;
+
+ if (src->mnt_opts) {
+ opts->mnt_opts = kcalloc(n, sizeof(char *), GFP_KERNEL);
+ if (!opts->mnt_opts)
+ return -ENOMEM;
+
+ for (i = 0; i < n; i++) {
+ if (src->mnt_opts[i]) {
+ opts->mnt_opts[i] = kstrdup(src->mnt_opts[i],
+ GFP_KERNEL);
+ if (!opts->mnt_opts[i])
+ return -ENOMEM;
+ }
+ }
+ }
+
+ if (src->mnt_opts_flags) {
+ opts->mnt_opts_flags = kmemdup(src->mnt_opts_flags,
+ n * sizeof(int), GFP_KERNEL);
+ if (!opts->mnt_opts_flags)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void selinux_fs_context_free(struct fs_context *fc)
+{
+ struct security_mnt_opts *opts = fc->security;
+
+ if (opts) {
+ security_free_mnt_opts(opts);
+ fc->security = NULL;
+ }
+}
+
+static int selinux_fs_context_parse_option(struct fs_context *fc, char *opt, size_t len)
+{
+ struct security_mnt_opts *opts = fc->security;
+ substring_t args[MAX_OPT_ARGS];
+ unsigned int have;
+ char *c, **oo;
+ int token, ctx, i, *of;
+
+ token = match_token(opt, tokens, args);
+ if (token == Opt_error)
+ return 0; /* Doesn't belong to us. */
+
+ have = 0;
+ for (i = 0; i < opts->num_mnt_opts; i++)
+ have |= 1 << opts->mnt_opts_flags[i];
+ if (have & (1 << token))
+ return -EINVAL;
+
+ switch (token) {
+ case Opt_context:
+ if (have & (1 << Opt_defcontext))
+ goto incompatible;
+ ctx = CONTEXT_MNT;
+ goto copy_context_string;
+
+ case Opt_fscontext:
+ ctx = FSCONTEXT_MNT;
+ goto copy_context_string;
+
+ case Opt_rootcontext:
+ ctx = ROOTCONTEXT_MNT;
+ goto copy_context_string;
+
+ case Opt_defcontext:
+ if (have & (1 << Opt_context))
+ goto incompatible;
+ ctx = DEFCONTEXT_MNT;
+ goto copy_context_string;
+
+ case Opt_labelsupport:
+ return 1;
+
+ default:
+ return -EINVAL;
+ }
+
+copy_context_string:
+ if (opts->num_mnt_opts > 3)
+ return -EINVAL;
+
+ of = krealloc(opts->mnt_opts_flags,
+ (opts->num_mnt_opts + 1) * sizeof(int), GFP_KERNEL);
+ if (!of)
+ return -ENOMEM;
+ of[opts->num_mnt_opts] = 0;
+ opts->mnt_opts_flags = of;
+
+ oo = krealloc(opts->mnt_opts,
+ (opts->num_mnt_opts + 1) * sizeof(char *), GFP_KERNEL);
+ if (!oo)
+ return -ENOMEM;
+ oo[opts->num_mnt_opts] = NULL;
+ opts->mnt_opts = oo;
+
+ c = match_strdup(&args[0]);
+ if (!c)
+ return -ENOMEM;
+ opts->mnt_opts[opts->num_mnt_opts] = c;
+ opts->mnt_opts_flags[opts->num_mnt_opts] = ctx;
+ opts->num_mnt_opts++;
+ return 1;
+
+incompatible:
+ return -EINVAL;
+}
+
+/*
+ * Validate the security parameters supplied for a reconfiguration/remount
+ * event.
+ */
+static int selinux_validate_for_sb_reconfigure(struct fs_context *fc)
+{
+ struct super_block *sb = fc->root->d_sb;
+ struct superblock_security_struct *sbsec = sb->s_security;
+ struct security_mnt_opts *opts = fc->security;
+ int rc, i, *flags;
+ char **mount_options;
+
+ if (!(sbsec->flags & SE_SBINITIALIZED))
+ return 0;
+
+ mount_options = opts->mnt_opts;
+ flags = opts->mnt_opts_flags;
+
+ for (i = 0; i < opts->num_mnt_opts; i++) {
+ u32 sid;
+
+ if (flags[i] == SBLABEL_MNT)
+ continue;
+
+ rc = security_context_str_to_sid(&selinux_state, mount_options[i],
+ &sid, GFP_KERNEL);
+ if (rc) {
+ pr_warn("SELinux: security_context_str_to_sid"
+ "(%s) failed for (dev %s, type %s) errno=%d\n",
+ mount_options[i], sb->s_id, sb->s_type->name, rc);
+ goto inval;
+ }
+
+ switch (flags[i]) {
+ case FSCONTEXT_MNT:
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+ goto bad_option;
+ break;
+ case CONTEXT_MNT:
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+ goto bad_option;
+ break;
+ case ROOTCONTEXT_MNT: {
+ struct inode_security_struct *root_isec;
+ root_isec = backing_inode_security(sb->s_root);
+
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+ goto bad_option;
+ break;
+ }
+ case DEFCONTEXT_MNT:
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+ goto bad_option;
+ break;
+ default:
+ goto inval;
+ }
+ }
+
+ rc = 0;
+out:
+ return rc;
+
+bad_option:
+ pr_warn("SELinux: unable to change security options "
+ "during remount (dev %s, type=%s)\n",
+ sb->s_id, sb->s_type->name);
+inval:
+ rc = -EINVAL;
+ goto out;
+}
+
+/*
+ * Validate the security context assembled from the option data supplied to
+ * mount.
+ */
+static int selinux_fs_context_validate(struct fs_context *fc)
+{
+ if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE)
+ return selinux_validate_for_sb_reconfigure(fc);
+ return 0;
+}
+
+/*
+ * Set the security context on a superblock.
+ */
+static int selinux_sb_get_tree(struct fs_context *fc)
+{
+ const struct cred *cred = current_cred();
+ struct common_audit_data ad;
+ int rc;
+
+ rc = selinux_set_mnt_opts(fc->root->d_sb, fc->security, 0, NULL);
+ if (rc)
+ return rc;
+
+ /* Allow all mounts performed by the kernel */
+ if (fc->purpose == FS_CONTEXT_FOR_KERNEL_MOUNT)
+ return 0;
+
+ ad.type = LSM_AUDIT_DATA_DENTRY;
+ ad.u.dentry = fc->root;
+ return superblock_has_perm(cred, fc->root->d_sb, FILESYSTEM__MOUNT, &ad);
+}
+
+static int selinux_sb_mountpoint(struct fs_context *fc, struct path *mountpoint,
+ unsigned int mnt_flags)
+{
+ const struct cred *cred = current_cred();
+
+ return path_has_perm(cred, mountpoint, FILE__MOUNTON);
+}
+
/* inode security operations */
static int selinux_inode_alloc_security(struct inode *inode)
@@ -6905,6 +7161,14 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
+ LSM_HOOK_INIT(fs_context_alloc, selinux_fs_context_alloc),
+ LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
+ LSM_HOOK_INIT(fs_context_free, selinux_fs_context_free),
+ LSM_HOOK_INIT(fs_context_parse_option, selinux_fs_context_parse_option),
+ LSM_HOOK_INIT(fs_context_validate, selinux_fs_context_validate),
+ LSM_HOOK_INIT(sb_get_tree, selinux_sb_get_tree),
+ LSM_HOOK_INIT(sb_mountpoint, selinux_sb_mountpoint),
+
LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 08/32] smack: Implement filesystem context security hooks [ver #9]
[not found] <153126248868.14533.9751473662727327569.stgit@warthog.procyon.org.uk>
2018-07-10 22:42 ` [PATCH 06/32] vfs: Add LSM hooks for the new mount API [ver #9] David Howells
2018-07-10 22:42 ` [PATCH 07/32] selinux: Implement the new mount API LSM hooks " David Howells
@ 2018-07-10 22:42 ` David Howells
2018-07-10 23:13 ` Casey Schaufler
2018-07-10 22:42 ` [PATCH 09/32] apparmor: Implement security hooks for the new mount API " David Howells
2018-07-10 22:42 ` [PATCH 10/32] tomoyo: " David Howells
4 siblings, 1 reply; 10+ messages in thread
From: David Howells @ 2018-07-10 22:42 UTC (permalink / raw)
To: linux-security-module
Implement filesystem context security hooks for the smack LSM.
Question: Should the ->fs_context_parse_source() hook be implemented to
check the labels on any source devices specified?
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Casey Schaufler <casey@schaufler-ca.com>
cc: linux-security-module at vger.kernel.org
---
security/smack/smack_lsm.c | 309 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 309 insertions(+)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 7ad226018f51..39780b06469b 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -42,6 +42,7 @@
#include <linux/shm.h>
#include <linux/binfmts.h>
#include <linux/parser.h>
+#include <linux/fs_context.h>
#include "smack.h"
#define TRANS_TRUE "TRUE"
@@ -521,6 +522,307 @@ static int smack_syslog(int typefrom_file)
return rc;
}
+/*
+ * Mount context operations
+ */
+
+struct smack_fs_context {
+ union {
+ struct {
+ char *fsdefault;
+ char *fsfloor;
+ char *fshat;
+ char *fsroot;
+ char *fstransmute;
+ };
+ char *ptrs[5];
+
+ };
+ struct superblock_smack *sbsp;
+ struct inode_smack *isp;
+ bool transmute;
+};
+
+/**
+ * smack_fs_context_free - Free the security data from a filesystem context
+ * @fc: The filesystem context to be cleaned up.
+ */
+static void smack_fs_context_free(struct fs_context *fc)
+{
+ struct smack_fs_context *ctx = fc->security;
+ int i;
+
+ if (ctx) {
+ for (i = 0; i < ARRAY_SIZE(ctx->ptrs); i++)
+ kfree(ctx->ptrs[i]);
+ kfree(ctx->isp);
+ kfree(ctx->sbsp);
+ kfree(ctx);
+ fc->security = NULL;
+ }
+}
+
+/**
+ * smack_fs_context_alloc - Allocate security data for a filesystem context
+ * @fc: The filesystem context.
+ * @reference: Reference dentry (automount/reconfigure) or NULL
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_fs_context_alloc(struct fs_context *fc,
+ struct dentry *reference)
+{
+ struct smack_fs_context *ctx;
+ struct superblock_smack *sbsp;
+ struct inode_smack *isp;
+ struct smack_known *skp;
+
+ ctx = kzalloc(sizeof(struct smack_fs_context), GFP_KERNEL);
+ if (!ctx)
+ goto nomem;
+ fc->security = ctx;
+
+ sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
+ if (!sbsp)
+ goto nomem_free;
+ ctx->sbsp = sbsp;
+
+ isp = new_inode_smack(NULL);
+ if (!isp)
+ goto nomem_free;
+ ctx->isp = isp;
+
+ if (reference) {
+ if (reference->d_sb->s_security)
+ memcpy(sbsp, reference->d_sb->s_security, sizeof(*sbsp));
+ } else if (!smack_privileged(CAP_MAC_ADMIN)) {
+ /* Unprivileged mounts get root and default from the caller. */
+ skp = smk_of_current();
+ sbsp->smk_root = skp;
+ sbsp->smk_default = skp;
+ } else {
+ sbsp->smk_root = &smack_known_floor;
+ sbsp->smk_default = &smack_known_floor;
+ sbsp->smk_floor = &smack_known_floor;
+ sbsp->smk_hat = &smack_known_hat;
+ /* SMK_SB_INITIALIZED will be zero from kzalloc. */
+ }
+
+ return 0;
+
+nomem_free:
+ smack_fs_context_free(fc);
+nomem:
+ return -ENOMEM;
+}
+
+/**
+ * smack_fs_context_dup - Duplicate the security data on fs_context duplication
+ * @fc: The new filesystem context.
+ * @src_fc: The source filesystem context being duplicated.
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_fs_context_dup(struct fs_context *fc,
+ struct fs_context *src_fc)
+{
+ struct smack_fs_context *dst, *src = src_fc->security;
+ int i;
+
+ dst = kzalloc(sizeof(struct smack_fs_context), GFP_KERNEL);
+ if (!dst)
+ goto nomem;
+ fc->security = dst;
+
+ dst->sbsp = kmemdup(src->sbsp, sizeof(struct superblock_smack),
+ GFP_KERNEL);
+ if (!dst->sbsp)
+ goto nomem_free;
+
+ for (i = 0; i < ARRAY_SIZE(dst->ptrs); i++) {
+ if (src->ptrs[i]) {
+ dst->ptrs[i] = kstrdup(src->ptrs[i], GFP_KERNEL);
+ if (!dst->ptrs[i])
+ goto nomem_free;
+ }
+ }
+
+ return 0;
+
+nomem_free:
+ smack_fs_context_free(fc);
+nomem:
+ return -ENOMEM;
+}
+
+/**
+ * smack_fs_context_parse_option - Parse a single mount option
+ * @fc: The new filesystem context being constructed.
+ * @opt: The option text buffer.
+ * @len: The length of the text.
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_fs_context_parse_option(struct fs_context *fc, char *p, size_t len)
+{
+ struct smack_fs_context *ctx = fc->security;
+ substring_t args[MAX_OPT_ARGS];
+ int rc = -ENOMEM;
+ int token;
+
+ /* Unprivileged mounts don't get to specify Smack values. */
+ if (!smack_privileged(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ token = match_token(p, smk_mount_tokens, args);
+ switch (token) {
+ case Opt_fsdefault:
+ if (ctx->fsdefault)
+ goto error_dup;
+ ctx->fsdefault = match_strdup(&args[0]);
+ if (!ctx->fsdefault)
+ goto error;
+ break;
+ case Opt_fsfloor:
+ if (ctx->fsfloor)
+ goto error_dup;
+ ctx->fsfloor = match_strdup(&args[0]);
+ if (!ctx->fsfloor)
+ goto error;
+ break;
+ case Opt_fshat:
+ if (ctx->fshat)
+ goto error_dup;
+ ctx->fshat = match_strdup(&args[0]);
+ if (!ctx->fshat)
+ goto error;
+ break;
+ case Opt_fsroot:
+ if (ctx->fsroot)
+ goto error_dup;
+ ctx->fsroot = match_strdup(&args[0]);
+ if (!ctx->fsroot)
+ goto error;
+ break;
+ case Opt_fstransmute:
+ if (ctx->fstransmute)
+ goto error_dup;
+ ctx->fstransmute = match_strdup(&args[0]);
+ if (!ctx->fstransmute)
+ goto error;
+ break;
+ default:
+ pr_warn("Smack: unknown mount option\n");
+ goto error_inval;
+ }
+
+ return 0;
+
+error_dup:
+ pr_warn("Smack: duplicate mount option\n");
+error_inval:
+ rc = -EINVAL;
+error:
+ return rc;
+}
+
+/**
+ * smack_fs_context_validate - Validate the filesystem context security data
+ * @fc: The filesystem context.
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_fs_context_validate(struct fs_context *fc)
+{
+ struct smack_fs_context *ctx = fc->security;
+ struct superblock_smack *sbsp = ctx->sbsp;
+ struct inode_smack *isp = ctx->isp;
+ struct smack_known *skp;
+
+ if (ctx->fsdefault) {
+ skp = smk_import_entry(ctx->fsdefault, 0);
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sbsp->smk_default = skp;
+ }
+
+ if (ctx->fsfloor) {
+ skp = smk_import_entry(ctx->fsfloor, 0);
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sbsp->smk_floor = skp;
+ }
+
+ if (ctx->fshat) {
+ skp = smk_import_entry(ctx->fshat, 0);
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sbsp->smk_hat = skp;
+ }
+
+ if (ctx->fsroot || ctx->fstransmute) {
+ skp = smk_import_entry(ctx->fstransmute ?: ctx->fsroot, 0);
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sbsp->smk_root = skp;
+ ctx->transmute = !!ctx->fstransmute;
+ }
+
+ isp->smk_inode = sbsp->smk_root;
+ return 0;
+}
+
+/**
+ * smack_sb_get_tree - Assign the context to a newly created superblock
+ * @fc: The new filesystem context.
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_sb_get_tree(struct fs_context *fc)
+{
+ struct smack_fs_context *ctx = fc->security;
+ struct superblock_smack *sbsp = ctx->sbsp;
+ struct dentry *root = fc->root;
+ struct inode *inode = d_backing_inode(root);
+ struct super_block *sb = root->d_sb;
+ struct inode_smack *isp;
+ bool transmute = ctx->transmute;
+
+ if (sb->s_security)
+ return 0;
+
+ if (!smack_privileged(CAP_MAC_ADMIN)) {
+ /*
+ * For a handful of fs types with no user-controlled
+ * backing store it's okay to trust security labels
+ * in the filesystem. The rest are untrusted.
+ */
+ if (fc->user_ns != &init_user_ns &&
+ sb->s_magic != SYSFS_MAGIC && sb->s_magic != TMPFS_MAGIC &&
+ sb->s_magic != RAMFS_MAGIC) {
+ transmute = true;
+ sbsp->smk_flags |= SMK_SB_UNTRUSTED;
+ }
+ }
+
+ sbsp->smk_flags |= SMK_SB_INITIALIZED;
+ sb->s_security = sbsp;
+ ctx->sbsp = NULL;
+
+ /* Initialize the root inode. */
+ isp = inode->i_security;
+ if (isp == NULL) {
+ isp = ctx->isp;
+ ctx->isp = NULL;
+ inode->i_security = isp;
+ } else
+ isp->smk_inode = sbsp->smk_root;
+
+ if (transmute)
+ isp->smk_flags |= SMK_INODE_TRANSMUTE;
+
+ return 0;
+}
/*
* Superblock Hooks.
@@ -4647,6 +4949,13 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
LSM_HOOK_INIT(syslog, smack_syslog),
+ LSM_HOOK_INIT(fs_context_alloc, smack_fs_context_alloc),
+ LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup),
+ LSM_HOOK_INIT(fs_context_free, smack_fs_context_free),
+ LSM_HOOK_INIT(fs_context_parse_option, smack_fs_context_parse_option),
+ LSM_HOOK_INIT(fs_context_validate, smack_fs_context_validate),
+ LSM_HOOK_INIT(sb_get_tree, smack_sb_get_tree),
+
LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
LSM_HOOK_INIT(sb_free_security, smack_sb_free_security),
LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 09/32] apparmor: Implement security hooks for the new mount API [ver #9]
[not found] <153126248868.14533.9751473662727327569.stgit@warthog.procyon.org.uk>
` (2 preceding siblings ...)
2018-07-10 22:42 ` [PATCH 08/32] smack: Implement filesystem context security " David Howells
@ 2018-07-10 22:42 ` David Howells
2018-07-10 22:42 ` [PATCH 10/32] tomoyo: " David Howells
4 siblings, 0 replies; 10+ messages in thread
From: David Howells @ 2018-07-10 22:42 UTC (permalink / raw)
To: linux-security-module
Implement hooks to check the creation of new mountpoints for AppArmor.
Unfortunately, the DFA evaluation puts the option data in last, after the
details of the mountpoint, so we have to cache the mount options in the
fs_context using those hooks till we get to the new mountpoint hook.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: John Johansen <john.johansen@canonical.com>
cc: apparmor at lists.ubuntu.com
cc: linux-security-module at vger.kernel.org
---
security/apparmor/include/mount.h | 11 +++++
security/apparmor/lsm.c | 80 +++++++++++++++++++++++++++++++++++++
security/apparmor/mount.c | 46 +++++++++++++++++++++
3 files changed, 135 insertions(+), 2 deletions(-)
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
index 25d6067fa6ef..0441bfae30fa 100644
--- a/security/apparmor/include/mount.h
+++ b/security/apparmor/include/mount.h
@@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/path.h>
+#include <linux/fs_context.h>
#include "domain.h"
#include "policy.h"
@@ -27,7 +28,13 @@
#define AA_AUDIT_DATA 0x40
#define AA_MNT_CONT_MATCH 0x40
-#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
+#define AA_SB_IGNORE_MASK (SB_KERNMOUNT | SB_NOSEC | SB_ACTIVE | SB_BORN)
+
+struct apparmor_fs_context {
+ struct fs_context fc;
+ char *saved_options;
+ size_t saved_size;
+};
int aa_remount(struct aa_label *label, const struct path *path,
unsigned long flags, void *data);
@@ -45,6 +52,8 @@ int aa_move_mount(struct aa_label *label, const struct path *path,
int aa_new_mount(struct aa_label *label, const char *dev_name,
const struct path *path, const char *type, unsigned long flags,
void *data);
+int aa_new_mount_fc(struct aa_label *label, struct fs_context *fc,
+ const struct path *mountpoint);
int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index c65307dcd652..29803dc604f8 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -520,6 +520,78 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
}
+static int apparmor_fs_context_alloc(struct fs_context *fc, struct dentry *reference)
+{
+ struct apparmor_fs_context *afc;
+
+ afc = kzalloc(sizeof(*afc), GFP_KERNEL);
+ if (!afc)
+ return -ENOMEM;
+
+ fc->security = afc;
+ return 0;
+}
+
+static int apparmor_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
+{
+ fc->security = NULL;
+ return 0;
+}
+
+static void apparmor_fs_context_free(struct fs_context *fc)
+{
+ struct apparmor_fs_context *afc = fc->security;
+
+ if (afc) {
+ kfree(afc->saved_options);
+ kfree(afc);
+ }
+}
+
+/*
+ * As a temporary hack, we buffer all the options. The problem is that we need
+ * to pass them to the DFA evaluator *after* mount point parameters, which
+ * means deferring the entire check to the sb_mountpoint hook.
+ */
+static int apparmor_fs_context_parse_option(struct fs_context *fc, char *opt, size_t len)
+{
+ struct apparmor_fs_context *afc = fc->security;
+ size_t space = 0;
+ char *p, *q;
+
+ if (afc->saved_size > 0)
+ space = 1;
+
+ p = krealloc(afc->saved_options, afc->saved_size + space + len + 1, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ q = p + afc->saved_size;
+ if (q != p)
+ *q++ = ' ';
+ memcpy(q, opt, len);
+ q += len;
+ *q = 0;
+
+ afc->saved_options = p;
+ afc->saved_size += 1 + len;
+ return 0;
+}
+
+static int apparmor_sb_mountpoint(struct fs_context *fc, struct path *mountpoint,
+ unsigned int mnt_flags)
+{
+ struct aa_label *label;
+ int error = 0;
+
+ label = __begin_current_label_crit_section();
+ if (!unconfined(label))
+ error = aa_new_mount_fc(label, fc, mountpoint);
+ __end_current_label_crit_section(label);
+
+ return error;
+}
+
static int apparmor_sb_mount(const char *dev_name, const struct path *path,
const char *type, unsigned long flags, void *data)
{
@@ -530,7 +602,7 @@ static int apparmor_sb_mount(const char *dev_name, const struct path *path,
if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
flags &= ~MS_MGC_MSK;
- flags &= ~AA_MS_IGNORE_MASK;
+ flags &= ~AA_SB_IGNORE_MASK;
label = __begin_current_label_crit_section();
if (!unconfined(label)) {
@@ -1133,6 +1205,12 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(capget, apparmor_capget),
LSM_HOOK_INIT(capable, apparmor_capable),
+ LSM_HOOK_INIT(fs_context_alloc, apparmor_fs_context_alloc),
+ LSM_HOOK_INIT(fs_context_dup, apparmor_fs_context_dup),
+ LSM_HOOK_INIT(fs_context_free, apparmor_fs_context_free),
+ LSM_HOOK_INIT(fs_context_parse_option, apparmor_fs_context_parse_option),
+ LSM_HOOK_INIT(sb_mountpoint, apparmor_sb_mountpoint),
+
LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
index 8c3787399356..3c95fffb76ac 100644
--- a/security/apparmor/mount.c
+++ b/security/apparmor/mount.c
@@ -554,6 +554,52 @@ int aa_new_mount(struct aa_label *label, const char *dev_name,
return error;
}
+int aa_new_mount_fc(struct aa_label *label, struct fs_context *fc,
+ const struct path *mountpoint)
+{
+ struct apparmor_fs_context *afc = fc->security;
+ struct aa_profile *profile;
+ char *buffer = NULL, *dev_buffer = NULL;
+ bool binary;
+ int error;
+ struct path tmp_path, *dev_path = NULL;
+
+ AA_BUG(!label);
+ AA_BUG(!mountpoint);
+
+ binary = fc->fs_type->fs_flags & FS_BINARY_MOUNTDATA;
+
+ if (fc->fs_type->fs_flags & FS_REQUIRES_DEV) {
+ if (!fc->source)
+ return -ENOENT;
+
+ error = kern_path(fc->source, LOOKUP_FOLLOW, &tmp_path);
+ if (error)
+ return error;
+ dev_path = &tmp_path;
+ }
+
+ get_buffers(buffer, dev_buffer);
+ if (dev_path) {
+ error = fn_for_each_confined(label, profile,
+ match_mnt(profile, mountpoint, buffer, dev_path, dev_buffer,
+ fc->fs_type->name,
+ fc->sb_flags & ~AA_SB_IGNORE_MASK,
+ afc->saved_options, binary));
+ } else {
+ error = fn_for_each_confined(label, profile,
+ match_mnt_path_str(profile, mountpoint, buffer,
+ fc->source, fc->fs_type->name,
+ fc->sb_flags & ~AA_SB_IGNORE_MASK,
+ afc->saved_options, binary, NULL));
+ }
+ put_buffers(buffer, dev_buffer);
+ if (dev_path)
+ path_put(dev_path);
+
+ return error;
+}
+
static int profile_umount(struct aa_profile *profile, struct path *path,
char *buffer)
{
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 10/32] tomoyo: Implement security hooks for the new mount API [ver #9]
[not found] <153126248868.14533.9751473662727327569.stgit@warthog.procyon.org.uk>
` (3 preceding siblings ...)
2018-07-10 22:42 ` [PATCH 09/32] apparmor: Implement security hooks for the new mount API " David Howells
@ 2018-07-10 22:42 ` David Howells
2018-07-10 23:34 ` Tetsuo Handa
4 siblings, 1 reply; 10+ messages in thread
From: David Howells @ 2018-07-10 22:42 UTC (permalink / raw)
To: linux-security-module
Implement the security hook to check the creation of a new mountpoint for
Tomoyo.
As far as I can tell, Tomoyo doesn't make use of the mount data or parse
any mount options, so I haven't implemented any of the fs_context hooks for
it.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
cc: tomoyo-dev-en at lists.sourceforge.jp
cc: linux-security-module at vger.kernel.org
---
security/tomoyo/common.h | 3 +++
security/tomoyo/mount.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
security/tomoyo/tomoyo.c | 15 +++++++++++++++
3 files changed, 63 insertions(+)
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 539bcdd30bb8..e637ce73f7f9 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -971,6 +971,9 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
const u8 index);
int tomoyo_mkdev_perm(const u8 operation, const struct path *path,
const unsigned int mode, unsigned int dev);
+int tomoyo_mount_permission_fc(struct fs_context *fc,
+ const struct path *mountpoint,
+ unsigned int mnt_flags);
int tomoyo_mount_permission(const char *dev_name, const struct path *path,
const char *type, unsigned long flags,
void *data_page);
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
index 7dc7f59b7dde..9ec84ab6f5e1 100644
--- a/security/tomoyo/mount.c
+++ b/security/tomoyo/mount.c
@@ -6,6 +6,7 @@
*/
#include <linux/slab.h>
+#include <linux/fs_context.h>
#include <uapi/linux/mount.h>
#include "common.h"
@@ -236,3 +237,47 @@ int tomoyo_mount_permission(const char *dev_name, const struct path *path,
tomoyo_read_unlock(idx);
return error;
}
+
+/**
+ * tomoyo_mount_permission_fc - Check permission to create a new mount.
+ * @fc: Context describing the object to be mounted.
+ * @mountpoint: The target object to mount on.
+ * @mnt: The MNT_* flags to be set on the mountpoint.
+ *
+ * Check the permission to create a mount of the object described in @fc. Note
+ * that the source object may be a newly created superblock or may be an
+ * existing one picked from the filesystem (bind mount).
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_mount_permission_fc(struct fs_context *fc,
+ const struct path *mountpoint,
+ unsigned int mnt_flags)
+{
+ struct tomoyo_request_info r;
+ unsigned int ms_flags = 0;
+ int error;
+ int idx;
+
+ if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT) ==
+ TOMOYO_CONFIG_DISABLED)
+ return 0;
+
+ /* Convert MNT_* flags to MS_* equivalents. */
+ if (mnt_flags & MNT_NOSUID) ms_flags |= MS_NOSUID;
+ if (mnt_flags & MNT_NODEV) ms_flags |= MS_NODEV;
+ if (mnt_flags & MNT_NOEXEC) ms_flags |= MS_NOEXEC;
+ if (mnt_flags & MNT_NOATIME) ms_flags |= MS_NOATIME;
+ if (mnt_flags & MNT_NODIRATIME) ms_flags |= MS_NODIRATIME;
+ if (mnt_flags & MNT_RELATIME) ms_flags |= MS_RELATIME;
+ if (mnt_flags & MNT_READONLY) ms_flags |= MS_RDONLY;
+
+ idx = tomoyo_read_lock();
+ /* TODO: There may be multiple sources; for the moment, just pick the
+ * first if there is one.
+ */
+ error = tomoyo_mount_acl(&r, fc->source, mountpoint, fc->fs_type->name,
+ ms_flags);
+ tomoyo_read_unlock(idx);
+ return error;
+}
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 213b8c593668..31fd6bd4f657 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -391,6 +391,20 @@ static int tomoyo_path_chroot(const struct path *path)
return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL);
}
+/**
+ * tomoyo_sb_mount - Target for security_sb_mountpoint().
+ * @fc: Context describing the object to be mounted.
+ * @mountpoint: The target object to mount on.
+ * @mnt_flags: Mountpoint specific options (as MNT_* flags).
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_sb_mountpoint(struct fs_context *fc, struct path *mountpoint,
+ unsigned int mnt_flags)
+{
+ return tomoyo_mount_permission_fc(fc, mountpoint, mnt_flags);
+}
+
/**
* tomoyo_sb_mount - Target for security_sb_mount().
*
@@ -519,6 +533,7 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(path_chmod, tomoyo_path_chmod),
LSM_HOOK_INIT(path_chown, tomoyo_path_chown),
LSM_HOOK_INIT(path_chroot, tomoyo_path_chroot),
+ LSM_HOOK_INIT(sb_mountpoint, tomoyo_sb_mountpoint),
LSM_HOOK_INIT(sb_mount, tomoyo_sb_mount),
LSM_HOOK_INIT(sb_umount, tomoyo_sb_umount),
LSM_HOOK_INIT(sb_pivotroot, tomoyo_sb_pivotroot),
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 08/32] smack: Implement filesystem context security hooks [ver #9]
2018-07-10 22:42 ` [PATCH 08/32] smack: Implement filesystem context security " David Howells
@ 2018-07-10 23:13 ` Casey Schaufler
2018-07-10 23:19 ` David Howells
0 siblings, 1 reply; 10+ messages in thread
From: Casey Schaufler @ 2018-07-10 23:13 UTC (permalink / raw)
To: linux-security-module
On 7/10/2018 3:42 PM, David Howells wrote:
> Implement filesystem context security hooks for the smack LSM.
>
> Question: Should the ->fs_context_parse_source() hook be implemented to
> check the labels on any source devices specified?
Checking the label on a block device when doing a mount
is just going to end in tears. If you're remounting from
an already mounted filesystem it might make sense to check
that the new mount doesn't provide greater access than the
existing mount. If the original mount has smackfsdefault="_"
I could see prohibiting the additional mount having
smackfsdefault="*" on a filesystem that doesn't support
xattrs. But that requires that a (hopefully) privileged
process be involved, and we expect them to have a clue.
So no, I don't see it necessary.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Casey Schaufler <casey@schaufler-ca.com>
> cc: linux-security-module at vger.kernel.org
> ---
>
> security/smack/smack_lsm.c | 309 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 309 insertions(+)
>
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 7ad226018f51..39780b06469b 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -42,6 +42,7 @@
> #include <linux/shm.h>
> #include <linux/binfmts.h>
> #include <linux/parser.h>
> +#include <linux/fs_context.h>
> #include "smack.h"
>
> #define TRANS_TRUE "TRUE"
> @@ -521,6 +522,307 @@ static int smack_syslog(int typefrom_file)
> return rc;
> }
>
> +/*
> + * Mount context operations
> + */
> +
> +struct smack_fs_context {
> + union {
> + struct {
> + char *fsdefault;
> + char *fsfloor;
> + char *fshat;
> + char *fsroot;
> + char *fstransmute;
> + };
> + char *ptrs[5];
> +
> + };
> + struct superblock_smack *sbsp;
> + struct inode_smack *isp;
> + bool transmute;
> +};
> +
> +/**
> + * smack_fs_context_free - Free the security data from a filesystem context
> + * @fc: The filesystem context to be cleaned up.
> + */
> +static void smack_fs_context_free(struct fs_context *fc)
> +{
> + struct smack_fs_context *ctx = fc->security;
> + int i;
> +
> + if (ctx) {
> + for (i = 0; i < ARRAY_SIZE(ctx->ptrs); i++)
> + kfree(ctx->ptrs[i]);
> + kfree(ctx->isp);
> + kfree(ctx->sbsp);
> + kfree(ctx);
> + fc->security = NULL;
> + }
> +}
> +
> +/**
> + * smack_fs_context_alloc - Allocate security data for a filesystem context
> + * @fc: The filesystem context.
> + * @reference: Reference dentry (automount/reconfigure) or NULL
> + *
> + * Returns 0 on success or -ENOMEM on error.
> + */
> +static int smack_fs_context_alloc(struct fs_context *fc,
> + struct dentry *reference)
> +{
> + struct smack_fs_context *ctx;
> + struct superblock_smack *sbsp;
> + struct inode_smack *isp;
> + struct smack_known *skp;
> +
> + ctx = kzalloc(sizeof(struct smack_fs_context), GFP_KERNEL);
> + if (!ctx)
> + goto nomem;
> + fc->security = ctx;
> +
> + sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
> + if (!sbsp)
> + goto nomem_free;
> + ctx->sbsp = sbsp;
> +
> + isp = new_inode_smack(NULL);
> + if (!isp)
> + goto nomem_free;
> + ctx->isp = isp;
> +
> + if (reference) {
> + if (reference->d_sb->s_security)
> + memcpy(sbsp, reference->d_sb->s_security, sizeof(*sbsp));
> + } else if (!smack_privileged(CAP_MAC_ADMIN)) {
> + /* Unprivileged mounts get root and default from the caller. */
> + skp = smk_of_current();
> + sbsp->smk_root = skp;
> + sbsp->smk_default = skp;
> + } else {
> + sbsp->smk_root = &smack_known_floor;
> + sbsp->smk_default = &smack_known_floor;
> + sbsp->smk_floor = &smack_known_floor;
> + sbsp->smk_hat = &smack_known_hat;
> + /* SMK_SB_INITIALIZED will be zero from kzalloc. */
> + }
> +
> + return 0;
> +
> +nomem_free:
> + smack_fs_context_free(fc);
> +nomem:
> + return -ENOMEM;
> +}
> +
> +/**
> + * smack_fs_context_dup - Duplicate the security data on fs_context duplication
> + * @fc: The new filesystem context.
> + * @src_fc: The source filesystem context being duplicated.
> + *
> + * Returns 0 on success or -ENOMEM on error.
> + */
> +static int smack_fs_context_dup(struct fs_context *fc,
> + struct fs_context *src_fc)
> +{
> + struct smack_fs_context *dst, *src = src_fc->security;
> + int i;
> +
> + dst = kzalloc(sizeof(struct smack_fs_context), GFP_KERNEL);
> + if (!dst)
> + goto nomem;
> + fc->security = dst;
> +
> + dst->sbsp = kmemdup(src->sbsp, sizeof(struct superblock_smack),
> + GFP_KERNEL);
> + if (!dst->sbsp)
> + goto nomem_free;
> +
> + for (i = 0; i < ARRAY_SIZE(dst->ptrs); i++) {
> + if (src->ptrs[i]) {
> + dst->ptrs[i] = kstrdup(src->ptrs[i], GFP_KERNEL);
> + if (!dst->ptrs[i])
> + goto nomem_free;
> + }
> + }
> +
> + return 0;
> +
> +nomem_free:
> + smack_fs_context_free(fc);
> +nomem:
> + return -ENOMEM;
> +}
> +
> +/**
> + * smack_fs_context_parse_option - Parse a single mount option
> + * @fc: The new filesystem context being constructed.
> + * @opt: The option text buffer.
> + * @len: The length of the text.
> + *
> + * Returns 0 on success or -ENOMEM on error.
> + */
> +static int smack_fs_context_parse_option(struct fs_context *fc, char *p, size_t len)
> +{
> + struct smack_fs_context *ctx = fc->security;
> + substring_t args[MAX_OPT_ARGS];
> + int rc = -ENOMEM;
> + int token;
> +
> + /* Unprivileged mounts don't get to specify Smack values. */
> + if (!smack_privileged(CAP_MAC_ADMIN))
> + return -EPERM;
> +
> + token = match_token(p, smk_mount_tokens, args);
> + switch (token) {
> + case Opt_fsdefault:
> + if (ctx->fsdefault)
> + goto error_dup;
> + ctx->fsdefault = match_strdup(&args[0]);
> + if (!ctx->fsdefault)
> + goto error;
> + break;
> + case Opt_fsfloor:
> + if (ctx->fsfloor)
> + goto error_dup;
> + ctx->fsfloor = match_strdup(&args[0]);
> + if (!ctx->fsfloor)
> + goto error;
> + break;
> + case Opt_fshat:
> + if (ctx->fshat)
> + goto error_dup;
> + ctx->fshat = match_strdup(&args[0]);
> + if (!ctx->fshat)
> + goto error;
> + break;
> + case Opt_fsroot:
> + if (ctx->fsroot)
> + goto error_dup;
> + ctx->fsroot = match_strdup(&args[0]);
> + if (!ctx->fsroot)
> + goto error;
> + break;
> + case Opt_fstransmute:
> + if (ctx->fstransmute)
> + goto error_dup;
> + ctx->fstransmute = match_strdup(&args[0]);
> + if (!ctx->fstransmute)
> + goto error;
> + break;
> + default:
> + pr_warn("Smack: unknown mount option\n");
> + goto error_inval;
> + }
> +
> + return 0;
> +
> +error_dup:
> + pr_warn("Smack: duplicate mount option\n");
> +error_inval:
> + rc = -EINVAL;
> +error:
> + return rc;
> +}
> +
> +/**
> + * smack_fs_context_validate - Validate the filesystem context security data
> + * @fc: The filesystem context.
> + *
> + * Returns 0 on success or -ENOMEM on error.
> + */
> +static int smack_fs_context_validate(struct fs_context *fc)
> +{
> + struct smack_fs_context *ctx = fc->security;
> + struct superblock_smack *sbsp = ctx->sbsp;
> + struct inode_smack *isp = ctx->isp;
> + struct smack_known *skp;
> +
> + if (ctx->fsdefault) {
> + skp = smk_import_entry(ctx->fsdefault, 0);
> + if (IS_ERR(skp))
> + return PTR_ERR(skp);
> + sbsp->smk_default = skp;
> + }
> +
> + if (ctx->fsfloor) {
> + skp = smk_import_entry(ctx->fsfloor, 0);
> + if (IS_ERR(skp))
> + return PTR_ERR(skp);
> + sbsp->smk_floor = skp;
> + }
> +
> + if (ctx->fshat) {
> + skp = smk_import_entry(ctx->fshat, 0);
> + if (IS_ERR(skp))
> + return PTR_ERR(skp);
> + sbsp->smk_hat = skp;
> + }
> +
> + if (ctx->fsroot || ctx->fstransmute) {
> + skp = smk_import_entry(ctx->fstransmute ?: ctx->fsroot, 0);
> + if (IS_ERR(skp))
> + return PTR_ERR(skp);
> + sbsp->smk_root = skp;
> + ctx->transmute = !!ctx->fstransmute;
> + }
> +
> + isp->smk_inode = sbsp->smk_root;
> + return 0;
> +}
> +
> +/**
> + * smack_sb_get_tree - Assign the context to a newly created superblock
> + * @fc: The new filesystem context.
> + *
> + * Returns 0 on success or -ENOMEM on error.
> + */
> +static int smack_sb_get_tree(struct fs_context *fc)
> +{
> + struct smack_fs_context *ctx = fc->security;
> + struct superblock_smack *sbsp = ctx->sbsp;
> + struct dentry *root = fc->root;
> + struct inode *inode = d_backing_inode(root);
> + struct super_block *sb = root->d_sb;
> + struct inode_smack *isp;
> + bool transmute = ctx->transmute;
> +
> + if (sb->s_security)
> + return 0;
> +
> + if (!smack_privileged(CAP_MAC_ADMIN)) {
> + /*
> + * For a handful of fs types with no user-controlled
> + * backing store it's okay to trust security labels
> + * in the filesystem. The rest are untrusted.
> + */
> + if (fc->user_ns != &init_user_ns &&
> + sb->s_magic != SYSFS_MAGIC && sb->s_magic != TMPFS_MAGIC &&
> + sb->s_magic != RAMFS_MAGIC) {
> + transmute = true;
> + sbsp->smk_flags |= SMK_SB_UNTRUSTED;
> + }
> + }
> +
> + sbsp->smk_flags |= SMK_SB_INITIALIZED;
> + sb->s_security = sbsp;
> + ctx->sbsp = NULL;
> +
> + /* Initialize the root inode. */
> + isp = inode->i_security;
> + if (isp == NULL) {
> + isp = ctx->isp;
> + ctx->isp = NULL;
> + inode->i_security = isp;
> + } else
> + isp->smk_inode = sbsp->smk_root;
> +
> + if (transmute)
> + isp->smk_flags |= SMK_INODE_TRANSMUTE;
> +
> + return 0;
> +}
>
> /*
> * Superblock Hooks.
> @@ -4647,6 +4949,13 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
> LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
> LSM_HOOK_INIT(syslog, smack_syslog),
>
> + LSM_HOOK_INIT(fs_context_alloc, smack_fs_context_alloc),
> + LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup),
> + LSM_HOOK_INIT(fs_context_free, smack_fs_context_free),
> + LSM_HOOK_INIT(fs_context_parse_option, smack_fs_context_parse_option),
> + LSM_HOOK_INIT(fs_context_validate, smack_fs_context_validate),
> + LSM_HOOK_INIT(sb_get_tree, smack_sb_get_tree),
> +
> LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
> LSM_HOOK_INIT(sb_free_security, smack_sb_free_security),
> LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 08/32] smack: Implement filesystem context security hooks [ver #9]
2018-07-10 23:13 ` Casey Schaufler
@ 2018-07-10 23:19 ` David Howells
2018-07-10 23:28 ` Casey Schaufler
0 siblings, 1 reply; 10+ messages in thread
From: David Howells @ 2018-07-10 23:19 UTC (permalink / raw)
To: linux-security-module
Casey Schaufler <casey@schaufler-ca.com> wrote:
> > Implement filesystem context security hooks for the smack LSM.
> >
> > Question: Should the ->fs_context_parse_source() hook be implemented to
> > check the labels on any source devices specified?
>
> Checking the label on a block device when doing a mount
> is just going to end in tears. If you're remounting from
> an already mounted filesystem it might make sense to check
> that the new mount doesn't provide greater access than the
> existing mount. If the original mount has smackfsdefault="_"
> I could see prohibiting the additional mount having
> smackfsdefault="*" on a filesystem that doesn't support
> xattrs. But that requires that a (hopefully) privileged
> process be involved, and we expect them to have a clue.
> So no, I don't see it necessary.
I think I may have meant the device file rather than the actual device
content.
David
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 08/32] smack: Implement filesystem context security hooks [ver #9]
2018-07-10 23:19 ` David Howells
@ 2018-07-10 23:28 ` Casey Schaufler
0 siblings, 0 replies; 10+ messages in thread
From: Casey Schaufler @ 2018-07-10 23:28 UTC (permalink / raw)
To: linux-security-module
On 7/10/2018 4:19 PM, David Howells wrote:
> Casey Schaufler <casey@schaufler-ca.com> wrote:
>
>>> Implement filesystem context security hooks for the smack LSM.
>>>
>>> Question: Should the ->fs_context_parse_source() hook be implemented to
>>> check the labels on any source devices specified?
>> Checking the label on a block device when doing a mount
>> is just going to end in tears. If you're remounting from
>> an already mounted filesystem it might make sense to check
>> that the new mount doesn't provide greater access than the
>> existing mount. If the original mount has smackfsdefault="_"
>> I could see prohibiting the additional mount having
>> smackfsdefault="*" on a filesystem that doesn't support
>> xattrs. But that requires that a (hopefully) privileged
>> process be involved, and we expect them to have a clue.
>> So no, I don't see it necessary.
> I think I may have meant the device file rather than the actual device
> content.
You may have! I see no reason to look at the label on /dev/sdb1
when mounting it. There's already sufficient privilege required
to protect that in my mind.
>
> David
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 10/32] tomoyo: Implement security hooks for the new mount API [ver #9]
2018-07-10 22:42 ` [PATCH 10/32] tomoyo: " David Howells
@ 2018-07-10 23:34 ` Tetsuo Handa
0 siblings, 0 replies; 10+ messages in thread
From: Tetsuo Handa @ 2018-07-10 23:34 UTC (permalink / raw)
To: linux-security-module
David Howells wrote:
> Implement the security hook to check the creation of a new mountpoint for
> Tomoyo.
>
> As far as I can tell, Tomoyo doesn't make use of the mount data or parse
> any mount options, so I haven't implemented any of the fs_context hooks for
> it.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> cc: tomoyo-dev-en at lists.sourceforge.jp
> cc: linux-security-module at vger.kernel.org
>
Would you provide examples of each possible combination as a C program?
For example, if one mount point from multiple sources with different
options are possible, please describe such pattern using syscall so that
LSM modules can run it to see whether they are working as expected.
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 07/32] selinux: Implement the new mount API LSM hooks [ver #9]
2018-07-10 22:42 ` [PATCH 07/32] selinux: Implement the new mount API LSM hooks " David Howells
@ 2018-07-11 14:08 ` Stephen Smalley
0 siblings, 0 replies; 10+ messages in thread
From: Stephen Smalley @ 2018-07-11 14:08 UTC (permalink / raw)
To: linux-security-module
On 07/10/2018 06:42 PM, David Howells wrote:
> Implement the new mount API LSM hooks for SELinux. At some point the old
> hooks will need to be removed.
>
> Question: Should the ->fs_context_parse_source() hook be implemented to
> check the labels on any source devices specified?
The hook interface doesn't appear to lend itself to such validation, since you are just passing a string, not an inode.
Looking up the inode within the security module could easily yield a different object than what is ultimately used for the actual mount.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Paul Moore <paul@paul-moore.com>
> cc: Stephen Smalley <sds@tycho.nsa.gov>
> cc: selinux at tycho.nsa.gov
> cc: linux-security-module at vger.kernel.org
> ---
>
> security/selinux/hooks.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 264 insertions(+)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 5bb53edd74cc..bdecae4b7306 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -48,6 +48,7 @@
> #include <linux/fdtable.h>
> #include <linux/namei.h>
> #include <linux/mount.h>
> +#include <linux/fs_context.h>
> #include <linux/netfilter_ipv4.h>
> #include <linux/netfilter_ipv6.h>
> #include <linux/tty.h>
> @@ -2973,6 +2974,261 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
> FILESYSTEM__UNMOUNT, NULL);
> }
>
> +/* fsopen mount context operations */
> +
> +static int selinux_fs_context_alloc(struct fs_context *fc,
> + struct dentry *reference)
> +{
> + struct security_mnt_opts *opts;
> +
> + opts = kzalloc(sizeof(*opts), GFP_KERNEL);
> + if (!opts)
> + return -ENOMEM;
> +
> + fc->security = opts;
> + return 0;
> +}
> +
> +static int selinux_fs_context_dup(struct fs_context *fc,
> + struct fs_context *src_fc)
> +{
> + const struct security_mnt_opts *src = src_fc->security;
> + struct security_mnt_opts *opts;
> + int i, n;
> +
> + opts = kzalloc(sizeof(*opts), GFP_KERNEL);
> + if (!opts)
> + return -ENOMEM;
> + fc->security = opts;
> +
> + if (!src || !src->num_mnt_opts)
> + return 0;
> + n = opts->num_mnt_opts = src->num_mnt_opts;
> +
> + if (src->mnt_opts) {
> + opts->mnt_opts = kcalloc(n, sizeof(char *), GFP_KERNEL);
> + if (!opts->mnt_opts)
> + return -ENOMEM;
> +
> + for (i = 0; i < n; i++) {
> + if (src->mnt_opts[i]) {
> + opts->mnt_opts[i] = kstrdup(src->mnt_opts[i],
> + GFP_KERNEL);
> + if (!opts->mnt_opts[i])
> + return -ENOMEM;
> + }
> + }
> + }
> +
> + if (src->mnt_opts_flags) {
> + opts->mnt_opts_flags = kmemdup(src->mnt_opts_flags,
> + n * sizeof(int), GFP_KERNEL);
> + if (!opts->mnt_opts_flags)
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +static void selinux_fs_context_free(struct fs_context *fc)
> +{
> + struct security_mnt_opts *opts = fc->security;
> +
> + if (opts) {
> + security_free_mnt_opts(opts);
> + fc->security = NULL;
> + }
> +}
> +
> +static int selinux_fs_context_parse_option(struct fs_context *fc, char *opt, size_t len)
> +{
> + struct security_mnt_opts *opts = fc->security;
> + substring_t args[MAX_OPT_ARGS];
> + unsigned int have;
> + char *c, **oo;
> + int token, ctx, i, *of;
> +
> + token = match_token(opt, tokens, args);
> + if (token == Opt_error)
> + return 0; /* Doesn't belong to us. */
> +
> + have = 0;
> + for (i = 0; i < opts->num_mnt_opts; i++)
> + have |= 1 << opts->mnt_opts_flags[i];
> + if (have & (1 << token))
> + return -EINVAL;
> +
> + switch (token) {
> + case Opt_context:
> + if (have & (1 << Opt_defcontext))
> + goto incompatible;
> + ctx = CONTEXT_MNT;
> + goto copy_context_string;
> +
> + case Opt_fscontext:
> + ctx = FSCONTEXT_MNT;
> + goto copy_context_string;
> +
> + case Opt_rootcontext:
> + ctx = ROOTCONTEXT_MNT;
> + goto copy_context_string;
> +
> + case Opt_defcontext:
> + if (have & (1 << Opt_context))
> + goto incompatible;
> + ctx = DEFCONTEXT_MNT;
> + goto copy_context_string;
> +
> + case Opt_labelsupport:
> + return 1;
> +
> + default:
> + return -EINVAL;
> + }
> +
> +copy_context_string:
> + if (opts->num_mnt_opts > 3)
> + return -EINVAL;
> +
> + of = krealloc(opts->mnt_opts_flags,
> + (opts->num_mnt_opts + 1) * sizeof(int), GFP_KERNEL);
> + if (!of)
> + return -ENOMEM;
> + of[opts->num_mnt_opts] = 0;
> + opts->mnt_opts_flags = of;
> +
> + oo = krealloc(opts->mnt_opts,
> + (opts->num_mnt_opts + 1) * sizeof(char *), GFP_KERNEL);
> + if (!oo)
> + return -ENOMEM;
> + oo[opts->num_mnt_opts] = NULL;
> + opts->mnt_opts = oo;
> +
> + c = match_strdup(&args[0]);
> + if (!c)
> + return -ENOMEM;
> + opts->mnt_opts[opts->num_mnt_opts] = c;
> + opts->mnt_opts_flags[opts->num_mnt_opts] = ctx;
> + opts->num_mnt_opts++;
> + return 1;
> +
> +incompatible:
> + return -EINVAL;
> +}
> +
> +/*
> + * Validate the security parameters supplied for a reconfiguration/remount
> + * event.
> + */
> +static int selinux_validate_for_sb_reconfigure(struct fs_context *fc)
> +{
> + struct super_block *sb = fc->root->d_sb;
> + struct superblock_security_struct *sbsec = sb->s_security;
> + struct security_mnt_opts *opts = fc->security;
> + int rc, i, *flags;
> + char **mount_options;
> +
> + if (!(sbsec->flags & SE_SBINITIALIZED))
> + return 0;
> +
> + mount_options = opts->mnt_opts;
> + flags = opts->mnt_opts_flags;
> +
> + for (i = 0; i < opts->num_mnt_opts; i++) {
> + u32 sid;
> +
> + if (flags[i] == SBLABEL_MNT)
> + continue;
> +
> + rc = security_context_str_to_sid(&selinux_state, mount_options[i],
> + &sid, GFP_KERNEL);
> + if (rc) {
> + pr_warn("SELinux: security_context_str_to_sid"
> + "(%s) failed for (dev %s, type %s) errno=%d\n",
> + mount_options[i], sb->s_id, sb->s_type->name, rc);
> + goto inval;
> + }
> +
> + switch (flags[i]) {
> + case FSCONTEXT_MNT:
> + if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
> + goto bad_option;
> + break;
> + case CONTEXT_MNT:
> + if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
> + goto bad_option;
> + break;
> + case ROOTCONTEXT_MNT: {
> + struct inode_security_struct *root_isec;
> + root_isec = backing_inode_security(sb->s_root);
> +
> + if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
> + goto bad_option;
> + break;
> + }
> + case DEFCONTEXT_MNT:
> + if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
> + goto bad_option;
> + break;
> + default:
> + goto inval;
> + }
> + }
> +
> + rc = 0;
> +out:
> + return rc;
> +
> +bad_option:
> + pr_warn("SELinux: unable to change security options "
> + "during remount (dev %s, type=%s)\n",
> + sb->s_id, sb->s_type->name);
> +inval:
> + rc = -EINVAL;
> + goto out;
> +}
> +
> +/*
> + * Validate the security context assembled from the option data supplied to
> + * mount.
> + */
> +static int selinux_fs_context_validate(struct fs_context *fc)
> +{
> + if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE)
> + return selinux_validate_for_sb_reconfigure(fc);
> + return 0;
> +}
> +
> +/*
> + * Set the security context on a superblock.
> + */
> +static int selinux_sb_get_tree(struct fs_context *fc)
> +{
> + const struct cred *cred = current_cred();
> + struct common_audit_data ad;
> + int rc;
> +
> + rc = selinux_set_mnt_opts(fc->root->d_sb, fc->security, 0, NULL);
> + if (rc)
> + return rc;
> +
> + /* Allow all mounts performed by the kernel */
> + if (fc->purpose == FS_CONTEXT_FOR_KERNEL_MOUNT)
> + return 0;
> +
> + ad.type = LSM_AUDIT_DATA_DENTRY;
> + ad.u.dentry = fc->root;
> + return superblock_has_perm(cred, fc->root->d_sb, FILESYSTEM__MOUNT, &ad);
> +}
> +
> +static int selinux_sb_mountpoint(struct fs_context *fc, struct path *mountpoint,
> + unsigned int mnt_flags)
> +{
> + const struct cred *cred = current_cred();
> +
> + return path_has_perm(cred, mountpoint, FILE__MOUNTON);
> +}
> +
> /* inode security operations */
>
> static int selinux_inode_alloc_security(struct inode *inode)
> @@ -6905,6 +7161,14 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
> LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
> LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
>
> + LSM_HOOK_INIT(fs_context_alloc, selinux_fs_context_alloc),
> + LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
> + LSM_HOOK_INIT(fs_context_free, selinux_fs_context_free),
> + LSM_HOOK_INIT(fs_context_parse_option, selinux_fs_context_parse_option),
> + LSM_HOOK_INIT(fs_context_validate, selinux_fs_context_validate),
> + LSM_HOOK_INIT(sb_get_tree, selinux_sb_get_tree),
> + LSM_HOOK_INIT(sb_mountpoint, selinux_sb_mountpoint),
> +
> LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
> LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
> LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
>
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2018-07-11 14:08 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <153126248868.14533.9751473662727327569.stgit@warthog.procyon.org.uk>
2018-07-10 22:42 ` [PATCH 06/32] vfs: Add LSM hooks for the new mount API [ver #9] David Howells
2018-07-10 22:42 ` [PATCH 07/32] selinux: Implement the new mount API LSM hooks " David Howells
2018-07-11 14:08 ` Stephen Smalley
2018-07-10 22:42 ` [PATCH 08/32] smack: Implement filesystem context security " David Howells
2018-07-10 23:13 ` Casey Schaufler
2018-07-10 23:19 ` David Howells
2018-07-10 23:28 ` Casey Schaufler
2018-07-10 22:42 ` [PATCH 09/32] apparmor: Implement security hooks for the new mount API " David Howells
2018-07-10 22:42 ` [PATCH 10/32] tomoyo: " David Howells
2018-07-10 23:34 ` Tetsuo Handa
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox