From patchwork Thu Mar 21 12:14:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thibault Ferrante X-Patchwork-Id: 1914398 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4V0kxd4LSwz1yWs for ; Thu, 21 Mar 2024 23:17:57 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1rnHMa-0000Qd-1r; Thu, 21 Mar 2024 12:17:40 +0000 Received: from smtp-relay-canonical-1.internal ([10.131.114.174] helo=smtp-relay-canonical-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1rnHKG-0007tZ-6o for kernel-team@lists.ubuntu.com; Thu, 21 Mar 2024 12:15:17 +0000 Received: from Q58-sff.buildd (2.general.thibf.uk.vpn [10.172.200.120]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-canonical-1.canonical.com (Postfix) with ESMTPSA id DA795445AA; Thu, 21 Mar 2024 12:15:15 +0000 (UTC) From: Thibault Ferrante To: kernel-team@lists.ubuntu.com Subject: [SRU][J][PATCH 7/9] ipc: Check permissions for checkpoint_restart sysctls at open time Date: Thu, 21 Mar 2024 13:14:55 +0100 Message-ID: <20240321121457.362921-8-thibault.ferrante@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240321121457.362921-1-thibault.ferrante@canonical.com> References: <20240321121457.362921-1-thibault.ferrante@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Alexey Gladkov BugLink: https://bugs.launchpad.net/bugs/2058485 As Eric Biederman pointed out, it is possible not to use a custom proc_handler and check permissions for every write, but to use a .permission handler. That will allow the checkpoint_restart sysctls to perform all of their permission checks at open time, and not need any other special code. Link: https://lore.kernel.org/lkml/87czib9g38.fsf@email.froward.int.ebiederm.org/ Fixes: 1f5c135ee509 ("ipc: Store ipc sysctls in the ipc namespace") Signed-off-by: Eric W. Biederman Signed-off-by: Alexey Gladkov Link: https://lkml.kernel.org/r/65fa8459803830608da4610a39f33c76aa933eb9.1651584847.git.legion@kernel.org Signed-off-by: Eric W. Biederman (cherry picked from commit 0889f44e281034e180daa6daf3e2d57c012452d4) Signed-off-by: Thibault Ferrante --- ipc/ipc_sysctl.c | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index eb7ba8e0a355c..5a58598d48c8c 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -68,25 +68,6 @@ static int proc_ipc_sem_dointvec(struct ctl_table *table, int write, return ret; } -#ifdef CONFIG_CHECKPOINT_RESTORE -static int proc_ipc_dointvec_minmax_checkpoint_restore(struct ctl_table *table, - int write, void *buffer, size_t *lenp, loff_t *ppos) -{ - struct ipc_namespace *ns = table->extra1; - struct ctl_table ipc_table; - - if (write && !checkpoint_restore_ns_capable(ns->user_ns)) - return -EPERM; - - memcpy(&ipc_table, table, sizeof(ipc_table)); - - ipc_table.extra1 = SYSCTL_ZERO; - ipc_table.extra2 = SYSCTL_INT_MAX; - - return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); -} -#endif - int ipc_mni = IPCMNI; int ipc_mni_shift = IPCMNI_SHIFT; int ipc_min_cycle = RADIX_TREE_MAP_SIZE; @@ -172,22 +153,28 @@ static struct ctl_table ipc_sysctls[] = { .procname = "sem_next_id", .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id, .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id), - .mode = 0666, - .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore, + .mode = 0444, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_INT_MAX, }, { .procname = "msg_next_id", .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id, .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id), - .mode = 0666, - .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore, + .mode = 0444, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_INT_MAX, }, { .procname = "shm_next_id", .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id, .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id), - .mode = 0666, - .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore, + .mode = 0444, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_INT_MAX, }, #endif {} @@ -203,8 +190,25 @@ static int set_is_seen(struct ctl_table_set *set) return ¤t->nsproxy->ipc_ns->ipc_set == set; } +static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table) +{ + int mode = table->mode; + +#ifdef CONFIG_CHECKPOINT_RESTORE + struct ipc_namespace *ns = current->nsproxy->ipc_ns; + + if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || + (table->data == &ns->ids[IPC_MSG_IDS].next_id) || + (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && + checkpoint_restore_ns_capable(ns->user_ns)) + mode = 0666; +#endif + return mode; +} + static struct ctl_table_root set_root = { .lookup = set_lookup, + .permissions = ipc_permissions, }; bool setup_ipc_sysctls(struct ipc_namespace *ns) @@ -244,15 +248,12 @@ bool setup_ipc_sysctls(struct ipc_namespace *ns) #ifdef CONFIG_CHECKPOINT_RESTORE } else if (tbl[i].data == &init_ipc_ns.ids[IPC_SEM_IDS].next_id) { tbl[i].data = &ns->ids[IPC_SEM_IDS].next_id; - tbl[i].extra1 = ns; } else if (tbl[i].data == &init_ipc_ns.ids[IPC_MSG_IDS].next_id) { tbl[i].data = &ns->ids[IPC_MSG_IDS].next_id; - tbl[i].extra1 = ns; } else if (tbl[i].data == &init_ipc_ns.ids[IPC_SHM_IDS].next_id) { tbl[i].data = &ns->ids[IPC_SHM_IDS].next_id; - tbl[i].extra1 = ns; #endif } else { tbl[i].data = NULL;