From patchwork Mon Nov 5 13:28:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Goldstein X-Patchwork-Id: 10668299 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C5F011709 for ; Mon, 5 Nov 2018 13:28:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C7C2829451 for ; Mon, 5 Nov 2018 13:28:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B7DD929459; Mon, 5 Nov 2018 13:28:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1F41D29451 for ; Mon, 5 Nov 2018 13:28:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729404AbeKEWsL (ORCPT ); Mon, 5 Nov 2018 17:48:11 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:42937 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726723AbeKEWsL (ORCPT ); Mon, 5 Nov 2018 17:48:11 -0500 Received: by mail-wr1-f67.google.com with SMTP id y15-v6so9516234wru.9; Mon, 05 Nov 2018 05:28:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=KYpkvUmKQWGpPqm3TaF328+d0FYc9UTzH6vttalYo/o=; b=hcYDB96BbQF6IB1o4+8QV00wR9wR3HjSRy+NTwI/TNZxtUf358HTv3Hy0Egs5aCMJT ePvwqwgaopbqED0/VxGVa5ERQw7LLMNnBqtQN30MycZ+JhNgISxx9Lo+wk8iWRk+U9GV 6njKZJXr6unYY5ZmHu95egaOyx3d32DdA4WMWlZlY8jn5XKayiSla3RSleu68yXBXpoT pR6mCYl6vmoEt7XaqprgDaj1c7vugdTI/3y2PW4ukLiHSy/qtT8/SlcImmKXKGGaF/KZ Lwy/gtX2LmGfwyJSFKVj0pjuVgnyYt9HyFHJ6KTByKWKhSHRoCU2svkCU18tLqtqlufM rHdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=KYpkvUmKQWGpPqm3TaF328+d0FYc9UTzH6vttalYo/o=; b=bnzSB3sRkSJ8ur6jbDxKCicGsFjkTBi0NjPk7PXZH9ae/OzNUXMafui6cpMOk6Ah3g 3ZtVuN5yIsRshipFJbuYTRDCmIU+5NGczfKktfkBv/PYV9CFuUWzFLHqszRWGAtJ/5vd vs2uExc64QxSbrBUEOBca0+dH5hqLRXJq6bv66f0V7lQiOsGApdMjpHGHxAxQTKYskqQ f/45tyV06zo3ESPKPWbwe1Y1Y9AerqpbyX7EX6bGzPt+ttP9o+bpzfVQXiHSj0KWJL9R HZJnZ6RyD44pJ2KfZ/Sik0csP9XfWrLoDVoUbZEm7lktDLpTC90dFACbTuJ8SmNJXFGL RvOw== X-Gm-Message-State: AGRZ1gJStScHEFtTRU3v++o2ti361tie5yMMjFCDC9PicQsPYi09YK2x +A+v+eAjNqtSkjz1FGzX+C0= X-Google-Smtp-Source: AJdET5ebmkbep7ps9+u5XCBDU3FwO5hvPGqiCcPjpQ3LrDXwL2DKiskJw8Lk+P5AHJ9jxrIlf28aCA== X-Received: by 2002:a05:6000:10e:: with SMTP id o14mr20417042wrx.279.1541424503360; Mon, 05 Nov 2018 05:28:23 -0800 (PST) Received: from localhost.localdomain (bzq-166-168-31-246.red.bezeqint.net. [31.168.166.246]) by smtp.gmail.com with ESMTPSA id j203-v6sm37223061wmd.46.2018.11.05.05.28.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 05 Nov 2018 05:28:22 -0800 (PST) From: Amir Goldstein To: Jan Kara Cc: Matthew Bobrowski , linux-fsdevel@vger.kernel.org, linux-api@vger.kernel.org Subject: [PATCH] fanotify: support limited functionality for unprivileged users Date: Mon, 5 Nov 2018 15:28:16 +0200 Message-Id: <20181105132816.12241-1-amir73il@gmail.com> X-Mailer: git-send-email 2.17.1 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for new fanotify_init() flag FAN_UNPRIVILEGED. User may request an unprivileged event listener using this flag even if user is privileged. An unprivileged event listener does not get an open file descriptor in the event nor the process pid of another process. An unprivileged event listener and cannot request permission events, cannot set mount/filesystem marks and cannot request unlimited queue/marks. This enables the limited functionality similar to inotify when watching a single inode for OPEN/ACCESS/MODIFY/CLOSE events, but at least it does not require CAP_ADMIN privileges. Going forward, this limited functionality will be enriched with more event types and the ability to watch multiple objects by indetifying the object in the event with its nfs file handle. Note that even though events do not report the event creator pid, fanotify does not merge similar events on the same object that were generated by different processes. This in aligned with exiting behavior when generating processes are outside of the listener pidns (which results in reporting 0 pid to listener). Cc: Signed-off-by: Amir Goldstein --- Jan, I realize you are still catching up with current dev cycle fixes, but I have mentioned FAN_UNPRIVILEGED several times on public API discussions, so making the patch public as well. The FAN_UNPRIVILEGED functionality was tested manually and with some WIP LTP tests. Matthew Bobrowski is working on some more LTP tests. FAN_UNPRIVILEGED has merit on its own and depends on no other patches, but it is more of a prelude for more upcoming API changes. FWIW, this patch shouldn't have any conflicts neither with my FAN_EVENT_ON_CHILD fix patch nor with Matthew's FAN_OPEN_EXEC patches. Thanks, Amir. fs/notify/fanotify/fanotify_user.c | 45 ++++++++++++++++++++++++++---- include/linux/fanotify.h | 11 +++++++- include/uapi/linux/fanotify.h | 1 + 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index e03be5071362..3e64326085ba 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -132,10 +132,21 @@ static int fill_event_metadata(struct fsnotify_group *group, metadata->vers = FANOTIFY_METADATA_VERSION; metadata->reserved = 0; metadata->mask = fsn_event->mask & FANOTIFY_OUTGOING_EVENTS; - metadata->pid = pid_vnr(event->pid); - if (unlikely(fsn_event->mask & FAN_Q_OVERFLOW)) + /* + * An unprivileged event listener does not get an open file descriptor + * in the event nor another generating process pid. If the event was + * generated by the unprivileged process itself, self pid is reported. + */ + if (!FAN_GROUP_FLAG(group, FAN_UNPRIVILEGED) || + task_tgid(current) == event->pid) + metadata->pid = pid_vnr(event->pid); + else + metadata->pid = 0; + + if (FAN_GROUP_FLAG(group, FAN_UNPRIVILEGED) || + unlikely(fsn_event->mask & FAN_Q_OVERFLOW)) { metadata->fd = FAN_NOFD; - else { + } else { metadata->fd = create_fd(group, event, file); if (metadata->fd < 0) ret = metadata->fd; @@ -683,12 +694,26 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) int f_flags, fd; struct user_struct *user; struct fanotify_event_info *oevent; + unsigned int class = flags & FANOTIFY_CLASS_BITS; pr_debug("%s: flags=%x event_f_flags=%x\n", __func__, flags, event_f_flags); - if (!capable(CAP_SYS_ADMIN)) + if (flags & FAN_UNPRIVILEGED) { + /* + * User can request an unprivileged event listener even if + * user is privileged. An unprivileged event listener does not + * get an open file descriptor in the event nor the proccess id + * of another process. An unprivileged event listener and cannot + * request permission events, cannot set mount/filesystem marks + * and cannot request unlimited queue/marks. + */ + if ((flags & ~FANOTIFY_UNPRIV_INIT_FLAGS) || + class != FAN_CLASS_NOTIF) + return -EINVAL; + } else if (!capable(CAP_SYS_ADMIN)) { return -EPERM; + } #ifdef CONFIG_AUDITSYSCALL if (flags & ~(FANOTIFY_INIT_FLAGS | FAN_ENABLE_AUDIT)) @@ -745,7 +770,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) group->fanotify_data.f_flags = event_f_flags; init_waitqueue_head(&group->fanotify_data.access_waitq); INIT_LIST_HEAD(&group->fanotify_data.access_list); - switch (flags & FANOTIFY_CLASS_BITS) { + switch (class) { case FAN_CLASS_NOTIF: group->priority = FS_PRIO_0; break; @@ -865,6 +890,14 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, group->priority == FS_PRIO_0) goto fput_and_out; + /* + * An unprivileged event listener is not allowed to watch a mount + * point nor a filesystem. + */ + if (FAN_GROUP_FLAG(group, FAN_UNPRIVILEGED) && + mark_type != FAN_MARK_INODE) + goto fput_and_out; + if (flags & FAN_MARK_FLUSH) { ret = 0; if (mark_type == FAN_MARK_MOUNT) @@ -944,7 +977,7 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark, */ static int __init fanotify_user_setup(void) { - BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 7); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 8); BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index a5a60691e48b..4d31be37ba2a 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -21,7 +21,16 @@ #define FANOTIFY_INIT_FLAGS (FANOTIFY_CLASS_BITS | \ FAN_REPORT_TID | \ FAN_CLOEXEC | FAN_NONBLOCK | \ - FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS) + FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS | \ + FAN_UNPRIVILEGED) + +/* + * fanotify_init() flags allowed for unprivileged users. + * It's only ok to add FAN_CLASS_NOTIF to this mask because it is zero and + * because it is the only class we allow for unprivileged users. + */ +#define FANOTIFY_UNPRIV_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \ + FAN_CLASS_NOTIF | FAN_UNPRIVILEGED) #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \ FAN_MARK_FILESYSTEM) diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h index b86740d1c50a..6d7dbab3fb14 100644 --- a/include/uapi/linux/fanotify.h +++ b/include/uapi/linux/fanotify.h @@ -39,6 +39,7 @@ #define FAN_UNLIMITED_QUEUE 0x00000010 #define FAN_UNLIMITED_MARKS 0x00000020 #define FAN_ENABLE_AUDIT 0x00000040 +#define FAN_UNPRIVILEGED 0x00000080 /* Flags to determine fanotify event format */ #define FAN_REPORT_TID 0x00000100 /* event->pid is thread id */