From patchwork Thu Jul 14 21:27:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12918498 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 897E9CCA47B for ; Thu, 14 Jul 2022 21:28:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240837AbiGNV2M (ORCPT ); Thu, 14 Jul 2022 17:28:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56708 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240830AbiGNV2I (ORCPT ); Thu, 14 Jul 2022 17:28:08 -0400 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 51CED6D9F4 for ; Thu, 14 Jul 2022 14:28:07 -0700 (PDT) Received: by mail-wm1-x32c.google.com with SMTP id az2-20020a05600c600200b003a301c985fcso1705992wmb.4 for ; Thu, 14 Jul 2022 14:28:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=6EjxlpzqkEruqpB4jK0ApOUhySpRy99/daelbcmn7yU=; b=gsOyIN8SH+sjQITqxMdlTlv991SO58KioRRft3QDPyaK/dBCRrTnmQSNdshHaF/VrA qOrVQd2E30tcu55Qcg7Ne47loN5PzEPY7kfSgoFNFfN5ybaZFrjHOg0jBu7EMCPmY32d ICWUiIkCh8oM1qIXfjXi/ZtHtYbxpWo152MQ2Bqn8YdqKRlLkOTyspripqjmpJZDNi0y OwgMYRQfWSsEDfdJGflvjM2vwY3DdrFjJ8vLLCPhV+Yi5x1NGf0LQCZsFo3MGuV9TaK2 afAo33Upwe5bdWpT5ZlXQcMJdwE4q38ZUR7aHmUEMSvB4NkJgxVRMpbq8HkpN0j0wE6m 3yBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=6EjxlpzqkEruqpB4jK0ApOUhySpRy99/daelbcmn7yU=; b=jIpGScUkHIm6G53g8gKPez3i67aHWsWNSGqxTkp0E+WzBsMnv5o2k8mo/URhSMFEFR TVbjZ5jsXYm2UNeWHecbGTrVVqoNw/N5PqcWxG5kzUf7xOUwnwSsq5gYawMiH/Lqu4wP MBEJBp0yjfKY8FQwF4ItEB9lX/13W05q+HC8zW/WQs8aL9DEf8DHsEZn76IzFYOFwhO/ Ug9bBGnZPdoUNLVGJDpu1RxxD9iKku1ZS8qL7Alkfmhn7QkbIidL0KccDC+Rlvtm0bfy ouZoFYvUfhtVDp8MP91ITWXsxVQbkSYKV3cQU7fPzf2gyl1yFXITLy9rKlqvQhTFnygb 3S6w== X-Gm-Message-State: AJIora/49fi1xJFY7hbfeM6EQlmS+pYrVi8S/KZrRBKKwU5lYElVJGTu ItRC9AVHOpFigb1s7xMSG7jZbTT3eCY= X-Google-Smtp-Source: AGRyM1vz/y+g5ZrOQSJ0FA+69a8OkYuxQHDUVk/yjwi8yrMgmJeWK6rhm7TIt1MXQdmojWs9YsV8jg== X-Received: by 2002:a1c:7c16:0:b0:3a0:4c5f:ce13 with SMTP id x22-20020a1c7c16000000b003a04c5fce13mr11004191wmc.73.1657834085487; Thu, 14 Jul 2022 14:28:05 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id h17-20020adffd51000000b0021d746d4820sm2233873wrs.37.2022.07.14.14.28.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Jul 2022 14:28:04 -0700 (PDT) Message-Id: <6147751c9c13cba5afbf72e1107fdfeef91edcaa.1657834081.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 14 Jul 2022 21:27:57 +0000 Subject: [PATCH v8 1/5] Documentation/git-config.txt: add SCOPES section Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Johannes Schindelin , Glen Choo , Glen Choo Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Glen Choo From: Glen Choo In a subsequent commit, we will introduce "protected configuration", which is easiest to describe in terms of configuration scopes (i.e. it's the union of the 'system', 'global', and 'command' scopes). This description is fine for ML discussions, but it's inadequate for end users because we don't provide a good description of "configuration scopes" in the public docs. 145d59f482 (config: add '--show-scope' to print the scope of a config value, 2020-02-10) introduced the word "scope" to our public docs, but that only enumerates the scopes and assumes the user can figure out what those values mean. Add a SCOPES section to Documentation/git-config.txt that describes the configuration scopes, their corresponding CLI options, and mentions that some configuration options are only respected in certain scopes. Then, use the word "scope" to simplify the FILES section and change some confusing wording. Signed-off-by: Glen Choo --- Documentation/git-config.txt | 82 ++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 23 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 9376e39aef2..53c7c65f9ed 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -297,23 +297,20 @@ The default is to use a pager. FILES ----- -If not set explicitly with `--file`, there are four files where -'git config' will search for configuration options: +By default, 'git config' will read configuration options from multiple +files: $(prefix)/etc/gitconfig:: System-wide configuration file. $XDG_CONFIG_HOME/git/config:: - Second user-specific configuration file. If $XDG_CONFIG_HOME is not set - or empty, `$HOME/.config/git/config` will be used. Any single-valued - variable set in this file will be overwritten by whatever is in - `~/.gitconfig`. It is a good idea not to create this file if - you sometimes use older versions of Git, as support for this - file was added fairly recently. - ~/.gitconfig:: - User-specific configuration file. Also called "global" - configuration file. + User-specific configuration files. When the XDG_CONFIG_HOME environment + variable is not set or empty, $HOME/.config/ is used as + $XDG_CONFIG_HOME. ++ +These are also called "global" configuration files. If both files exist, both +files are read in the order given above. $GIT_DIR/config:: Repository specific configuration file. @@ -322,28 +319,67 @@ $GIT_DIR/config.worktree:: This is optional and is only searched when `extensions.worktreeConfig` is present in $GIT_DIR/config. -If no further options are given, all reading options will read all of these -files that are available. If the global or the system-wide configuration -file are not available they will be ignored. If the repository configuration -file is not available or readable, 'git config' will exit with a non-zero -error code. However, in neither case will an error message be issued. +You may also provide additional configuration parameters when running any +git command by using the `-c` option. See linkgit:git[1] for details. + +Options will be read from all of these files that are available. If the +global or the system-wide configuration files are missing or unreadable they +will be ignored. If the repository configuration file is missing or unreadable, +'git config' will exit with a non-zero error code. An error message is produced +if the file is unreadable, but not if it is missing. The files are read in the order given above, with last value found taking precedence over values read earlier. When multiple values are taken then all values of a key from all files will be used. -You may override individual configuration parameters when running any git -command by using the `-c` option. See linkgit:git[1] for details. - -All writing options will per default write to the repository specific +By default, options are only written to the repository specific configuration file. Note that this also affects options like `--replace-all` and `--unset`. *'git config' will only ever change one file at a time*. -You can override these rules using the `--global`, `--system`, -`--local`, `--worktree`, and `--file` command-line options; see -<> above. +You can limit which configuration sources are read from or written to by +specifying the path of a file with the `--file` option, or by specifying a +configuration scope with `--system`, `--global`, `--local`, or `--worktree`. +For more, see <> above. + +SCOPES +------ + +Each configuration source falls within a configuration scope. The scopes +are: + +system:: + $(prefix)/etc/gitconfig + +global:: + $XDG_CONFIG_HOME/git/config ++ +~/.gitconfig + +local:: + $GIT_DIR/config + +worktree:: + $GIT_DIR/config.worktree + +command:: + GIT_CONFIG_{COUNT,KEY,VALUE} environment variables (see <> + below) ++ +the `-c` option + +With the exception of 'command', each scope corresponds to a command line +option: `--system`, `--global`, `--local`, `--worktree`. + +When reading options, specifying a scope will only read options from the +files within that scope. When writing options, specifying a scope will write +to the files within that scope (instead of the repository specific +configuration file). See <> above for a complete description. +Most configuration options are respected regardless of the scope it is +defined in, but some options are only respected in certain scopes. See the +respective option's documentation for the full details. +[[ENVIRONMENT]] ENVIRONMENT ----------- From patchwork Thu Jul 14 21:27:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12918499 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 49255C433EF for ; Thu, 14 Jul 2022 21:28:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240859AbiGNV2X (ORCPT ); Thu, 14 Jul 2022 17:28:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56760 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240827AbiGNV2K (ORCPT ); Thu, 14 Jul 2022 17:28:10 -0400 Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6BF246D9F4 for ; Thu, 14 Jul 2022 14:28:09 -0700 (PDT) Received: by mail-wr1-x433.google.com with SMTP id d16so4215096wrv.10 for ; Thu, 14 Jul 2022 14:28:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=KmQ5rKdKW/vCdCzeR5S6o2R6WXND2dUPlfpoTf8jznQ=; b=S+Y+uWD5oHlHTmInz42FMJt+braYGmgRkAOCIK3gfifhgy1FKfHQVt59QlSx+qHJ6u yvbnhxLlqyhwJcuqjnteWZ9zTgPzAPAgVRlvAOAnH4BeWzq9th/kkyhq7ZOvfvPlcMuC p4NixrfEgCP7Hud7uNwY9zoNwFE0BeeZZY4RV1UnM5YSgFT7jE2IC1mBZWS0lbb/lgcC fpqp32jE0q9Vy1j3hbov+E47+ys9oEjvTeUOx2d9bX1/kvTIxw3y/oCYg469VjkvIpEF pZs+gC5bizehPC+PV6EV5LXHHYZDBhC13gmrKVYPbo2bqQH14m3Gb9KCSIyEzBCXhtsc GVIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=KmQ5rKdKW/vCdCzeR5S6o2R6WXND2dUPlfpoTf8jznQ=; b=O9fAaHjD5oAKV8uMjmCDRAhZHo3LLrs7gjlu566g6BgRURo6+K0P1wNYOI4v5p26Um Ar8K5WbUOc0AwCqoa2K1kivyNrqIgSKBpI8Th/c63UHPQgYS2l1lOfXaVTHZ3p7hknuF nT895qZvjlLEG8T/D/9C+ZVIn/M0PWBzz2N2dcedosvbnHA+gzkuwyd4+Ocgh9C5UGWk WmUJX2lpXPm/yfUsdJneYrPTCHcS4eGZhhrhksSJ5+sZtBHc4motKhNfhBzHc3qjMMJ/ N0u5axJ9MSXv3SopCGFxo6IU+eAqDqahyprgIk2wvJuZN+CtR04m/X+yO5kgcaD44nKc Xdzw== X-Gm-Message-State: AJIora9N8Ws08dM3dlsg1sBgAt7F+k+BlUku8I/tCsrpWHsgRZhAKnMm eiCmKmKIAqjHKVtKNtdjQuDmVet4z9I= X-Google-Smtp-Source: AGRyM1v8gJeJ5rOyL2mlMlsmOSZf64cEV2U35Sx92iJmNmhKQyWaQ3gfcENSOUZvl9IwYiFr6fSmJg== X-Received: by 2002:a5d:4c49:0:b0:21d:6df5:beb7 with SMTP id n9-20020a5d4c49000000b0021d6df5beb7mr9977368wrt.286.1657834087398; Thu, 14 Jul 2022 14:28:07 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id g20-20020a05600c4ed400b003a2cfb9f5basm7959203wmq.16.2022.07.14.14.28.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Jul 2022 14:28:06 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Thu, 14 Jul 2022 21:27:58 +0000 Subject: [PATCH v8 2/5] Documentation: define protected configuration Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Johannes Schindelin , Glen Choo , Glen Choo Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Glen Choo From: Glen Choo For security reasons, there are config variables that are only trusted when they are specified in certain configuration scopes, which are sometimes referred to on-list as 'protected configuration' [1]. A future commit will introduce another such variable, so let's define our terms so that we can have consistent documentation and implementation. In our documentation, define 'protected configuration' as the system, global and command config scopes. As a shorthand, I will refer to variables that are only respected in protected configuration as 'protected configuration only', but this term is not used in the documentation. This definition of protected configuration is based on whether or not Git can reasonably protect the user by ignoring the configuration scope: - System, global and command line config are considered protected because an attacker who has control over any of those can do plenty of harm without Git, so we gain very little by ignoring those scopes. - On the other hand, local (and similarly, worktree) config are not considered protected because it is relatively easy for an attacker to control local config, e.g.: - On some shared user environments, a non-admin attacker can create a repository high up the directory hierarchy (e.g. C:\.git on Windows), and a user may accidentally use it when their PS1 automatically invokes "git" commands. `safe.directory` prevents attacks of this form by making sure that the user intended to use the shared repository. It obviously shouldn't be read from the repository, because that would end up trusting the repository that Git was supposed to reject. - "git upload-pack" is expected to run in repositories that may not be controlled by the user. We cannot ignore all config in that repository (because "git upload-pack" would fail), but we can limit the risks by ignoring `uploadpack.packObjectsHook`. Only `uploadpack.packObjectsHook` is 'protected configuration only'. The following variables are intentionally excluded: - `safe.directory` should be 'protected configuration only', but it does not technically fit the definition because it is not respected in the "command" scope. A future commit will fix this. - `trace2.*` happens to read the same scopes as `safe.directory` because they share an implementation. However, this is not for security reasons; it is because we want to start tracing so early that repository-level config and "-c" are not available [2]. This requirement is unique to `trace2.*`, so it does not makes sense for protected configuration to be subject to the same constraints. [1] For example, https://lore.kernel.org/git/6af83767-576b-75c4-c778-0284344a8fe7@github.com/ [2] https://lore.kernel.org/git/a0c89d0d-669e-bf56-25d2-cbb09b012e70@jeffhostetler.com/ Signed-off-by: Glen Choo --- Documentation/config/uploadpack.txt | 6 +++--- Documentation/git-config.txt | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Documentation/config/uploadpack.txt b/Documentation/config/uploadpack.txt index 32fad5bbe81..16264d82a72 100644 --- a/Documentation/config/uploadpack.txt +++ b/Documentation/config/uploadpack.txt @@ -49,9 +49,9 @@ uploadpack.packObjectsHook:: `pack-objects` to the hook, and expects a completed packfile on stdout. + -Note that this configuration variable is ignored if it is seen in the -repository-level config (this is a safety measure against fetching from -untrusted repositories). +Note that this configuration variable is only respected when it is specified +in protected configuration (see <>). This is a safety measure +against fetching from untrusted repositories. uploadpack.allowFilter:: If this option is set, `upload-pack` will support partial diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 53c7c65f9ed..7a2bcb2f6cb 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -341,6 +341,7 @@ specifying the path of a file with the `--file` option, or by specifying a configuration scope with `--system`, `--global`, `--local`, or `--worktree`. For more, see <> above. +[[SCOPES]] SCOPES ------ @@ -379,6 +380,18 @@ Most configuration options are respected regardless of the scope it is defined in, but some options are only respected in certain scopes. See the respective option's documentation for the full details. +Protected configuration +~~~~~~~~~~~~~~~~~~~~~~~ + +Protected configuration refers to the 'system', 'global', and 'command' scopes. +For security reasons, certain options are only respected when they are +specified in protected configuration, and ignored otherwise. + +Git treats these scopes as if they are controlled by the user or a trusted +administrator. This is because an attacker who controls these scopes can do +substantial harm without using Git, so it is assumed that the user's environment +protects these scopes against attackers. + [[ENVIRONMENT]] ENVIRONMENT ----------- From patchwork Thu Jul 14 21:27:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12918500 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 59075C43334 for ; Thu, 14 Jul 2022 21:28:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240879AbiGNV2Y (ORCPT ); Thu, 14 Jul 2022 17:28:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240834AbiGNV2M (ORCPT ); Thu, 14 Jul 2022 17:28:12 -0400 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B235D6E890 for ; Thu, 14 Jul 2022 14:28:10 -0700 (PDT) Received: by mail-wm1-x32c.google.com with SMTP id c131-20020a1c3589000000b003a2cc290135so3791908wma.2 for ; Thu, 14 Jul 2022 14:28:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=J4CvAbjeuCvHoUuQXrBO02hBvLwYnILTUOCSZqFIdtw=; b=W/8WiKDl6X/CWLDdqAm9pnCC8FuchbDGd1fH46Zg17TYLu3CjshLrHVHRilm4hhJcj 9p00wXlIrL2yku+0tsVX9AmvkNT7SsaRbbbzYUcN7bAdJuyWYCXPSy0yJcbx0Whs6d8F hflDNiSe0wbKOft0AwtlLL2yd/7qXvz4UGJXcapPXoJUxUiHC9E9nrzs3T8ew+hFRFfA pujrg5T8G4S37xXgsWExOylBQk0360IcM5gxOEA7IcGJOw/GEyRlFzUpW7/x8NIfxxel 612Gy+w1OIXvtqO9guNNjyXWwtkGbpgjoRuGUlu/5BXQ8Q2/824Aq5tppXJRv5Sl1Cxz IAJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=J4CvAbjeuCvHoUuQXrBO02hBvLwYnILTUOCSZqFIdtw=; b=HyBM3YxNfe6NGXbpVx/mtqXHILLhbgda/z8IsV+GZe0llGVXLFhHdwXKi7FvvGhkHl 9Q+MmDNnvCJH2mOS/5iKlbVi6dHVfD1ENDiPoPVGn0JpZTwnE/IDH6A/DFmXkuxR/gqH iFScQQfbu0eRSLJGf89D60nZBCEsLlXLsW7RHr5sJ+fKN85yEwmvxTCImhssdo8p9AZu SS8DprKqahyTFu7XEOaCxTaFvf12RRIxSrTJIV9sAvFJt9QJVfu7PDOOFK+0DubjUmCn KJychJIJVxDB18H3eDX3vQC5CUn3x5ixwUUfSvcBKTFMTlHCPb8JPo6b+cCpTu4t1MFi 2G5Q== X-Gm-Message-State: AJIora/4RYeCvQxgmQk3CfOYNRjrKefy1eBBr1O8RhYVpKFS5+FcrE0y kIzibA4xIORWD8EuB3qoM0Pp8lhZ2sc= X-Google-Smtp-Source: AGRyM1vikOAQV0Au4O6UGxOS7kY+lIY/pFIRpf7Q8UZTFAK0FEAsP7eNx3QHrTwJbo1uSEpUjcIC1g== X-Received: by 2002:a05:600c:a4c:b0:39c:6517:1136 with SMTP id c12-20020a05600c0a4c00b0039c65171136mr11115685wmq.12.1657834088902; Thu, 14 Jul 2022 14:28:08 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id t64-20020a1c4643000000b003a30c3d0c9csm152938wma.8.2022.07.14.14.28.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Jul 2022 14:28:08 -0700 (PDT) Message-Id: <30ac73716cbc234a1f176d2d417bf0e2b0b335cf.1657834081.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 14 Jul 2022 21:27:59 +0000 Subject: [PATCH v8 3/5] config: learn `git_protected_config()` Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Johannes Schindelin , Glen Choo , Glen Choo Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Glen Choo From: Glen Choo `uploadpack.packObjectsHook` is the only 'protected configuration only' variable today, but we've noted that `safe.directory` and the upcoming `safe.bareRepository` should also be 'protected configuration only'. So, for consistency, we'd like to have a single implementation for protected configuration. The primary constraints are: 1. Reading from protected configuration should be fast. Nearly all "git" commands inside a bare repository will read both `safe.directory` and `safe.bareRepository`, so we cannot afford to be slow. 2. Protected configuration must be readable when the gitdir is not known. `safe.directory` and `safe.bareRepository` both affect repository discovery and the gitdir is not known at that point [1]. The chosen implementation in this commit is to read protected configuration and cache the values in a global configset. This is similar to the caching behavior we get with the_repository->config. Introduce git_protected_config(), which reads protected configuration and caches them in the global configset protected_config. Then, refactor `uploadpack.packObjectsHook` to use git_protected_config(). The protected configuration functions are named similarly to their non-protected counterparts, e.g. git_protected_config_check_init() vs git_config_check_init(). In light of constraint 1, this implementation can still be improved. git_protected_config() iterates through every variable in protected_config, which is wasteful, but it makes the conversion simple because it matches existing patterns. We will likely implement constant time lookup functions for protected configuration in a future series (such functions already exist for non-protected configuration, i.e. repo_config_get_*()). An alternative that avoids introducing another configset is to continue to read all config using git_config(), but only accept values that have the correct config scope [2]. This technically fulfills constraint 2, because git_config() simply ignores the local and worktree config when the gitdir is not known. However, this would read incomplete config into the_repository->config, which would need to be reset when the gitdir is known and git_config() needs to read the local and worktree config. Resetting the_repository->config might be reasonable while we only have these 'protected configuration only' variables, but it's not clear whether this extends well to future variables. [1] In this case, we do have a candidate gitdir though, so with a little refactoring, it might be possible to provide a gitdir. [2] This is how `uploadpack.packObjectsHook` was implemented prior to this commit. Signed-off-by: Glen Choo --- config.c | 43 ++++++++++++++++++++++++++++++++++++ config.h | 16 ++++++++++++++ t/t5544-pack-objects-hook.sh | 7 +++++- upload-pack.c | 27 +++++++++++++--------- 4 files changed, 82 insertions(+), 11 deletions(-) diff --git a/config.c b/config.c index 9b0e9c93285..015bec360f5 100644 --- a/config.c +++ b/config.c @@ -81,6 +81,17 @@ static enum config_scope current_parsing_scope; static int pack_compression_seen; static int zlib_compression_seen; +/* + * Config that comes from trusted scopes, namely: + * - CONFIG_SCOPE_SYSTEM (e.g. /etc/gitconfig) + * - CONFIG_SCOPE_GLOBAL (e.g. $HOME/.gitconfig, $XDG_CONFIG_HOME/git) + * - CONFIG_SCOPE_COMMAND (e.g. "-c" option, environment variables) + * + * This is declared here for code cleanliness, but unlike the other + * static variables, this does not hold config parser state. + */ +static struct config_set protected_config; + static int config_file_fgetc(struct config_source *conf) { return getc_unlocked(conf->u.file); @@ -2378,6 +2389,11 @@ int git_configset_add_file(struct config_set *cs, const char *filename) return git_config_from_file(config_set_callback, filename, cs); } +int git_configset_add_parameters(struct config_set *cs) +{ + return git_config_from_parameters(config_set_callback, cs); +} + int git_configset_get_value(struct config_set *cs, const char *key, const char **value) { const struct string_list *values = NULL; @@ -2619,6 +2635,33 @@ int repo_config_get_pathname(struct repository *repo, return ret; } +/* Read values into protected_config. */ +static void read_protected_config(void) +{ + char *xdg_config = NULL, *user_config = NULL, *system_config = NULL; + + git_configset_init(&protected_config); + + system_config = git_system_config(); + git_global_config(&user_config, &xdg_config); + + git_configset_add_file(&protected_config, system_config); + git_configset_add_file(&protected_config, xdg_config); + git_configset_add_file(&protected_config, user_config); + git_configset_add_parameters(&protected_config); + + free(system_config); + free(xdg_config); + free(user_config); +} + +void git_protected_config(config_fn_t fn, void *data) +{ + if (!protected_config.hash_initialized) + read_protected_config(); + configset_iter(&protected_config, fn, data); +} + /* Functions used historically to read configuration from 'the_repository' */ void git_config(config_fn_t fn, void *data) { diff --git a/config.h b/config.h index 7654f61c634..ca994d77147 100644 --- a/config.h +++ b/config.h @@ -446,6 +446,15 @@ void git_configset_init(struct config_set *cs); */ int git_configset_add_file(struct config_set *cs, const char *filename); +/** + * Parses command line options and environment variables, and adds the + * variable-value pairs to the `config_set`. Returns 0 on success, or -1 + * if there is an error in parsing. The caller decides whether to free + * the incomplete configset or continue using it when the function + * returns -1. + */ +int git_configset_add_parameters(struct config_set *cs); + /** * Finds and returns the value list, sorted in order of increasing priority * for the configuration variable `key` and config set `cs`. When the @@ -505,6 +514,13 @@ int repo_config_get_maybe_bool(struct repository *repo, int repo_config_get_pathname(struct repository *repo, const char *key, const char **dest); +/* + * Functions for reading protected config. By definition, protected + * config ignores repository config, so these do not take a `struct + * repository` parameter. + */ +void git_protected_config(config_fn_t fn, void *data); + /** * Querying For Specific Variables * ------------------------------- diff --git a/t/t5544-pack-objects-hook.sh b/t/t5544-pack-objects-hook.sh index dd5f44d986f..54f54f8d2eb 100755 --- a/t/t5544-pack-objects-hook.sh +++ b/t/t5544-pack-objects-hook.sh @@ -56,7 +56,12 @@ test_expect_success 'hook does not run from repo config' ' ! grep "hook running" stderr && test_path_is_missing .git/hook.args && test_path_is_missing .git/hook.stdin && - test_path_is_missing .git/hook.stdout + test_path_is_missing .git/hook.stdout && + + # check that global config is used instead + test_config_global uploadpack.packObjectsHook ./hook && + git clone --no-local . dst2.git 2>stderr && + grep "hook running" stderr ' test_expect_success 'hook works with partial clone' ' diff --git a/upload-pack.c b/upload-pack.c index 3a851b36066..09f48317b02 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -1321,18 +1321,27 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data) data->advertise_sid = git_config_bool(var, value); } - if (current_config_scope() != CONFIG_SCOPE_LOCAL && - current_config_scope() != CONFIG_SCOPE_WORKTREE) { - if (!strcmp("uploadpack.packobjectshook", var)) - return git_config_string(&data->pack_objects_hook, var, value); - } - if (parse_object_filter_config(var, value, data) < 0) return -1; return parse_hide_refs_config(var, value, "uploadpack"); } +static int upload_pack_protected_config(const char *var, const char *value, void *cb_data) +{ + struct upload_pack_data *data = cb_data; + + if (!strcmp("uploadpack.packobjectshook", var)) + return git_config_string(&data->pack_objects_hook, var, value); + return 0; +} + +static void get_upload_pack_config(struct upload_pack_data *data) +{ + git_config(upload_pack_config, data); + git_protected_config(upload_pack_protected_config, data); +} + void upload_pack(const int advertise_refs, const int stateless_rpc, const int timeout) { @@ -1340,8 +1349,7 @@ void upload_pack(const int advertise_refs, const int stateless_rpc, struct upload_pack_data data; upload_pack_data_init(&data); - - git_config(upload_pack_config, &data); + get_upload_pack_config(&data); data.stateless_rpc = stateless_rpc; data.timeout = timeout; @@ -1695,8 +1703,7 @@ int upload_pack_v2(struct repository *r, struct packet_reader *request) upload_pack_data_init(&data); data.use_sideband = LARGE_PACKET_MAX; - - git_config(upload_pack_config, &data); + get_upload_pack_config(&data); while (state != FETCH_DONE) { switch (state) { From patchwork Thu Jul 14 21:28:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12918501 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 187C3C433EF for ; Thu, 14 Jul 2022 21:28:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240852AbiGNV2Z (ORCPT ); Thu, 14 Jul 2022 17:28:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57066 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240493AbiGNV2W (ORCPT ); Thu, 14 Jul 2022 17:28:22 -0400 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D3E5C6E889 for ; Thu, 14 Jul 2022 14:28:12 -0700 (PDT) Received: by mail-wm1-x332.google.com with SMTP id v67-20020a1cac46000000b003a1888b9d36so3812668wme.0 for ; Thu, 14 Jul 2022 14:28:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=3Jrh+W7kpE1LBYTVD/EsZcJLLfqG63kOKPgXVwLryUo=; b=HMSRUC9JE6Wh24ckMLFU8UZD0EY58yI+OPDkn0gU6GWMt6ysMlhfykJgMzq9MGEXdC I+kFmoH7qf41eUFsyoB2XUQfJ5XnIDkYr+Z77JtrSmn4WMw8HJ+OIyDWVnj/xrJUJuVA 0pyJrtv9TdgXkqa3JdIG5kKsKl9VUjrbcxqOVGNZoB6mm9rWtqmKIbQRSXQ0j5vjfU29 +BeexmqDGdleaR2KI/+R1jdICe0ZtKQ9A7wfqOhOFgq4xRcBX4VrcKnhH09yPOm9BVIA A38lsPl8va7YT17U60WCafEHo51mOyt4Fh2oLT7lkwKG5Mc2kx+9dM4RbfhzmF/fMkn9 0+MA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=3Jrh+W7kpE1LBYTVD/EsZcJLLfqG63kOKPgXVwLryUo=; b=nacEOzKQpVWuciR9s7d9KuVvsTKISf8dM1TEb8culWRe2j1JLvPwnwNRHK15W3V10Y g9wTM1Q7uwNYltPzI4DZJXQSqcc7u3VApc9yQzDeCMx64hfom3nCZYugT6usy3sjrDZG ob49TDCA04JyD0wDzigQGqyxURgztSuR9oFbNK2BewphsyPs1bfKNnoXKKilor/fx1BA cV/W9YGzd2tSGzsHp3dqdjAzu9GFVmZNsCo0WBpzW3X4anDWRiBuuJAdtJQq/NPbXMTy 8nLDCFD3SewXvCKsnpLQMx+BqVW5vDQSTsAq479reL66uAWFy0wQUGcDDOg0WODcZd4m TPmQ== X-Gm-Message-State: AJIora9vXP9Run+HY9h8Fc+hFlo0025p+IgDchWuHfprXZeExXYS5VGw rf/w3EWyKZW9Obj2gIXmv6KgO9ceWnk= X-Google-Smtp-Source: AGRyM1udkwBfxsn52IumWJe1OPhA2RmcdrEi/RyFqOrwf8LTfPFs5+LDLHeGWQOapCDe5eWBX/8rZg== X-Received: by 2002:a7b:ce04:0:b0:3a1:92e0:d889 with SMTP id m4-20020a7bce04000000b003a192e0d889mr10886030wmc.131.1657834091076; Thu, 14 Jul 2022 14:28:11 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id p6-20020a05600c358600b003a2e2ba94ecsm6514785wmq.40.2022.07.14.14.28.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Jul 2022 14:28:09 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Thu, 14 Jul 2022 21:28:00 +0000 Subject: [PATCH v8 4/5] safe.directory: use git_protected_config() Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Johannes Schindelin , Glen Choo , Glen Choo Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Glen Choo From: Glen Choo Use git_protected_config() to read `safe.directory` instead of read_very_early_config(), making it 'protected configuration only'. As a result, `safe.directory` now respects "-c", so update the tests and docs accordingly. It used to ignore "-c" due to how it was implemented, not because of security or correctness concerns [1]. [1] https://lore.kernel.org/git/xmqqlevabcsu.fsf@gitster.g/ Signed-off-by: Glen Choo --- Documentation/config/safe.txt | 6 +++--- setup.c | 2 +- t/t0033-safe-directory.sh | 24 ++++++++++-------------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt index fa02f3ccc54..f72b4408798 100644 --- a/Documentation/config/safe.txt +++ b/Documentation/config/safe.txt @@ -12,9 +12,9 @@ via `git config --add`. To reset the list of safe directories (e.g. to override any such directories specified in the system config), add a `safe.directory` entry with an empty value. + -This config setting is only respected when specified in a system or global -config, not when it is specified in a repository config, via the command -line option `-c safe.directory=`, or in environment variables. +This config setting is only respected in protected configuration (see +<>). This prevents the untrusted repository from tampering with this +value. + The value of this setting is interpolated, i.e. `~/` expands to a path relative to the home directory and `%(prefix)/` expands to a diff --git a/setup.c b/setup.c index 09b6549ba9e..ec5b9139e32 100644 --- a/setup.c +++ b/setup.c @@ -1155,7 +1155,7 @@ static int ensure_valid_ownership(const char *gitfile, * constant regardless of what failed above. data.is_safe should be * initialized to false, and might be changed by the callback. */ - read_very_early_config(safe_directory_cb, &data); + git_protected_config(safe_directory_cb, &data); return data.is_safe; } diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh index 3908597d42d..f4d737dadd0 100755 --- a/t/t0033-safe-directory.sh +++ b/t/t0033-safe-directory.sh @@ -16,24 +16,20 @@ test_expect_success 'safe.directory is not set' ' expect_rejected_dir ' -test_expect_success 'ignoring safe.directory on the command line' ' - test_must_fail git -c safe.directory="$(pwd)" status 2>err && - grep "dubious ownership" err +test_expect_success 'safe.directory on the command line' ' + git -c safe.directory="$(pwd)" status ' -test_expect_success 'ignoring safe.directory in the environment' ' - test_must_fail env GIT_CONFIG_COUNT=1 \ - GIT_CONFIG_KEY_0="safe.directory" \ - GIT_CONFIG_VALUE_0="$(pwd)" \ - git status 2>err && - grep "dubious ownership" err +test_expect_success 'safe.directory in the environment' ' + env GIT_CONFIG_COUNT=1 \ + GIT_CONFIG_KEY_0="safe.directory" \ + GIT_CONFIG_VALUE_0="$(pwd)" \ + git status ' -test_expect_success 'ignoring safe.directory in GIT_CONFIG_PARAMETERS' ' - test_must_fail env \ - GIT_CONFIG_PARAMETERS="${SQ}safe.directory${SQ}=${SQ}$(pwd)${SQ}" \ - git status 2>err && - grep "dubious ownership" err +test_expect_success 'safe.directory in GIT_CONFIG_PARAMETERS' ' + env GIT_CONFIG_PARAMETERS="${SQ}safe.directory${SQ}=${SQ}$(pwd)${SQ}" \ + git status ' test_expect_success 'ignoring safe.directory in repo config' ' From patchwork Thu Jul 14 21:28:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12918502 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E39D2C43334 for ; Thu, 14 Jul 2022 21:28:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240895AbiGNV21 (ORCPT ); Thu, 14 Jul 2022 17:28:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57076 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240857AbiGNV2X (ORCPT ); Thu, 14 Jul 2022 17:28:23 -0400 Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 12F3E6E8AF for ; Thu, 14 Jul 2022 14:28:14 -0700 (PDT) Received: by mail-wr1-x429.google.com with SMTP id b26so4251542wrc.2 for ; Thu, 14 Jul 2022 14:28:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=J2Cb2WV8SPtEBLtqk3N15f0DIedhfAPPcbM8ECmqUYk=; b=QUnynFfM4XStAJym8LTUm8t51Dg4lUZwz3Pa4eUoGgBXVGy4ScW1RwpaYoX073Xvbw o2HBFWJe4mBGP38BDrFOi9u+oUbaEWWth6wX1Oo+IumHVX42X2Y15culyWkaDQEiau7R VQ+fNKbGEKqA9noiybbSdNb0nyc0QrVdCAC1bl1ZRGTVSEaUGu3TQeYE6ZE/txYna2CD emrCjkTyk1VP4LudyydQ0qPD14UMiBs3jhjXARDXrZCUdBwxea9XgXNu+1BuHg5RRTNC h4HPk2mPbBbHHcO8MJVyNJW/4SuRgI/zsnODAnimhpoUkEQPIAqql5FS9UUpGWn4URbn 0iLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=J2Cb2WV8SPtEBLtqk3N15f0DIedhfAPPcbM8ECmqUYk=; b=fKfM+Fed+djpUz6kXrhA72Q8W+QyOUnDaP89KP0qDUzBENldklgIOg6Cfd+Vp6Y1Cs HepQmdG699P1Rie/PL15j6JDApDYu7yOUGFY3hepLtkgWn7WdMuWkL/lz52uSoOrH5Fe KLJvIrPujTmEFJJYQ4sIqMTGzyEAmuD6Cq8bnN8JXmg1qGUjXrlfGeEZnx4YzK+M9HQl qJTdsD3wy043vr7RiLySCjHZ63UFSvRfzoPGRbxIurpeYq8CJF02Fc08+o4qQVInBiOE dXGDY5gSwWc8nFXxKFzPX3VrfeAmHuYmy9IyXHMAaVj2EkgEeGwytGCQxYJrSgttKL5R WU9w== X-Gm-Message-State: AJIora/Am0jFD9fHVF2//I/auKFj78g+gU75DblzqrXtFB5EDYqiuqAS t+wjMt3jDV1N8TGBSpIRZWBvvKpxQA0= X-Google-Smtp-Source: AGRyM1sAtcWGXm6rBgsZN46S7LuY5W3UTS/AUDIBgCUPvkPycAaRjYos6mzoyA1wOUVG+OZ6qh+zvA== X-Received: by 2002:a05:6000:1f0b:b0:21d:6dae:7d04 with SMTP id bv11-20020a0560001f0b00b0021d6dae7d04mr9967844wrb.414.1657834092162; Thu, 14 Jul 2022 14:28:12 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id n66-20020a1ca445000000b003a02de5de80sm6665224wme.4.2022.07.14.14.28.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Jul 2022 14:28:11 -0700 (PDT) Message-Id: <50069bba9a5933fd968a8aa52acefc2a305204f5.1657834082.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 14 Jul 2022 21:28:01 +0000 Subject: [PATCH v8 5/5] setup.c: create `safe.bareRepository` Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Johannes Schindelin , Glen Choo , Glen Choo Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Glen Choo From: Glen Choo There is a known social engineering attack that takes advantage of the fact that a working tree can include an entire bare repository, including a config file. A user could run a Git command inside the bare repository thinking that the config file of the 'outer' repository would be used, but in reality, the bare repository's config file (which is attacker-controlled) is used, which may result in arbitrary code execution. See [1] for a fuller description and deeper discussion. A simple mitigation is to forbid bare repositories unless specified via `--git-dir` or `GIT_DIR`. In environments that don't use bare repositories, this would be minimally disruptive. Create a config variable, `safe.bareRepository`, that tells Git whether or not to die() when working with a bare repository. This config is an enum of: - "all": allow all bare repositories (this is the default) - "explicit": only allow bare repositories specified via --git-dir or GIT_DIR. If we want to protect users from such attacks by default, neither value will suffice - "all" provides no protection, but "explicit" is impractical for bare repository users. A more usable default would be to allow only non-embedded bare repositories ([2] contains one such proposal), but detecting if a repository is embedded is potentially non-trivial, so this work is not implemented in this series. [1]: https://lore.kernel.org/git/kl6lsfqpygsj.fsf@chooglen-macbookpro.roam.corp.google.com [2]: https://lore.kernel.org/git/5b969c5e-e802-c447-ad25-6acc0b784582@github.com Signed-off-by: Glen Choo --- Documentation/config/safe.txt | 19 +++++++++++ setup.c | 57 ++++++++++++++++++++++++++++++++- t/t0035-safe-bare-repository.sh | 54 +++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100755 t/t0035-safe-bare-repository.sh diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt index f72b4408798..bde7f31459b 100644 --- a/Documentation/config/safe.txt +++ b/Documentation/config/safe.txt @@ -1,3 +1,22 @@ +safe.bareRepository:: + Specifies which bare repositories Git will work with. The currently + supported values are: ++ +* `all`: Git works with all bare repositories. This is the default. +* `explicit`: Git only works with bare repositories specified via + the top-level `--git-dir` command-line option, or the `GIT_DIR` + environment variable (see linkgit:git[1]). ++ +If you do not use bare repositories in your workflow, then it may be +beneficial to set `safe.bareRepository` to `explicit` in your global +config. This will protect you from attacks that involve cloning a +repository that contains a bare repository and running a Git command +within that directory. ++ +This config setting is only respected in protected configuration (see +<>). This prevents the untrusted repository from tampering with +this value. + safe.directory:: These config entries specify Git-tracked directories that are considered safe even if they are owned by someone other than the diff --git a/setup.c b/setup.c index ec5b9139e32..8c683e92b62 100644 --- a/setup.c +++ b/setup.c @@ -10,6 +10,10 @@ static int inside_git_dir = -1; static int inside_work_tree = -1; static int work_tree_config_is_bogus; +enum allowed_bare_repo { + ALLOWED_BARE_REPO_EXPLICIT = 0, + ALLOWED_BARE_REPO_ALL, +}; static struct startup_info the_startup_info; struct startup_info *startup_info = &the_startup_info; @@ -1160,6 +1164,46 @@ static int ensure_valid_ownership(const char *gitfile, return data.is_safe; } +static int allowed_bare_repo_cb(const char *key, const char *value, void *d) +{ + enum allowed_bare_repo *allowed_bare_repo = d; + + if (strcasecmp(key, "safe.bareRepository")) + return 0; + + if (!strcmp(value, "explicit")) { + *allowed_bare_repo = ALLOWED_BARE_REPO_EXPLICIT; + return 0; + } + if (!strcmp(value, "all")) { + *allowed_bare_repo = ALLOWED_BARE_REPO_ALL; + return 0; + } + return -1; +} + +static enum allowed_bare_repo get_allowed_bare_repo(void) +{ + enum allowed_bare_repo result = ALLOWED_BARE_REPO_ALL; + git_protected_config(allowed_bare_repo_cb, &result); + return result; +} + +static const char *allowed_bare_repo_to_string( + enum allowed_bare_repo allowed_bare_repo) +{ + switch (allowed_bare_repo) { + case ALLOWED_BARE_REPO_EXPLICIT: + return "explicit"; + case ALLOWED_BARE_REPO_ALL: + return "all"; + default: + BUG("invalid allowed_bare_repo %d", + allowed_bare_repo); + } + return NULL; +} + enum discovery_result { GIT_DIR_NONE = 0, GIT_DIR_EXPLICIT, @@ -1169,7 +1213,8 @@ enum discovery_result { GIT_DIR_HIT_CEILING = -1, GIT_DIR_HIT_MOUNT_POINT = -2, GIT_DIR_INVALID_GITFILE = -3, - GIT_DIR_INVALID_OWNERSHIP = -4 + GIT_DIR_INVALID_OWNERSHIP = -4, + GIT_DIR_DISALLOWED_BARE = -5, }; /* @@ -1297,6 +1342,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir, } if (is_git_directory(dir->buf)) { + if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT) + return GIT_DIR_DISALLOWED_BARE; if (!ensure_valid_ownership(NULL, NULL, dir->buf)) return GIT_DIR_INVALID_OWNERSHIP; strbuf_addstr(gitdir, "."); @@ -1443,6 +1490,14 @@ const char *setup_git_directory_gently(int *nongit_ok) } *nongit_ok = 1; break; + case GIT_DIR_DISALLOWED_BARE: + if (!nongit_ok) { + die(_("cannot use bare repository '%s' (safe.bareRepository is '%s')"), + dir.buf, + allowed_bare_repo_to_string(get_allowed_bare_repo())); + } + *nongit_ok = 1; + break; case GIT_DIR_NONE: /* * As a safeguard against setup_git_directory_gently_1 returning diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh new file mode 100755 index 00000000000..ecbdc8238db --- /dev/null +++ b/t/t0035-safe-bare-repository.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +test_description='verify safe.bareRepository checks' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +pwd="$(pwd)" + +expect_accepted () { + git "$@" rev-parse --git-dir +} + +expect_rejected () { + test_must_fail git "$@" rev-parse --git-dir 2>err && + grep -F "cannot use bare repository" err +} + +test_expect_success 'setup bare repo in worktree' ' + git init outer-repo && + git init --bare outer-repo/bare-repo +' + +test_expect_success 'safe.bareRepository unset' ' + expect_accepted -C outer-repo/bare-repo +' + +test_expect_success 'safe.bareRepository=all' ' + test_config_global safe.bareRepository all && + expect_accepted -C outer-repo/bare-repo +' + +test_expect_success 'safe.bareRepository=explicit' ' + test_config_global safe.bareRepository explicit && + expect_rejected -C outer-repo/bare-repo +' + +test_expect_success 'safe.bareRepository in the repository' ' + # safe.bareRepository must not be "explicit", otherwise + # git config fails with "fatal: not in a git directory" (like + # safe.directory) + test_config -C outer-repo/bare-repo safe.bareRepository \ + all && + test_config_global safe.bareRepository explicit && + expect_rejected -C outer-repo/bare-repo +' + +test_expect_success 'safe.bareRepository on the command line' ' + test_config_global safe.bareRepository explicit && + expect_accepted -C outer-repo/bare-repo \ + -c safe.bareRepository=all +' + +test_done