From patchwork Thu Jul 7 23:01:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12910374 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 13F8FC433EF for ; Thu, 7 Jul 2022 23:02:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236797AbiGGXCB (ORCPT ); Thu, 7 Jul 2022 19:02:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49624 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229638AbiGGXCA (ORCPT ); Thu, 7 Jul 2022 19:02:00 -0400 Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 94EFE61D56 for ; Thu, 7 Jul 2022 16:01:59 -0700 (PDT) Received: by mail-wm1-x334.google.com with SMTP id l68so11475767wml.3 for ; Thu, 07 Jul 2022 16:01:59 -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=8Qz+S/OrOXvnbR+HijT7+g7W+Gpg9orhEeI8xyfH0Dg=; b=YgJYlh/e87qwIUpm/e3JujX516XP1ynSOaWYKEPXZJvTFZ8ub2ANSnfy1lnVW54CG9 PAOGeNNpiPc98hd4inkxDL62Hrv+I1d6BZTGxuEw/yT9kYL8CVa2hj1x6rQleLd5bMLH QCXE/DIcDH+2rIcUk5d4ML8TF0eib78i3NmRYKu/axzMWKKGVxnF64zIC1xtVyslLIjv eWsWddhUr/Ae3Vvl6zffdaQZ87fqHcWw35E5fDWlppaDt2brf9HWe4IW3ldgiNoWU2bX ucZgRvoXiYI/MlbX66WyCfmqTr3blnfaVkI98eGs4uHAVQbXtSn6EQgIgTLUYQAey0Sa C/KA== 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=8Qz+S/OrOXvnbR+HijT7+g7W+Gpg9orhEeI8xyfH0Dg=; b=4zIG26Ax//2/IJTy2pf97srpyq+2UrzPndXvAudWwuESyey//Hb8c7EuB0ItsMrFP2 41lNIWji7iJGNr/IrgrIBT/MgRjCU26RlkFYy34je8yLw4PoxE6GnAVjcX26AxSX8gTY 5L+jhvSIyxD+IWO2NEtRs1nfz0CgZCF2V952gP1RyS18tRLc20YznqtgIMKoUQRsm8QL 4K1RxemQkjzizqI5UKXIz2I46l83OHIZEMyocodMffz46lOnuGUD1NljZBgx/uTgEY7t inzAs6bd4KVtkBD/0YvbLdvoeKDSsPRf/512bUyhJ/5JS03q/uaHslFdcHJGJZeHj05F ELNg== X-Gm-Message-State: AJIora8v/KI1dvuoIk57IiCjOOf4wNGuP5s3vhmeoICs2CqduEZjF3Z7 Ef7Bo1mvlEwAPYX0nDfTAU+dNcPwlzU= X-Google-Smtp-Source: AGRyM1tglgw2uiRH9pV8iPngrU5i6MvDj1QMQQN+8EAcmQSSwyyY2cf3xCgM25L54LFTbcuarcGTXA== X-Received: by 2002:a05:600c:1ca9:b0:3a0:43a9:5e1a with SMTP id k41-20020a05600c1ca900b003a043a95e1amr189227wms.155.1657234917778; Thu, 07 Jul 2022 16:01:57 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id a16-20020a5d5090000000b0021d819c8f6dsm3882006wrt.39.2022.07.07.16.01.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:01:56 -0700 (PDT) Message-Id: <5c58db3bb2189f3b4193a682aa3b43f3bfa95796.1657234914.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 07 Jul 2022 23:01:50 +0000 Subject: [PATCH v7 1/5] Documentation/git-config.txt: add SCOPES section Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , "brian m. carlson" , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , 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 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 | 65 ++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 9376e39aef2..c4ce61a0493 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -297,8 +297,8 @@ 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. @@ -322,27 +322,64 @@ $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 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. Note that neither case +produces an error message. 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:: + environment variables ++ +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 ----------- From patchwork Thu Jul 7 23:01:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12910376 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 97CFFC433EF for ; Thu, 7 Jul 2022 23:02:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236839AbiGGXCH (ORCPT ); Thu, 7 Jul 2022 19:02:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49642 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236808AbiGGXCC (ORCPT ); Thu, 7 Jul 2022 19:02:02 -0400 Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C425861D56 for ; Thu, 7 Jul 2022 16:02:00 -0700 (PDT) Received: by mail-wr1-x434.google.com with SMTP id o4so28275681wrh.3 for ; Thu, 07 Jul 2022 16:02:00 -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=byqMmsgnHvuT3IFtXPJEwT40pUJAAW0lFE4L3PklnTs=; b=hgQ/sHh4byZBKcaI0h9NFwVh0ZmVXJAsD3J7FXEeiP0dAte3RQAokO62r7LoW+C/6t qAGl1OhDzaZHF4zMgiR14sfsj9LYJRgesTx/7PFZKYTteuob7kAs8FCkraDJnEpq6VWH EKrq4EZNEsM42dc++vlOo2iZgPRHKxRUFTghwC/7DP0llQ8xdix8j35Bt4EdsgTPPoih ZDRPL+Fu5i2S+BUQC+bwADnKDnbHwpDT1WBt1iX1E9t//pcC9HXTfl4ZrC9Mbpet1oOq E0mGoeinMlBMy8onT+2eOKJLdWBFafpks6V6LC09MVRqKpPnYkZMr6TvCIxqw0HEkFV4 WjJA== 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=byqMmsgnHvuT3IFtXPJEwT40pUJAAW0lFE4L3PklnTs=; b=LOe47E5POz+bD6XDOPqgwOYOO02/WBA+rtSaWBO8eG+gMTOzHKf1GC6b/NuimO+iLP X7hk4T3zzgMtDbDzVJjRci6E3UYZAiUfZv4gufI1w0vZkC/aax8kDt9PgFPq+yLf4PDE FtqeXZxSl3g2ZG43CWukSRAtEwscYeBNPeskzD+ZB7nF4btUUTn+beteyhG4uuqAgECc a5B+7HxHO6OCjwDQC0A5LcTUMcTerCxoTLrZNKsjxxOA6+2oRUv3Rizv3cFWM8wTXrmv 9hEXkbVYNTCKY+2r71XvCmt46lfv/cApnmu7CxjInCuHJ7F27jzox4c4yDmhfFs8iHH6 tk5Q== X-Gm-Message-State: AJIora84ieWXp9w+h9CsxVKtQsuHXSjbv6bgzE2bCL8gI6gt9sDSFkQH ifO4UYS/qsLQj0HEQZJT0Rf+OMsCSEE= X-Google-Smtp-Source: AGRyM1v5M+/Rw+GAOCgky4kg4FWvM3VIyffAMdEuavXEst5Z1hf9s4gk6PHWoSHDNy4W49lnK0tJNw== X-Received: by 2002:adf:fa4a:0:b0:21d:6904:f0b9 with SMTP id y10-20020adffa4a000000b0021d6904f0b9mr237373wrr.167.1657234919036; Thu, 07 Jul 2022 16:01:59 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id z9-20020a5d4409000000b0021d86796294sm2665685wrq.59.2022.07.07.16.01.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:01:58 -0700 (PDT) Message-Id: <58f25612aa385c3ac9f48f908ccc4d0d02d58b8c.1657234914.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 07 Jul 2022 23:01:51 +0000 Subject: [PATCH v7 2/5] Documentation: define protected configuration Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , "brian m. carlson" , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , 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 c4ce61a0493..2dc74f510f2 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -344,6 +344,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 ------ @@ -381,6 +382,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 ----------- From patchwork Thu Jul 7 23:01:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12910377 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 9F43BC43334 for ; Thu, 7 Jul 2022 23:02:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236843AbiGGXCR (ORCPT ); Thu, 7 Jul 2022 19:02:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49658 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236823AbiGGXCD (ORCPT ); Thu, 7 Jul 2022 19:02:03 -0400 Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 09FEF61D58 for ; Thu, 7 Jul 2022 16:02:02 -0700 (PDT) Received: by mail-wr1-x432.google.com with SMTP id h17so15114771wrx.0 for ; Thu, 07 Jul 2022 16:02:01 -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=+47/GbOutYwggWiEVTgWMbNChHz1yDrXOQT+AmNQ6P0=; b=mfhf+B9Bxh0GbslVYnm0dFVKx5zK18yqKNQbBjNlyDRJ8IhESL+ctizL2x8TKaV9Oa Ck6SkJQKz1sXHldvUeuhx4qN2UOiwmYPsvUN843duGjMi1OMJjrEsq9XjHN5P/TomyDg Zds4T+57Nbv0N6rJphZ2uHPQaxFu0RDhy4lnhoSS+sLv1xEJQAwCZJnHU/LRmKkmp2OZ OZNJg3Pwab2yAph1TE++G0pB5RRW5ztwsVIPvXOvzW13fpuqXPPM1jVTB8W2Ug9rFYmG 9fda9HiLoQV0NyFLMIcA2meD5O1ppK0LW0nAWJaRrnUpkFxcI/Eo+hpz2i0ANElzMoRa Boyg== 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=+47/GbOutYwggWiEVTgWMbNChHz1yDrXOQT+AmNQ6P0=; b=sCDIITJ0+X77ok/uN0z0W+bjaJKoyZ+2LPQ1lcuI5L0gVP9K9LV6w+n1kJaYG+Xvfc w4MnISW+GOq29xaDdG+3EwBHQkDMchbYaOWTNKNp5XhfdjzJf9+y1HgbTm6ByW/h55j+ bLXHHkfrqQDx0z32HRm0mju7cPwoIbptEOpK2CvexuRW0h5xi0OC9UUHyj/YG0VAblxi 5/C8o/Rzpmt7Vp2OF6LRangMLzjK6zF3AluQvqNR6Iid2Pvftedskb/QAr6SRk3sZTkh 73czHzjE8VzvXuJspB6G6F/TJdiVB/1vN6ofk1vGBgbmFzU5sOsUMZQEJ/2zEshc5UvR sw8w== X-Gm-Message-State: AJIora+EXhc4i0QlNpK8oNUzU3N3bghYokBjbJpCV6J13lJ1uCys4+qk fqlq978noYBIVC4OGlrJb+au6/no3Ec= X-Google-Smtp-Source: AGRyM1swETGGcE0hE9pjJ57ASAsPe8+6mEl1c9x5KXHnqDrzTcBFsi4hp277chFmghu3/hAYbHvZVA== X-Received: by 2002:a05:6000:1a88:b0:21b:ca70:f61d with SMTP id f8-20020a0560001a8800b0021bca70f61dmr235145wry.619.1657234920218; Thu, 07 Jul 2022 16:02:00 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id k12-20020adff5cc000000b0021d80f53324sm4188835wrp.7.2022.07.07.16.01.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:01:59 -0700 (PDT) Message-Id: <3683d20f23218260bf4f4555a385205f03012565.1657234914.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 07 Jul 2022 23:01:52 +0000 Subject: [PATCH v7 3/5] config: learn `git_protected_config()` Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , "brian m. carlson" , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , 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 `discovery.bare` 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 `discovery.bare`, so we cannot afford to be slow. 2. Protected configuration must be readable when the gitdir is not known. `safe.directory` and `discovery.bare` 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 7 23:01:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12910378 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 72AA9C433EF for ; Thu, 7 Jul 2022 23:02:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236859AbiGGXCS (ORCPT ); Thu, 7 Jul 2022 19:02:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49668 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236824AbiGGXCE (ORCPT ); Thu, 7 Jul 2022 19:02:04 -0400 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4AC4661D61 for ; Thu, 7 Jul 2022 16:02:03 -0700 (PDT) Received: by mail-wr1-x42c.google.com with SMTP id n10so2968371wrc.4 for ; Thu, 07 Jul 2022 16:02:03 -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=vK/cK2CsYvziF+h6RxKNGee1lI7W8gvh+Wi2KpMeAJo=; b=UNEbkqZrK1rGHQWtMDCXUb8SDnBcBCCbcCapbeoVoDADoH78JVW5NO1J6gueJXeNJJ zeLmpiXrjABeZmf9cPkwzy+BKrpigE8OlGxT6vbp/rnR1ngUIJ9EsXsSN1ZO5iMtAHFz PXdl/ioJB6IMWAq9pzvGqxaNlagjft90O7t5Q2pwuFAlK0u7I2A9Zco20F1qnjxUekLU lzMpwWwVZwYR6wKDCSEOTDGFIHt9tzXZ0oxonV9dZwYjXoi8BastU0TOyFCUfBUs4Pzf /5J8/GIqy6R8+aYyBdlrpKHUsHPbn13VG6O3SEQkhxlmwBxGjSltgpX5b6KcPyHRaRu+ 4OlQ== 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=vK/cK2CsYvziF+h6RxKNGee1lI7W8gvh+Wi2KpMeAJo=; b=w3Zf5ion5vhqweoes9UfvNVlxDPGROwwz/46H7s1A087SMp8G4e8Hyth7s6+cdgyVj XGUn61LFWMwhYis43Dg1DjolkRbZQVxqnazcC0xtxOQxd6MYywARS77uQrML+zIC4i4W EB3PA6XG7hSUr6vX5/UFHMo5JaXw9clgWx0GSenrX75fI0l0efE8RDEAQHm0HXoSmS9B 6cYJdgM9t1Jto2tagAocWyM956SU08pdapI8qntNOOkFrQH8MOmr1HxY2fILBw7/gn9f m585RCKb7QwfFjYDN/2gvI8ohLDXRL48oKJ9OZztkyTxnMkLTc+CmvgKZS5T1DGqXWni ld7w== X-Gm-Message-State: AJIora+5xnb0RaAjSFQfiqXoS6ZxnO0jdzEOq4KyXlZd7dNjdB8iOpYX EurCFjK1kpQOpCV4zJueltJ2VfBEcqk= X-Google-Smtp-Source: AGRyM1vom6pSLDeaIaRV2721znrDNisMfkeirbNNuC0g5guj1rxw8LbWiGt7y6booDeY0HibnEwz4Q== X-Received: by 2002:adf:f20e:0:b0:21d:8aa6:69da with SMTP id p14-20020adff20e000000b0021d8aa669damr263785wro.66.1657234921462; Thu, 07 Jul 2022 16:02:01 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id t7-20020adfe447000000b0021d83071683sm3469011wrm.64.2022.07.07.16.02.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:02:00 -0700 (PDT) Message-Id: <6394818ffd84928910273eedcd9f84e7e47f9dce.1657234915.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 07 Jul 2022 23:01:53 +0000 Subject: [PATCH v7 4/5] safe.directory: use git_protected_config() Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , "brian m. carlson" , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , 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 faf5095e44d..c8e3c32814d 100644 --- a/setup.c +++ b/setup.c @@ -1137,7 +1137,7 @@ static int ensure_valid_ownership(const char *path) is_path_owned_by_current_user(path)) return 1; - 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 238b25f91a3..5a1cd0d0947 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 "unsafe repository" 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 "unsafe repository" 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 "unsafe repository" 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 7 23:01:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glen Choo X-Patchwork-Id: 12910379 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 D2547C43334 for ; Thu, 7 Jul 2022 23:02:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236913AbiGGXCV (ORCPT ); Thu, 7 Jul 2022 19:02:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49670 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236826AbiGGXCE (ORCPT ); Thu, 7 Jul 2022 19:02:04 -0400 Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 694C865D58 for ; Thu, 7 Jul 2022 16:02:03 -0700 (PDT) Received: by mail-wr1-x434.google.com with SMTP id o4so28275838wrh.3 for ; Thu, 07 Jul 2022 16:02:03 -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=Dubs6AAl7Oy/A3rvgA7PHKaHn0sZ1RdxAvUqFkWj+rU=; b=Sfg/SAa5jEI87cLc3uOCKjvPta9DqgT//VYZ78t5AsaYWVm4AwOQ/JNcK04GqUEKJt qrsxCfXKNWfLNyH9sCxhi38Vv1WVTaNLrM6X84zVwvRa0Sc6SuQvU4oTgtnf6IoB+Lyn pZcmooo1XT4Fxc+BsmWOf1lwcdjfKhDeMRpdp71lZiKO+ne5FnmGTnp7FBXHZQuWeqcp cL4kSjzl7VWpiT4qFSEPTzgg3oBO/LHwb+itJZXxMzcvBuERXbNNL5xzzdXVXkmHEq9k k0k/Xl1NzSN2bmUNWeW0FtDp3PO+y/iwmaLejX5YHYSZUFg5gllzt6xVW4dyjbN1aAjZ FE/g== 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=Dubs6AAl7Oy/A3rvgA7PHKaHn0sZ1RdxAvUqFkWj+rU=; b=MqmOceEBt9+U8h6dWzzKi8y9yIYy48MULb/9hCvl/w2snPOFfi8wRY2/uqc62hBQgT /wt8Ml1DG8I0BlsfPG5UB7XcKFgQ5eax0afWY+DZ904KXWWiuYe4Ve1if7/l1FLRifE5 dfAKRh0eaMY1Jl82+KRpvNpN5z34VbrkgLBrT58PUs+oRQP88R88eF/pxLVYcJUCvQci RNNGjZSwlDUedAMykM2S7ztWU5Xlm9hEVd3DsWqtpSKSITB/RywcDpp7ozHp9PqE50CB PcKqheTfT4trEGR4gL5B1ozt+34Esplu0kVwESC8foh+/bnF9s5pRBT45L/QRV33VER+ znpg== X-Gm-Message-State: AJIora/U7tcv0BLo4VnWWaAC3vCWDqlyf9IZsDO8/86KDJ9KS/PcCxi7 EWIsJ2lfqQZYrlrLOrl2xfQhYJ3NsCM= X-Google-Smtp-Source: AGRyM1vwYTD3GrZ7p9+InEiDTenshGhjw/5PI74tFg/vX02vxWg2ygsMDN9+5brzJY/peRuHBZtRFQ== X-Received: by 2002:a5d:5e8d:0:b0:21b:a919:7da with SMTP id ck13-20020a5d5e8d000000b0021ba91907damr265248wrb.530.1657234922672; Thu, 07 Jul 2022 16:02:02 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id b18-20020a05600c4e1200b003a2d47d3051sm193754wmq.41.2022.07.07.16.02.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jul 2022 16:02:02 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Thu, 07 Jul 2022 23:01:54 +0000 Subject: [PATCH v7 5/5] setup.c: create `discovery.bare` Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Taylor Blau , "brian m. carlson" , Derrick Stolee , Junio C Hamano , Emily Shaffer , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , 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, `discovery.bare`, that tells Git whether or not to die() when it discovers a bare repository. This only affects repository discovery, thus it has no effect if discovery was not done, e.g. if the user passes `--git-dir=my-dir`, discovery will be skipped and my-dir will be used as the repo regardless of the `discovery.bare` value. This config is an enum of: - "always": always allow bare repositories (this is the default) - "never": never allow bare repositories If we want to protect users from such attacks by default, neither value will suffice - "always" provides no protection, but "never" 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.txt | 2 ++ Documentation/config/discovery.txt | 21 +++++++++++ setup.c | 57 +++++++++++++++++++++++++++++- t/t0035-discovery-bare.sh | 52 +++++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 Documentation/config/discovery.txt create mode 100755 t/t0035-discovery-bare.sh diff --git a/Documentation/config.txt b/Documentation/config.txt index e284b042f22..9a5e1329772 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -409,6 +409,8 @@ include::config/diff.txt[] include::config/difftool.txt[] +include::config/discovery.txt[] + include::config/extensions.txt[] include::config/fastimport.txt[] diff --git a/Documentation/config/discovery.txt b/Documentation/config/discovery.txt new file mode 100644 index 00000000000..6f38b86884b --- /dev/null +++ b/Documentation/config/discovery.txt @@ -0,0 +1,21 @@ +discovery.bare:: + Specifies whether Git will work with a bare repository that + wasn't specified via the top-level `--git-dir` command-line + option, or the `GIT_DIR` environment variable (see + linkgit:git[1]). If the repository is specified, Git will always + use the specified repository, regardless of this value. ++ +This config setting is only respected in protected configuration (see +<>). This prevents the untrusted repository from tampering with +this value. ++ +The currently supported values are: ++ +* `always`: Git always works with bare repositories +* `never`: Git never works with bare repositories ++ +If you do not use bare repositories in your workflow, then it may be +beneficial to set `discovery.bare` to `never` 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. diff --git a/setup.c b/setup.c index c8e3c32814d..84cd02a1209 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 discovery_bare_allowed { + DISCOVERY_BARE_NEVER = 0, + DISCOVERY_BARE_ALWAYS, +}; static struct startup_info the_startup_info; struct startup_info *startup_info = &the_startup_info; @@ -1142,6 +1146,46 @@ static int ensure_valid_ownership(const char *path) return data.is_safe; } +static int discovery_bare_cb(const char *key, const char *value, void *d) +{ + enum discovery_bare_allowed *discovery_bare_allowed = d; + + if (strcmp(key, "discovery.bare")) + return 0; + + if (!strcmp(value, "never")) { + *discovery_bare_allowed = DISCOVERY_BARE_NEVER; + return 0; + } + if (!strcmp(value, "always")) { + *discovery_bare_allowed = DISCOVERY_BARE_ALWAYS; + return 0; + } + return -1; +} + +static enum discovery_bare_allowed get_discovery_bare(void) +{ + enum discovery_bare_allowed result = DISCOVERY_BARE_ALWAYS; + git_protected_config(discovery_bare_cb, &result); + return result; +} + +static const char *discovery_bare_allowed_to_string( + enum discovery_bare_allowed discovery_bare_allowed) +{ + switch (discovery_bare_allowed) { + case DISCOVERY_BARE_NEVER: + return "never"; + case DISCOVERY_BARE_ALWAYS: + return "always"; + default: + BUG("invalid discovery_bare_allowed %d", + discovery_bare_allowed); + } + return NULL; +} + enum discovery_result { GIT_DIR_NONE = 0, GIT_DIR_EXPLICIT, @@ -1151,7 +1195,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, }; /* @@ -1248,6 +1293,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir, } if (is_git_directory(dir->buf)) { + if (get_discovery_bare() == DISCOVERY_BARE_NEVER) + return GIT_DIR_DISALLOWED_BARE; if (!ensure_valid_ownership(dir->buf)) return GIT_DIR_INVALID_OWNERSHIP; strbuf_addstr(gitdir, "."); @@ -1394,6 +1441,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' (discovery.bare is '%s')"), + dir.buf, + discovery_bare_allowed_to_string(get_discovery_bare())); + } + *nongit_ok = 1; + break; case GIT_DIR_NONE: /* * As a safeguard against setup_git_directory_gently_1 returning diff --git a/t/t0035-discovery-bare.sh b/t/t0035-discovery-bare.sh new file mode 100755 index 00000000000..8f802746530 --- /dev/null +++ b/t/t0035-discovery-bare.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +test_description='verify discovery.bare 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 'discovery.bare unset' ' + expect_accepted -C outer-repo/bare-repo +' + +test_expect_success 'discovery.bare=always' ' + test_config_global discovery.bare always && + expect_accepted -C outer-repo/bare-repo +' + +test_expect_success 'discovery.bare=never' ' + test_config_global discovery.bare never && + expect_rejected -C outer-repo/bare-repo +' + +test_expect_success 'discovery.bare in the repository' ' + # discovery.bare must not be "never", otherwise git config fails + # with "fatal: not in a git directory" (like safe.directory) + test_config -C outer-repo/bare-repo discovery.bare always && + test_config_global discovery.bare never && + expect_rejected -C outer-repo/bare-repo +' + +test_expect_success 'discovery.bare on the command line' ' + test_config_global discovery.bare never && + expect_accepted -C outer-repo/bare-repo \ + -c discovery.bare=always +' + +test_done