From nobody Mon Feb 9 00:02:14 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 1490052700298411.8305131926908; Mon, 20 Mar 2017 16:31:40 -0700 (PDT) Received: from localhost ([::1]:35593 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cq6m2-00030S-SO for importer@patchew.org; Mon, 20 Mar 2017 19:31:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40659) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cq6Qc-0001Zd-Fd for qemu-devel@nongnu.org; Mon, 20 Mar 2017 19:09:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cq6QX-0004pZ-Tf for qemu-devel@nongnu.org; Mon, 20 Mar 2017 19:09:30 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:41491 helo=mx0a-001b2d01.pphosted.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cq6QX-0004p1-Ld for qemu-devel@nongnu.org; Mon, 20 Mar 2017 19:09:25 -0400 Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v2KN8YpG074854 for ; Mon, 20 Mar 2017 19:09:25 -0400 Received: from e16.ny.us.ibm.com (e16.ny.us.ibm.com [129.33.205.206]) by mx0a-001b2d01.pphosted.com with ESMTP id 29aj6q9hsr-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Mon, 20 Mar 2017 19:09:24 -0400 Received: from localhost by e16.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 20 Mar 2017 19:09:24 -0400 Received: from b01cxnp22033.gho.pok.ibm.com (9.57.198.23) by e16.ny.us.ibm.com (146.89.104.203) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 20 Mar 2017 19:09:22 -0400 Received: from b01ledav005.gho.pok.ibm.com (b01ledav005.gho.pok.ibm.com [9.57.199.110]) by b01cxnp22033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v2KN9LRu31653902; Mon, 20 Mar 2017 23:09:21 GMT Received: from b01ledav005.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 16F51AE051; Mon, 20 Mar 2017 19:09:14 -0400 (EDT) Received: from localhost (unknown [9.53.92.194]) by b01ledav005.gho.pok.ibm.com (Postfix) with ESMTP id 05A42AE03C; Mon, 20 Mar 2017 19:09:14 -0400 (EDT) From: Michael Roth To: qemu-devel@nongnu.org Date: Mon, 20 Mar 2017 18:07:50 -0500 X-Mailer: git-send-email 2.7.4 In-Reply-To: <1490051325-3770-1-git-send-email-mdroth@linux.vnet.ibm.com> References: <1490051325-3770-1-git-send-email-mdroth@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 17032023-0024-0000-0000-0000021F8DD5 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00006819; HX=3.00000240; KW=3.00000007; PH=3.00000004; SC=3.00000206; SDB=6.00836553; UDB=6.00411162; IPR=6.00614321; BA=6.00005224; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00014732; XFM=3.00000013; UTC=2017-03-20 23:09:23 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17032023-0025-0000-0000-000042B6B6E1 Message-Id: <1490051325-3770-27-git-send-email-mdroth@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-03-20_16:, , 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-1702020001 definitions=main-1703200196 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.158.5 Subject: [Qemu-devel] [PATCH 26/81] 9pfs: local: mkdir: don't follow symlinks 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: Greg Kurz , qemu-stable@nongnu.org, Greg Kurz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Greg Kurz The local_mkdir() callback is vulnerable to symlink attacks because it calls: (1) mkdir() which follows symbolic links for all path elements but the rightmost one (2) local_set_xattr()->setxattr() which follows symbolic links for all path elements (3) local_set_mapped_file_attr() which calls in turn local_fopen() and mkdir(), both functions following symbolic links for all path elements but the rightmost one (4) local_post_create_passthrough() which calls in turn lchown() and chmod(), both functions also following symbolic links This patch converts local_mkdir() to rely on opendir_nofollow() and mkdirat() to fix (1), as well as local_set_xattrat(), local_set_mapped_file_attrat() and local_set_cred_passthrough() to fix (2), (3) and (4) respectively. The mapped and mapped-file security modes are supposed to be identical, except for the place where credentials and file modes are stored. While here, we also make that explicit by sharing the call to mkdirat(). This partly fixes CVE-2016-9602. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi (cherry picked from commit 3f3a16990b09e62d787bd2eb2dd51aafbe90019a) Signed-off-by: Greg Kurz Signed-off-by: Michael Roth --- hw/9pfs/9p-local.c | 55 ++++++++++++++++++++------------------------------= ---- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index f71cc11..76ac205 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -800,62 +800,47 @@ out: static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, FsCred *credp) { - char *path; int err =3D -1; - int serrno =3D 0; - V9fsString fullname; - char *buffer =3D NULL; + int dirfd; =20 - v9fs_string_init(&fullname); - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); - path =3D fullname.data; + dirfd =3D local_opendir_nofollow(fs_ctx, dir_path->data); + if (dirfd =3D=3D -1) { + return -1; + } =20 - /* Determine the security model */ - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - buffer =3D rpath(fs_ctx, path); - err =3D mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); + if (fs_ctx->export_flags & V9FS_SM_MAPPED || + fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + err =3D mkdirat(dirfd, name, SM_LOCAL_DIR_MODE_BITS); if (err =3D=3D -1) { goto out; } - credp->fc_mode =3D credp->fc_mode|S_IFDIR; - err =3D local_set_xattr(buffer, credp); - if (err =3D=3D -1) { - serrno =3D errno; - goto err_end; - } - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - buffer =3D rpath(fs_ctx, path); - err =3D mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); - if (err =3D=3D -1) { - goto out; + credp->fc_mode =3D credp->fc_mode | S_IFDIR; + + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + err =3D local_set_xattrat(dirfd, name, credp); + } else { + err =3D local_set_mapped_file_attrat(dirfd, name, credp); } - credp->fc_mode =3D credp->fc_mode|S_IFDIR; - err =3D local_set_mapped_file_attr(fs_ctx, path, credp); if (err =3D=3D -1) { - serrno =3D errno; goto err_end; } - } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || - (fs_ctx->export_flags & V9FS_SM_NONE)) { - buffer =3D rpath(fs_ctx, path); - err =3D mkdir(buffer, credp->fc_mode); + } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH || + fs_ctx->export_flags & V9FS_SM_NONE) { + err =3D mkdirat(dirfd, name, credp->fc_mode); if (err =3D=3D -1) { goto out; } - err =3D local_post_create_passthrough(fs_ctx, path, credp); + err =3D local_set_cred_passthrough(fs_ctx, dirfd, name, credp); if (err =3D=3D -1) { - serrno =3D errno; goto err_end; } } goto out; =20 err_end: - remove(buffer); - errno =3D serrno; + unlinkat_preserve_errno(dirfd, name, AT_REMOVEDIR); out: - g_free(buffer); - v9fs_string_free(&fullname); + close_preserve_errno(dirfd); return err; } =20 --=20 2.7.4