{"id":2231573,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2231573/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-ext4/patch/177758363676.1314717.13141985577257882201.stgit@frogsfrogsfrogs/","project":{"id":8,"url":"http://patchwork.ozlabs.org/api/1.1/projects/8/?format=json","name":"Linux ext4 filesystem development","link_name":"linux-ext4","list_id":"linux-ext4.vger.kernel.org","list_email":"linux-ext4@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<177758363676.1314717.13141985577257882201.stgit@frogsfrogsfrogs>","date":"2026-04-30T21:17:06","name":"[08/13] mount_service: enable unprivileged users in a similar manner as fusermount","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"92e1b9677c5d38220329234941a48f649e8c30d0","submitter":{"id":77032,"url":"http://patchwork.ozlabs.org/api/1.1/people/77032/?format=json","name":"Darrick J. Wong","email":"djwong@kernel.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-ext4/patch/177758363676.1314717.13141985577257882201.stgit@frogsfrogsfrogs/mbox/","series":[{"id":502386,"url":"http://patchwork.ozlabs.org/api/1.1/series/502386/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-ext4/list/?series=502386","date":"2026-04-30T21:15:17","name":"[01/13] Refactor mount code / move common functions to mount_util.c","version":1,"mbox":"http://patchwork.ozlabs.org/series/502386/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2231573/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2231573/checks/","tags":{},"headers":{"Return-Path":"\n <SRS0=7HwI=C5=vger.kernel.org=linux-ext4+bounces-16260-patchwork-incoming=ozlabs.org@ozlabs.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-ext4@vger.kernel.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","patchwork-incoming@ozlabs.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=ThoE5uK4;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=ozlabs.org\n (client-ip=150.107.74.76; helo=mail.ozlabs.org;\n envelope-from=srs0=7hwi=c5=vger.kernel.org=linux-ext4+bounces-16260-patchwork-incoming=ozlabs.org@ozlabs.org;\n receiver=patchwork.ozlabs.org)","gandalf.ozlabs.org;\n arc=pass smtp.remote-ip=\"2600:3c15:e001:75::12fc:5321\"\n arc.chain=subspace.kernel.org","gandalf.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org","gandalf.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=ThoE5uK4;\n\tdkim-atps=neutral","gandalf.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-ext4+bounces-16260-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"ThoE5uK4\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201"],"Received":["from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g66TQ3DvGz1yHZ\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 01 May 2026 07:18:02 +1000 (AEST)","from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\n\tby gandalf.ozlabs.org (Postfix) with ESMTP id 4g66TQ2f8yz4wSd\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 01 May 2026 07:18:02 +1000 (AEST)","by gandalf.ozlabs.org (Postfix)\n\tid 4g66TQ2V2Rz4wck; Fri, 01 May 2026 07:18:02 +1000 (AEST)","from sin.lore.kernel.org (sin.lore.kernel.org\n [IPv6:2600:3c15:e001:75::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby gandalf.ozlabs.org (Postfix) with ESMTPS id 4g66TL51wpz4wSd\n\tfor <patchwork-incoming@ozlabs.org>; Fri, 01 May 2026 07:17:58 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id 3CF32300682F\n\tfor <patchwork-incoming@ozlabs.org>; Thu, 30 Apr 2026 21:17:11 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id DA30A37B40C;\n\tThu, 30 Apr 2026 21:17:07 +0000 (UTC)","from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C9ED20E030;\n\tThu, 30 Apr 2026 21:17:07 +0000 (UTC)","by smtp.kernel.org (Postfix) with ESMTPSA id 36B25C2BCB3;\n\tThu, 30 Apr 2026 21:17:07 +0000 (UTC)"],"ARC-Seal":["i=2; a=rsa-sha256; d=ozlabs.org; s=201707; t=1777583882; cv=pass;\n\tb=pXnH5R38NzRB6Oep9oBe9L+0OWb50WlKjEJAFb64Md87STO4egaH8qfq39ZSaOVmNv8b2Te5uVtS3h2wq8vwwUzCyhIFkE9CVzB6mSzYLKbBldOWg1K6hg/wGbdJmx9GrjKpSC15BDKE/zTsC/pMLTXjjTEz97ez39o/+9j3QhKDRaKvhs1KiiA3PTBJAG5swAQu4fQlgeVChJ2cPVnIqSRd/ur/bsJoKsRAYjL/VYOMJqL5UrXHlA26auaezsyGYS0kDUBZiA8bjR0HBd8o+elQJ3ZBDmooOtdSrBi2AmfeZrTmav2krke1+yARQOBDGGupL/0IBO2SLk2lcQ3qRg==","i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777583827; cv=none;\n b=Atzs1oEXRrRCE4ht/MfNgVYaij8JHL+1sKGkS4uyxheVCupT6m5dn+YESsmEy3vmn5hnQyNEpDTyzbsRKaJvxaqBVrxv7AvcKcyTeaHC+oVggipEfHjEifwBd0RboJMeJrDQnWsNLekFXYk4HHKM8v2Nc+600O0QXHzHppTesU8="],"ARC-Message-Signature":["i=2; a=rsa-sha256; d=ozlabs.org; s=201707;\n\tt=1777583882; c=relaxed/relaxed;\n\tbh=6EPJ3Du6B/7Pk7LgMuv0CT+uSI7DYXZlitS35xaBvyw=;\n\th=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References:\n\t MIME-Version:Content-Type;\n b=BZO6i5N9CoyyoVGJ1fU0CaC9sDm512+tbFVqCH+OFz2kJ+nnMSSuP82RiveKbIn5uu+zuXAEvTBgIuLqS41jCijU/AM9+6hfi066P3xmDKzIlpP4NEtX0A9SuQH2mU+asBzM1pGxaYzae5rvO7z2X8DPt0RBV6v9MeLWxhyV4xKGPSsXW46D1A7TDbZkb3Jv011J3BsI/ntQU8wkxxUIebrCwHfD1PqxJFEYtDnF/MBxW16ZIP3+r6Ok5CUGFA+5Dp7+u4/S+IBjLHqIoZ3EHznitRTCWpb9PrfP7wpFpAFBzCr9NP18IawqUfC+XmaZcDC00+BSNtFO+DVRkmIY3w==","i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777583827; c=relaxed/simple;\n\tbh=w4TsrncluomBkkDSJxichIaC08DLJqCYx5JoLMX6Qvs=;\n\th=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References:\n\t MIME-Version:Content-Type;\n b=ulg8DMHpv/dySJ5AnCGSwgV5LttbazbWTT7a4jkOjVJxhyeSqTAYKsAgFInffFBLS2CTykya8w78PQw4W4ilgYJ6r0TchekH8bkz59RBEZE3cSgcq7Us0qpM40/9MLVdFOspbGWP+iNAMC2JutncBAhOP5MqJa0EQWs6KKCndvU="],"ARC-Authentication-Results":["i=2; gandalf.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org;\n dkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=ThoE5uK4; dkim-atps=neutral;\n spf=pass (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-ext4+bounces-16260-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org) smtp.mailfrom=vger.kernel.org","i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=ThoE5uK4; arc=none smtp.client-ip=10.30.226.201"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1777583827;\n\tbh=w4TsrncluomBkkDSJxichIaC08DLJqCYx5JoLMX6Qvs=;\n\th=Date:Subject:From:To:Cc:In-Reply-To:References:From;\n\tb=ThoE5uK4LEYY37bFKurOsyYBfMYP2OtXXH9/Zigl6/5DeIb891qpHv6Pa8W4oSptN\n\t 7CbCwa586MbLwmo0fp94Uhxs/HDGD1gewi0WXNQCoHsijTh3+2iF5GrqrTBRFLOKg9\n\t GGahUSgcOFhEbGJPRr7HbYyTWNCww2WmAnyeM2GhDoixQlhE/hzUX054q8E01hF7MK\n\t Kw9UP0C6zBkKMtsjIvLBzV6RosFyHY4kEA3xJYlPpiJQSvFQDtwvFxaEbQGQuViWVs\n\t gEych4BNk6NDZfCsggQmOpApYkht8WE59OwVvN08+beSmWHV7HG5mhbI2uc/rTOL74\n\t WDx+s3xyK4lIA==","Date":"Thu, 30 Apr 2026 14:17:06 -0700","Subject":"[PATCH 08/13] mount_service: enable unprivileged users in a similar\n manner as fusermount","From":"\"Darrick J. Wong\" <djwong@kernel.org>","To":"bernd@bsbernd.com, djwong@kernel.org","Cc":"linux-fsdevel@vger.kernel.org, fuse-devel@lists.linux.dev,\n linux-ext4@vger.kernel.org, miklos@szeredi.hu, neal@gompa.dev,\n joannelkoong@gmail.com","Message-ID":"<177758363676.1314717.13141985577257882201.stgit@frogsfrogsfrogs>","In-Reply-To":"<177758363484.1314717.11777978893472254088.stgit@frogsfrogsfrogs>","References":"<177758363484.1314717.11777978893472254088.stgit@frogsfrogsfrogs>","Precedence":"bulk","X-Mailing-List":"linux-ext4@vger.kernel.org","List-Id":"<linux-ext4.vger.kernel.org>","List-Subscribe":"<mailto:linux-ext4+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-ext4+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"7bit","X-Spam-Status":"No, score=-1.2 required=5.0 tests=ARC_SIGNED,ARC_VALID,\n\tDKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DMARC_PASS,\n\tMAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=disabled\n\tversion=4.0.1","X-Spam-Checker-Version":"SpamAssassin 4.0.1 (2024-03-25) on gandalf.ozlabs.org"},"content":"From: Darrick J. Wong <djwong@kernel.org>\n\nSome Linux distributions allow unprivileged users to mount fuse\nfilesystems through the use of the setuid fusermount helper program.  It\nwould be useful to provide similar functionality when mounting a\nfilesystem that runs as a systemd service.\n\nTherefore, read the fuse config file and implement the same checks as\nfusermount.  The only new requirement is that the unprivileged user must\nbe able to open the mountpoint for write access if it's a regular file;\nor have write access if it's a directory.\n\nSigned-off-by: \"Darrick J. Wong\" <djwong@kernel.org>\n---\n util/mount_service.c |  232 +++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 227 insertions(+), 5 deletions(-)","diff":"diff --git a/util/mount_service.c b/util/mount_service.c\nindex 915a0c4b610792..95de56f2b625fe 100644\n--- a/util/mount_service.c\n+++ b/util/mount_service.c\n@@ -38,6 +38,7 @@\n #include \"fuse_i.h\"\n #include \"fuse_service_priv.h\"\n #include \"mount_service.h\"\n+#include \"fuser_conf.h\"\n \n struct mount_service {\n \t/* prefix for printing error messages */\n@@ -313,8 +314,10 @@ static int mount_service_connect(struct mount_service *mo)\n \tif (ret)\n \t\treturn ret;\n \n+\tdrop_privs();\n \tret = connect(sockfd, (const struct sockaddr *)&name, sizeof(name));\n \tif (ret && (errno == ENOENT || errno == ECONNREFUSED)) {\n+\t\trestore_privs();\n \t\tfprintf(stderr, \"%s: no safe filesystem driver for %s available.\\n\",\n \t\t\tmo->msgtag, mo->subtype);\n \t\tclose(sockfd);\n@@ -323,10 +326,12 @@ static int mount_service_connect(struct mount_service *mo)\n \tif (ret) {\n \t\tint error = errno;\n \n+\t\trestore_privs();\n \t\tfprintf(stderr, \"%s: %s: %s\\n\",\n \t\t\tmo->msgtag, name.sun_path, strerror(error));\n \t\tgoto out;\n \t}\n+\trestore_privs();\n \n \tret = try_drop_passrights(mo, sockfd);\n \tif (ret)\n@@ -349,7 +354,7 @@ static int mount_service_send_hello(struct mount_service *mo)\n \tstruct fuse_service_hello_reply reply = { };\n \tssize_t size;\n \n-\tif (getuid() == 0)\n+\tif (getuid() == 0 || user_allow_other)\n \t\thello.flags |= htonl(FUSE_SERVICE_FLAG_ALLOW_OTHER);\n \n \tsize = __send_packet(mo, &hello, sizeof(hello));\n@@ -586,14 +591,17 @@ static int mount_service_send_required_files(struct mount_service *mo,\n {\n \tint ret;\n \n+\tdrop_privs();\n \tmo->fusedevfd = open(fusedev, O_RDWR | O_CLOEXEC);\n \tif (mo->fusedevfd < 0) {\n \t\tint error = errno;\n \n+\t\trestore_privs();\n \t\tfprintf(stderr, \"%s: %s: %s\\n\",\n \t\t\tmo->msgtag, fusedev, strerror(error));\n \t\treturn -1;\n \t}\n+\trestore_privs();\n \n \tret = mount_service_send_file(mo, FUSE_SERVICE_ARGV, mo->argvfd);\n \tif (ret)\n@@ -710,14 +718,17 @@ static int prepare_bdev(struct mount_service *mo,\n \tif (oc->block_size) {\n \t\tint block_size = ntohl(oc->block_size);\n \n+\t\tdrop_privs();\n \t\tret = ioctl(fd, BLKBSZSET, &block_size);\n \t\tif (ret) {\n \t\t\tint error = errno;\n \n+\t\t\trestore_privs();\n \t\t\tfprintf(stderr, \"%s: %s: %s\\n\",\n \t\t\t\tmo->msgtag, oc->path, strerror(error));\n \t\t\treturn -error;\n \t\t}\n+\t\trestore_privs();\n \t}\n \n \treturn 0;\n@@ -754,6 +765,7 @@ static int mount_service_open_path(struct mount_service *mo,\n \t}\n \n \topen_flags = ntohl(oc->open_flags) | O_CLOEXEC;\n+\tdrop_privs();\n \tfd = open(oc->path, open_flags, ntohl(oc->create_mode));\n \tif (fd < 0) {\n \t\tint error = errno;\n@@ -762,11 +774,13 @@ static int mount_service_open_path(struct mount_service *mo,\n \t\t * Don't print a busy device error report because the\n \t\t * filesystem might decide to retry.\n \t\t */\n+\t\trestore_privs();\n \t\tif (error != EBUSY && !(request_flags & FUSE_SERVICE_OPEN_QUIET))\n \t\t\tfprintf(stderr, \"%s: %s: %s\\n\",\n \t\t\t\tmo->msgtag, oc->path, strerror(error));\n \t\treturn mount_service_send_file_error(mo, error, oc->path);\n \t}\n+\trestore_privs();\n \n \tif (S_ISBLK(expected_fmt)) {\n \t\tret = prepare_bdev(mo, oc, fd);\n@@ -994,6 +1008,15 @@ static int mount_service_handle_mntopts_cmd(struct mount_service *mo,\n \t\t\t*equals = 0;\n \t\t}\n \n+\t\tif (getuid() != 0 && !user_allow_other &&\n+\t\t    (!strcmp(tok, \"allow_other\") ||\n+\t\t     !strcmp(tok, \"allow_root\"))) {\n+\t\t\tfprintf(stderr,\n+\"%s: option %s only allowed if 'user_allow_other' is set in %s\\n\",\n+\t\t\t\tmo->msgtag, tok, FUSE_CONF);\n+\t\t\treturn mount_service_send_reply(mo, EPERM);\n+\t\t}\n+\n #ifdef HAVE_NEW_MOUNT_API\n \t\tif (mo->fsopenfd >= 0) {\n \t\t\tint ret;\n@@ -1077,19 +1100,64 @@ static int mount_service_handle_mtabopts_cmd(struct mount_service *mo,\n \treturn mount_service_send_reply(mo, 0);\n }\n \n+static int open_mountpoint(const char *mntpt, bool *require_dir)\n+{\n+\tint ret;\n+\n+\t*require_dir = false;\n+\n+\tif (getuid() == 0) {\n+\t\t/*\n+\t\t * Open the alleged mountpoint.  We're root, so we only bother\n+\t\t * checking for readability.\n+\t\t */\n+\t\treturn open(mntpt, O_RDONLY | O_CLOEXEC);\n+\t}\n+\n+\t/*\n+\t * Open the alleged mountpoint.  For unprivileged callers, we only\n+\t * allow mounting on paths that the user can write to.\n+\t */\n+\tret = open(mntpt, O_WRONLY | O_CLOEXEC);\n+\tif (ret >= 0 || errno != EISDIR)\n+\t\treturn ret;\n+\n+\t/*\n+\t * However, we can't open directories with write access.  Try again in\n+\t * readonly mode, but require the caller to verify that we actually got\n+\t * a directory.\n+\t */\n+\t*require_dir = true;\n+\tret = open(mntpt, O_RDONLY | O_CLOEXEC);\n+\tif (ret >= 0 || (errno != EACCES && errno != EPERM))\n+\t\treturn ret;\n+\n+#ifdef O_PATH\n+\t/*\n+\t * If we can't open at all, let's try opening this directory with\n+\t * O_PATH.\n+\t */\n+\treturn open(mntpt, O_PATH | O_CLOEXEC);\n+#else\n+\t/* No idea what to do now */\n+\terrno = EACCES;\n+\treturn -1;\n+#endif\n+}\n+\n static int attach_to_mountpoint(struct mount_service *mo, mode_t expected_fmt,\n \t\t\t\tchar *mntpt)\n {\n \tstruct stat stbuf;\n \tchar *res_mntpt;\n+\tbool require_dir;\n \tint mountfd = -1;\n \tint error;\n \tint ret;\n \n-\t/*\n-\t * Open the alleged mountpoint, make sure it's a dir or a file.\n-\t */\n-\tmountfd = open(mntpt, O_RDONLY | O_CLOEXEC);\n+\tdrop_privs();\n+\n+\tmountfd = open_mountpoint(mntpt, &require_dir);\n \tif (mountfd < 0) {\n \t\terror = errno;\n \t\tfprintf(stderr, \"%s: %s: %s\\n\", mo->msgtag, mntpt,\n@@ -1117,6 +1185,13 @@ static int attach_to_mountpoint(struct mount_service *mo, mode_t expected_fmt,\n \t\tgoto out_mountfd;\n \t}\n \n+\tif (require_dir && !S_ISDIR(stbuf.st_mode)) {\n+\t\terror = EACCES;\n+\t\tfprintf(stderr, \"%s: %s: Mount point must be directory.\\n\",\n+\t\t\tmo->msgtag, mntpt);\n+\t\tgoto out_mountfd;\n+\t}\n+\n \t/*\n \t * Resolve the (possibly relative) mountpoint path before chdir'ing\n \t * onto it.\n@@ -1193,6 +1268,7 @@ static int attach_to_mountpoint(struct mount_service *mo, mode_t expected_fmt,\n \tmo->mountfd = mountfd;\n \tmo->resv_mountpoint = res_mntpt;\n \n+\trestore_privs();\n \treturn mount_service_send_reply(mo, 0);\n \n out_res_mntpt:\n@@ -1201,6 +1277,7 @@ static int attach_to_mountpoint(struct mount_service *mo, mode_t expected_fmt,\n \tclose(mountfd);\n out_error:\n \tfree(mntpt);\n+\trestore_privs();\n \treturn mount_service_send_reply(mo, error);\n }\n \n@@ -1580,6 +1657,141 @@ static int mount_service_fsopen_mount(struct mount_service *mo,\n # define mount_service_fsopen_mount(...)\t(FUSE_MOUNT_FALLBACK_NEEDED)\n #endif\n \n+static int check_nonroot_file_access(struct mount_service *mo)\n+{\n+\tstruct stat sb1, sb2;\n+\tint fd;\n+\tint ret;\n+\n+\t/*\n+\t * If we already succeeded in opening the file with write access, then\n+\t * we're good.\n+\t */\n+\tret = fcntl(mo->mountfd, F_GETFL);\n+\tif (ret < 0) {\n+\t\tint error = errno;\n+\n+\t\tfprintf(stderr, \"%s: %s: %s\\n\", mo->msgtag, mo->mountpoint,\n+\t\t\tstrerror(error));\n+\t\treturn -1;\n+\t}\n+\n+\tif ((ret & O_ACCMODE) != O_RDONLY)\n+\t\treturn 0;\n+\n+\tret = fstat(mo->mountfd, &sb1);\n+\tif (ret) {\n+\t\tint error = errno;\n+\n+\t\tfprintf(stderr, \"%s: %s: %s\\n\",\n+\t\t\tmo->msgtag, mo->mountpoint, strerror(error));\n+\t\treturn -1;\n+\t}\n+\n+\t/* Try to reopen the file with write access this time. */\n+\tfd = open(mo->real_mountpoint, O_WRONLY | O_CLOEXEC);\n+\tif (fd < 0) {\n+\t\tint error = errno;\n+\n+\t\tfprintf(stderr, \"%s: %s: %s\\n\",\n+\t\t\tmo->msgtag, mo->mountpoint, strerror(error));\n+\t\treturn -1;\n+\t}\n+\n+\t/* Is this the same file? */\n+\tret = fstat(fd, &sb2);\n+\tif (ret) {\n+\t\tint error = errno;\n+\n+\t\tfprintf(stderr, \"%s: %s: %s\\n\",\n+\t\t\tmo->msgtag, mo->mountpoint, strerror(error));\n+\t\tgoto out_fd;\n+\t}\n+\n+\tif (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {\n+\t\tfprintf(stderr, \"%s: %s: Mount point moved during fuse startup.\\n\",\n+\t\t\tmo->msgtag, mo->mountpoint);\n+\t\tret = -1;\n+\t\tgoto out_fd;\n+\t}\n+\n+\t/*\n+\t * We reopened the same file with write access, everything is ok.  Swap\n+\t * the two file descriptors so that we retain our write access.\n+\t */\n+\tret = mo->mountfd;\n+\tmo->mountfd = fd;\n+\tfd = ret;\n+\tret = 0;\n+out_fd:\n+\tclose(fd);\n+\treturn ret;\n+}\n+\n+static void adjust_nonroot_mount_flags(struct mount_service *mo,\n+\t\t\t\t       struct fuse_service_mount_command *oc)\n+{\n+\tconst struct mount_flags *mf;\n+\tuint32_t ms_flags = ntohl(oc->ms_flags);\n+\n+\t/* only care that the unsafe flags are set to the value of @on */\n+\tfor (mf = mount_flags; mf->opt != NULL; mf++) {\n+\t\tif (mf->safe)\n+\t\t\tcontinue;\n+\t\tif (!!(ms_flags & mf->flag) == !!mf->on) {\n+\t\t\tms_flags = (ms_flags & ~mf->flag) |\n+\t\t\t\t   (mf->on ? 0 : mf->flag);\n+\n+\t\t\tfprintf(stderr, \"%s: unsafe option %s ignored\\n\",\n+\t\t\t\tmo->msgtag, mf->opt);\n+\t\t}\n+\t}\n+\n+\toc->ms_flags = htonl(ms_flags);\n+}\n+\n+/*\n+ * fuse.conf can limit the number of unprivileged fuse mounts.  For\n+ * unprivileged mounts (via setuid) we also require write access to the\n+ * mountpoint, and we'll only accept certain underlying filesystems.\n+ */\n+static int check_nonroot_access(struct mount_service *mo,\n+\t\t\t\tstruct fuse_service_mount_command *oc,\n+\t\t\t\tconst struct stat *stbuf)\n+{\n+\tstruct statfs fs_buf;\n+\tint ret;\n+\n+\tret = check_nonroot_mount_count(mo->msgtag);\n+\tif (ret)\n+\t\treturn -EUSERS;\n+\n+\tret = fstatfs(mo->mountfd, &fs_buf);\n+\tif (ret) {\n+\t\tint error = errno;\n+\n+\t\tfprintf(stderr, \"%s: %s: %s\\n\",\n+\t\t\tmo->msgtag, mo->mountpoint, strerror(error));\n+\t\treturn -error;\n+\t}\n+\n+\tadjust_nonroot_mount_flags(mo, oc);\n+\n+\tdrop_privs();\n+\tif (S_ISDIR(stbuf->st_mode))\n+\t\tret = check_nonroot_dir_access(mo->msgtag,\n+\t\t\t\t\t       mo->mountpoint,\n+\t\t\t\t\t       mo->real_mountpoint,\n+\t\t\t\t\t       stbuf);\n+\telse\n+\t\tret = check_nonroot_file_access(mo);\n+\tif (!ret)\n+\t\tret = check_nonroot_fstype(mo->msgtag, &fs_buf);\n+\trestore_privs();\n+\n+\treturn ret ? -EPERM : 0;\n+}\n+\n static int mount_service_handle_mount_cmd(struct mount_service *mo,\n \t\t\t\t\t  struct fuse_service_packet *p,\n \t\t\t\t\t  size_t psz)\n@@ -1621,6 +1833,12 @@ static int mount_service_handle_mount_cmd(struct mount_service *mo,\n \t\treturn mount_service_send_reply(mo, error);\n \t}\n \n+\tif (getuid() != 0) {\n+\t\tret = check_nonroot_access(mo, oc, &stbuf);\n+\t\tif (ret)\n+\t\t\treturn mount_service_send_reply(mo, -ret);\n+\t}\n+\n \tif (mo->fsopenfd >= 0) {\n \t\tret = mount_service_fsopen_mount(mo, oc, &stbuf);\n \t\tif (ret != FUSE_MOUNT_FALLBACK_NEEDED)\n@@ -1752,6 +1970,10 @@ int mount_service_main(int argc, char *argv[])\n \telse\n \t\tmo.msgtag = \"mount.service\";\n \n+\tdrop_privs();\n+\tread_conf(mo.msgtag);\n+\trestore_privs();\n+\n \tret = mount_service_init(&mo, argc, argv);\n \tif (ret)\n \t\treturn EXIT_FAILURE;\n","prefixes":["08/13"]}