From patchwork Wed Jan 25 15:28:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 48189 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp345065wrn; Wed, 25 Jan 2023 07:52:12 -0800 (PST) X-Google-Smtp-Source: AMrXdXuM8gTuLpYBcYUqjOKvYDpgNp7TVgOWP2lcjbsf+j31Dw7YJAEz6IkTw9NkfGLF6L4deNT+ X-Received: by 2002:a17:90b:4b92:b0:229:f4e1:d4b1 with SMTP id lr18-20020a17090b4b9200b00229f4e1d4b1mr23464098pjb.22.1674661932090; Wed, 25 Jan 2023 07:52:12 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674661932; cv=none; d=google.com; s=arc-20160816; b=dsr3W+HlHB+H+KbMZk+e/2+uiP/o+c59m2g0wArYXdbzEHdoDNB9yEXZb8nzmDYg7P GjSIvY9VCiVoC1uOHs8jDTmuqo2Qoy0qB/66WIexrqJV4tDZBswrGRK6gXhHWp3u+asu wBEuMTlVRJ6BAxHQ0laMcnrpfWgBXdjP9HIPLHjjxSy52a0qZEHg1u1T91XWtMAHuVvZ zjj1QVCPukemLeDnk6cpMTM486gY0/s5CPz8lmG70GYVMtOMfPTkM4J4nME1Fs9WGyar FGrbAOFVh/IpZRKfmBN/Jtxoj39K6MDm/al3RvNDrBaljeKdGFjuIongTm4rl+OYLKnn iq5g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=6PA4Vk1aaZyy72y2gUxAbhyDNFo3h9SUw3oX/CJ3Bs4=; b=ylWRbo+UnD2Q+8cQJ90UaF745xTuoIuI4eYJIejEl4o3AinuNMt9YKLyrCsfBc4BI1 EKbdFVP8EZ9z0abw/VMqo5eSFWcCxVNPQeaxZ5CHc6X6/aOiZGVujMbFuC3+5Uy7EDUT hdYz2A1eEz8EY499su+fpg3DZRC3LoE+LnCCyPV5Emy7R+By1pewQ0vl4TWv52vUJG1B s20prlq3w3DPI4CmR/smyA8Xs6CEojcrcgHgb55Tns1+fXmL7YUlDWz0hX8xo7zUv3+Y a+izlEXYmClDFvBWWL6U9zZ4YYws+f52NtAMMV3que5HGQucYPOYlrbIFx/S1Cw8nO/e 1GsQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id k8-20020a17090a590800b00228cb3af4aasi2244868pji.99.2023.01.25.07.52.00; Wed, 25 Jan 2023 07:52:12 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236075AbjAYPbL (ORCPT + 99 others); Wed, 25 Jan 2023 10:31:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53376 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236079AbjAYPbG (ORCPT ); Wed, 25 Jan 2023 10:31:06 -0500 Received: from us-smtp-delivery-44.mimecast.com (us-smtp-delivery-44.mimecast.com [205.139.111.44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4A3C59B75 for ; Wed, 25 Jan 2023 07:31:01 -0800 (PST) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-595-ZpQQD_SlPyav-ZCRRyDwfg-1; Wed, 25 Jan 2023 10:29:27 -0500 X-MC-Unique: ZpQQD_SlPyav-ZCRRyDwfg-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2B93E811E9C; Wed, 25 Jan 2023 15:29:27 +0000 (UTC) Received: from comp-core-i7-2640m-0182e6.redhat.com (ovpn-208-16.brq.redhat.com [10.40.208.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 68BFD2026D4B; Wed, 25 Jan 2023 15:29:25 +0000 (UTC) From: Alexey Gladkov To: LKML , containers@lists.linux.dev, linux-fsdevel@vger.kernel.org Cc: Alexey Dobriyan , Al Viro , Andrew Morton , Christian Brauner , Val Cowan Subject: [RFC PATCH v1 1/6] proc: Fix separator for subset option Date: Wed, 25 Jan 2023 16:28:48 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_SOFTFAIL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756010310507616801?= X-GMAIL-MSGID: =?utf-8?q?1756010310507616801?= Signed-off-by: Alexey Gladkov --- fs/proc/root.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/root.c b/fs/proc/root.c index 3c2ee3eb1138..5f1015b6418d 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -91,7 +91,7 @@ static int proc_parse_subset_param(struct fs_context *fc, char *value) struct proc_fs_context *ctx = fc->fs_private; while (value) { - char *ptr = strchr(value, ','); + char *ptr = strchr(value, '+'); if (ptr != NULL) *ptr++ = '\0'; From patchwork Wed Jan 25 15:28:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 48191 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp345337wrn; Wed, 25 Jan 2023 07:52:48 -0800 (PST) X-Google-Smtp-Source: AK7set8wgYFsQKEvu1+I6wD9q+0uhJLln0waJioQTnD3kxmbQootmzaoyq7SFosL0SYEyQJXnqT7 X-Received: by 2002:a17:90b:1bc6:b0:22b:f67b:fe67 with SMTP id oa6-20020a17090b1bc600b0022bf67bfe67mr5796815pjb.25.1674661967711; Wed, 25 Jan 2023 07:52:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674661967; cv=none; d=google.com; s=arc-20160816; b=oljnszA1PZWQY3b70jFO2VGtEZzwZHmtrXWIr2aCjb7Zqk4bSUxF2oCb41xhQzdfJ5 20xL1Y/T3dnXKu/HMuN0w6hQz2mspD1w/Cn7eRzuvwM7LUOeDDO8zSq7xdP9G0RAJQ2U 4jWHllZi6rfF1v21EgVzebcbGO3wmpUJk6X3AoDfCjkF780RcxKBuNR8Y+dq7jj8yyEi J6WmbbWQrkYJ1GFrvJ+cq+Q6DmapVcF+Non70e/gN9DqUwBnFtXcvY4pYLIOBqKFqTkv 7GB9UEeGyqaPKKyDxgFn2T83U+e32yf/8WBr92WViMCUOZjjDj37sTU5jlnh/TwS3HTD bLzQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=PR2hgy3lFW99VnetUijTiB3ybw0JJt2XJoR05V2uK/Q=; b=KRA/KbiarBEFBRitj9tqUU5QKACu1qKossjdC6CLRgBaj8Sx2MT2/sSfellxFCO+Yv zEI3S8A9oG4DDVn0xUt4hjUvHY7M2udSpexRHHwUiRRSJsaMwLTG0+sMxpquop3zjAfF eSqN5FcANMvEtY2s75YEgr4reVBrF5EZG+ekPy3DZGGgNeRbO1fHQU6/sHHjtwhRl0hc j9npPWspHwlnMLt0duJuTDtfk6Y+tyugv63LlC3fQTxDQTYZmtycuVdoCE2AGHMUrCuv 48eRQaEPRU5eM8L7ajyBzGIiDP5/JYGaSmaSsweeZA4mucCn2j41+V1uwKduEFa66DeS ZX1g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e7-20020a17090ab38700b002268e9e9b97si2385622pjr.31.2023.01.25.07.52.35; Wed, 25 Jan 2023 07:52:47 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236051AbjAYPaA (ORCPT + 99 others); Wed, 25 Jan 2023 10:30:00 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51474 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235873AbjAYP3u (ORCPT ); Wed, 25 Jan 2023 10:29:50 -0500 Received: from us-smtp-delivery-44.mimecast.com (us-smtp-delivery-44.mimecast.com [205.139.111.44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AD5C659245 for ; Wed, 25 Jan 2023 07:29:40 -0800 (PST) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-22-3L7hQhr3NEibyln3yWV5BQ-1; Wed, 25 Jan 2023 10:29:30 -0500 X-MC-Unique: 3L7hQhr3NEibyln3yWV5BQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4FF52857A81; Wed, 25 Jan 2023 15:29:29 +0000 (UTC) Received: from comp-core-i7-2640m-0182e6.redhat.com (ovpn-208-16.brq.redhat.com [10.40.208.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8003C2026D4B; Wed, 25 Jan 2023 15:29:27 +0000 (UTC) From: Alexey Gladkov To: LKML , containers@lists.linux.dev, linux-fsdevel@vger.kernel.org Cc: Alexey Dobriyan , Al Viro , Andrew Morton , Christian Brauner , Val Cowan Subject: [RFC PATCH v1 2/6] proc: Add allowlist to control access to procfs files Date: Wed, 25 Jan 2023 16:28:49 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_SOFTFAIL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756010347622301892?= X-GMAIL-MSGID: =?utf-8?q?1756010347622301892?= If, after creating a container and mounting procfs, the system configuration may change and new files may appear in procfs. Files including writable root or any other users. In most cases, it is known in advance which files in procfs the user needs in the container. It is much easier to control the list of what you want than to control the list of unwanted files. To do this, subset=allowlist is added to control the visibility of static files in procfs (not process pids). After that, the control file /proc/allowlist appears in the root of the filesystem. This file contains a list of files and directories that will be visible in this vmountpoint. Immediately after mount, this file contains only one name - the name of the file itself. The admin can add names, read this file to get the current state of the allowlist. The file behaves almost like a regular file. Changes are applied when the file is closed. To prevent changes to allowlist, admin should remove its name from the list of allowed files. After this change, the file will disappear. Signed-off-by: Alexey Gladkov --- fs/proc/Kconfig | 10 ++ fs/proc/Makefile | 1 + fs/proc/generic.c | 15 ++- fs/proc/internal.h | 29 +++++ fs/proc/proc_allowlist.c | 221 +++++++++++++++++++++++++++++++++++++++ fs/proc/root.c | 27 ++++- include/linux/proc_fs.h | 8 ++ 7 files changed, 306 insertions(+), 5 deletions(-) create mode 100644 fs/proc/proc_allowlist.c diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index 32b1116ae137..bfe80b1fd31f 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -108,3 +108,13 @@ config PROC_PID_ARCH_STATUS config PROC_CPU_RESCTRL def_bool n depends on PROC_FS + +config PROC_ALLOW_LIST + bool "/proc/allowlist support" + depends on PROC_FS + default n + help + Provides a way to restrict access to certain files in procfs. Mounting + procfs with subset=allowlist will add the file /proc/allowlist which + contains a list of files and directories that should be accessed. To + prevent the list from being changed, the file itself must be excluded. diff --git a/fs/proc/Makefile b/fs/proc/Makefile index bd08616ed8ba..3c7d3dacbd2f 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -34,3 +34,4 @@ proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PRINTK) += kmsg.o proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o proc-$(CONFIG_BOOT_CONFIG) += bootconfig.o +proc-$(CONFIG_PROC_ALLOW_LIST) += proc_allowlist.o diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 587b91d9d998..d4c8589987e7 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -43,7 +43,7 @@ void pde_free(struct proc_dir_entry *pde) kmem_cache_free(proc_dir_entry_cache, pde); } -static int proc_match(const char *name, struct proc_dir_entry *de, unsigned int len) +int proc_match(const char *name, struct proc_dir_entry *de, unsigned int len) { if (len < de->namelen) return -1; @@ -251,6 +251,9 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry, if (de) { pde_get(de); read_unlock(&proc_subdir_lock); + if (!proc_pde_access_allowed(proc_sb_info(dir->i_sb), de)) { + return ERR_PTR(-ENOENT); + } inode = proc_get_inode(dir->i_sb, de); if (!inode) return ERR_PTR(-ENOMEM); @@ -266,7 +269,7 @@ struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, { struct proc_fs_info *fs_info = proc_sb_info(dir->i_sb); - if (fs_info->pidonly == PROC_PIDONLY_ON) + if (fs_info->pidonly == PROC_PIDONLY_ON && !proc_has_allowlist(fs_info)) return ERR_PTR(-ENOENT); return proc_lookup_de(dir, dentry, PDE(dir)); @@ -284,6 +287,9 @@ struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, int proc_readdir_de(struct file *file, struct dir_context *ctx, struct proc_dir_entry *de) { + struct inode *inode = file_inode(file); + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); + int i; if (!dir_emit_dots(file, ctx)) @@ -307,7 +313,8 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx, struct proc_dir_entry *next; pde_get(de); read_unlock(&proc_subdir_lock); - if (!dir_emit(ctx, de->name, de->namelen, + if (proc_pde_access_allowed(fs_info, de) && + !dir_emit(ctx, de->name, de->namelen, de->low_ino, de->mode >> 12)) { pde_put(de); return 0; @@ -327,7 +334,7 @@ int proc_readdir(struct file *file, struct dir_context *ctx) struct inode *inode = file_inode(file); struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); - if (fs_info->pidonly == PROC_PIDONLY_ON) + if (fs_info->pidonly == PROC_PIDONLY_ON && !proc_has_allowlist(fs_info)) return 1; return proc_readdir_de(file, ctx, PDE(inode)); diff --git a/fs/proc/internal.h b/fs/proc/internal.h index b701d0207edf..999d105f6f96 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -84,6 +84,16 @@ static inline void pde_make_permanent(struct proc_dir_entry *pde) pde->flags |= PROC_ENTRY_PERMANENT; } +static inline bool pde_is_allowlist(const struct proc_dir_entry *pde) +{ + return pde->flags & PROC_ENTRY_ALLOWLIST; +} + +static inline void pde_make_allowlist(struct proc_dir_entry *pde) +{ + pde->flags |= PROC_ENTRY_ALLOWLIST; +} + extern struct kmem_cache *proc_dir_entry_cache; void pde_free(struct proc_dir_entry *pde); @@ -187,6 +197,7 @@ struct proc_dir_entry *proc_create_reg(const char *name, umode_t mode, struct proc_dir_entry **parent, void *data); struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, struct proc_dir_entry *dp); +extern int proc_match(const char *, struct proc_dir_entry *, unsigned int); extern struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int); struct dentry *proc_lookup_de(struct inode *, struct dentry *, struct proc_dir_entry *); extern int proc_readdir(struct file *, struct dir_context *); @@ -318,3 +329,21 @@ static inline void pde_force_lookup(struct proc_dir_entry *pde) /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ pde->proc_dops = &proc_net_dentry_ops; } + +/* + * proc_allowlist.c + */ +#ifdef CONFIG_PROC_ALLOW_LIST +extern bool proc_has_allowlist(struct proc_fs_info *); +extern bool proc_pde_access_allowed(struct proc_fs_info *, struct proc_dir_entry *); +#else +static inline bool proc_has_allowlist(struct proc_fs_info *fs_info) +{ + return false; +} + +static inline bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry *pde) +{ + return true; +} +#endif diff --git a/fs/proc/proc_allowlist.c b/fs/proc/proc_allowlist.c new file mode 100644 index 000000000000..b38e11b04199 --- /dev/null +++ b/fs/proc/proc_allowlist.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/fs/proc/proc_allowlist.c + * + * Copyright (C) 2022 + * + * Author: Alexey Gladkov + */ +#include +#include +#include +#include +#include +#include "internal.h" + +#define FILE_SEQFILE(f) ((struct seq_file *)((f)->private_data)) +#define FILE_DATA(f) (FILE_SEQFILE(f)->private) + +bool proc_has_allowlist(struct proc_fs_info *fs_info) +{ + bool ret; + unsigned long flags; + + read_lock_irqsave(&fs_info->allowlist_lock, flags); + ret = (fs_info->allowlist == NULL); + read_unlock_irqrestore(&fs_info->allowlist_lock, flags); + + return ret; +} + +bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry *de) +{ + bool ret = false; + char *ptr; + unsigned long flags; + + read_lock_irqsave(&fs_info->allowlist_lock, flags); + + if (!fs_info->allowlist) { + read_unlock_irqrestore(&fs_info->allowlist_lock, flags); + + if (!pde_is_allowlist(de)) + ret = true; + + return ret; + } + + ptr = fs_info->allowlist; + + while (*ptr != '\0') { + struct proc_dir_entry *pde; + char *sep, *end; + size_t len, pathlen; + + if (!(sep = strchr(ptr, '\n'))) + pathlen = strlen(ptr); + else + pathlen = (sep - ptr); + + if (!pathlen) + goto next; + + pde = de; + end = NULL; + len = pathlen; + + while (ptr != end && len > 0) { + end = ptr + len - 1; + + while (1) { + if (*end == '/') { + end++; + break; + } + if (end == ptr) + break; + end--; + } + + if (proc_match(end, pde, ptr + len - end)) + goto next; + + len = end - ptr - 1; + pde = pde->parent; + } + + ret = true; + break; +next: + ptr += pathlen + 1; + } + + read_unlock_irqrestore(&fs_info->allowlist_lock, flags); + + return ret; +} + +static int show_allowlist(struct seq_file *m, void *v) +{ + struct proc_fs_info *fs_info = proc_sb_info(m->file->f_inode->i_sb); + char *p = fs_info->allowlist; + unsigned long flags; + + read_lock_irqsave(&fs_info->allowlist_lock, flags); + if (p) + seq_puts(m, p); + read_unlock_irqrestore(&fs_info->allowlist_lock, flags); + + return 0; +} + +static int open_allowlist(struct inode *inode, struct file *file) +{ + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + // we need this because shrink_dcache_sb() can't drop our own dentry. + if (!proc_pde_access_allowed(fs_info, PDE(inode))) + return -ENOENT; + + // we want a null-terminated string so not all 128K are available. + ret = single_open_size(file, show_allowlist, NULL, SZ_128K); + + if (!ret && (file->f_mode & FMODE_WRITE) && + (file->f_flags & O_APPEND) && !(file->f_flags & O_TRUNC)) + show_allowlist(FILE_SEQFILE(file), NULL); + + return ret; +} + +static ssize_t write_allowlist(struct file *file, const char __user *buffer, size_t count, loff_t *pos) +{ + struct seq_file *seq_file = FILE_SEQFILE(file); + ssize_t ret; + ssize_t n = count; + const char *ptr = buffer; + + if ((seq_file->count + count) >= (seq_file->size - 1)) + return -EFBIG; + + while (n > 0) { + char chunk[SZ_256]; + loff_t chkpos = 0; + ssize_t i, len; + + len = simple_write_to_buffer(chunk, sizeof(chunk), &chkpos, ptr, n); + if (len < 0) + return len; + + for (i = 0; i < len; i++) { + if (!isprint(chunk[i]) && chunk[i] != '\n') + return -EINVAL; + } + + ret = seq_write(seq_file, chunk, len); + if (ret < 0) + return -EINVAL; + + ptr += len; + n -= len; + } + + if (pos) + *pos += count; + + return count; +} + +static int close_allowlist(struct inode *inode, struct file *file) +{ + struct seq_file *seq_file = FILE_SEQFILE(file); + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); + + if (seq_file->buf && (file->f_mode & FMODE_WRITE)) { + char *buf; + + if (!seq_get_buf(seq_file, &buf)) + return -EIO; + *buf = '\0'; + + if (strcmp(seq_file->buf, fs_info->allowlist)) { + unsigned long flags; + + buf = kstrndup(seq_file->buf, seq_file->count, GFP_KERNEL_ACCOUNT); + if (!buf) + return -EIO; + + write_lock_irqsave(&fs_info->allowlist_lock, flags); + + shrink_dcache_sb(inode->i_sb); + + kfree(fs_info->allowlist); + fs_info->allowlist = buf; + + write_unlock_irqrestore(&fs_info->allowlist_lock, flags); + } + } + + return single_release(inode, file); +} + +static const struct proc_ops proc_allowlist_ops = { + .proc_open = open_allowlist, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_write = write_allowlist, + .proc_release = close_allowlist, +}; + +static int __init proc_allowlist_init(void) +{ + struct proc_dir_entry *pde; + pde = proc_create("allowlist", S_IRUSR | S_IWUSR, NULL, &proc_allowlist_ops); + pde_make_permanent(pde); + pde_make_allowlist(pde); + return 0; +} +fs_initcall(proc_allowlist_init); diff --git a/fs/proc/root.c b/fs/proc/root.c index 5f1015b6418d..1564f5cd118d 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -32,6 +32,7 @@ struct proc_fs_context { enum proc_hidepid hidepid; int gid; enum proc_pidonly pidonly; + enum proc_allowlist allowlist; }; enum proc_param { @@ -99,6 +100,9 @@ static int proc_parse_subset_param(struct fs_context *fc, char *value) if (*value != '\0') { if (!strcmp(value, "pid")) { ctx->pidonly = PROC_PIDONLY_ON; + } else if (IS_ENABLED(CONFIG_PROC_ALLOW_LIST) && + !strcmp(value, "allowlist")) { + ctx->allowlist = PROC_ALLOWLIST_ON; } else { return invalf(fc, "proc: unsupported subset option - %s\n", value); } @@ -142,6 +146,18 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param) return 0; } +static char *proc_init_allowlist(void) +{ + char *content = kstrdup("allowlist\n", GFP_KERNEL_ACCOUNT); + + if (!content) { + pr_err("proc_init_allowlist: allocation allowlist failed\n"); + return NULL; + } + + return content; +} + static void proc_apply_options(struct proc_fs_info *fs_info, struct fs_context *fc, struct user_namespace *user_ns) @@ -152,8 +168,14 @@ static void proc_apply_options(struct proc_fs_info *fs_info, fs_info->pid_gid = make_kgid(user_ns, ctx->gid); if (ctx->mask & (1 << Opt_hidepid)) fs_info->hide_pid = ctx->hidepid; - if (ctx->mask & (1 << Opt_subset)) + if (ctx->mask & (1 << Opt_subset)) { fs_info->pidonly = ctx->pidonly; + if (ctx->allowlist == PROC_ALLOWLIST_ON) { + fs_info->allowlist = proc_init_allowlist(); + } else { + fs_info->allowlist = NULL; + } + } } static int proc_fill_super(struct super_block *s, struct fs_context *fc) @@ -167,6 +189,8 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc) if (!fs_info) return -ENOMEM; + rwlock_init(&fs_info->allowlist_lock); + fs_info->pid_ns = get_pid_ns(ctx->pid_ns); proc_apply_options(fs_info, fc, current_user_ns()); @@ -271,6 +295,7 @@ static void proc_kill_sb(struct super_block *sb) kill_anon_super(sb); put_pid_ns(fs_info->pid_ns); + kfree(fs_info->allowlist); kfree(fs_info); } diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 0260f5ea98fe..9105d75aeb18 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -24,6 +24,7 @@ enum { #else PROC_ENTRY_PERMANENT = 1U << 0, #endif + PROC_ENTRY_ALLOWLIST = 1U << 1, }; struct proc_ops { @@ -58,6 +59,11 @@ enum proc_pidonly { PROC_PIDONLY_ON = 1, }; +enum proc_allowlist { + PROC_ALLOWLIST_OFF = 0, + PROC_ALLOWLIST_ON = 1, +}; + struct proc_fs_info { struct pid_namespace *pid_ns; struct dentry *proc_self; /* For /proc/self */ @@ -65,6 +71,8 @@ struct proc_fs_info { kgid_t pid_gid; enum proc_hidepid hide_pid; enum proc_pidonly pidonly; + char *allowlist; + rwlock_t allowlist_lock; }; static inline struct proc_fs_info *proc_sb_info(struct super_block *sb) From patchwork Wed Jan 25 15:28:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 48192 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp345501wrn; Wed, 25 Jan 2023 07:53:09 -0800 (PST) X-Google-Smtp-Source: AK7set9v/h0EWdajxwJqpvQJh2L3G3LgoLuelT1j3lElQU7eqp2sqBO7QU8FpZ/x/zAQ5y2PDkrY X-Received: by 2002:a17:90b:33ca:b0:22c:1b7:fa68 with SMTP id lk10-20020a17090b33ca00b0022c01b7fa68mr3878117pjb.48.1674661989274; Wed, 25 Jan 2023 07:53:09 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674661989; cv=none; d=google.com; s=arc-20160816; b=iDRwiieOhT1aqBE4/q8DhwBve62q+6zq8yqCJU62Ns2QmSsGWsFI/KyJGbXDGxTaJu ACxp6WaR2mypEpFvcbZFKCZu8SPbiLY5Xb4PJr0YtpODoRCnyLH35S4lsQ6QC+hon2Z6 jjho1QZRTOtp63JrYln3QWILszyvF4wyUPQ72HXt8g7Kek3PlnK4zDB/KYJ1Igf2xDzg 18xysHRyLCaRjekR7Xk3Bm+hyYCwNoHg6mIsuZNpFaY7f7MJfuIpM4oo6MMapVoW4Lw3 sJQ3S+Gm9iOxSxHxN4851hqG6mkhlYrmKwfdSSDioeulDfdrnRpDrDBtFwgf3ASIc73J VHvQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=41B6tMbs2fyb+mP+gRH1nEV6xWY9946Lc7J4gUun1lE=; b=Jkat3F8VaXhmrXf2Jb/foIJhFAvwpFCW2YqkbGxsvYbsNg22Ji26OLzKwL+l63B9rm Pan33Qa5c28i1VKetvQURCGN8MTqbQKJOcNFmzA1l0Wa70E9i9bNokqBcinwdQ2O7we4 viFh3lohF3QvLmNQ1PKxjuiSH3bu0oehAnAZ9VnDSXFUKHrStt+D6QwN4U0L1kUSlrZx +pNElNAKRi15PCQ94DdU4uL5Igzx5ODMwns0W9+qoHJbRKfk89qm9DcGr8mhUmTkDlup GiPCj26sXZKlfEHFGeHj0Xm5d0o2UwyHa07mt1hsfGJqs1yRCbi1IhEyAUKN9VlyM5G7 B9CA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id q25-20020a638c59000000b004ae2bd6b8casi5719445pgn.808.2023.01.25.07.52.36; Wed, 25 Jan 2023 07:53:09 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236095AbjAYPbR (ORCPT + 99 others); Wed, 25 Jan 2023 10:31:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53374 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236080AbjAYPbG (ORCPT ); Wed, 25 Jan 2023 10:31:06 -0500 Received: from us-smtp-delivery-44.mimecast.com (us-smtp-delivery-44.mimecast.com [205.139.111.44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 904405999A for ; Wed, 25 Jan 2023 07:31:01 -0800 (PST) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-341-08M_FhysPKuYZMQaiPJFQg-1; Wed, 25 Jan 2023 10:29:31 -0500 X-MC-Unique: 08M_FhysPKuYZMQaiPJFQg-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 69DC72804832; Wed, 25 Jan 2023 15:29:31 +0000 (UTC) Received: from comp-core-i7-2640m-0182e6.redhat.com (ovpn-208-16.brq.redhat.com [10.40.208.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9A4D72026D76; Wed, 25 Jan 2023 15:29:29 +0000 (UTC) From: Alexey Gladkov To: LKML , containers@lists.linux.dev, linux-fsdevel@vger.kernel.org Cc: Alexey Dobriyan , Al Viro , Andrew Morton , Christian Brauner , Val Cowan Subject: [RFC PATCH v1 3/6] proc: Check that subset= option has been set Date: Wed, 25 Jan 2023 16:28:50 +0100 Message-Id: <346dd92ea62d8469416e12ab71b67b775eb2494b.1674660533.git.legion@kernel.org> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_SOFTFAIL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756010370105830067?= X-GMAIL-MSGID: =?utf-8?q?1756010370105830067?= Refactor subset option. Before this option had only one value - pid. Now another meaning has appeared and therefore their combinations are possible. Signed-off-by: Alexey Gladkov --- fs/proc/generic.c | 4 ++-- fs/proc/inode.c | 16 +++++++++++++--- fs/proc/internal.h | 6 ------ fs/proc/proc_allowlist.c | 22 ++++------------------ fs/proc/root.c | 27 +++++++++++++++++++-------- include/linux/proc_fs.h | 15 +++++---------- 6 files changed, 43 insertions(+), 47 deletions(-) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index d4c8589987e7..71a38b275814 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -269,7 +269,7 @@ struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, { struct proc_fs_info *fs_info = proc_sb_info(dir->i_sb); - if (fs_info->pidonly == PROC_PIDONLY_ON && !proc_has_allowlist(fs_info)) + if ((fs_info->subset & PROC_SUBSET_PIDONLY) && !(fs_info->subset & PROC_SUBSET_ALLOWLIST)) return ERR_PTR(-ENOENT); return proc_lookup_de(dir, dentry, PDE(dir)); @@ -334,7 +334,7 @@ int proc_readdir(struct file *file, struct dir_context *ctx) struct inode *inode = file_inode(file); struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); - if (fs_info->pidonly == PROC_PIDONLY_ON && !proc_has_allowlist(fs_info)) + if ((fs_info->subset & PROC_SUBSET_PIDONLY) && !(fs_info->subset & PROC_SUBSET_ALLOWLIST)) return 1; return proc_readdir_de(file, ctx, PDE(inode)); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index f495fdb39151..4c486237a16b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -184,9 +184,19 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root) seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid)); if (fs_info->hide_pid != HIDEPID_OFF) seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid)); - if (fs_info->pidonly != PROC_PIDONLY_OFF) - seq_printf(seq, ",subset=pid"); - + if (fs_info->subset & PROC_SUBSET_SET) { + bool need_delim = false; + seq_printf(seq, ",subset="); + if (fs_info->subset & PROC_SUBSET_PIDONLY) { + seq_printf(seq, "pid"); + need_delim = true; + } + if (fs_info->subset & PROC_SUBSET_ALLOWLIST) { + if (need_delim) + seq_printf(seq, "+"); + seq_printf(seq, "allowlist"); + } + } return 0; } diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 999d105f6f96..3e1b1f29b13d 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -334,14 +334,8 @@ static inline void pde_force_lookup(struct proc_dir_entry *pde) * proc_allowlist.c */ #ifdef CONFIG_PROC_ALLOW_LIST -extern bool proc_has_allowlist(struct proc_fs_info *); extern bool proc_pde_access_allowed(struct proc_fs_info *, struct proc_dir_entry *); #else -static inline bool proc_has_allowlist(struct proc_fs_info *fs_info) -{ - return false; -} - static inline bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry *pde) { return true; diff --git a/fs/proc/proc_allowlist.c b/fs/proc/proc_allowlist.c index b38e11b04199..2153acb8e467 100644 --- a/fs/proc/proc_allowlist.c +++ b/fs/proc/proc_allowlist.c @@ -16,38 +16,24 @@ #define FILE_SEQFILE(f) ((struct seq_file *)((f)->private_data)) #define FILE_DATA(f) (FILE_SEQFILE(f)->private) -bool proc_has_allowlist(struct proc_fs_info *fs_info) -{ - bool ret; - unsigned long flags; - - read_lock_irqsave(&fs_info->allowlist_lock, flags); - ret = (fs_info->allowlist == NULL); - read_unlock_irqrestore(&fs_info->allowlist_lock, flags); - - return ret; -} - bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry *de) { bool ret = false; char *ptr; unsigned long flags; - read_lock_irqsave(&fs_info->allowlist_lock, flags); - - if (!fs_info->allowlist) { - read_unlock_irqrestore(&fs_info->allowlist_lock, flags); - + if (!(fs_info->subset & PROC_SUBSET_ALLOWLIST)) { if (!pde_is_allowlist(de)) ret = true; return ret; } + read_lock_irqsave(&fs_info->allowlist_lock, flags); + ptr = fs_info->allowlist; - while (*ptr != '\0') { + while (ptr && *ptr != '\0') { struct proc_dir_entry *pde; char *sep, *end; size_t len, pathlen; diff --git a/fs/proc/root.c b/fs/proc/root.c index 1564f5cd118d..6e9b125072e5 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -31,8 +31,7 @@ struct proc_fs_context { unsigned int mask; enum proc_hidepid hidepid; int gid; - enum proc_pidonly pidonly; - enum proc_allowlist allowlist; + unsigned int subset; }; enum proc_param { @@ -91,6 +90,8 @@ static int proc_parse_subset_param(struct fs_context *fc, char *value) { struct proc_fs_context *ctx = fc->fs_private; + ctx->subset |= PROC_SUBSET_SET; + while (value) { char *ptr = strchr(value, '+'); @@ -99,10 +100,10 @@ static int proc_parse_subset_param(struct fs_context *fc, char *value) if (*value != '\0') { if (!strcmp(value, "pid")) { - ctx->pidonly = PROC_PIDONLY_ON; + ctx->subset |= PROC_SUBSET_PIDONLY; } else if (IS_ENABLED(CONFIG_PROC_ALLOW_LIST) && !strcmp(value, "allowlist")) { - ctx->allowlist = PROC_ALLOWLIST_ON; + ctx->subset |= PROC_SUBSET_ALLOWLIST; } else { return invalf(fc, "proc: unsupported subset option - %s\n", value); } @@ -169,8 +170,8 @@ static void proc_apply_options(struct proc_fs_info *fs_info, if (ctx->mask & (1 << Opt_hidepid)) fs_info->hide_pid = ctx->hidepid; if (ctx->mask & (1 << Opt_subset)) { - fs_info->pidonly = ctx->pidonly; - if (ctx->allowlist == PROC_ALLOWLIST_ON) { + fs_info->subset = ctx->subset; + if (ctx->subset & PROC_SUBSET_ALLOWLIST) { fs_info->allowlist = proc_init_allowlist(); } else { fs_info->allowlist = NULL; @@ -346,14 +347,21 @@ static int proc_root_getattr(struct user_namespace *mnt_userns, static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags) { - if (!proc_pid_lookup(dentry, flags)) - return NULL; + struct proc_fs_info *fs_info = proc_sb_info(dir->i_sb); + + if (!(fs_info->subset & PROC_SUBSET_SET) || (fs_info->subset & PROC_SUBSET_PIDONLY)) { + if (!proc_pid_lookup(dentry, flags)) + return NULL; + } return proc_lookup(dir, dentry, flags); } static int proc_root_readdir(struct file *file, struct dir_context *ctx) { + struct inode *inode = file_inode(file); + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); + if (ctx->pos < FIRST_PROCESS_ENTRY) { int error = proc_readdir(file, ctx); if (unlikely(error <= 0)) @@ -361,6 +369,9 @@ static int proc_root_readdir(struct file *file, struct dir_context *ctx) ctx->pos = FIRST_PROCESS_ENTRY; } + if ((fs_info->subset & PROC_SUBSET_SET) && !(fs_info->subset & PROC_SUBSET_PIDONLY)) + return 1; + return proc_pid_readdir(file, ctx); } diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 9105d75aeb18..08d0d0ae6e42 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -53,15 +53,10 @@ enum proc_hidepid { HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable pids */ }; -/* definitions for proc mount option pidonly */ -enum proc_pidonly { - PROC_PIDONLY_OFF = 0, - PROC_PIDONLY_ON = 1, -}; - -enum proc_allowlist { - PROC_ALLOWLIST_OFF = 0, - PROC_ALLOWLIST_ON = 1, +enum proc_subset { + PROC_SUBSET_SET = (1 << 0), + PROC_SUBSET_PIDONLY = (1 << 1), + PROC_SUBSET_ALLOWLIST = (1 << 2), }; struct proc_fs_info { @@ -70,7 +65,7 @@ struct proc_fs_info { struct dentry *proc_thread_self; /* For /proc/thread-self */ kgid_t pid_gid; enum proc_hidepid hide_pid; - enum proc_pidonly pidonly; + unsigned int subset; char *allowlist; rwlock_t allowlist_lock; }; From patchwork Wed Jan 25 15:28:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 48193 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp345839wrn; Wed, 25 Jan 2023 07:53:54 -0800 (PST) X-Google-Smtp-Source: AMrXdXu2HakUSlmyXp3DOENiXsZr1mdZ8GFXzLD8Dg4YdnLpcy3w3h2Ox9kX1Y6tXWjWLXwN3+Uf X-Received: by 2002:a17:90b:2347:b0:228:f6d0:f14d with SMTP id ms7-20020a17090b234700b00228f6d0f14dmr33485955pjb.32.1674662033812; Wed, 25 Jan 2023 07:53:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674662033; cv=none; d=google.com; s=arc-20160816; b=L4+9hoEfYqlAWCTcqUFAyBfxOztCWwpRvT3ZtzqgtJiXXDuLqBgh0DW10DoW/IWZjr bFrFjo9OjDj+iKC5PXS6kVyIeeesZTem4BZBtwj68gLrYp4R5RBwkfU6oO80eqGMk8tb Rxr9crVszWJTyj4JWKxHmStKpS+5aZgC7gpF8cQzL7VRpcuLvLygYy0bs1AaOpfYecdQ xcZtk9mdRcHKNrJTNHSQaN+pu6pWcx1LJlB6n/JySakZW4l/MsYLvtdekJ6kasaEtwYl hTUSDke3XpapuRJg/QdFgT2bQGGU/WjRxrjzh8ridAaa3ijizzpitnAItsK2ZVsIhyUR JwGQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=X8i+2xAs+1XX7enWEvraFZH/M50c7zPbVr8UsbUZJmE=; b=nbVCYdw2N/Taa0zckSK6HQoOZH34COR/CN5no7O8oV8nRaEOQsApk+kF7pZQot8zqq K7FwhM88dwI2MPRoOD2Kf35zdk3VPrZ6dBmMFQX284quRE4y9tpauTlzx5EBB/orVKy+ udiXe6GcjyrbV6hVSFbZU/RwNlAbK+/t1t8I8Ayqcu95ziTESPI4I4BfBn2iE1649KN+ y3eU0my28lw/+3a+WnFuKaXrqHzUyRZsKZ7RVM9QbeIoUomJaMsunVJVy1Rmpq6OMiEC s6KHXn7d7oAdXK8xXIAlMQLfRnhQsmI0Rb7mGAect0xu0lmkSallTw/gOHuBCG0LpWIJ md/A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v5-20020a17090a4ec500b002298cb34320si2565051pjl.116.2023.01.25.07.53.42; Wed, 25 Jan 2023 07:53:53 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229806AbjAYPuT (ORCPT + 99 others); Wed, 25 Jan 2023 10:50:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33816 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234845AbjAYPuS (ORCPT ); Wed, 25 Jan 2023 10:50:18 -0500 X-Greylist: delayed 1232 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Wed, 25 Jan 2023 07:50:17 PST Received: from us-smtp-delivery-44.mimecast.com (unknown [207.211.30.44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 11FF75867F for ; Wed, 25 Jan 2023 07:50:16 -0800 (PST) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-619-LG1apAgMNhCnHMZXWZtq6A-1; Wed, 25 Jan 2023 10:29:34 -0500 X-MC-Unique: LG1apAgMNhCnHMZXWZtq6A-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 73EAC85C6E2; Wed, 25 Jan 2023 15:29:33 +0000 (UTC) Received: from comp-core-i7-2640m-0182e6.redhat.com (ovpn-208-16.brq.redhat.com [10.40.208.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id B32BE2026D4B; Wed, 25 Jan 2023 15:29:31 +0000 (UTC) From: Alexey Gladkov To: LKML , containers@lists.linux.dev, linux-fsdevel@vger.kernel.org Cc: Alexey Dobriyan , Al Viro , Andrew Morton , Christian Brauner , Val Cowan Subject: [RFC PATCH v1 4/6] proc: Allow to use the allowlist filter in userns Date: Wed, 25 Jan 2023 16:28:51 +0100 Message-Id: <76e8b2d0c0651af6906351b7d43fa2a4d117dc04.1674660533.git.legion@kernel.org> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 X-Spam-Status: No, score=-1.1 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, RDNS_NONE,SPF_HELO_NONE,SPF_SOFTFAIL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756010416818037673?= X-GMAIL-MSGID: =?utf-8?q?1756010416818037673?= Signed-off-by: Alexey Gladkov --- fs/proc/proc_allowlist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/proc/proc_allowlist.c b/fs/proc/proc_allowlist.c index 2153acb8e467..c605f73622bd 100644 --- a/fs/proc/proc_allowlist.c +++ b/fs/proc/proc_allowlist.c @@ -100,7 +100,7 @@ static int open_allowlist(struct inode *inode, struct file *file) struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); int ret; - if (!capable(CAP_SYS_ADMIN)) + if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN)) return -EPERM; // we need this because shrink_dcache_sb() can't drop our own dentry. @@ -199,7 +199,7 @@ static const struct proc_ops proc_allowlist_ops = { static int __init proc_allowlist_init(void) { struct proc_dir_entry *pde; - pde = proc_create("allowlist", S_IRUSR | S_IWUSR, NULL, &proc_allowlist_ops); + pde = proc_create("allowlist", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, NULL, &proc_allowlist_ops); pde_make_permanent(pde); pde_make_allowlist(pde); return 0; From patchwork Wed Jan 25 15:28:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 48188 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp344890wrn; Wed, 25 Jan 2023 07:51:49 -0800 (PST) X-Google-Smtp-Source: AK7set92ur6nzIpBhLOAsa/FN00A16EwHyFge+0aqG3YiuMj8z8/1TOsYT/iLmJTj5rqd0iywWP6 X-Received: by 2002:a17:902:d486:b0:196:1a56:b1d3 with SMTP id c6-20020a170902d48600b001961a56b1d3mr5986104plg.11.1674661909588; Wed, 25 Jan 2023 07:51:49 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674661909; cv=none; d=google.com; s=arc-20160816; b=RhS275I7Lt4i5N6yGhfzQJbis561LyJOzkjlSzTTQSCTZg2UQ5I2YY8R4Sz0hnvgwe VWxgbH8uzk4MVc9JtQnDURNrS6wZJqhZx3rZfUfRYt92FU3sTfqvA5t9wBJJcySrdWXU BtJANCxwmHuPHoG9Pk//urQN4pcrX4TVh+9sduSfYohWzTMF/tjrZeCNzPh63Ov06mFH X5OSgspfVVLx8cTgASmkco+/4BnbwaZ8VXKOzDTizZdRqx2IbPuvtGpcv1YK61UhaaEz 16U6NK4DuKu8gdFtqXvM3YwChwyG/m/xQRN9Sa0k5tfsipBx4l3zhtIOFH23hMHh5hZh d/fQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=fx5JS76Ki94fGwYdSV0Ot04ZMMlSHYmk8xcLigZqQYg=; b=wqAU1i8HfXF/2RPoZIJO3QWNVl/Q+UthJBf/s4RKlYSz2slLpX3SfPNYxF5rsaDGsy DRcZQh9QZS88asDvvCOUo2CEyeelEDlBb75JMVyX38EdqsRBQMCgOUcn0LJiQkOvPCv8 f/GqxVDArv7RCAEzneuQMrflKCIcAxQ+P6w8L5Y35HaISp4kIDHZdKxeE3LzVGv2IhEr guicHd7INL5/Iecn2aBZugZUCzKYzdKM9dNc3ZvDCN5WF4xG4OGRHh7KDgN2uc7zC8Bs bej1Pu0kFWQ9NXRRqbAAT7ZjBKdXd/YuUnBbBxZIB4cShq58zo9YVoE8RFOieTCuCHCd Kk8w== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id i15-20020a170902c94f00b001895ff6908dsi6333313pla.580.2023.01.25.07.51.38; Wed, 25 Jan 2023 07:51:49 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235993AbjAYPbN (ORCPT + 99 others); Wed, 25 Jan 2023 10:31:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53176 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236078AbjAYPbG (ORCPT ); Wed, 25 Jan 2023 10:31:06 -0500 Received: from us-smtp-delivery-44.mimecast.com (us-smtp-delivery-44.mimecast.com [205.139.111.44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7463F301BD for ; Wed, 25 Jan 2023 07:31:01 -0800 (PST) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-407-s0K0uYCeMX6KY8aP2rrCxQ-1; Wed, 25 Jan 2023 10:29:36 -0500 X-MC-Unique: s0K0uYCeMX6KY8aP2rrCxQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8A695811E6E; Wed, 25 Jan 2023 15:29:35 +0000 (UTC) Received: from comp-core-i7-2640m-0182e6.redhat.com (ovpn-208-16.brq.redhat.com [10.40.208.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id C796A2026D4B; Wed, 25 Jan 2023 15:29:33 +0000 (UTC) From: Alexey Gladkov To: LKML , containers@lists.linux.dev, linux-fsdevel@vger.kernel.org Cc: Alexey Dobriyan , Al Viro , Andrew Morton , Christian Brauner , Val Cowan Subject: [RFC PATCH v1 5/6] proc: Validate incoming allowlist Date: Wed, 25 Jan 2023 16:28:52 +0100 Message-Id: <18bb5a8c0c81211cba5b865b4fbb5c2dd6b9e688.1674660533.git.legion@kernel.org> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_SOFTFAIL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756010286856840121?= X-GMAIL-MSGID: =?utf-8?q?1756010286856840121?= Signed-off-by: Alexey Gladkov --- fs/proc/internal.h | 10 +++ fs/proc/proc_allowlist.c | 165 ++++++++++++++++++++++++++++++--------- fs/proc/root.c | 22 +----- include/linux/proc_fs.h | 7 +- 4 files changed, 149 insertions(+), 55 deletions(-) diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 3e1b1f29b13d..2ca4e53a4b4b 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -334,8 +334,18 @@ static inline void pde_force_lookup(struct proc_dir_entry *pde) * proc_allowlist.c */ #ifdef CONFIG_PROC_ALLOW_LIST +extern int proc_allowlist_append(struct list_head *, const char *, size_t); +extern void proc_allowlist_free(struct list_head *); extern bool proc_pde_access_allowed(struct proc_fs_info *, struct proc_dir_entry *); #else +static inline int proc_allowlist_append(struct list_head *, const char *, size_t) +{ + return 0; +} +static inline void proc_allowlist_free(struct list_head *) +{ + return; +} static inline bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry *pde) { return true; diff --git a/fs/proc/proc_allowlist.c b/fs/proc/proc_allowlist.c index c605f73622bd..0115015c74f0 100644 --- a/fs/proc/proc_allowlist.c +++ b/fs/proc/proc_allowlist.c @@ -11,16 +11,56 @@ #include #include #include +#include #include "internal.h" #define FILE_SEQFILE(f) ((struct seq_file *)((f)->private_data)) #define FILE_DATA(f) (FILE_SEQFILE(f)->private) +int proc_allowlist_append(struct list_head *allowlist, const char *path, size_t len) +{ + struct allowlist_entry *new; + + if (!len) + return 0; + + new = kmalloc(sizeof(*new), GFP_KERNEL_ACCOUNT); + if (!new) + goto nomem; + + new->path = kstrndup(path, len, GFP_KERNEL_ACCOUNT); + if (!new->path) + goto nomem; + + INIT_LIST_HEAD(&new->list); + list_add_tail(&new->list, allowlist); + + return 0; +nomem: + if (new) { + kfree(new->path); + kfree(new); + } + return -ENOMEM; +} + +void proc_allowlist_free(struct list_head *allowlist) +{ + struct list_head *el, *next; + struct allowlist_entry *entry; + + list_for_each_safe(el, next, allowlist) { + entry = list_entry(el, struct allowlist_entry, list); + kfree(entry->path); + kfree(entry); + } +} + bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry *de) { bool ret = false; - char *ptr; unsigned long flags; + struct list_head *el, *next; if (!(fs_info->subset & PROC_SUBSET_ALLOWLIST)) { if (!pde_is_allowlist(de)) @@ -31,24 +71,13 @@ bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry read_lock_irqsave(&fs_info->allowlist_lock, flags); - ptr = fs_info->allowlist; - - while (ptr && *ptr != '\0') { - struct proc_dir_entry *pde; - char *sep, *end; - size_t len, pathlen; + list_for_each_safe(el, next, &fs_info->allowlist) { + struct allowlist_entry *entry = list_entry(el, struct allowlist_entry, list); - if (!(sep = strchr(ptr, '\n'))) - pathlen = strlen(ptr); - else - pathlen = (sep - ptr); - - if (!pathlen) - goto next; - - pde = de; - end = NULL; - len = pathlen; + struct proc_dir_entry *pde = de; + char *end = NULL; + char *ptr = entry->path; + size_t len = strlen(entry->path); while (ptr != end && len > 0) { end = ptr + len - 1; @@ -72,8 +101,7 @@ bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry ret = true; break; -next: - ptr += pathlen + 1; +next: ; } read_unlock_irqrestore(&fs_info->allowlist_lock, flags); @@ -84,12 +112,18 @@ bool proc_pde_access_allowed(struct proc_fs_info *fs_info, struct proc_dir_entry static int show_allowlist(struct seq_file *m, void *v) { struct proc_fs_info *fs_info = proc_sb_info(m->file->f_inode->i_sb); - char *p = fs_info->allowlist; unsigned long flags; + struct list_head *el, *next; + struct allowlist_entry *entry; read_lock_irqsave(&fs_info->allowlist_lock, flags); - if (p) - seq_puts(m, p); + + list_for_each_safe(el, next, &fs_info->allowlist) { + entry = list_entry(el, struct allowlist_entry, list); + seq_puts(m, entry->path); + seq_puts(m, "\n"); + } + read_unlock_irqrestore(&fs_info->allowlist_lock, flags); return 0; @@ -155,34 +189,93 @@ static ssize_t write_allowlist(struct file *file, const char __user *buffer, siz return count; } +static int allowlist_cmp(void *priv, const struct list_head *a, const struct list_head *b) +{ + struct allowlist_entry *ia = list_entry(a, struct allowlist_entry, list); + struct allowlist_entry *ib = list_entry(b, struct allowlist_entry, list); + + return strcmp(ia->path, ib->path); +} + +static int recreate_allowlist(struct proc_fs_info *fs_info, const char *buf, size_t buflen) +{ + const char *ptr = buf; + size_t len = buflen; + size_t lineno = 1; + int ret = 0; + LIST_HEAD(allowlist); + + while (len > 0) { + char *sep; + size_t pathlen; + + if (!(sep = memchr(ptr, '\n', len))) + pathlen = buflen; + else + pathlen = (sep - ptr); + + if (pathlen > 0) { + ret = -ENAMETOOLONG; + if (pathlen >= PATH_MAX) { + pr_crit("allowlist:%lu: pathname is too long\n", lineno); + goto err; + } + + ret = -EINVAL; + if (*ptr == '/') { + pr_crit("allowlist:%lu: the name must be relative to the mount point\n", lineno); + goto err; + } + if (!isalpha(*ptr)) { + pr_crit("allowlist:%lu: name must start with a letter\n", lineno); + goto err; + } + + proc_allowlist_append(&allowlist, ptr, pathlen); + } + + ptr += pathlen + 1; + len -= pathlen + 1; + + lineno++; + } + + proc_allowlist_free(&fs_info->allowlist); + INIT_LIST_HEAD(&fs_info->allowlist); + + if (!list_empty(&allowlist)) { + list_replace(&allowlist, &fs_info->allowlist); + list_sort(NULL, &fs_info->allowlist, allowlist_cmp); + } + + return 0; +err: + proc_allowlist_free(&allowlist); + return ret; +} + static int close_allowlist(struct inode *inode, struct file *file) { struct seq_file *seq_file = FILE_SEQFILE(file); struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); if (seq_file->buf && (file->f_mode & FMODE_WRITE)) { + unsigned long flags; char *buf; if (!seq_get_buf(seq_file, &buf)) return -EIO; *buf = '\0'; - if (strcmp(seq_file->buf, fs_info->allowlist)) { - unsigned long flags; - - buf = kstrndup(seq_file->buf, seq_file->count, GFP_KERNEL_ACCOUNT); - if (!buf) - return -EIO; - - write_lock_irqsave(&fs_info->allowlist_lock, flags); - - shrink_dcache_sb(inode->i_sb); - - kfree(fs_info->allowlist); - fs_info->allowlist = buf; + write_lock_irqsave(&fs_info->allowlist_lock, flags); + if (recreate_allowlist(fs_info, seq_file->buf, seq_file->count) < 0) { write_unlock_irqrestore(&fs_info->allowlist_lock, flags); + return -EIO; } + + shrink_dcache_sb(inode->i_sb); + write_unlock_irqrestore(&fs_info->allowlist_lock, flags); } return single_release(inode, file); diff --git a/fs/proc/root.c b/fs/proc/root.c index 6e9b125072e5..18436d70bb12 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -147,18 +147,6 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param) return 0; } -static char *proc_init_allowlist(void) -{ - char *content = kstrdup("allowlist\n", GFP_KERNEL_ACCOUNT); - - if (!content) { - pr_err("proc_init_allowlist: allocation allowlist failed\n"); - return NULL; - } - - return content; -} - static void proc_apply_options(struct proc_fs_info *fs_info, struct fs_context *fc, struct user_namespace *user_ns) @@ -171,11 +159,8 @@ static void proc_apply_options(struct proc_fs_info *fs_info, fs_info->hide_pid = ctx->hidepid; if (ctx->mask & (1 << Opt_subset)) { fs_info->subset = ctx->subset; - if (ctx->subset & PROC_SUBSET_ALLOWLIST) { - fs_info->allowlist = proc_init_allowlist(); - } else { - fs_info->allowlist = NULL; - } + if (ctx->subset & PROC_SUBSET_ALLOWLIST) + proc_allowlist_append(&fs_info->allowlist, "allowlist", 10); } } @@ -191,6 +176,7 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc) return -ENOMEM; rwlock_init(&fs_info->allowlist_lock); + INIT_LIST_HEAD(&fs_info->allowlist); fs_info->pid_ns = get_pid_ns(ctx->pid_ns); proc_apply_options(fs_info, fc, current_user_ns()); @@ -296,7 +282,7 @@ static void proc_kill_sb(struct super_block *sb) kill_anon_super(sb); put_pid_ns(fs_info->pid_ns); - kfree(fs_info->allowlist); + proc_allowlist_free(&fs_info->allowlist); kfree(fs_info); } diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 08d0d0ae6e42..81c6b4b2ae97 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -59,6 +59,11 @@ enum proc_subset { PROC_SUBSET_ALLOWLIST = (1 << 2), }; +struct allowlist_entry { + struct list_head list; + char *path; +}; + struct proc_fs_info { struct pid_namespace *pid_ns; struct dentry *proc_self; /* For /proc/self */ @@ -66,8 +71,8 @@ struct proc_fs_info { kgid_t pid_gid; enum proc_hidepid hide_pid; unsigned int subset; - char *allowlist; rwlock_t allowlist_lock; + struct list_head allowlist; }; static inline struct proc_fs_info *proc_sb_info(struct super_block *sb) From patchwork Wed Jan 25 15:28:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 48194 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp346633wrn; Wed, 25 Jan 2023 07:55:59 -0800 (PST) X-Google-Smtp-Source: AK7set+DikZG2YUYTjfXq/rWlA4h4XEDmgJtF4WN4XUjhJ8ZuFoi3D0flaC+kQe60aCNVdkvKrHf X-Received: by 2002:a17:903:1108:b0:196:12f1:76f5 with SMTP id n8-20020a170903110800b0019612f176f5mr7366963plh.52.1674662159261; Wed, 25 Jan 2023 07:55:59 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674662159; cv=none; d=google.com; s=arc-20160816; b=R30ACWlLGItzEf3maxcIqgoMKyuUwxdUsGihTfDzvkxwAO4p4XfBbPTd42rMZy+R7i dkOBgGR32k4MB/PRysrSyxuiq+LStxgPXD9GJdcGO8JCe0E47qUu9vM+eDOMemIpJbr0 Ek9E9Z0YBZMAl5jKWaqRHZHQlwmco1AWO6LseEQv5i3Gj38wpdDTYb9KKSZkqeGBldcG Za+kSVptFOGb+L6lMey1oaKMl4dq5nYzuP7HR4AmgWciirmCgOCRT5v8e/gXqNtcWfOv dMpJsEY1zcfYP1lKXdrBiMDxDqsk+cxw4tPHGlsu/XXpOduln0TcrShCLKTgJtsca5Y5 mE4w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=v1V84e0aGOmID6b7Zl/EdtLePOodNQQZKlfDOW2ldFo=; b=lpRCfaC4EcuCWBxWFFI6XOwKCaXKKtl0ELNBSnHsSJsrd8J6LUVh87GXsPrMimllkb XHx7TC7sUVQ871h2eZY3+qkush33rCy6FL3ZQfnAp3nEqfTf9UuwqzDBKyODLmRsuqOA R9H/6tk9t9/tCrb7rGdWkz8WnOI3HHKfMK1WccI1TVrEYN+sdg7vSgD5u4tuAVxHbCJN 2WdDgzre4I7Hhxl+fL1Rck06N64rpN9DK1/cpGvwnZftUdzFrcFCa7hsB5SUHLyN5yuD QXnnI7ImfTto1C3MjCfHtDsccuCNgGgThBabbEfrr0isbB408FA75NchbLeUOPYq2Pd+ AsCA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c1-20020a170903234100b00186989178b0si6750388plh.132.2023.01.25.07.55.46; Wed, 25 Jan 2023 07:55:59 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236066AbjAYPaE (ORCPT + 99 others); Wed, 25 Jan 2023 10:30:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51790 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236050AbjAYP3u (ORCPT ); Wed, 25 Jan 2023 10:29:50 -0500 Received: from us-smtp-delivery-44.mimecast.com (us-smtp-delivery-44.mimecast.com [205.139.111.44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0024E59B63 for ; Wed, 25 Jan 2023 07:29:42 -0800 (PST) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-554-J2YxgZukPJadicB8_9FLOw-1; Wed, 25 Jan 2023 10:29:38 -0500 X-MC-Unique: J2YxgZukPJadicB8_9FLOw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 97A4E800B30; Wed, 25 Jan 2023 15:29:37 +0000 (UTC) Received: from comp-core-i7-2640m-0182e6.redhat.com (ovpn-208-16.brq.redhat.com [10.40.208.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id D290B2026D4B; Wed, 25 Jan 2023 15:29:35 +0000 (UTC) From: Alexey Gladkov To: LKML , containers@lists.linux.dev, linux-fsdevel@vger.kernel.org Cc: Alexey Dobriyan , Al Viro , Andrew Morton , Christian Brauner , Val Cowan Subject: [RFC PATCH v1 6/6] doc: proc: Add description of subset=allowlist Date: Wed, 25 Jan 2023 16:28:53 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_SOFTFAIL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756010548149005403?= X-GMAIL-MSGID: =?utf-8?q?1756010548149005403?= Signed-off-by: Alexey Gladkov --- Documentation/filesystems/proc.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index e224b6d5b642..c2598bca8193 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -2213,6 +2213,16 @@ information about processes information, just add identd to this group. subset=pid hides all top level files and directories in the procfs that are not related to tasks. +subset=allowlist allows you to specify a list of files and directories to +which you want to provide access. If the option is specified, then the +/proc/allowlist will appear at the top level of the filesystem. By default, this +file contains only its name. The user can add or remove other filenames and +directories. To prohibit editing the allowlist, you need to exclude its name +from the list of allowed ones. + +Different subset= option arguments can be combined using the plus(+) delimiter. +For example: subset=pid+allowlist + Chapter 5: Filesystem behavior ==============================