From patchwork Tue Mar 23 17:08:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ondrej Mosnacek X-Patchwork-Id: 12158839 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9FE78C433DB for ; Tue, 23 Mar 2021 17:09:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 69C3E619C0 for ; Tue, 23 Mar 2021 17:09:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229884AbhCWRIn (ORCPT ); Tue, 23 Mar 2021 13:08:43 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:35193 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229986AbhCWRIi (ORCPT ); Tue, 23 Mar 2021 13:08:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616519317; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vFIa4cgk0W/ljtmFE5KfqiIeffPv2ZpFB5dDiHh6344=; b=WEzgEBy4n+BIpVf/DKottKuMBnLpH0kjvLqDhDhqevVN7Qmqb1beOdd/+oex6vPYcbXNiP dmUC8QlnJQB9J1xgaPuH5uqA2SpF7qh46l9HAo0eOBGZXy6a5sjuOumD2ejI+2t3mf+zzJ H9HzpgOVEwJFOXUiUcOctTOSnG5z13M= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-238-h6n2mEHLP7W4pbAMbyXpqA-1; Tue, 23 Mar 2021 13:08:36 -0400 X-MC-Unique: h6n2mEHLP7W4pbAMbyXpqA-1 Received: by mail-ej1-f70.google.com with SMTP id d6so1351797ejd.15 for ; Tue, 23 Mar 2021 10:08:34 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vFIa4cgk0W/ljtmFE5KfqiIeffPv2ZpFB5dDiHh6344=; b=o3rdErHiCMTrCVtEbiIbjJo53kb1U/Xop7ufoZYbTtP313KR8YYT4Jps76SIxkxp1p q4nkdLrvlBbVqmnNUa4MDE8PyWAsEYn7pEewocUzT2+cw9N5AnmGrr/0n/UapyET0fqk DNhKAF9Kut3xbz6r0VIzWRsrXRiPt5kunr+KmgML0D3Bdh9JwtDUWtqiKuLW4AmEpuyY zp2sDRs+l5gC5FMsqfuVh+PWzJfGoy1PaudvyfuBlW8qPcoocMAtocY0agDa1LhZmCB2 FRE8mAb14tyyVL7eNQaHmBZdeYl98rDPXUeOAGIq1RhVRmwxZzQAe8Ow+Vx8mV4Uo6Nu hKKQ== X-Gm-Message-State: AOAM533bN+w9RVbMfwrGLrc/Wk3SIHM3imoQ4buwRh07Z35a9O672cJQ hwGlPFRolq2hoYD4bDlvxdQPDZWsD7Q5RYdYxH0ch37j8JaYyO8iCp3wIcblQzLhcuH62EOH1Xn x9TJbZ+Q4CC5HTOXQwvWKgA8JCQ74u7vwGxCBYA4Kv2gh4+g+bAR3fgwslICQbWpH+FOGoQ== X-Received: by 2002:a17:907:3ea0:: with SMTP id hs32mr5713835ejc.411.1616519313537; Tue, 23 Mar 2021 10:08:33 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwyDv5MQ3u1S55piqRbWbMtdmvfyUMtrmV++WiF6m4ibN88MrALKwYTh1lBK7V61MELijMgqg== X-Received: by 2002:a17:907:3ea0:: with SMTP id hs32mr5713817ejc.411.1616519313381; Tue, 23 Mar 2021 10:08:33 -0700 (PDT) Received: from omos.redhat.com ([2a02:8308:b105:dd00:277b:6436:24db:9466]) by smtp.gmail.com with ESMTPSA id k9sm13337948edn.68.2021.03.23.10.08.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Mar 2021 10:08:32 -0700 (PDT) From: Ondrej Mosnacek To: selinux@vger.kernel.org Subject: [RFC PATCH userspace 1/6] selinux_restorecon: simplify fl_head allocation by using calloc() Date: Tue, 23 Mar 2021 18:08:25 +0100 Message-Id: <20210323170830.182553-2-omosnace@redhat.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210323170830.182553-1-omosnace@redhat.com> References: <20210323170830.182553-1-omosnace@redhat.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Signed-off-by: Ondrej Mosnacek --- libselinux/src/selinux_restorecon.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c index 63fb8dc5..62b54079 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -427,10 +427,9 @@ static int filespec_add(ino_t ino, const char *con, const char *file, struct stat64 sb; if (!fl_head) { - fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); + fl_head = calloc(HASH_BUCKETS, sizeof(file_spec_t)); if (!fl_head) goto oom; - memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); } h = (ino + (ino >> HASH_BITS)) & HASH_MASK; From patchwork Tue Mar 23 17:08:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ondrej Mosnacek X-Patchwork-Id: 12158845 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3C33C433E1 for ; Tue, 23 Mar 2021 17:09:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 91D9A6188B for ; Tue, 23 Mar 2021 17:09:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229504AbhCWRIp (ORCPT ); Tue, 23 Mar 2021 13:08:45 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:51834 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229984AbhCWRIi (ORCPT ); Tue, 23 Mar 2021 13:08:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616519317; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QjQ7iJahwyEc5OLEV3uVX6G8Ao8xq7GsiItKh1IgUJI=; b=LNounjUYqatodSjvOMnuLfeS/U19u7w0ZpuiRIOiItiCiec7F4JuQT50ZAZjRN+JGoJM4u q38xxaMo1lpdBFVNrVZeGtu6dl/uLkZI1EHXzg+MGz2evR8xRaSlGUamA4pLDsuiIumk44 IjSezM/iomim99hK7YUggHvxHjx6Oak= Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-10-aa4o6I_DPZyWNgbv0my3VA-1; Tue, 23 Mar 2021 13:08:36 -0400 X-MC-Unique: aa4o6I_DPZyWNgbv0my3VA-1 Received: by mail-ed1-f70.google.com with SMTP id q25so1257313eds.16 for ; Tue, 23 Mar 2021 10:08:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=QjQ7iJahwyEc5OLEV3uVX6G8Ao8xq7GsiItKh1IgUJI=; b=ad23xGz1a22kGxrAVfIpfJ/AueT3lQqox9wC8q5SbaimlxEcnJf0ieUdR9lRGpnCNb CNugYrK1vSQRxOO2r6Qrr0EEX/rB4Yz3BQ+sQ6CL4pPIEIZL2VcH8jr4jaATc6DNzBba IU5HfT8bVYcHw4jtB2dtKagE400n3t2qiQkukCzyqfRj9QnRGS58J2Bb0xiWE/JdrMh4 7Om0DUjqUvtBQGrvLUTBToZjyUN9grurFhnLQI6ytuVYWomiokeJBX2eo7iYMmqaQDUp pwbh9HNBVmyUXNytLThePpff6+rpw9gpf7AuZDDVAx9RzIMf1pvZ+x67ZZNaSGekomI/ /DDQ== X-Gm-Message-State: AOAM531Xf6MPSANVFDj+y13jTbDzd9qRCrOPQb2QW85mREAEYMGLxgyz KmmsqIzZ500o5fyf+LhjEmp47q14mwZGEtsqNHPtBLup5+a7Ntbqk7K2RTOqO+VUinyPNPoFgj8 RkqSdsiEoHkvCMVll06vn3GYPR1TBLlUZK4SmnUXK/FHPuY7EyRSt9h2VTbDZko8EcBCFZA== X-Received: by 2002:a17:906:1155:: with SMTP id i21mr5862309eja.218.1616519314615; Tue, 23 Mar 2021 10:08:34 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzq9k0CU6ZloMLxdG+NanocNayd+Xez8QsTyWuaWwnlQ/sYGsKqvEVaL77burZRDSwCBbX05g== X-Received: by 2002:a17:906:1155:: with SMTP id i21mr5862284eja.218.1616519314363; Tue, 23 Mar 2021 10:08:34 -0700 (PDT) Received: from omos.redhat.com ([2a02:8308:b105:dd00:277b:6436:24db:9466]) by smtp.gmail.com with ESMTPSA id k9sm13337948edn.68.2021.03.23.10.08.33 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Mar 2021 10:08:33 -0700 (PDT) From: Ondrej Mosnacek To: selinux@vger.kernel.org Subject: [RFC PATCH userspace 2/6] selinux_restorecon: protect file_spec list with a mutex Date: Tue, 23 Mar 2021 18:08:26 +0100 Message-Id: <20210323170830.182553-3-omosnace@redhat.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210323170830.182553-1-omosnace@redhat.com> References: <20210323170830.182553-1-omosnace@redhat.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Not very useful on its own, but will allow to implement a parallel version of selinux_restorecon() in subsequent patches. Signed-off-by: Ondrej Mosnacek --- libselinux/src/selinux_restorecon.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c index 62b54079..f4a973eb 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -413,6 +413,7 @@ typedef struct file_spec { } file_spec_t; static file_spec_t *fl_head; +static pthread_mutex_t fl_mutex = PTHREAD_MUTEX_INITIALIZER; /* * Try to add an association between an inode and a context. If there is a @@ -426,6 +427,8 @@ static int filespec_add(ino_t ino, const char *con, const char *file, int h, ret; struct stat64 sb; + __pthread_mutex_lock(&fl_mutex); + if (!fl_head) { fl_head = calloc(HASH_BUCKETS, sizeof(file_spec_t)); if (!fl_head) @@ -446,11 +449,11 @@ static int filespec_add(ino_t ino, const char *con, const char *file, fl->con = strdup(con); if (!fl->con) goto oom; - return 1; + goto unlock_1; } if (strcmp(fl->con, con) == 0) - return 1; + goto unlock_1; selinux_log(SELINUX_ERROR, "conflicting specifications for %s and %s, using %s.\n", @@ -459,6 +462,9 @@ static int filespec_add(ino_t ino, const char *con, const char *file, fl->file = strdup(file); if (!fl->file) goto oom; + + __pthread_mutex_unlock(&fl_mutex); + if (flags->conflicterror) { selinux_log(SELINUX_ERROR, "treating conflicting specifications as an error.\n"); @@ -483,13 +489,19 @@ static int filespec_add(ino_t ino, const char *con, const char *file, goto oom_freefl; fl->next = prevfl->next; prevfl->next = fl; + + __pthread_mutex_unlock(&fl_mutex); return 0; oom_freefl: free(fl); oom: + __pthread_mutex_unlock(&fl_mutex); selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); return -1; +unlock_1: + __pthread_mutex_unlock(&fl_mutex); + return 1; } /* From patchwork Tue Mar 23 17:08:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ondrej Mosnacek X-Patchwork-Id: 12158843 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E959FC433E3 for ; Tue, 23 Mar 2021 17:09:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AAC1E619C1 for ; Tue, 23 Mar 2021 17:09:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229590AbhCWRIq (ORCPT ); Tue, 23 Mar 2021 13:08:46 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:31196 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230012AbhCWRIj (ORCPT ); Tue, 23 Mar 2021 13:08:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616519318; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rjzJasRBxw34UbMKn+ObE744UMZilgb5zYojamytsI8=; b=GNoJ9pnjTRhg7N+BbZ3IjCcEme3imHNADmjGeZBvbUZ6XVCtRWzw2I6pWq6hUkk1+FxWaV 9WuJsLVpAo9fN6NAyCa3asekKwjT/6V+nNf512Oofl4OeAHtKQGPQZ7ZlqqDzoYDs6hUWX GYkGTsiDfl9jaRushAiF75pvvLzDw9I= Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-252-LUy7l5UIMDiOd2KsTVuCcQ-1; Tue, 23 Mar 2021 13:08:37 -0400 X-MC-Unique: LUy7l5UIMDiOd2KsTVuCcQ-1 Received: by mail-ed1-f70.google.com with SMTP id h2so1264296edw.10 for ; Tue, 23 Mar 2021 10:08:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rjzJasRBxw34UbMKn+ObE744UMZilgb5zYojamytsI8=; b=AJs7eV3UnutOJxNfsk3iNU8GZb9A9Fz+99U+QYdUitlcScLESjAKuyV8UIsB44tMjI V/OayecN4RflQAxu30a19w5c5Ws+ReTpfoc5JeaVuBi2p7DPhe/5axf8LTdQ8hUw6quV AiMzVMGoB9jyVpEh5b93UmnsrxXbRaOPRByu9QFK4J53RVVP3YuXvLnN2JdPesLBC+K8 lmEyW5JVvkwMcQw5h5pM/URJf8aU4Ue3LVZSQLgVqfKU+E56tDa95Wcfy04kHEHzDXwH 0zFXQ602yr3cwSXfcX2mX2bnkgHXEomrKo9pxJEozJQd7z7PHLesAgfSTZ536SdovAQk JIrQ== X-Gm-Message-State: AOAM531tqAFyWipbNTVgtc7pEJvLLdg5xmXglNB+bT+HBI6KXtKy/2CS PKi9Bpu7TMk8ujlP6a9R/+UtruczCIsYgYvP4tN5tIISWkee9IK3IYQM641qQOQARaOew9Kir7H y48OrGAdW5WxGr/8kCyh72/PuO6YVxichBw1jIO2mj09jBX1PO6DksnR5i+9P/6/G9j60ug== X-Received: by 2002:a05:6402:26c9:: with SMTP id x9mr5456950edd.322.1616519315602; Tue, 23 Mar 2021 10:08:35 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyVdsePbng62/IVqwDwk27v+GpHwfAVpTiDtxP2rvISUUejiBtM9J2YWnrfEtyX2VVE+XkU5g== X-Received: by 2002:a05:6402:26c9:: with SMTP id x9mr5456933edd.322.1616519315409; Tue, 23 Mar 2021 10:08:35 -0700 (PDT) Received: from omos.redhat.com ([2a02:8308:b105:dd00:277b:6436:24db:9466]) by smtp.gmail.com with ESMTPSA id k9sm13337948edn.68.2021.03.23.10.08.34 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Mar 2021 10:08:34 -0700 (PDT) From: Ondrej Mosnacek To: selinux@vger.kernel.org Subject: [RFC PATCH userspace 3/6] selinux_restorecon: introduce selinux_log_sync() Date: Tue, 23 Mar 2021 18:08:27 +0100 Message-Id: <20210323170830.182553-4-omosnace@redhat.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210323170830.182553-1-omosnace@redhat.com> References: <20210323170830.182553-1-omosnace@redhat.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Add a thread-safe version of selinux_log() and initially use it in filespec_add(). Together with the previous patch this makes filespec_add() thread-safe, which will be utilized in subsequent patches. Signed-off-by: Ondrej Mosnacek --- libselinux/src/selinux_restorecon.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c index f4a973eb..0ebe56b1 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -46,6 +46,15 @@ static bool selabel_no_digest; static char *rootpath = NULL; static int rootpathlen; +/* Thread-safe log function for parallel restorecon */ +static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; + +#define selinux_log_sync(type, ...) do { \ + __pthread_mutex_lock(&log_mutex); \ + selinux_log(type, __VA_ARGS__); \ + __pthread_mutex_unlock(&log_mutex); \ +} while(0) + /* Information on excluded fs and directories. */ struct edir { char *directory; @@ -455,7 +464,7 @@ static int filespec_add(ino_t ino, const char *con, const char *file, if (strcmp(fl->con, con) == 0) goto unlock_1; - selinux_log(SELINUX_ERROR, + selinux_log_sync(SELINUX_ERROR, "conflicting specifications for %s and %s, using %s.\n", file, fl->file, fl->con); free(fl->file); @@ -466,7 +475,7 @@ static int filespec_add(ino_t ino, const char *con, const char *file, __pthread_mutex_unlock(&fl_mutex); if (flags->conflicterror) { - selinux_log(SELINUX_ERROR, + selinux_log_sync(SELINUX_ERROR, "treating conflicting specifications as an error.\n"); return -1; } @@ -497,7 +506,7 @@ oom_freefl: free(fl); oom: __pthread_mutex_unlock(&fl_mutex); - selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); + selinux_log_sync(SELINUX_ERROR, "%s: Out of memory\n", __func__); return -1; unlock_1: __pthread_mutex_unlock(&fl_mutex); From patchwork Tue Mar 23 17:08:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ondrej Mosnacek X-Patchwork-Id: 12158847 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C0775C433E0 for ; Tue, 23 Mar 2021 17:09:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7CCDF619BF for ; Tue, 23 Mar 2021 17:09:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229548AbhCWRIp (ORCPT ); Tue, 23 Mar 2021 13:08:45 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:31393 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230041AbhCWRIk (ORCPT ); Tue, 23 Mar 2021 13:08:40 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616519320; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iWlLcLYJa2dEQ7oAa+m9wPMNeHbRvEZAQGwbu1ooBpI=; b=is66XjI+CbpPBt12BCLeDMH3M3TYXVm6xjMu8UhsI5YabwNqZ1NN88TXWnsRrPufLRJYtu gtywVD6pz1mpQs2/7EU4bvD78qRl08wxpiSMC6vtbVMee1bcuKwy5e6QI1PQXQ2pNHhJwn DWk4s7jeV4JX1JtYnVbM7P3hMM38CTw= Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-421-Sv4FyXSINa6S62ha67UsfQ-1; Tue, 23 Mar 2021 13:08:38 -0400 X-MC-Unique: Sv4FyXSINa6S62ha67UsfQ-1 Received: by mail-ej1-f71.google.com with SMTP id 11so1346617ejz.20 for ; Tue, 23 Mar 2021 10:08:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=iWlLcLYJa2dEQ7oAa+m9wPMNeHbRvEZAQGwbu1ooBpI=; b=W1dC0jdeUdsg1uzVKfdKEe4X+8NFP91uYsFprK40FwnQE1kcRABeNc/5p85JE0H4vS drpIfh3dC7OKZ2dD4YRJX7g1iAyCZNjZeEKxTzfS4v5ELIlmbRG+kS1o+xeTP6+AXEM4 rN27zZk2YIje4NAYl9qhNwDYYKlv/mcfQb2/QfpVxHL3AhCSrWd7K94kxP7EbVV7b81H DfTP3+JWrqRHktK/cBAu220yOIo17TlpsID6a5g1FTaoPHxBpSArUK3Rnj9Nc2/rZhwk EdYTDrbMSMRTqFXnZENAsAlse7OiSIz7joC9y0PGP01/dgS/Y8AVhTT7iOT5lCjTIHZH ZZwQ== X-Gm-Message-State: AOAM533lHYctyR9EN7mnGt9ksB7w+bXs7SmF2B5y1S2Kq9/aP7gxUzwZ 2v+U7MH3GdbsQP04NzbxfA5rJSSWSweH2N1DGJwvMGV4KKzB8TUuBNba6U+Rk+6PUlcuhZjTjs5 nflPyG+XbK2IgvO8ySyS6Gxoj7YV4gCkc+s2qV9IntyTPbg5O2yHV5oHslg75/dLl6H2sQw== X-Received: by 2002:a17:907:76c7:: with SMTP id kf7mr5787906ejc.470.1616519316675; Tue, 23 Mar 2021 10:08:36 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzlyRPSjXmb8yDcI31LkKTo3MU88GW/6v0Rlx8RG9vdNTEuZK0+VVaZqp6f+RTJdhW136VUEg== X-Received: by 2002:a17:907:76c7:: with SMTP id kf7mr5787884ejc.470.1616519316453; Tue, 23 Mar 2021 10:08:36 -0700 (PDT) Received: from omos.redhat.com ([2a02:8308:b105:dd00:277b:6436:24db:9466]) by smtp.gmail.com with ESMTPSA id k9sm13337948edn.68.2021.03.23.10.08.35 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Mar 2021 10:08:35 -0700 (PDT) From: Ondrej Mosnacek To: selinux@vger.kernel.org Subject: [RFC PATCH userspace 4/6] selinux_restorecon: add a global mutex to synchronize progress output Date: Tue, 23 Mar 2021 18:08:28 +0100 Message-Id: <20210323170830.182553-5-omosnace@redhat.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210323170830.182553-1-omosnace@redhat.com> References: <20210323170830.182553-1-omosnace@redhat.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Another small incremental change to pave the way for a parallel selinux_restorecon() function. Signed-off-by: Ondrej Mosnacek --- libselinux/src/selinux_restorecon.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c index 0ebe56b1..3f3ac2e6 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -69,6 +69,7 @@ static int exclude_count = 0; static struct edir *exclude_lst = NULL; static uint64_t fc_count = 0; /* Number of files processed so far */ static uint64_t efile_count; /* Estimated total number of files */ +static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER; /* Store information on directories with xattr's. */ struct dir_xattr *dir_xattr_list; @@ -658,6 +659,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, } if (flags->progress) { + __pthread_mutex_lock(&progress_mutex); fc_count++; if (fc_count % STAR_COUNT == 0) { if (flags->mass_relabel && efile_count > 0) { @@ -669,6 +671,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, } fflush(stdout); } + __pthread_mutex_unlock(&progress_mutex); } if (flags->add_assoc) { From patchwork Tue Mar 23 17:08:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ondrej Mosnacek X-Patchwork-Id: 12158851 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 61D45C433E0 for ; Tue, 23 Mar 2021 17:09:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 360B5619C0 for ; Tue, 23 Mar 2021 17:09:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229576AbhCWRJP (ORCPT ); Tue, 23 Mar 2021 13:09:15 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:44269 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229500AbhCWRIp (ORCPT ); Tue, 23 Mar 2021 13:08:45 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616519324; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=I38yXDHFa4uxNwBuj98Efn8uILfqOyoEoS0hI3iovKo=; b=DQjKx7y24C3Af4VCZqyiioB141WCq15aIk9H7uMEXvmaCB/Y+B3HA5+4PpPyYWjhJWBrnt mpIxBWMvzrYsZCZMZPhJ++dhb6M8/JO7Pdtu39nXZxLhtFNXgCLVaSr+gFeaSQxitGkJ1E QLZFH5RsP9sKCFXIbkshCyRqdJB7Cd0= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-65-peoHeuKbM7eRt6j3s4N0tQ-1; Tue, 23 Mar 2021 13:08:39 -0400 X-MC-Unique: peoHeuKbM7eRt6j3s4N0tQ-1 Received: by mail-ej1-f70.google.com with SMTP id v27so1366800ejq.0 for ; Tue, 23 Mar 2021 10:08:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=I38yXDHFa4uxNwBuj98Efn8uILfqOyoEoS0hI3iovKo=; b=BTKO3FGi3a4ZC2Zdai3BHsM5iHvoIdMpoX0JHEYluXA5/8ZWRlKPiQyqsweZahjw1y NVrIN/fLj6Fzw3X0ur8ED5bmKOU6upJsggO+pZ1Moe7SpnWf4T/F27o19mYVgs+76cy3 pkGHGBTgJMd5JE0GbONyxKbw4AYDf4CKICDGiij3Btzomz1mOcFvq3Gqf5SrBu74mJAn HQKWtSZYMCM9HFxhNuU93VPIqyUSXOCrePfSBjqPBuY5quHk7VXSYJH/Mw8SIfFvOkbV R85ytp4ju+b2+TEzxmf/O5iE/AN9YgvXouXGNG8wmT/b/IvppHwDK6tXtFHBhWFb0r0r BYQQ== X-Gm-Message-State: AOAM531QuGwcQJysODPWxbEpytraAEoFhxIKlzR1FZReVBpGLwhfqSnZ +0UZFLtswD/w1Sfh/S7wxFsgyqrfO+AGVV2fJtkrmV8bl6adBo8dqwpmwkwm91H07wd09WXmq/Y npWLoEQ+9183xIrA8sam2UxdCzMZtvypFRJKk060Y9KUGt9FzOn1Ya1IVC1pnIVd5CSsg7w== X-Received: by 2002:a17:907:68a:: with SMTP id wn10mr5918403ejb.551.1616519317794; Tue, 23 Mar 2021 10:08:37 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz+OFk4xeOob6yCa6KTvv02YJ1ihO4LVBaUN3Zg7aF6BJNCiRLlwZQz3cawFZsskTK8cqRezg== X-Received: by 2002:a17:907:68a:: with SMTP id wn10mr5918367ejb.551.1616519317406; Tue, 23 Mar 2021 10:08:37 -0700 (PDT) Received: from omos.redhat.com ([2a02:8308:b105:dd00:277b:6436:24db:9466]) by smtp.gmail.com with ESMTPSA id k9sm13337948edn.68.2021.03.23.10.08.36 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Mar 2021 10:08:36 -0700 (PDT) From: Ondrej Mosnacek To: selinux@vger.kernel.org Subject: [RFC PATCH userspace 5/6] selinux_restorecon: introduce selinux_restorecon_parallel(3) Date: Tue, 23 Mar 2021 18:08:29 +0100 Message-Id: <20210323170830.182553-6-omosnace@redhat.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210323170830.182553-1-omosnace@redhat.com> References: <20210323170830.182553-1-omosnace@redhat.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Refactor selinux_restorecon(3) to allow for distributing the relabeling to multiple threads and add a new function selinux_restorecon_parallel(3), which allows specifying the number of threads to use. The existing selinux_restorecon(3) function maintains the same interface and maintains the same behavior (i.e. relabeling is done on a single thread). The parallel implementation takes a simple approach of performing all the directory tree traversal in a critical section and only letting the relabeling of individual objects run in parallel. Thankfully, this approach turns out to be efficient enough in practice, as shown by restorecon benchmarks (detailed in a subsequent patch that switches setfiles & restorecon to use selinux_restorecon_parallel(3)). Note that to be able to use the parallelism, the calling application/ library must be explicitly linked to the libpthread library (statically or dynamically). This is necessary to mantain the requirement that libselinux shouldn't explicitly link with libpthread. (I don't know what exactly was the reason behind this requirement as the commit logs are fuzzy, but special care has been taken in the past to maintain it, so I didn't want to break it...) Signed-off-by: Ondrej Mosnacek --- libselinux/include/selinux/restorecon.h | 14 + libselinux/man/man3/selinux_restorecon.3 | 29 ++ .../man/man3/selinux_restorecon_parallel.3 | 1 + libselinux/src/libselinux.map | 5 + libselinux/src/selinux_internal.h | 14 + libselinux/src/selinux_restorecon.c | 461 ++++++++++++------ 6 files changed, 365 insertions(+), 159 deletions(-) create mode 100644 libselinux/man/man3/selinux_restorecon_parallel.3 diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h index 466de39a..1821a3dc 100644 --- a/libselinux/include/selinux/restorecon.h +++ b/libselinux/include/selinux/restorecon.h @@ -2,6 +2,7 @@ #define _RESTORECON_H_ #include +#include #include #ifdef __cplusplus @@ -23,6 +24,19 @@ extern "C" { */ extern int selinux_restorecon(const char *pathname, unsigned int restorecon_flags); +/** + * selinux_restorecon_parallel - Relabel files, optionally use more threads. + * @pathname: specifies file/directory to relabel. + * @restorecon_flags: specifies the actions to be performed when relabeling. + * @nthreads: specifies the number of threads to use (0 = use number of CPUs + * currently online) + * + * Same as selinux_restorecon(3), but allows to use multiple threads to do + * the work. + */ +extern int selinux_restorecon_parallel(const char *pathname, + unsigned int restorecon_flags, + size_t nthreads); /* * restorecon_flags options */ diff --git a/libselinux/man/man3/selinux_restorecon.3 b/libselinux/man/man3/selinux_restorecon.3 index ad637406..334d2930 100644 --- a/libselinux/man/man3/selinux_restorecon.3 +++ b/libselinux/man/man3/selinux_restorecon.3 @@ -11,6 +11,14 @@ selinux_restorecon \- restore file(s) default SELinux security contexts .br .BI "unsigned int " restorecon_flags ");" .in +.sp +.BI "int selinux_restorecon_parallel(const char *" pathname , +.in +\w'int selinux_restorecon_parallel('u +.br +.BI "unsigned int " restorecon_flags "," +.br +.BI "size_t " nthreads ");" +.in . .SH "DESCRIPTION" .BR selinux_restorecon () @@ -187,6 +195,27 @@ unless the .B SELINUX_RESTORECON_IGNORE_MOUNTS flag has been set. .RE +.sp +.BR selinux_restorecon_parallel() +is similar to +.BR selinux_restorecon (3), +but accepts another parameter that allows to run relabeling over multiple +threads: +.sp +.RS +.IR nthreads +specifies the number of threads to use during relabeling. When set to 1, +the behavior is the same as calling +.BR selinux_restorecon (3). +When set to 0, the function will try to use as many threads as there are +online CPU cores. When set to any other number, the function will try to use +the given number of threads. +.sp +Note that to use the parallel relabeling capability, the calling process +must be linked with the +.B libpthread +library (either at compile time or dynamically at run time). Otherwise the +function will print a warning and fall back to the single threaded mode. . .SH "RETURN VALUE" On success, zero is returned. On error, \-1 is returned and diff --git a/libselinux/man/man3/selinux_restorecon_parallel.3 b/libselinux/man/man3/selinux_restorecon_parallel.3 new file mode 100644 index 00000000..092d8412 --- /dev/null +++ b/libselinux/man/man3/selinux_restorecon_parallel.3 @@ -0,0 +1 @@ +.so man3/selinux_restorecon.3 diff --git a/libselinux/src/libselinux.map b/libselinux/src/libselinux.map index 2a368e93..68a1ad32 100644 --- a/libselinux/src/libselinux.map +++ b/libselinux/src/libselinux.map @@ -240,3 +240,8 @@ LIBSELINUX_1.0 { local: *; }; + +LIBSELINUX_3.2 { + global: + selinux_restorecon_parallel; +} LIBSELINUX_1.0; diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h index 27e9ac53..bca9398a 100644 --- a/libselinux/src/selinux_internal.h +++ b/libselinux/src/selinux_internal.h @@ -69,6 +69,20 @@ extern int selinux_page_size ; pthread_mutex_unlock(LOCK); \ } while (0) +#pragma weak pthread_create +#pragma weak pthread_cond_init +#pragma weak pthread_cond_signal +#pragma weak pthread_cond_destroy +#pragma weak pthread_cond_wait + +/* check if all functions needed to do parallel operations are available */ +#define __pthread_supported ( \ + pthread_create && \ + pthread_cond_init && \ + pthread_cond_destroy && \ + pthread_cond_signal && \ + pthread_cond_wait \ +) #define SELINUXDIR "/etc/selinux/" #define SELINUXCONFIG SELINUXDIR "config" diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c index 3f3ac2e6..adbaeeae 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -621,7 +621,7 @@ out: } static int restorecon_sb(const char *pathname, const struct stat *sb, - struct rest_flags *flags) + struct rest_flags *flags, bool first) { char *newcon = NULL; char *curcon = NULL; @@ -633,9 +633,9 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, if (rootpath) { if (strncmp(rootpath, lookup_path, rootpathlen) != 0) { - selinux_log(SELINUX_ERROR, - "%s is not located in alt_rootpath %s\n", - lookup_path, rootpath); + selinux_log_sync(SELINUX_ERROR, + "%s is not located in alt_rootpath %s\n", + lookup_path, rootpath); return -1; } lookup_path += rootpathlen; @@ -650,10 +650,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, sb->st_mode); if (rc < 0) { - if (errno == ENOENT && flags->warnonnomatch) - selinux_log(SELINUX_INFO, - "Warning no default label for %s\n", - lookup_path); + if (errno == ENOENT && flags->warnonnomatch && first) + selinux_log_sync(SELINUX_INFO, + "Warning no default label for %s\n", + lookup_path); return 0; /* no match, but not an error */ } @@ -678,8 +678,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, rc = filespec_add(sb->st_ino, newcon, pathname, flags); if (rc < 0) { - selinux_log(SELINUX_ERROR, - "filespec_add error: %s\n", pathname); + selinux_log_sync(SELINUX_ERROR, + "filespec_add error: %s\n", pathname); freecon(newcon); return -1; } @@ -692,8 +692,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, } if (flags->log_matches) - selinux_log(SELINUX_INFO, "%s matched by %s\n", - pathname, newcon); + selinux_log_sync(SELINUX_INFO, "%s matched by %s\n", + pathname, newcon); if (lgetfilecon_raw(pathname, &curcon) < 0) { if (errno != ENODATA) @@ -706,9 +706,9 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, if (!flags->set_specctx && curcon && (is_context_customizable(curcon) > 0)) { if (flags->verbose) { - selinux_log(SELINUX_INFO, + selinux_log_sync(SELINUX_INFO, "%s not reset as customized by admin to %s\n", - pathname, curcon); + pathname, curcon); } goto out; } @@ -734,10 +734,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, } if (flags->verbose) - selinux_log(SELINUX_INFO, - "%s %s from %s to %s\n", - updated ? "Relabeled" : "Would relabel", - pathname, curcon, newcon); + selinux_log_sync(SELINUX_INFO, + "%s %s from %s to %s\n", + updated ? "Relabeled" : "Would relabel", + pathname, curcon, newcon); if (flags->syslog_changes && !flags->nochange) { if (curcon) @@ -757,9 +757,9 @@ out1: freecon(newcon); return rc; err: - selinux_log(SELINUX_ERROR, - "Could not set context for %s: %s\n", - pathname, strerror(errno)); + selinux_log_sync(SELINUX_ERROR, + "Could not set context for %s: %s\n", + pathname, strerror(errno)); rc = -1; goto out1; } @@ -825,65 +825,217 @@ oom: goto free; } +struct rest_state { + struct rest_flags flags; + dev_t dev_num; + struct statfs sfsb; + bool ignore_digest; + bool setrestorecondigest; + bool parallel; -/* - * Public API - */ + FTS *fts; + FTSENT *ftsent_first; + struct dir_hash_node *head, *current; + bool abort; + int error; + int saved_errno; + size_t inprogress; + pthread_cond_t cond_finish; + pthread_mutex_t mutex; +}; -/* selinux_restorecon(3) - Main function that is responsible for labeling */ -int selinux_restorecon(const char *pathname_orig, - unsigned int restorecon_flags) +static void *selinux_restorecon_thread(void *arg) { - struct rest_flags flags; + struct rest_state *state = arg; + FTS *fts = state->fts; + FTSENT *ftsent; + int error; + char ent_path[PATH_MAX]; + struct stat ent_st; + bool first = false; + + if (state->parallel) + pthread_mutex_lock(&state->mutex); + + if (state->ftsent_first) { + ftsent = state->ftsent_first; + state->ftsent_first = NULL; + first = true; + goto loop_body; + } + + while ((errno = 0, ftsent = fts_read(fts)) != NULL) { +loop_body: + /* If the FTS_XDEV flag is set and the device is different */ + if (state->flags.set_xdev && + ftsent->fts_statp->st_dev != state->dev_num) + continue; + + switch (ftsent->fts_info) { + case FTS_DC: + selinux_log_sync(SELINUX_ERROR, + "Directory cycle on %s.\n", + ftsent->fts_path); + errno = ELOOP; + state->error = -1; + state->abort = true; + goto finish; + case FTS_DP: + continue; + case FTS_DNR: + selinux_log_sync(SELINUX_ERROR, + "Could not read %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_NS: + selinux_log_sync(SELINUX_ERROR, + "Could not stat %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_ERR: + selinux_log_sync(SELINUX_ERROR, + "Error on %s: %s.\n", + ftsent->fts_path, + strerror(ftsent->fts_errno)); + fts_set(fts, ftsent, FTS_SKIP); + continue; + case FTS_D: + if (state->sfsb.f_type == SYSFS_MAGIC && + !selabel_partial_match(fc_sehandle, + ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + + if (check_excluded(ftsent->fts_path)) { + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + + if (state->setrestorecondigest) { + struct dir_hash_node *new_node = NULL; + + if (check_context_match_for_dir(ftsent->fts_path, + &new_node, + state->error) && + !state->ignore_digest) { + selinux_log_sync(SELINUX_INFO, + "Skipping restorecon on directory(%s)\n", + ftsent->fts_path); + fts_set(fts, ftsent, FTS_SKIP); + continue; + } + + if (new_node && !state->error) { + if (!state->current) { + state->current = new_node; + state->head = state->current; + } else { + state->current->next = new_node; + state->current = new_node; + } + } + } + /* fall through */ + default: + strcpy(ent_path, ftsent->fts_path); + ent_st = *ftsent->fts_statp; + if (state->parallel) { + state->inprogress += 1; + pthread_mutex_unlock(&state->mutex); + } + + error = restorecon_sb(ent_path, &ent_st, &state->flags, + first); + + if (state->parallel) { + pthread_mutex_lock(&state->mutex); + state->inprogress -= 1; + if (state->abort) + goto unlock; + } + + state->error |= error; + first = false; + if (error && state->flags.abort_on_error) { + state->abort = true; + goto finish; + } + break; + } + } + +finish: + if (!state->saved_errno) + state->saved_errno = errno; +unlock: + if (state->parallel) { + if (state->inprogress == 0) + pthread_cond_signal(&state->cond_finish); + pthread_mutex_unlock(&state->mutex); + } + return NULL; +} + +static int selinux_restorecon_common(const char *pathname_orig, + unsigned int restorecon_flags, + size_t nthreads) +{ + struct rest_state state; - flags.nochange = (restorecon_flags & + state.flags.nochange = (restorecon_flags & SELINUX_RESTORECON_NOCHANGE) ? true : false; - flags.verbose = (restorecon_flags & + state.flags.verbose = (restorecon_flags & SELINUX_RESTORECON_VERBOSE) ? true : false; - flags.progress = (restorecon_flags & + state.flags.progress = (restorecon_flags & SELINUX_RESTORECON_PROGRESS) ? true : false; - flags.mass_relabel = (restorecon_flags & + state.flags.mass_relabel = (restorecon_flags & SELINUX_RESTORECON_MASS_RELABEL) ? true : false; - flags.recurse = (restorecon_flags & + state.flags.recurse = (restorecon_flags & SELINUX_RESTORECON_RECURSE) ? true : false; - flags.set_specctx = (restorecon_flags & + state.flags.set_specctx = (restorecon_flags & SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false; - flags.userealpath = (restorecon_flags & + state.flags.userealpath = (restorecon_flags & SELINUX_RESTORECON_REALPATH) ? true : false; - flags.set_xdev = (restorecon_flags & + state.flags.set_xdev = (restorecon_flags & SELINUX_RESTORECON_XDEV) ? true : false; - flags.add_assoc = (restorecon_flags & + state.flags.add_assoc = (restorecon_flags & SELINUX_RESTORECON_ADD_ASSOC) ? true : false; - flags.abort_on_error = (restorecon_flags & + state.flags.abort_on_error = (restorecon_flags & SELINUX_RESTORECON_ABORT_ON_ERROR) ? true : false; - flags.syslog_changes = (restorecon_flags & + state.flags.syslog_changes = (restorecon_flags & SELINUX_RESTORECON_SYSLOG_CHANGES) ? true : false; - flags.log_matches = (restorecon_flags & + state.flags.log_matches = (restorecon_flags & SELINUX_RESTORECON_LOG_MATCHES) ? true : false; - flags.ignore_noent = (restorecon_flags & + state.flags.ignore_noent = (restorecon_flags & SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false; - flags.warnonnomatch = true; - flags.conflicterror = (restorecon_flags & + state.flags.warnonnomatch = true; + state.flags.conflicterror = (restorecon_flags & SELINUX_RESTORECON_CONFLICT_ERROR) ? true : false; ignore_mounts = (restorecon_flags & SELINUX_RESTORECON_IGNORE_MOUNTS) ? true : false; - bool ignore_digest = (restorecon_flags & + state.ignore_digest = (restorecon_flags & SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false; - bool setrestorecondigest = true; + state.setrestorecondigest = true; + + state.head = NULL; + state.current = NULL; + state.abort = false; + state.error = 0; + state.saved_errno = 0; struct stat sb; - struct statfs sfsb; - FTS *fts; - FTSENT *ftsent; char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname; char *paths[2] = { NULL, NULL }; int fts_flags, error, sverrno; - dev_t dev_num = 0; struct dir_hash_node *current = NULL; - struct dir_hash_node *head = NULL; - if (flags.verbose && flags.progress) - flags.verbose = false; + if (state.flags.verbose && state.flags.progress) + state.flags.verbose = false; __selinux_once(fc_once, restorecon_init); @@ -896,13 +1048,31 @@ int selinux_restorecon(const char *pathname_orig, */ if (selabel_no_digest || (restorecon_flags & SELINUX_RESTORECON_SKIP_DIGEST)) - setrestorecondigest = false; + state.setrestorecondigest = false; + + if (!__pthread_supported) { + if (nthreads != 1) { + nthreads = 1; + selinux_log(SELINUX_WARNING, + "Threading functionality not available, falling back to 1 thread."); + } + } else if (nthreads == 0) { + long nproc = sysconf(_SC_NPROCESSORS_ONLN); + + if (nproc > 0) { + nthreads = nproc; + } else { + nthreads = 1; + selinux_log(SELINUX_WARNING, + "Unable to detect CPU count, falling back to 1 thread."); + } + } /* * Convert passed-in pathname to canonical pathname by resolving * realpath of containing dir, then appending last component name. */ - if (flags.userealpath) { + if (state.flags.userealpath) { char *basename_cpy = strdup(pathname_orig); if (!basename_cpy) goto realpatherr; @@ -947,7 +1117,7 @@ int selinux_restorecon(const char *pathname_orig, paths[0] = pathname; if (lstat(pathname, &sb) < 0) { - if (flags.ignore_noent && errno == ENOENT) { + if (state.flags.ignore_noent && errno == ENOENT) { free(pathdnamer); free(pathname); return 0; @@ -962,21 +1132,21 @@ int selinux_restorecon(const char *pathname_orig, /* Skip digest if not a directory */ if (!S_ISDIR(sb.st_mode)) - setrestorecondigest = false; + state.setrestorecondigest = false; - if (!flags.recurse) { + if (!state.flags.recurse) { if (check_excluded(pathname)) { error = 0; goto cleanup; } - error = restorecon_sb(pathname, &sb, &flags); + error = restorecon_sb(pathname, &sb, &state.flags, true); goto cleanup; } /* Obtain fs type */ - memset(&sfsb, 0, sizeof sfsb); - if (!S_ISLNK(sb.st_mode) && statfs(pathname, &sfsb) < 0) { + memset(&state.sfsb, 0, sizeof(state.sfsb)); + if (!S_ISLNK(sb.st_mode) && statfs(pathname, &state.sfsb) < 0) { selinux_log(SELINUX_ERROR, "statfs(%s) failed: %s\n", pathname, strerror(errno)); @@ -985,21 +1155,21 @@ int selinux_restorecon(const char *pathname_orig, } /* Skip digest on in-memory filesystems and /sys */ - if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC || - sfsb.f_type == SYSFS_MAGIC) - setrestorecondigest = false; + if (state.sfsb.f_type == RAMFS_MAGIC || state.sfsb.f_type == TMPFS_MAGIC || + state.sfsb.f_type == SYSFS_MAGIC) + state.setrestorecondigest = false; - if (flags.set_xdev) + if (state.flags.set_xdev) fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV; else fts_flags = FTS_PHYSICAL | FTS_NOCHDIR; - fts = fts_open(paths, fts_flags, NULL); - if (!fts) + state.fts = fts_open(paths, fts_flags, NULL); + if (!state.fts) goto fts_err; - ftsent = fts_read(fts); - if (!ftsent) + state.ftsent_first = fts_read(state.fts); + if (!state.ftsent_first) goto fts_err; /* @@ -1011,100 +1181,54 @@ int selinux_restorecon(const char *pathname_orig, * directories with a different device number when the FTS_XDEV flag * is set (from http://marc.info/?l=selinux&m=124688830500777&w=2). */ - dev_num = ftsent->fts_statp->st_dev; + state.dev_num = state.ftsent_first->fts_statp->st_dev; - error = 0; - do { - /* If the FTS_XDEV flag is set and the device is different */ - if (flags.set_xdev && ftsent->fts_statp->st_dev != dev_num) - continue; - - switch (ftsent->fts_info) { - case FTS_DC: - selinux_log(SELINUX_ERROR, - "Directory cycle on %s.\n", - ftsent->fts_path); - errno = ELOOP; - error = -1; - goto out; - case FTS_DP: - continue; - case FTS_DNR: - selinux_log(SELINUX_ERROR, - "Could not read %s: %s.\n", - ftsent->fts_path, - strerror(ftsent->fts_errno)); - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_NS: - selinux_log(SELINUX_ERROR, - "Could not stat %s: %s.\n", - ftsent->fts_path, - strerror(ftsent->fts_errno)); - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_ERR: - selinux_log(SELINUX_ERROR, - "Error on %s: %s.\n", - ftsent->fts_path, - strerror(ftsent->fts_errno)); - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_D: - if (sfsb.f_type == SYSFS_MAGIC && - !selabel_partial_match(fc_sehandle, - ftsent->fts_path)) { - fts_set(fts, ftsent, FTS_SKIP); - continue; - } + if (nthreads == 1) { + state.parallel = false; + selinux_restorecon_thread(&state); + } else { + size_t i; + pthread_t thread; + + pthread_mutex_init(&state.mutex, NULL); + pthread_cond_init(&state.cond_finish, NULL); + + state.parallel = true; + /* + * Start (nthreads - 1) threads - this thread is going to + * take part, too. + */ + for (i = 1; i < nthreads; i++) { + pthread_create(&thread, NULL, selinux_restorecon_thread, + &state); + /* + * If thread creation failed - doesn't matter, we just + * let the successfully created threads do the job. + */ + } - if (check_excluded(ftsent->fts_path)) { - fts_set(fts, ftsent, FTS_SKIP); - continue; - } + /* Let's join in on the fun! */ + selinux_restorecon_thread(&state); - if (setrestorecondigest) { - struct dir_hash_node *new_node = NULL; + pthread_mutex_lock(&state.mutex); + if (state.inprogress != 0) + pthread_cond_wait(&state.cond_finish, &state.mutex); + pthread_mutex_unlock(&state.mutex); - if (check_context_match_for_dir(ftsent->fts_path, - &new_node, - error) && - !ignore_digest) { - selinux_log(SELINUX_INFO, - "Skipping restorecon on directory(%s)\n", - ftsent->fts_path); - fts_set(fts, ftsent, FTS_SKIP); - continue; - } + pthread_mutex_destroy(&state.mutex); + pthread_cond_destroy(&state.cond_finish); + } - if (new_node && !error) { - if (!current) { - current = new_node; - head = current; - } else { - current->next = new_node; - current = current->next; - } - } - } - /* fall through */ - default: - error |= restorecon_sb(ftsent->fts_path, - ftsent->fts_statp, &flags); - if (flags.warnonnomatch) - flags.warnonnomatch = false; - if (error && flags.abort_on_error) - goto out; - break; - } - } while ((ftsent = fts_read(fts)) != NULL); + error = state.error; + if (state.saved_errno) + goto out; /* * Labeling successful. Write partial match digests for subdirectories. * TODO: Write digest upon FTS_DP if no error occurs in its descents. */ - if (setrestorecondigest && !flags.nochange && !error) { - current = head; + if (state.setrestorecondigest && !state.flags.nochange && !error) { + current = state.head; while (current != NULL) { if (setxattr(current->path, RESTORECON_PARTIAL_MATCH_DIGEST, @@ -1120,22 +1244,21 @@ int selinux_restorecon(const char *pathname_orig, } out: - if (flags.progress && flags.mass_relabel) + if (state.flags.progress && state.flags.mass_relabel) fprintf(stdout, "\r%s 100.0%%\n", pathname); - sverrno = errno; - (void) fts_close(fts); - errno = sverrno; + (void) fts_close(state.fts); + errno = state.saved_errno; cleanup: - if (flags.add_assoc) { - if (flags.verbose) + if (state.flags.add_assoc) { + if (state.flags.verbose) filespec_eval(); filespec_destroy(); } free(pathdnamer); free(pathname); - current = head; + current = state.head; while (current != NULL) { struct dir_hash_node *next = current->next; @@ -1169,6 +1292,26 @@ fts_err: goto cleanup; } + +/* + * Public API + */ + +/* selinux_restorecon(3) - Main function that is responsible for labeling */ +int selinux_restorecon(const char *pathname_orig, + unsigned int restorecon_flags) +{ + return selinux_restorecon_common(pathname_orig, restorecon_flags, 1); +} + +/* selinux_restorecon_parallel(3) - Parallel version of selinux_restorecon(3) */ +int selinux_restorecon_parallel(const char *pathname_orig, + unsigned int restorecon_flags, + size_t nthreads) +{ + return selinux_restorecon_common(pathname_orig, restorecon_flags, nthreads); +} + /* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */ void selinux_restorecon_set_sehandle(struct selabel_handle *hndl) { From patchwork Tue Mar 23 17:08:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ondrej Mosnacek X-Patchwork-Id: 12158849 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 487C7C433C1 for ; Tue, 23 Mar 2021 17:09:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1D97B6188B for ; Tue, 23 Mar 2021 17:09:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229764AbhCWRJP (ORCPT ); Tue, 23 Mar 2021 13:09:15 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:30061 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230050AbhCWRIn (ORCPT ); Tue, 23 Mar 2021 13:08:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616519322; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XsOY1N9DVLuUMCekvDNDqyoYEic1JhxmkoreO8nLHX0=; b=XGQ9pRnd7py35vwy9gU47u9KUt6F/f43zhnpcoZZDIyq4VQXaQDqzKpZ71ESIlQkOlX0Q7 UzCLLbEfPh2BWKp0xHTRa96YDud8aCyjpY/UaLG7J1Xo6QnHPFq4ppp+ySh8SIbwSAK/xm ZR5jqbwzifDb1N1prRT8hlvbf0dGLTA= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-149-Gzk33Vc6P0mSUUahf_C8aQ-1; Tue, 23 Mar 2021 13:08:40 -0400 X-MC-Unique: Gzk33Vc6P0mSUUahf_C8aQ-1 Received: by mail-ej1-f70.google.com with SMTP id e7so1360448ejx.5 for ; Tue, 23 Mar 2021 10:08:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XsOY1N9DVLuUMCekvDNDqyoYEic1JhxmkoreO8nLHX0=; b=Byw17IqbnnOAMkRQq/IF/c6m+mEekXPquil78RLHBTRL/O5Qf/I++8fW7i7tJ7Cxil MZ8xMuWtgqI9Nu9t/86lct0CgOor0nZTp28LMTxZAYWZHIn7VUnALp5r85vnUZcWRnoN gUAvOUs00lfF87BEZq4N9QYKdOcvGlc3juOj6GdvV9MiLYAEvmhHT8vE/kGfFQPrxKhq JBioLBz2ubR2n1Q7jap1LvAWJOojlzUkS2dpEIguMjaICaabtViAECnHumH1OcE1avSP FFEEtxA1AHV9CSW9EFrzXr0Nr/gCA6Uu25E/RsoR6ct0ISQLSV4HmU1u0p+KnHvNgWyl jsJA== X-Gm-Message-State: AOAM531Ao3chnjoBCFpgse6RJ3eLd6+tEeWaAKE3a+KABszOZrroSLiA ca2CLW0NwaTXVqTuxB7VSaUVTDc9/ZzlD0VQh3p2XT7k09DjZb5KyDejxe63h7nZ/n45nYeXITY Z8+Wco8IRKu8RAwDCNzbHjlOgwVEjt8qJ4JWJyEqrIsSifChY0ha8Vdu6/MFwJhz5Nbbp9w== X-Received: by 2002:a05:6402:1103:: with SMTP id u3mr5423031edv.205.1616519318604; Tue, 23 Mar 2021 10:08:38 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyK7fS5ZZcWmSFE+SY0WZbpcdZMSF9nK5k1dO2OuLPqNIbwSkm/JfWXtOv8liaCaylS4JBtGw== X-Received: by 2002:a05:6402:1103:: with SMTP id u3mr5423000edv.205.1616519318309; Tue, 23 Mar 2021 10:08:38 -0700 (PDT) Received: from omos.redhat.com ([2a02:8308:b105:dd00:277b:6436:24db:9466]) by smtp.gmail.com with ESMTPSA id k9sm13337948edn.68.2021.03.23.10.08.37 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Mar 2021 10:08:37 -0700 (PDT) From: Ondrej Mosnacek To: selinux@vger.kernel.org Subject: [RFC PATCH userspace 6/6] setfiles/restorecon: support parallel relabeling Date: Tue, 23 Mar 2021 18:08:30 +0100 Message-Id: <20210323170830.182553-7-omosnace@redhat.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210323170830.182553-1-omosnace@redhat.com> References: <20210323170830.182553-1-omosnace@redhat.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Use the newly introduced selinux_restorecon_parallel(3) in setfiles/restorecon and a -T option to both to allow enabling parallel relabeling. The default behavior without specifying the -T option is to use 1 thread; parallel relabeling must be requested explicitly by passing -T 0 (which will use as many threads as there are available CPU cores) or -T , which will use threads. === Benchmarks === As measured on a 32-core cloud VM with Fedora 34. Not a fully representative environment, but still the scaling is quite good. WITHOUT PATCHES: $ time restorecon -rn /usr/src real 0m23,580s user 0m22,681s sys 0m0,707s WITH PATCHES: $ time restorecon -rn -T 1 /usr/src real 0m23,493s user 0m22,637s sys 0m0,668s $ time restorecon -rn -T 2 /usr/src real 0m13,438s user 0m25,536s sys 0m0,946s $ time restorecon -rn -T 8 /usr/src real 0m5,476s user 0m38,440s sys 0m3,016s $ time restorecon -rn -T 16 /usr/src real 0m3,868s user 0m51,292s sys 0m5,289s $ time restorecon -rn -T 32 /usr/src real 0m2,817s user 1m0,317s sys 0m6,157s Note that the benchmarks were performed in read-only mode (-n), so the labels were only read and looked up in the database, not written. When fixing labels on a heavily mislabeled system, the scaling would likely be event better, since a larger % of work could be done in parallel. Signed-off-by: Ondrej Mosnacek --- policycoreutils/setfiles/Makefile | 2 +- policycoreutils/setfiles/restore.c | 7 ++++--- policycoreutils/setfiles/restore.h | 2 +- policycoreutils/setfiles/restorecon.8 | 9 +++++++++ policycoreutils/setfiles/setfiles.8 | 9 +++++++++ policycoreutils/setfiles/setfiles.c | 28 ++++++++++++++++----------- 6 files changed, 41 insertions(+), 16 deletions(-) diff --git a/policycoreutils/setfiles/Makefile b/policycoreutils/setfiles/Makefile index a3bbbe11..82de8f2a 100644 --- a/policycoreutils/setfiles/Makefile +++ b/policycoreutils/setfiles/Makefile @@ -6,7 +6,7 @@ MANDIR = $(PREFIX)/share/man AUDITH ?= $(shell test -f /usr/include/libaudit.h && echo y) CFLAGS ?= -g -Werror -Wall -W -override LDLIBS += -lselinux -lsepol +override LDLIBS += -lselinux -lsepol -lpthread ifeq ($(AUDITH), y) override CFLAGS += -DUSE_AUDIT diff --git a/policycoreutils/setfiles/restore.c b/policycoreutils/setfiles/restore.c index 9d688c60..74d48bb3 100644 --- a/policycoreutils/setfiles/restore.c +++ b/policycoreutils/setfiles/restore.c @@ -72,7 +72,7 @@ void restore_finish(void) } } -int process_glob(char *name, struct restore_opts *opts) +int process_glob(char *name, struct restore_opts *opts, size_t nthreads) { glob_t globbuf; size_t i = 0; @@ -91,8 +91,9 @@ int process_glob(char *name, struct restore_opts *opts) continue; if (len > 0 && strcmp(&globbuf.gl_pathv[i][len], "/..") == 0) continue; - rc = selinux_restorecon(globbuf.gl_pathv[i], - opts->restorecon_flags); + rc = selinux_restorecon_parallel(globbuf.gl_pathv[i], + opts->restorecon_flags, + nthreads); if (rc < 0) errors = rc; } diff --git a/policycoreutils/setfiles/restore.h b/policycoreutils/setfiles/restore.h index ac6ad680..bb35a1db 100644 --- a/policycoreutils/setfiles/restore.h +++ b/policycoreutils/setfiles/restore.h @@ -49,7 +49,7 @@ struct restore_opts { void restore_init(struct restore_opts *opts); void restore_finish(void); void add_exclude(const char *directory); -int process_glob(char *name, struct restore_opts *opts); +int process_glob(char *name, struct restore_opts *opts, size_t nthreads); extern char **exclude_list; #endif diff --git a/policycoreutils/setfiles/restorecon.8 b/policycoreutils/setfiles/restorecon.8 index 668486f6..e07db2c8 100644 --- a/policycoreutils/setfiles/restorecon.8 +++ b/policycoreutils/setfiles/restorecon.8 @@ -33,6 +33,8 @@ restorecon \- restore file(s) default SELinux security contexts. .RB [ \-W ] .RB [ \-I | \-D ] .RB [ \-x ] +.RB [ \-T +.IR nthreads ] .SH "DESCRIPTION" This manual page describes the @@ -160,6 +162,13 @@ prevent .B restorecon from crossing file system boundaries. .TP +.BI \-T \ nthreads +use up to +.I nthreads +threads. Specify 0 to create as many threads as there are available +CPU cores; 1 to use only a single thread (default); or any positive +number to use the given number of threads (if possible). +.TP .SH "ARGUMENTS" .IR pathname \ ... The pathname for the file(s) to be relabeled. diff --git a/policycoreutils/setfiles/setfiles.8 b/policycoreutils/setfiles/setfiles.8 index 4d28bc9a..15f939d1 100644 --- a/policycoreutils/setfiles/setfiles.8 +++ b/policycoreutils/setfiles/setfiles.8 @@ -19,6 +19,8 @@ setfiles \- set SELinux file security contexts. .RB [ \-W ] .RB [ \-F ] .RB [ \-I | \-D ] +.RB [ \-T +.IR nthreads ] .I spec_file .IR pathname \ ... @@ -161,6 +163,13 @@ quote marks or backslashes. The option of GNU .B find produces input suitable for this mode. +.TP +.BI \-T \ nthreads +use up to +.I nthreads +threads. Specify 0 to create as many threads as there are available +CPU cores; 1 to use only a single thread (default); or any positive +number to use the given number of threads (if possible). .SH "ARGUMENTS" .TP diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c index f018d161..2313a21f 100644 --- a/policycoreutils/setfiles/setfiles.c +++ b/policycoreutils/setfiles/setfiles.c @@ -1,4 +1,5 @@ #include "restore.h" +#include #include #include #include @@ -34,14 +35,14 @@ static __attribute__((__noreturn__)) void usage(const char *const name) { if (iamrestorecon) { fprintf(stderr, - "usage: %s [-iIDFmnprRv0x] [-e excludedir] pathname...\n" - "usage: %s [-iIDFmnprRv0x] [-e excludedir] -f filename\n", + "usage: %s [-iIDFmnprRv0xT] [-e excludedir] pathname...\n" + "usage: %s [-iIDFmnprRv0xT] [-e excludedir] -f filename\n", name, name); } else { fprintf(stderr, - "usage: %s [-diIDlmnpqvEFW] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file pathname...\n" - "usage: %s [-diIDlmnpqvEFW] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file -f filename\n" - "usage: %s -s [-diIDlmnpqvFW] spec_file\n", + "usage: %s [-diIDlmnpqvEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file pathname...\n" + "usage: %s [-diIDlmnpqvEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file -f filename\n" + "usage: %s -s [-diIDlmnpqvFWT] spec_file\n", name, name, name); } exit(-1); @@ -144,12 +145,12 @@ int main(int argc, char **argv) int opt, i = 0; const char *input_filename = NULL; int use_input_file = 0; - char *buf = NULL; - size_t buf_len; + char *buf = NULL, *endptr; + size_t buf_len, nthreads = 1; const char *base; int errors = 0; - const char *ropts = "e:f:hiIDlmno:pqrsvFRW0x"; - const char *sopts = "c:de:f:hiIDlmno:pqr:svEFR:W0"; + const char *ropts = "e:f:hiIDlmno:pqrsvFRW0xT:"; + const char *sopts = "c:de:f:hiIDlmno:pqr:svEFR:W0T:"; const char *opts; union selinux_callback cb; @@ -370,6 +371,11 @@ int main(int argc, char **argv) usage(argv[0]); } break; + case 'T': + nthreads = strtoull(optarg, &endptr, 10); + if (*optarg == '\0' || *endptr != '\0') + usage(argv[0]); + break; case 'h': case '?': usage(argv[0]); @@ -448,13 +454,13 @@ int main(int argc, char **argv) buf[len - 1] = 0; if (!strcmp(buf, "/")) r_opts.mass_relabel = SELINUX_RESTORECON_MASS_RELABEL; - errors |= process_glob(buf, &r_opts) < 0; + errors |= process_glob(buf, &r_opts, nthreads) < 0; } if (strcmp(input_filename, "-") != 0) fclose(f); } else { for (i = optind; i < argc; i++) - errors |= process_glob(argv[i], &r_opts) < 0; + errors |= process_glob(argv[i], &r_opts, nthreads) < 0; } maybe_audit_mass_relabel(r_opts.mass_relabel, errors);