From: serge@hallyn.com (Serge E. Hallyn)
To: linux-security-module@vger.kernel.org
Subject: [PATCH] capabilities: fix buffer overread on very short xattr
Date: Mon, 1 Jan 2018 12:04:17 -0600 [thread overview]
Message-ID: <20180101180417.GA15627@mail.hallyn.com> (raw)
In-Reply-To: <20180101152831.13085-1-ebiggers3@gmail.com>
Quoting Eric Biggers (ebiggers3 at gmail.com):
> From: Eric Biggers <ebiggers@google.com>
>
> If userspace attempted to set a "security.capability" xattr shorter than
> 4 bytes (e.g. 'setfattr -n security.capability -v x file'), then
> cap_convert_nscap() read past the end of the buffer containing the xattr
> value because it accessed the ->magic_etc field without verifying that
> the xattr value is long enough to contain that field.
>
> Fix it by validating the xattr value size first.
>
> This bug was found using syzkaller with KASAN. The KASAN report was as
> follows (cleaned up slightly):
>
> BUG: KASAN: slab-out-of-bounds in cap_convert_nscap+0x514/0x630 security/commoncap.c:498
> Read of size 4 at addr ffff88002d8741c0 by task syz-executor1/2852
>
> CPU: 0 PID: 2852 Comm: syz-executor1 Not tainted 4.15.0-rc6-00200-gcc0aac99d977 #253
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-20171110_100015-anatol 04/01/2014
> Call Trace:
> __dump_stack lib/dump_stack.c:17 [inline]
> dump_stack+0xe3/0x195 lib/dump_stack.c:53
> print_address_description+0x73/0x260 mm/kasan/report.c:252
> kasan_report_error mm/kasan/report.c:351 [inline]
> kasan_report+0x235/0x350 mm/kasan/report.c:409
> cap_convert_nscap+0x514/0x630 security/commoncap.c:498
> setxattr+0x2bd/0x350 fs/xattr.c:446
> path_setxattr+0x168/0x1b0 fs/xattr.c:472
> SYSC_setxattr fs/xattr.c:487 [inline]
> SyS_setxattr+0x36/0x50 fs/xattr.c:483
> entry_SYSCALL_64_fastpath+0x18/0x85
>
> Fixes: 8db6c34f1dbc ("Introduce v3 namespaced file capabilities")
> Cc: <stable@vger.kernel.org> # v4.14+
> Signed-off-by: Eric Biggers <ebiggers@google.com>
Thanks, Eric!
Reviewed-by: Serge Hallyn <serge@hallyn.com>
> ---
> security/commoncap.c | 21 +++++++++------------
> 1 file changed, 9 insertions(+), 12 deletions(-)
>
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 4f8e09340956..48620c93d697 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -348,21 +348,18 @@ static __u32 sansflags(__u32 m)
> return m & ~VFS_CAP_FLAGS_EFFECTIVE;
> }
>
> -static bool is_v2header(size_t size, __le32 magic)
> +static bool is_v2header(size_t size, const struct vfs_cap_data *cap)
> {
> - __u32 m = le32_to_cpu(magic);
> if (size != XATTR_CAPS_SZ_2)
> return false;
> - return sansflags(m) == VFS_CAP_REVISION_2;
> + return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2;
> }
>
> -static bool is_v3header(size_t size, __le32 magic)
> +static bool is_v3header(size_t size, const struct vfs_cap_data *cap)
> {
> - __u32 m = le32_to_cpu(magic);
> -
> if (size != XATTR_CAPS_SZ_3)
> return false;
> - return sansflags(m) == VFS_CAP_REVISION_3;
> + return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_3;
> }
>
> /*
> @@ -405,7 +402,7 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
>
> fs_ns = inode->i_sb->s_user_ns;
> cap = (struct vfs_cap_data *) tmpbuf;
> - if (is_v2header((size_t) ret, cap->magic_etc)) {
> + if (is_v2header((size_t) ret, cap)) {
> /* If this is sizeof(vfs_cap_data) then we're ok with the
> * on-disk value, so return that. */
> if (alloc)
> @@ -413,7 +410,7 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
> else
> kfree(tmpbuf);
> return ret;
> - } else if (!is_v3header((size_t) ret, cap->magic_etc)) {
> + } else if (!is_v3header((size_t) ret, cap)) {
> kfree(tmpbuf);
> return -EINVAL;
> }
> @@ -470,9 +467,9 @@ static kuid_t rootid_from_xattr(const void *value, size_t size,
> return make_kuid(task_ns, rootid);
> }
>
> -static bool validheader(size_t size, __le32 magic)
> +static bool validheader(size_t size, const struct vfs_cap_data *cap)
> {
> - return is_v2header(size, magic) || is_v3header(size, magic);
> + return is_v2header(size, cap) || is_v3header(size, cap);
> }
>
> /*
> @@ -495,7 +492,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size)
>
> if (!*ivalue)
> return -EINVAL;
> - if (!validheader(size, cap->magic_etc))
> + if (!validheader(size, cap))
> return -EINVAL;
> if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP))
> return -EPERM;
> --
> 2.15.1
--
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
prev parent reply other threads:[~2018-01-01 18:04 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-01 15:28 [PATCH] capabilities: fix buffer overread on very short xattr Eric Biggers
2018-01-01 18:04 ` Serge E. Hallyn [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180101180417.GA15627@mail.hallyn.com \
--to=serge@hallyn.com \
--cc=linux-security-module@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox