From patchwork Fri Jun 22 21:43:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seth Forshee X-Patchwork-Id: 933618 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41CBss4JRrz9s2L; Sat, 23 Jun 2018 07:44:17 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1fWTqj-0004LA-47; Fri, 22 Jun 2018 21:44:09 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1fWTqe-0004KO-RO for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:04 +0000 Received: from mail-it0-f70.google.com ([209.85.214.70]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fWTqe-000297-DE for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:04 +0000 Received: by mail-it0-f70.google.com with SMTP id o188-v6so2837584ith.1 for ; Fri, 22 Jun 2018 14:44:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=GCGYEKYkNkJzaPcfASYykVzYBbNfyeTBgRPSewCW5d4=; b=KnUgoVwaHAN/bocGph7viJ1Ji20QIycXrQx4tK++QBODlofJZ48abTYZZKoHS5/q42 KikLMqxlETZGao5k2716FiR98zk0q/nb+RT45ztI6gcrnIVUX2Gnr2/Dm0BfmyjY36g8 JQ5NKZ3k0Eel30dWLQLIdDRKGJFFSLk/pMpAX5ZneZjJMTwtoY+pjxRh2wC4T8ducbTK QsxYWzyUsD1RBMNPBfzj1veywufHklptU9+9lt6KMeWOowimnAXFLIL3RIckZpTPpuhp yBfaXbH9XFAT61gc3Ku6/ZDnvGhGDBaS3jJHl3rFz4FB8uNveth37flBUTmaTCgIWOi/ tQcQ== X-Gm-Message-State: APt69E0nqwI03AfJ2EqcwbMZ1QmVl+aKOUhehe+vIFDxTj8Ekxd0dVM3 /Zk6S+B8sQ3QOzgWvVZvzHrSOOoECjX0m2GxQ8hJDb1ampZCQhYcKoeeGoJS3OsDvpW0DOGDkPn jgZ5y1XHnki3Lk5T7GrAnXti52qPE1pHbbYAbHPkEGw== X-Received: by 2002:a6b:998e:: with SMTP id b136-v6mr2788710ioe.116.1529703842723; Fri, 22 Jun 2018 14:44:02 -0700 (PDT) X-Google-Smtp-Source: AAOMgpcZb5v/8c1jNR28kn+1wWnrdexKxnmbAvxD3ouqi1JQ22fquwz2rvN13a1uyGhx5FcNpykMKw== X-Received: by 2002:a6b:998e:: with SMTP id b136-v6mr2788689ioe.116.1529703842303; Fri, 22 Jun 2018 14:44:02 -0700 (PDT) Received: from localhost ([2605:a601:ac7:2a20:110:4491:9f96:3555]) by smtp.gmail.com with ESMTPSA id 69-v6sm4156295iod.52.2018.06.22.14.44.01 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 22 Jun 2018 14:44:01 -0700 (PDT) From: Seth Forshee To: kernel-team@lists.ubuntu.com Subject: [SRU][Xenial][PATCH 1/4] Introduce v3 namespaced file capabilities Date: Fri, 22 Jun 2018 16:43:56 -0500 Message-Id: <20180622214359.17903-2-seth.forshee@canonical.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180622214359.17903-1-seth.forshee@canonical.com> References: <20180622214359.17903-1-seth.forshee@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: "Serge E. Hallyn" BugLink: http://bugs.launchpad.net/bugs/1778286 Root in a non-initial user ns cannot be trusted to write a traditional security.capability xattr. If it were allowed to do so, then any unprivileged user on the host could map his own uid to root in a private namespace, write the xattr, and execute the file with privilege on the host. However supporting file capabilities in a user namespace is very desirable. Not doing so means that any programs designed to run with limited privilege must continue to support other methods of gaining and dropping privilege. For instance a program installer must detect whether file capabilities can be assigned, and assign them if so but set setuid-root otherwise. The program in turn must know how to drop partial capabilities, and do so only if setuid-root. This patch introduces v3 of the security.capability xattr. It builds a vfs_ns_cap_data struct by appending a uid_t rootid to struct vfs_cap_data. This is the absolute uid_t (that is, the uid_t in user namespace which mounted the filesystem, usually init_user_ns) of the root id in whose namespaces the file capabilities may take effect. When a task asks to write a v2 security.capability xattr, if it is privileged with respect to the userns which mounted the filesystem, then nothing should change. Otherwise, the kernel will transparently rewrite the xattr as a v3 with the appropriate rootid. This is done during the execution of setxattr() to catch user-space-initiated capability writes. Subsequently, any task executing the file which has the noted kuid as its root uid, or which is in a descendent user_ns of such a user_ns, will run the file with capabilities. Similarly when asking to read file capabilities, a v3 capability will be presented as v2 if it applies to the caller's namespace. If a task writes a v3 security.capability, then it can provide a uid for the xattr so long as the uid is valid in its own user namespace, and it is privileged with CAP_SETFCAP over its namespace. The kernel will translate that rootid to an absolute uid, and write that to disk. After this, a task in the writer's namespace will not be able to use those capabilities (unless rootid was 0), but a task in a namespace where the given uid is root will. Only a single security.capability xattr may exist at a time for a given file. A task may overwrite an existing xattr so long as it is privileged over the inode. Note this is a departure from previous semantics, which required privilege to remove a security.capability xattr. This check can be re-added if deemed useful. This allows a simple setxattr to work, allows tar/untar to work, and allows us to tar in one namespace and untar in another while preserving the capability, without risking leaking privilege into a parent namespace. Example using tar: $ cp /bin/sleep sleepx $ mkdir b1 b2 $ lxc-usernsexec -m b:0:100000:1 -m b:1:$(id -u):1 -- chown 0:0 b1 $ lxc-usernsexec -m b:0:100001:1 -m b:1:$(id -u):1 -- chown 0:0 b2 $ lxc-usernsexec -m b:0:100000:1000 -- tar --xattrs-include=security.capability --xattrs -cf b1/sleepx.tar sleepx $ lxc-usernsexec -m b:0:100001:1000 -- tar --xattrs-include=security.capability --xattrs -C b2 -xf b1/sleepx.tar $ lxc-usernsexec -m b:0:100001:1000 -- getcap b2/sleepx b2/sleepx = cap_sys_admin+ep # /opt/ltp/testcases/bin/getv3xattr b2/sleepx v3 xattr, rootid is 100001 A patch to linux-test-project adding a new set of tests for this functionality is in the nsfscaps branch at github.com/hallyn/ltp Changelog: Nov 02 2016: fix invalid check at refuse_fcap_overwrite() Nov 07 2016: convert rootid from and to fs user_ns (From ebiederm: mar 28 2017) commoncap.c: fix typos - s/v4/v3 get_vfs_caps_from_disk: clarify the fs_ns root access check nsfscaps: change the code split for cap_inode_setxattr() Apr 09 2017: don't return v3 cap for caps owned by current root. return a v2 cap for a true v2 cap in non-init ns Apr 18 2017: . Change the flow of fscap writing to support s_user_ns writing. . Remove refuse_fcap_overwrite(). The value of the previous xattr doesn't matter. Apr 24 2017: . incorporate Eric's incremental diff . move cap_convert_nscap to setxattr and simplify its usage May 8, 2017: . fix leaking dentry refcount in cap_inode_getsecurity Signed-off-by: Serge Hallyn Signed-off-by: Eric W. Biederman (backported from commit 8db6c34f1dbc8e06aa016a9b829b06902c3e1340) Signed-off-by: Seth Forshee --- fs/xattr.c | 6 + include/linux/capability.h | 2 + include/linux/security.h | 2 + include/uapi/linux/capability.h | 22 ++- security/commoncap.c | 270 +++++++++++++++++++++++++++++--- 5 files changed, 280 insertions(+), 22 deletions(-) diff --git a/fs/xattr.c b/fs/xattr.c index 9d536be324ce..f3c0b172fd6d 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -361,6 +361,12 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value, if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) posix_acl_fix_xattr_from_user(kvalue, size); + else if (strcmp(kname, XATTR_NAME_CAPS) == 0) { + error = cap_convert_nscap(d, &kvalue, size); + if (error < 0) + goto out; + size = error; + } } error = vfs_setxattr(d, kname, kvalue, size, flags); diff --git a/include/linux/capability.h b/include/linux/capability.h index b20ffe23a09b..1df0b01a18d7 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -253,4 +253,6 @@ extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns); /* audit system wants to get cap info from files as well */ extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); +extern int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size); + #endif /* !_LINUX_CAPABILITY_H */ diff --git a/include/linux/security.h b/include/linux/security.h index 32a40430732e..fdec096e5330 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -85,6 +85,8 @@ extern int cap_inode_setxattr(struct dentry *dentry, const char *name, extern int cap_inode_removexattr(struct dentry *dentry, const char *name); extern int cap_inode_need_killpriv(struct dentry *dentry); extern int cap_inode_killpriv(struct dentry *dentry); +extern int cap_inode_getsecurity(const struct inode *inode, const char *name, + void **buffer, bool alloc); extern int cap_mmap_addr(unsigned long addr); extern int cap_mmap_file(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags); diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h index 12c37a197d24..a1b550cede30 100644 --- a/include/uapi/linux/capability.h +++ b/include/uapi/linux/capability.h @@ -62,9 +62,13 @@ typedef struct __user_cap_data_struct { #define VFS_CAP_U32_2 2 #define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2)) -#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2 -#define VFS_CAP_U32 VFS_CAP_U32_2 -#define VFS_CAP_REVISION VFS_CAP_REVISION_2 +#define VFS_CAP_REVISION_3 0x03000000 +#define VFS_CAP_U32_3 2 +#define XATTR_CAPS_SZ_3 (sizeof(__le32)*(2 + 2*VFS_CAP_U32_3)) + +#define XATTR_CAPS_SZ XATTR_CAPS_SZ_3 +#define VFS_CAP_U32 VFS_CAP_U32_3 +#define VFS_CAP_REVISION VFS_CAP_REVISION_3 struct vfs_cap_data { __le32 magic_etc; /* Little endian */ @@ -74,6 +78,18 @@ struct vfs_cap_data { } data[VFS_CAP_U32]; }; +/* + * same as vfs_cap_data but with a rootid at the end + */ +struct vfs_ns_cap_data { + __le32 magic_etc; + struct { + __le32 permitted; /* Little endian */ + __le32 inheritable; /* Little endian */ + } data[VFS_CAP_U32]; + __le32 rootid; +}; + #ifndef __KERNEL__ /* diff --git a/security/commoncap.c b/security/commoncap.c index 9b3edba566b1..c730ed00f427 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -337,6 +337,209 @@ int cap_inode_killpriv(struct dentry *dentry) return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS); } +static bool rootid_owns_currentns(kuid_t kroot) +{ + struct user_namespace *ns; + + if (!uid_valid(kroot)) + return false; + + for (ns = current_user_ns(); ; ns = ns->parent) { + if (from_kuid(ns, kroot) == 0) + return true; + if (ns == &init_user_ns) + break; + } + + return false; +} + +static __u32 sansflags(__u32 m) +{ + return m & ~VFS_CAP_FLAGS_EFFECTIVE; +} + +static bool is_v2header(size_t size, __le32 magic) +{ + __u32 m = le32_to_cpu(magic); + if (size != XATTR_CAPS_SZ_2) + return false; + return sansflags(m) == VFS_CAP_REVISION_2; +} + +static bool is_v3header(size_t size, __le32 magic) +{ + __u32 m = le32_to_cpu(magic); + + if (size != XATTR_CAPS_SZ_3) + return false; + return sansflags(m) == VFS_CAP_REVISION_3; +} + +/* + * getsecurity: We are called for security.* before any attempt to read the + * xattr from the inode itself. + * + * This gives us a chance to read the on-disk value and convert it. If we + * return -EOPNOTSUPP, then vfs_getxattr() will call the i_op handler. + * + * Note we are not called by vfs_getxattr_alloc(), but that is only called + * by the integrity subsystem, which really wants the unconverted values - + * so that's good. + */ +int cap_inode_getsecurity(const struct inode *inode, const char *name, + void **buffer, bool alloc) +{ + int size, ret; + kuid_t kroot; + uid_t root, mappedroot; + char *tmpbuf = NULL; + struct vfs_cap_data *cap; + struct vfs_ns_cap_data *nscap; + struct dentry *dentry; + struct user_namespace *fs_ns; + + if (strcmp(name, "capability") != 0) + return -EOPNOTSUPP; + + dentry = d_find_alias((struct inode *)inode); + if (!dentry) + return -EINVAL; + + size = sizeof(struct vfs_ns_cap_data); + ret = (int) vfs_getxattr_alloc(dentry, XATTR_NAME_CAPS, + &tmpbuf, size, GFP_NOFS); + dput(dentry); + + if (ret < 0) + return ret; + + fs_ns = inode->i_sb->s_user_ns; + cap = (struct vfs_cap_data *) tmpbuf; + if (is_v2header((size_t) ret, cap->magic_etc)) { + /* If this is sizeof(vfs_cap_data) then we're ok with the + * on-disk value, so return that. */ + if (alloc) + *buffer = tmpbuf; + else + kfree(tmpbuf); + return ret; + } else if (!is_v3header((size_t) ret, cap->magic_etc)) { + kfree(tmpbuf); + return -EINVAL; + } + + nscap = (struct vfs_ns_cap_data *) tmpbuf; + root = le32_to_cpu(nscap->rootid); + kroot = make_kuid(fs_ns, root); + + /* If the root kuid maps to a valid uid in current ns, then return + * this as a nscap. */ + mappedroot = from_kuid(current_user_ns(), kroot); + if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) { + if (alloc) { + *buffer = tmpbuf; + nscap->rootid = cpu_to_le32(mappedroot); + } else + kfree(tmpbuf); + return size; + } + + if (!rootid_owns_currentns(kroot)) { + kfree(tmpbuf); + return -EOPNOTSUPP; + } + + /* This comes from a parent namespace. Return as a v2 capability */ + size = sizeof(struct vfs_cap_data); + if (alloc) { + *buffer = kmalloc(size, GFP_ATOMIC); + if (*buffer) { + struct vfs_cap_data *cap = *buffer; + __le32 nsmagic, magic; + magic = VFS_CAP_REVISION_2; + nsmagic = le32_to_cpu(nscap->magic_etc); + if (nsmagic & VFS_CAP_FLAGS_EFFECTIVE) + magic |= VFS_CAP_FLAGS_EFFECTIVE; + memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32); + cap->magic_etc = cpu_to_le32(magic); + } + } + kfree(tmpbuf); + return size; +} + +static kuid_t rootid_from_xattr(const void *value, size_t size, + struct user_namespace *task_ns) +{ + const struct vfs_ns_cap_data *nscap = value; + uid_t rootid = 0; + + if (size == XATTR_CAPS_SZ_3) + rootid = le32_to_cpu(nscap->rootid); + + return make_kuid(task_ns, rootid); +} + +static bool validheader(size_t size, __le32 magic) +{ + return is_v2header(size, magic) || is_v3header(size, magic); +} + +/* + * User requested a write of security.capability. If needed, update the + * xattr to change from v2 to v3, or to fixup the v3 rootid. + * + * If all is ok, we return the new size, on error return < 0. + */ +int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size) +{ + struct vfs_ns_cap_data *nscap; + uid_t nsrootid; + const struct vfs_cap_data *cap = *ivalue; + __u32 magic, nsmagic; + struct inode *inode = d_backing_inode(dentry); + struct user_namespace *task_ns = current_user_ns(), + *fs_ns = inode->i_sb->s_user_ns; + kuid_t rootid; + size_t newsize; + + if (!*ivalue) + return -EINVAL; + if (!validheader(size, cap->magic_etc)) + return -EINVAL; + if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP)) + return -EPERM; + if (size == XATTR_CAPS_SZ_2) + if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP)) + /* user is privileged, just write the v2 */ + return size; + + rootid = rootid_from_xattr(*ivalue, size, task_ns); + if (!uid_valid(rootid)) + return -EINVAL; + + nsrootid = from_kuid(fs_ns, rootid); + if (nsrootid == -1) + return -EINVAL; + + newsize = sizeof(struct vfs_ns_cap_data); + nscap = kmalloc(newsize, GFP_ATOMIC); + if (!nscap) + return -ENOMEM; + nscap->rootid = cpu_to_le32(nsrootid); + nsmagic = VFS_CAP_REVISION_3; + magic = le32_to_cpu(cap->magic_etc); + if (magic & VFS_CAP_FLAGS_EFFECTIVE) + nsmagic |= VFS_CAP_FLAGS_EFFECTIVE; + nscap->magic_etc = cpu_to_le32(nsmagic); + memcpy(&nscap->data, &cap->data, sizeof(__le32) * 2 * VFS_CAP_U32); + + kvfree(*ivalue); + *ivalue = nscap; + return newsize; +} + /* * Calculate the new process capability sets from the capability sets attached * to a file. @@ -390,26 +593,31 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data __u32 magic_etc; unsigned tocopy, i; int size; - struct vfs_cap_data caps; + struct vfs_ns_cap_data data, *nscaps = &data; + struct vfs_cap_data *caps = (struct vfs_cap_data *) &data; + kuid_t rootkuid; + struct user_namespace *fs_ns = inode->i_sb->s_user_ns; memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); if (!inode || !inode->i_op->getxattr) return -ENODATA; - size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps, + size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ); if (size == -ENODATA || size == -EOPNOTSUPP) /* no data, that's ok */ return -ENODATA; + if (size < 0) return size; if (size < sizeof(magic_etc)) return -EINVAL; - cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc); + cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps->magic_etc); + rootkuid = make_kuid(fs_ns, 0); switch (magic_etc & VFS_CAP_REVISION_MASK) { case VFS_CAP_REVISION_1: if (size != XATTR_CAPS_SZ_1) @@ -421,15 +629,27 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data return -EINVAL; tocopy = VFS_CAP_U32_2; break; + case VFS_CAP_REVISION_3: + if (size != XATTR_CAPS_SZ_3) + return -EINVAL; + tocopy = VFS_CAP_U32_3; + rootkuid = make_kuid(fs_ns, le32_to_cpu(nscaps->rootid)); + break; + default: return -EINVAL; } + /* Limit the caps to the mounter of the filesystem + * or the more limited uid specified in the xattr. + */ + if (!rootid_owns_currentns(rootkuid)) + return -ENODATA; CAP_FOR_EACH_U32(i) { if (i >= tocopy) break; - cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted); - cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); + cpu_caps->permitted.cap[i] = le32_to_cpu(caps->data[i].permitted); + cpu_caps->inheritable.cap[i] = le32_to_cpu(caps->data[i].inheritable); } cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; @@ -461,8 +681,8 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); if (rc < 0) { if (rc == -EINVAL) - printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n", - __func__, rc, bprm->filename); + printk(KERN_NOTICE "Invalid argument reading file caps for %s\n", + bprm->filename); else if (rc == -ENODATA) rc = 0; goto out; @@ -660,15 +880,19 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name, { struct user_namespace *user_ns = dentry->d_sb->s_user_ns; - if (!strcmp(name, XATTR_NAME_CAPS)) { - if (!ns_capable(user_ns, CAP_SETFCAP)) - return -EPERM; + /* Ignore non-security xattrs */ + if (strncmp(name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) != 0) + return 0; + + /* + * For XATTR_NAME_CAPS the check will be done in + * cap_convert_nscap(), called by setxattr() + */ + if (strcmp(name, XATTR_NAME_CAPS) == 0) return 0; - } - if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof(XATTR_SECURITY_PREFIX) - 1) && - !ns_capable(user_ns, CAP_SYS_ADMIN)) + if (!ns_capable(user_ns, CAP_SYS_ADMIN)) return -EPERM; return 0; } @@ -688,15 +912,22 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name) { struct user_namespace *user_ns = dentry->d_sb->s_user_ns; - if (!strcmp(name, XATTR_NAME_CAPS)) { - if (!ns_capable(user_ns, CAP_SETFCAP)) + /* Ignore non-security xattrs */ + if (strncmp(name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) != 0) + return 0; + + if (strcmp(name, XATTR_NAME_CAPS) == 0) { + /* security.capability gets namespaced */ + struct inode *inode = d_backing_inode(dentry); + if (!inode) + return -EINVAL; + if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP)) return -EPERM; return 0; } - if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof(XATTR_SECURITY_PREFIX) - 1) && - !ns_capable(user_ns, CAP_SYS_ADMIN)) + if (!ns_capable(user_ns, CAP_SYS_ADMIN)) return -EPERM; return 0; } @@ -1086,6 +1317,7 @@ struct security_hook_list capability_hooks[] = { LSM_HOOK_INIT(bprm_secureexec, cap_bprm_secureexec), LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), + LSM_HOOK_INIT(inode_getsecurity, cap_inode_getsecurity), LSM_HOOK_INIT(mmap_addr, cap_mmap_addr), LSM_HOOK_INIT(mmap_file, cap_mmap_file), LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid), From patchwork Fri Jun 22 21:43:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seth Forshee X-Patchwork-Id: 933617 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41CBss5WH1z9s3C; Sat, 23 Jun 2018 07:44:17 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1fWTqg-0004Kn-V9; Fri, 22 Jun 2018 21:44:06 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1fWTqf-0004Kd-AQ for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:05 +0000 Received: from mail-it0-f71.google.com ([209.85.214.71]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fWTqf-000298-0D for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:05 +0000 Received: by mail-it0-f71.google.com with SMTP id n66-v6so4080796itg.0 for ; Fri, 22 Jun 2018 14:44:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=7FdMzrJUjql+gD1R4nY79CKGZ8j42h3LhOk4MoIDMq0=; b=ptNOMmqSvG9y864YUVy+dzY1XIj+9eecvmJZLqmf8aHKBkCdsWy/tc+o/ZtpOvggAL dIIPGr4Em7nHWSSJXTXBNYq7QrtJmAmXGKxs/p3iDSjvUKyJ/oMkz1cOR7a/dvjgABm2 wkmADasWW66v+xk/aUpYs848rww2IK91acbkmaR1C4JFc647zKEKXFcHq+ggqDtKTzuM PTtfCJLhokXiUCgAg9WHcdDzs60oCClBwMIWDQ2mmAa3Nn1/XW/ozdzVsoL6B2pa7Be1 PFywFDcA1AxvMQd5GWH+lJqWQYPgRYC81/1w1A9LKx9BaaP2eCm/6QckAaQp2ZFFMkJQ LiTA== X-Gm-Message-State: APt69E0ITUzWAJmGSzJAlC5QR3EATjR39N1tn0+sYirUIk4qiGJXQJJU lHdmGxrUHWXr9WKoZrjLT7xCt2pnDuIPT9CTxBdRmRtDNvVzrDgzp1PRLL9hghNUCm9Aa00lLOO dNQZvEJr/3rzHKACQaSxIUZ3f8dBf+esrdr4M6Ykxpg== X-Received: by 2002:a6b:2286:: with SMTP id i128-v6mr2802750ioi.289.1529703843788; Fri, 22 Jun 2018 14:44:03 -0700 (PDT) X-Google-Smtp-Source: AAOMgpf7i/zML9wIpLbl2pBflJC/pG8r4FRgaJYaJ9vlGriAA7jgQMkQHSCunI2o0SdijuNPUGgIHA== X-Received: by 2002:a6b:2286:: with SMTP id i128-v6mr2802740ioi.289.1529703843536; Fri, 22 Jun 2018 14:44:03 -0700 (PDT) Received: from localhost ([2605:a601:ac7:2a20:110:4491:9f96:3555]) by smtp.gmail.com with ESMTPSA id k139-v6sm1285503itk.27.2018.06.22.14.44.02 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 22 Jun 2018 14:44:02 -0700 (PDT) From: Seth Forshee To: kernel-team@lists.ubuntu.com Subject: [SRU][Xenial][PATCH 2/4] commoncap: move assignment of fs_ns to avoid null pointer dereference Date: Fri, 22 Jun 2018 16:43:57 -0500 Message-Id: <20180622214359.17903-3-seth.forshee@canonical.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180622214359.17903-1-seth.forshee@canonical.com> References: <20180622214359.17903-1-seth.forshee@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Colin Ian King BugLink: http://bugs.launchpad.net/bugs/1778286 The pointer fs_ns is assigned from inode->i_ib->s_user_ns before a null pointer check on inode, hence if inode is actually null we will get a null pointer dereference on this assignment. Fix this by only dereferencing inode after the null pointer check on inode. Detected by CoverityScan CID#1455328 ("Dereference before null check") Fixes: 8db6c34f1dbc ("Introduce v3 namespaced file capabilities") Signed-off-by: Colin Ian King Cc: stable@vger.kernel.org Acked-by: Serge Hallyn Signed-off-by: James Morris (backported from commit 76ba89c76f2c74e208d93a9e7c698e39eeb3b85c) Signed-off-by: Seth Forshee --- security/commoncap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/commoncap.c b/security/commoncap.c index c730ed00f427..6b4a8788c753 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -596,13 +596,14 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data struct vfs_ns_cap_data data, *nscaps = &data; struct vfs_cap_data *caps = (struct vfs_cap_data *) &data; kuid_t rootkuid; - struct user_namespace *fs_ns = inode->i_sb->s_user_ns; + struct user_namespace *fs_ns; memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); if (!inode || !inode->i_op->getxattr) return -ENODATA; + fs_ns = inode->i_sb->s_user_ns; size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ); if (size == -ENODATA || size == -EOPNOTSUPP) From patchwork Fri Jun 22 21:43:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seth Forshee X-Patchwork-Id: 933619 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41CBst0zxhz9s3R; Sat, 23 Jun 2018 07:44:18 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1fWTqj-0004LV-Ap; Fri, 22 Jun 2018 21:44:09 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1fWTqg-0004Km-Vi for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:06 +0000 Received: from mail-io0-f197.google.com ([209.85.223.197]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fWTqg-00029E-LF for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:06 +0000 Received: by mail-io0-f197.google.com with SMTP id v10-v6so6152688iog.18 for ; Fri, 22 Jun 2018 14:44:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=ogN82aE4LlomWWCmrZIfbd/oJsAsrflaxyeF5KE0Mps=; b=t5ddRS8tv69oa49yKWlc33AYuM5k2sE/PLHNTEXBJqNc1tF7vFSsiyzMgWaMgbQhdu 3nymMxyL7Wjw1edn8hvzvNkiZ6LiQf0dmhgpN2PUL03ane89wiMdjfydjrCeTlnPJokO VoITqIic4MUg4iFJGoV4SboL4iTVJKN7yqfWAIXVVudw2+efaXJdGTAjFXsvGtwhA6HY yqq1bpyeDttbIkcGifoxYpJyROkSPZKlq/Ncce6/dmEBGVVghX7QNNzmf4mNAwRFU0su F2kTI7BgKscwOYLzZsN/oKX1bacy29Qp3L69P4U4C4uwcWGUPdQxfZq+ifoM0ZU6YZNz YN+w== X-Gm-Message-State: APt69E10jQwUlGKdy23AAHV/UmYmAn7vcehRRC5TnO0eJhxaWbOaAuMt R2Uoy2vVJOVviabs7j0sMb/FKvqZjZjySKHBedC+6Xz0FQNhIUhPMowS1M3b42R6IuhNRYWcibE 7rKe9E9As0nIzrBXBeAxn4K86htMR26cZ4rHL1txh7g== X-Received: by 2002:a6b:3bcb:: with SMTP id i194-v6mr2703867ioa.86.1529703845333; Fri, 22 Jun 2018 14:44:05 -0700 (PDT) X-Google-Smtp-Source: AAOMgpdSyWdw79LObYPb6QUNfnxhlvXzlrGAL31FEEKp6d8Rd901vW4u7gEMZUj5IXtjynS6ckSKHw== X-Received: by 2002:a6b:3bcb:: with SMTP id i194-v6mr2703863ioa.86.1529703845056; Fri, 22 Jun 2018 14:44:05 -0700 (PDT) Received: from localhost ([2605:a601:ac7:2a20:110:4491:9f96:3555]) by smtp.gmail.com with ESMTPSA id 81-v6sm181452itv.39.2018.06.22.14.44.03 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 22 Jun 2018 14:44:04 -0700 (PDT) From: Seth Forshee To: kernel-team@lists.ubuntu.com Subject: [SRU][Xenial][PATCH 3/4] capabilities: fix buffer overread on very short xattr Date: Fri, 22 Jun 2018 16:43:58 -0500 Message-Id: <20180622214359.17903-4-seth.forshee@canonical.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180622214359.17903-1-seth.forshee@canonical.com> References: <20180622214359.17903-1-seth.forshee@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Eric Biggers BugLink: http://bugs.launchpad.net/bugs/1778286 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: # v4.14+ Signed-off-by: Eric Biggers Reviewed-by: Serge Hallyn Signed-off-by: James Morris (cherry picked from commit dc32b5c3e6e2ef29cef76d9ce1b92d394446150e) Signed-off-by: Seth Forshee --- security/commoncap.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/security/commoncap.c b/security/commoncap.c index 6b4a8788c753..d42373adb762 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -359,21 +359,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; } /* @@ -416,7 +413,7 @@ int cap_inode_getsecurity(const struct inode *inode, const char *name, 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) @@ -424,7 +421,7 @@ int cap_inode_getsecurity(const struct inode *inode, const char *name, 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; } @@ -481,9 +478,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); } /* @@ -506,7 +503,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; From patchwork Fri Jun 22 21:43:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seth Forshee X-Patchwork-Id: 933620 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41CBst5wsmz9s31; Sat, 23 Jun 2018 07:44:18 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1fWTql-0004Me-JH; Fri, 22 Jun 2018 21:44:11 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1fWTqi-0004L4-7Z for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:08 +0000 Received: from mail-it0-f72.google.com ([209.85.214.72]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fWTqh-00029H-TW for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:08 +0000 Received: by mail-it0-f72.google.com with SMTP id 13-v6so2804485itl.7 for ; Fri, 22 Jun 2018 14:44:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=/A6QKo3F1PHHE0krrO5oajSvX3/OsGMXePuWzI5n/tA=; b=CjmZo2IFQP2Maad+I/HttIqTRR5oCekUiRlyn4xkcNI3TFyy+tmRX4MlgcwX1DDBKP LN3N503RPImo3393LZCR1qVxNxH0lMBq4SLCOm4oGFcactMmg1H7U3+wN+tyCKEoTka6 mhNxIM/uSBz82+nJc2FH9FF6e6m/fMExaXiv6U6WCFLsV/Ly+6OLfxOkaGIdvxQpfLq1 LCGmNke/ZGvmNyvUPU1d07gQjsNtPLAVCCWd+Vf2q4wO3ZOoXE3jgDXmiY4mMU+MvNri Xt8WY2/ZYSwlHHPfzJbfbcRzfRxJGsA6mohPkmdVt/QP4qmiPkdh/QcmUzuB9kd50cd/ HZQg== X-Gm-Message-State: APt69E1FIs+6rW0ndBp6i9peTr+/bLuoIdVie/ZM9niLZf1FtdIET3Ah ofGwKF/4cF4tInbJmjF3lsdf4MXJeUChNZYP7ONM8nBTsTvGVAZaur4pHnDHJhgCw3cdd7Ba/+5 PbLmVpzYlwDBvYHZmVxiqtfw3A51WackLbN/ECpzAqw== X-Received: by 2002:a6b:cd05:: with SMTP id d5-v6mr2789837iog.150.1529703846671; Fri, 22 Jun 2018 14:44:06 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKE9L/rBbymDzPYgxmXsgej/Si24S1cwN4rkKKT9yMNbMSo4tK+sk4PcV9rx/4YMm6u4cz+vg== X-Received: by 2002:a6b:cd05:: with SMTP id d5-v6mr2789828iog.150.1529703846398; Fri, 22 Jun 2018 14:44:06 -0700 (PDT) Received: from localhost ([2605:a601:ac7:2a20:110:4491:9f96:3555]) by smtp.gmail.com with ESMTPSA id n204-v6sm1178090itg.7.2018.06.22.14.44.05 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 22 Jun 2018 14:44:05 -0700 (PDT) From: Seth Forshee To: kernel-team@lists.ubuntu.com Subject: [SRU][Xenial][PATCH 4/4] commoncap: Handle memory allocation failure. Date: Fri, 22 Jun 2018 16:43:59 -0500 Message-Id: <20180622214359.17903-5-seth.forshee@canonical.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180622214359.17903-1-seth.forshee@canonical.com> References: <20180622214359.17903-1-seth.forshee@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Tetsuo Handa BugLink: http://bugs.launchpad.net/bugs/1778286 syzbot is reporting NULL pointer dereference at xattr_getsecurity() [1], for cap_inode_getsecurity() is returning sizeof(struct vfs_cap_data) when memory allocation failed. Return -ENOMEM if memory allocation failed. [1] https://syzkaller.appspot.com/bug?id=a55ba438506fe68649a5f50d2d82d56b365e0107 Signed-off-by: Tetsuo Handa Fixes: 8db6c34f1dbc8e06 ("Introduce v3 namespaced file capabilities") Reported-by: syzbot Cc: stable # 4.14+ Acked-by: Serge E. Hallyn Acked-by: James Morris Signed-off-by: Eric W. Biederman (cherry picked from commit 1f5781725dcbb026438e77091c91a94f678c3522) Signed-off-by: Seth Forshee --- security/commoncap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/commoncap.c b/security/commoncap.c index d42373adb762..814324f7f057 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -460,6 +460,8 @@ int cap_inode_getsecurity(const struct inode *inode, const char *name, magic |= VFS_CAP_FLAGS_EFFECTIVE; memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32); cap->magic_etc = cpu_to_le32(magic); + } else { + size = -ENOMEM; } } kfree(tmpbuf);