From nobody Tue Feb 10 03:39:28 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1487601995020208.42744644741128; Mon, 20 Feb 2017 06:46:35 -0800 (PST) Received: from localhost ([::1]:38959 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cfpEV-0002my-DA for importer@patchew.org; Mon, 20 Feb 2017 09:46:31 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53887) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cfp8G-0005tx-6w for qemu-devel@nongnu.org; Mon, 20 Feb 2017 09:40:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cfp8C-0003W0-VY for qemu-devel@nongnu.org; Mon, 20 Feb 2017 09:40:04 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:57950) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cfp8C-0003VY-MY for qemu-devel@nongnu.org; Mon, 20 Feb 2017 09:40:00 -0500 Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v1KEdZAx025432 for ; Mon, 20 Feb 2017 09:39:59 -0500 Received: from e37.co.us.ibm.com (e37.co.us.ibm.com [32.97.110.158]) by mx0a-001b2d01.pphosted.com with ESMTP id 28r11ybwcy-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Mon, 20 Feb 2017 09:39:59 -0500 Received: from localhost by e37.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 20 Feb 2017 07:39:57 -0700 Received: from d03dlp03.boulder.ibm.com (9.17.202.179) by e37.co.us.ibm.com (192.168.1.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 20 Feb 2017 07:39:54 -0700 Received: from b03cxnp08025.gho.boulder.ibm.com (b03cxnp08025.gho.boulder.ibm.com [9.17.130.17]) by d03dlp03.boulder.ibm.com (Postfix) with ESMTP id 48BA119D8026; Mon, 20 Feb 2017 07:39:06 -0700 (MST) Received: from b03ledav004.gho.boulder.ibm.com (b03ledav004.gho.boulder.ibm.com [9.17.130.235]) by b03cxnp08025.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v1KEdsvx8323390; Mon, 20 Feb 2017 07:39:54 -0700 Received: from b03ledav004.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E347578043; Mon, 20 Feb 2017 07:39:53 -0700 (MST) Received: from bahia.lan (unknown [9.164.137.25]) by b03ledav004.gho.boulder.ibm.com (Postfix) with ESMTP id 3BCDB78037; Mon, 20 Feb 2017 07:39:52 -0700 (MST) From: Greg Kurz To: qemu-devel@nongnu.org Date: Mon, 20 Feb 2017 15:39:51 +0100 In-Reply-To: <148760155821.31154.13876757160410915057.stgit@bahia.lan> References: <148760155821.31154.13876757160410915057.stgit@bahia.lan> User-Agent: StGit/0.17.1-20-gc0b1b-dirty MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 17022014-0024-0000-0000-000015F68037 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00006651; HX=3.00000240; KW=3.00000007; PH=3.00000004; SC=3.00000204; SDB=6.00824568; UDB=6.00403650; IPR=6.00602025; BA=6.00005157; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00014360; XFM=3.00000011; UTC=2017-02-20 14:39:56 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17022014-0025-0000-0000-000048E8E4A2 Message-Id: <148760159100.31154.15503472827834963062.stgit@bahia.lan> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-02-20_13:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=3 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1612050000 definitions=main-1702200144 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.156.1 Subject: [Qemu-devel] [PATCH 04/29] 9pfs: introduce openat_nofollow() helper X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jann Horn , Prasad J Pandit , Greg Kurz , "Aneesh Kumar K.V" , Stefan Hajnoczi Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 When using the passthrough security mode, symbolic links created by the guest are actual symbolic links on the host file system. Since the resolution of symbolic links during path walk is supposed to occur on the client side. The server should hence never receive any path pointing to an actual symbolic link. This isn't guaranteed by the protocol though, and malicious code in the guest can trick the server to issue various syscalls on paths whose one or more elements are symbolic links. In the case of the "local" backend using the "passthrough" or "none" security modes, the guest can directly create symbolic links to arbitrary locations on the host (as per spec). The "mapped-xattr" and "mapped-file" security modes are also affected to a lesser extent as they require some help from an external entity to create actual symbolic links on the host, i.e. anoter guest using "passthrough" mode for example. The current code hence relies on O_NOFOLLOW and "l*()" variants of system calls. Unfortunately, this only applies to the rightmost path component. A guest could maliciously replace any component in a trusted path with a symbolic link. This could allow any guest to escape a virtfs shared folder. This patch introduces a variant of the openat() syscall that successively opens each path element with O_NOFOLLOW. When passing a file descriptor pointing to a trusted directory, one is guaranteed to be returned a file descriptor pointing to a path which is beneath the trusted directory. This will be used by subsequent patches to implement symlink-safe path walk for any access to the backend. Suggested-by: Jann Horn Signed-off-by: Greg Kurz --- hw/9pfs/9p-util.c | 69 +++++++++++++++++++++++++++++++++++++++++++++= ++++ hw/9pfs/9p-util.h | 25 ++++++++++++++++++ hw/9pfs/Makefile.objs | 2 + 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 hw/9pfs/9p-util.c create mode 100644 hw/9pfs/9p-util.h diff --git a/hw/9pfs/9p-util.c b/hw/9pfs/9p-util.c new file mode 100644 index 000000000000..48292d948401 --- /dev/null +++ b/hw/9pfs/9p-util.c @@ -0,0 +1,69 @@ +/* + * 9p utilities + * + * Copyright IBM, Corp. 2017 + * + * Authors: + * Greg Kurz + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "9p-util.h" + +int openat_nofollow(int dirfd, const char *path, int flags, mode_t mode) +{ + const char *tail =3D path; + const char *c; + int fd; + + fd =3D dup(dirfd); + if (fd =3D=3D -1) { + return -1; + } + + while (*tail) { + int next_fd; + char *head; + + while (*tail =3D=3D '/') { + tail++; + } + + if (!*tail) { + break; + } + + head =3D g_strdup(tail); + c =3D strchr(tail, '/'); + if (c) { + head[c - tail] =3D 0; + next_fd =3D openat(fd, head, O_DIRECTORY | O_RDONLY | O_NOFOLL= OW); + } else { + /* We don't want bad things to happen like opening a file that + * sits outside the virtfs export, or hanging on a named pipe, + * or changing the controlling process of a terminal. + */ + flags |=3D O_NOFOLLOW | O_NONBLOCK | O_NOCTTY; + next_fd =3D openat(fd, head, flags, mode); + } + g_free(head); + if (next_fd =3D=3D -1) { + close_preserve_errno(fd); + return -1; + } + close(fd); + fd =3D next_fd; + + if (!c) { + break; + } + tail =3D c + 1; + } + /* O_NONBLOCK was only needed to open the file. Let's drop it. */ + assert(!fcntl(fd, F_SETFL, flags)); + + return fd; +} diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h new file mode 100644 index 000000000000..e19673d85222 --- /dev/null +++ b/hw/9pfs/9p-util.h @@ -0,0 +1,25 @@ +/* + * 9p utilities + * + * Copyright IBM, Corp. 2017 + * + * Authors: + * Greg Kurz + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_9P_UTIL_H +#define QEMU_9P_UTIL_H + +static inline void close_preserve_errno(int fd) +{ + int serrno =3D errno; + close(fd); + errno =3D serrno; +} + +int openat_nofollow(int dirfd, const char *path, int flags, mode_t mode); + +#endif diff --git a/hw/9pfs/Makefile.objs b/hw/9pfs/Makefile.objs index da0ae0cfdbae..32197e6671dd 100644 --- a/hw/9pfs/Makefile.objs +++ b/hw/9pfs/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y =3D 9p.o +common-obj-y =3D 9p.o 9p-util.o common-obj-y +=3D 9p-local.o 9p-xattr.o common-obj-y +=3D 9p-xattr-user.o 9p-posix-acl.o common-obj-y +=3D coth.o cofs.o codir.o cofile.o