Received: by 10.192.165.148 with SMTP id m20csp163306imm; Thu, 3 May 2018 17:11:15 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpzkH396Y8PR0qpT/Axhb0Cn7nL8EMqGzN50GhPcEUKm1oycZXDpxbgaCpXj0CQCNZ07hMP X-Received: by 2002:a17:902:6181:: with SMTP id u1-v6mr25373768plj.272.1525392675422; Thu, 03 May 2018 17:11:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525392675; cv=none; d=google.com; s=arc-20160816; b=pcNAD60dQbmcV51syc9mg9A6Q1Viw85HNhIxRMrD3DM21ElycgYQ1U3vfTNZovSc1G 1zDCaoBsG8Ska5pUHnM5PAyhAHaGXdIJJ6tgW4C44yCmbYlOQz4SA/NkSiFgCsXv2XeE 78nhiXhVGrxrA5M1cSTgX4+Y/0T5r2OAVMOHXZ4TZNC2r4f9ROdJWfRXE5NDyYU+Evb2 tcO3DJzAYUp7Pm8OloODncRg5OPVhZa1icwYM+7cZTw7zjK1nizoy/nz3R6oPeM2Em1h +Atyk7dbsOgxuIiFMaL+UwBXQU6Wm+XUXd9tDsJBDj5qpaFlGzQpSemxZh/rcF8KafD5 uxAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:organization:from:references:cc:to:subject :arc-authentication-results; bh=T9w1HecKeTHMUB/nEqKeEMmG/dh8Zqg1fV2IG22F/UU=; b=iH4txSSAywTFEvWEKJNOb0XOhsViGknbqWofLSXE4wGoUObA9a3nfqSnBUJEqpuiD1 2PNvw7d+P1aW09p23myminrVeg8s8M3NTCbEZwfvRqazsPy7kTQvT6KnmDjFlBYTK3i1 1OaBu0q2OEuXxYOyJ731xP6CMxuEWE17izLm3hc9Y0xRV9lSZKJlAUWpKEiTRWa9ubK+ 1SD29h1BzOSPwCbBIZBt1JWXSciYrNVhIcbdeKWoq0QlvfxlTtpq4NE7FbIB4wK6NybM St2sgYgAroiBU/4Mmd1IfVJsrOlCx261hPPkHx94halYqXPYoRpJ/lhxqNiflM3/jv3t j3VQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=canonical.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e71si15271877pfj.250.2018.05.03.17.11.01; Thu, 03 May 2018 17:11:15 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=canonical.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751519AbeEDAK1 (ORCPT + 99 others); Thu, 3 May 2018 20:10:27 -0400 Received: from youngberry.canonical.com ([91.189.89.112]:51518 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751133AbeEDAKX (ORCPT ); Thu, 3 May 2018 20:10:23 -0400 Received: from static-50-53-54-67.bvtn.or.frontiernet.net ([50.53.54.67] helo=[192.168.192.153]) by youngberry.canonical.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fEOIn-00046A-UV; Fri, 04 May 2018 00:10:22 +0000 Subject: Re: [PATCH 05/24] apparmor: Implement security hooks for the new mount API [ver #7] To: David Howells , viro@zeniv.linux.org.uk Cc: linux-nfs@vger.kernel.org, apparmor@lists.ubuntu.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-afs@lists.infradead.org References: <152414466005.23902.12967974041384198114.stgit@warthog.procyon.org.uk> <152414469709.23902.10439448759049886690.stgit@warthog.procyon.org.uk> From: John Johansen Organization: Canonical Message-ID: <4eaa0e19-684c-bef8-5aea-ddb5ef30828e@canonical.com> Date: Thu, 3 May 2018 17:10:18 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <152414469709.23902.10439448759049886690.stgit@warthog.procyon.org.uk> Content-Type: text/plain; charset=utf-8 Content-Language: en-GB Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 04/19/2018 06:31 AM, David Howells wrote: > 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 thanks David, this looks good, and has pasted the testing that I have done so far. I have started on the work that will allow us to reorder the match but its not ready yet and shouldn't hold this up. Acked-by: John Johansen > cc: John Johansen > cc: apparmor@lists.ubuntu.com > cc: linux-security-module@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 > #include > +#include > > #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 9ebc9e9c3854..14398dec2e38 100644 > --- a/security/apparmor/lsm.c > +++ b/security/apparmor/lsm.c > @@ -518,6 +518,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 super_block *src_sb) > +{ > + 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) > { > @@ -528,7 +600,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)) { > @@ -1124,6 +1196,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 45bb769d6cd7..3d477d288627 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) > { >