From nobody Thu Nov 6 18:52:24 2025 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 1488238770732254.43209894933932; Mon, 27 Feb 2017 15:39:30 -0800 (PST) Received: from localhost ([::1]:57630 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ciUt7-0008Iv-Ei for importer@patchew.org; Mon, 27 Feb 2017 18:39:29 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47186) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ciUHz-0000nQ-36 for qemu-devel@nongnu.org; Mon, 27 Feb 2017 18:01:10 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ciUHv-0004Cg-Pw for qemu-devel@nongnu.org; Mon, 27 Feb 2017 18:01:07 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:51151) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1ciUHv-0004BZ-6K for qemu-devel@nongnu.org; Mon, 27 Feb 2017 18:01:03 -0500 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v1RMra9v107522 for ; Mon, 27 Feb 2017 18:01:02 -0500 Received: from e06smtp12.uk.ibm.com (e06smtp12.uk.ibm.com [195.75.94.108]) by mx0a-001b2d01.pphosted.com with ESMTP id 28vm1w2uk9-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Mon, 27 Feb 2017 18:01:01 -0500 Received: from localhost by e06smtp12.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 27 Feb 2017 23:00:58 -0000 Received: from d06dlp02.portsmouth.uk.ibm.com (9.149.20.14) by e06smtp12.uk.ibm.com (192.168.101.142) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 27 Feb 2017 23:00:55 -0000 Received: from b06cxnps4076.portsmouth.uk.ibm.com (d06relay13.portsmouth.uk.ibm.com [9.149.109.198]) by d06dlp02.portsmouth.uk.ibm.com (Postfix) with ESMTP id 0F38F2190019; Mon, 27 Feb 2017 22:59:56 +0000 (GMT) Received: from d06av24.portsmouth.uk.ibm.com (d06av24.portsmouth.uk.ibm.com [9.149.105.60]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v1RN0s239961896; Mon, 27 Feb 2017 23:00:54 GMT Received: from d06av24.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BD09942041; Mon, 27 Feb 2017 23:00:49 +0000 (GMT) Received: from d06av24.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A30464203F; Mon, 27 Feb 2017 23:00:49 +0000 (GMT) Received: from smtp.lab.toulouse-stg.fr.ibm.com (unknown [9.101.4.1]) by d06av24.portsmouth.uk.ibm.com (Postfix) with ESMTP; Mon, 27 Feb 2017 23:00:49 +0000 (GMT) Received: from bahia.lan (icon-9-164-183-34.megacenter.de.ibm.com [9.164.183.34]) by smtp.lab.toulouse-stg.fr.ibm.com (Postfix) with ESMTP id F1AE7220711; Tue, 28 Feb 2017 00:00:53 +0100 (CET) From: Greg Kurz To: qemu-devel@nongnu.org Date: Tue, 28 Feb 2017 00:00:18 +0100 X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488236421-30983-1-git-send-email-groug@kaod.org> References: <1488236421-30983-1-git-send-email-groug@kaod.org> X-TM-AS-GCONF: 00 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 17022723-0008-0000-0000-000003F0FD90 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17022723-0009-0000-0000-00001C9C0C48 Message-Id: <1488236421-30983-29-git-send-email-groug@kaod.org> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-02-27_17:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=13 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1612050000 definitions=main-1702270213 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.156.1 Subject: [Qemu-devel] [PULL 28/31] 9pfs: local: mknod: 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: Peter Maydell , "Aneesh Kumar K.V" , 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" The local_mknod() callback is vulnerable to symlink attacks because it calls: (1) mknod() 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_mknod() to rely on opendir_nofollow() and mknodat() to fix (1), as well as local_set_xattrat() and local_set_mapped_file_attrat() to fix (2) and (3) respectively. A new local_set_cred_passthrough() helper based on fchownat() and fchmodat_nofollow() is introduced as a replacement to local_post_create_passthrough() to fix (4). 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 mknodat(). This partly fixes CVE-2016-9602. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi --- hw/9pfs/9p-local.c | 68 ++++++++++++++++++++++++++++----------------------= ---- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 907ecc59d494..bd95785ff129 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -543,6 +543,23 @@ err: return -1; } =20 +static int local_set_cred_passthrough(FsContext *fs_ctx, int dirfd, + const char *name, FsCred *credp) +{ + if (fchownat(dirfd, name, credp->fc_uid, credp->fc_gid, + AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) < 0) { + /* + * If we fail to change ownership and if we are + * using security model none. Ignore the error + */ + if ((fs_ctx->export_flags & V9FS_SEC_MASK) !=3D V9FS_SM_NONE) { + return -1; + } + } + + return fchmodat_nofollow(dirfd, name, credp->fc_mode & 07777); +} + static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, char *buf, size_t bufsz) { @@ -736,61 +753,46 @@ out: static int local_mknod(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 mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); + if (fs_ctx->export_flags & V9FS_SM_MAPPED || + fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + err =3D mknodat(dirfd, name, SM_LOCAL_MODE_BITS | S_IFREG, 0); if (err =3D=3D -1) { goto out; } - 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) { =20 - buffer =3D rpath(fs_ctx, path); - err =3D mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); - if (err =3D=3D -1) { - goto out; + 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); } - 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 mknod(buffer, credp->fc_mode, credp->fc_rdev); + } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH || + fs_ctx->export_flags & V9FS_SM_NONE) { + err =3D mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev); 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, 0); out: - g_free(buffer); - v9fs_string_free(&fullname); + close_preserve_errno(dirfd); return err; } =20 --=20 2.7.4