diff mbox series

[v5,3/4] t0034: add negative tests and allow git init to mostly work under sudo

Message ID 20220513010020.55361-4-carenas@gmail.com (mailing list archive)
State Accepted
Commit b9063afda17a2aa6310423c9f7b776c41f753091
Headers show
Series fix `sudo make install` regression in maint | expand

Commit Message

Carlo Marcelo Arenas Belón May 13, 2022, 1 a.m. UTC
Add a support library that provides one function that can be used
to run a "scriplet" of commands through sudo and that helps invoking
sudo in the slightly awkward way that is required to ensure it doesn't
block the call (if shell was allowed as tested in the prerequisite)
and it doesn't run the command through a different shell than the one
we intended.

Add additional negative tests as suggested by Junio and that use a
new workspace that is owned by root.

Document a regression that was introduced by previous commits where
root won't be able anymore to access directories they own unless
SUDO_UID is removed from their environment.

The tests document additional ways that this new restriction could
be worked around and the documentation explains why it might be instead
considered a feature, but a "fix" is planned for a future change.

Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 t/lib-sudo.sh                  | 15 ++++++++
 t/t0034-root-safe-directory.sh | 62 ++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)
 create mode 100644 t/lib-sudo.sh

Comments

Junio C Hamano May 13, 2022, 1:20 a.m. UTC | #1
Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:

> Add a support library that provides one function that can be used
> to run a "scriplet" of commands through sudo and that helps invoking
> sudo in the slightly awkward way that is required to ensure it doesn't
> block the call (if shell was allowed as tested in the prerequisite)
> and it doesn't run the command through a different shell than the one
> we intended.
>
> Add additional negative tests as suggested by Junio and that use a
> new workspace that is owned by root.
>
> Document a regression that was introduced by previous commits where
> root won't be able anymore to access directories they own unless
> SUDO_UID is removed from their environment.
>
> The tests document additional ways that this new restriction could
> be worked around and the documentation explains why it might be instead
> considered a feature, but a "fix" is planned for a future change.
>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Phillip Wood <phillip.wood123@gmail.com>
> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>  t/lib-sudo.sh                  | 15 ++++++++
>  t/t0034-root-safe-directory.sh | 62 ++++++++++++++++++++++++++++++++++
>  2 files changed, 77 insertions(+)
>  create mode 100644 t/lib-sudo.sh

Heh.  I am a bit surprised that double sudo would become a separate
prerequisite, instead of a new part of SUDO prerequisite.  After all
we expect from SUDO prerequisite quite a lot (e.g. most sane
installatios facing end-users will futz with $PATH, but we require
not to do so to satisfy the SUDO prereq) and it is already very
narrowly targetted to a throw-away CI environment whose sudo
basically lets us do anything.

But that is not a serious enough "thing" to trigger a reroll.

This step looks good to me (others I'll comment later).

Thanks.
Carlo Marcelo Arenas Belón May 14, 2022, 2:36 p.m. UTC | #2
On Thu, May 12, 2022 at 6:20 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Heh.  I am a bit surprised that double sudo would become a separate
> prerequisite,

It is because it goes away in the optional patch 4, since it won't be
needed anymore after that.
Also, it shared the same test with the other 2 workarounds which moved
into their own (one as you suggested is more of a statement of policy
that says, git trusts the developer and doesn't check if --git-dir or
--worktree (or equivalent means to explicitly identify those parts of
your repository) are used.

and the other, was always "special" since it was documented as an
indicator of what to do which could be considered a least privilege
marker as well.

without the optional patch that brings it back, root MUST indicate
through its use of that (or other "workarounds") that he really meant
to access a directory owned by root, and will instead defalt (when
appropriate) to use the id of the user that invoked sudo, which has
(normally) less privilege.

> of a new part of SUDO prerequisite.  After all
> we expect from SUDO prerequisite quite a lot (e.g. most sane
> installatios facing end-users will futz with $PATH, but we require
> not to do so to satisfy the SUDO prereq) and it is already very
> narrowly targetted to a throw-away CI environment whose sudo
> basically lets us do anything.

just because I didn't want this to become a bigger change that it was already
indeed I'd been "cutting" it since the very beginning, by first
dropping DOAS support and then avoiding moving things around so it
could be easy to backport.

I think I can provide a version of it that might be able to work with
less restrictions that it currently has, but that would get us into
the "test framework integration" that was specifically punted as well.

Carlo
Junio C Hamano May 15, 2022, 4:54 p.m. UTC | #3
Carlo Arenas <carenas@gmail.com> writes:

> On Thu, May 12, 2022 at 6:20 PM Junio C Hamano <gitster@pobox.com> wrote:
>>
>> Heh.  I am a bit surprised that double sudo would become a separate
>> prerequisite,
>
> It is because it goes away in the optional patch 4, since it won't be
> needed anymore after that.

Hmph, it may not be needed, but it should still work, in which case
it probably is still worth testing, even with the optional patch #4.

No?
Carlo Marcelo Arenas Belón May 15, 2022, 7:21 p.m. UTC | #4
On Sun, May 15, 2022 at 9:54 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> Carlo Arenas <carenas@gmail.com> writes:
>
> > On Thu, May 12, 2022 at 6:20 PM Junio C Hamano <gitster@pobox.com> wrote:
> >>
> >> Heh.  I am a bit surprised that double sudo would become a separate
> >> prerequisite,
> >
> > It is because it goes away in the optional patch 4, since it won't be
> > needed anymore after that.
>
> Hmph, it may not be needed, but it should still work, in which case
> it probably is still worth testing, even with the optional patch #4.

Just because it works, it doesn't mean we have to test it.

IMHO tests are better reserved for things that might not work or that
should work, so this gets in the same bucket than "triple sudo" would
go, and interestingly enough we could add that test without having to
add a new prerequisite too!

> No?

Your call, my assumption was (since this patch is part of this series,
albeit optional), that the "double sudo" need will be short lived and
therefore better not to have this test to begin with, or remove it as
soon as the need is gone, which in practice would be the time between
when this series (without the optional patch) is released, and the
time that optional path gets released (maybe as part of another
series, since it might be dropped from this one).

alternatively we can make it not optional, and then the test will
NEVER be needed.

Carlo
Junio C Hamano May 16, 2022, 5:27 a.m. UTC | #5
Carlo Arenas <carenas@gmail.com> writes:

>> Hmph, it may not be needed, but it should still work, in which case
>> it probably is still worth testing, even with the optional patch #4.
>
> Just because it works, it doesn't mean we have to test it.

Yes.  It all depends on the answer to this question: Is it
reasonably expected that any half-way intelligent Git user would not
be surprised to learn that "sudo sudo git status" would be a way to
work on a repository that is owned by root as root?  Given that
"sudo git status" is a good way to work on a repository that is
owned by you as root, perhaps the answer is yes, but I am not
a representative sample ;-)

If the answer is yes, then we would want to make sure it will
continue to work by having a test to protect it from future
breakage.  If not, and "sudo sudo git" (or worse "sudo sudo sudo
git") is something that would be imagined by the most wicked mind
and no sane person would imagine it would be a way to achieve
something useful, no, it does not have to be protected from any
future breakage.

So...
Carlo Marcelo Arenas Belón May 16, 2022, 1:07 p.m. UTC | #6
On Sun, May 15, 2022 at 10:27:04PM -0700, Junio C Hamano wrote:
> Carlo Arenas <carenas@gmail.com> writes:
> 
> >> Hmph, it may not be needed, but it should still work, in which case
> >> it probably is still worth testing, even with the optional patch #4.
> >
> > Just because it works, it doesn't mean we have to test it.
> 
> Yes.  It all depends on the answer to this question

Not quite, after all this is part of the "git" testsuite and therefore will
only apply if it would be testing git's functionality, and in this case it
does not.

More details below.

> Is it
> reasonably expected that any half-way intelligent Git user would not
> be surprised to learn that "sudo sudo git status" would be a way to
> work on a repository that is owned by root as root?  Given that
> "sudo git status" is a good way to work on a repository that is
> owned by you as root, perhaps the answer is yes, but I am not
> a representative sample ;-)
> 
> If the answer is yes, then we would want to make sure it will
> continue to work by having a test to protect it from future
> breakage.  If not, and "sudo sudo git" (or worse "sudo sudo sudo
> git") is something that would be imagined by the most wicked mind
> and no sane person would imagine it would be a way to achieve
> something useful, no, it does not have to be protected from any
> future breakage.

The answer is "yes", but it is because of a misunderstanding (which has
nothing to do with intelligence, but just experience with sudo and the type
of environment where it runs).

* sudo does NOT respect SUDO_UID, indeed is one of those few *NIX tools
  that doesn't even respect EUID but insist on only trusting the real id.
* once you run something through sudo, it creates an environment for you
  that is based on its security policy and not even the invoking user can
  change some of the parametersr it uses to do that, only "root" can.
* that means that once you invoke the first sudo, then the second runs as
  root and ignores the SUDO_UID the first sudo creates, so by the time git
  gets to run, it will only see the SUDO_UID that the one that invoked it
  creates, and since that sudo was running as root it MUST be the same than
  a root owned file/directory would use, hence why it works for that root
  owned repository and would fail in one that is owned by the original user.

there is no new functionality or code path difference inside git between the
first and second invocation of sudo, the only relevant difference is that
the starting environment from the two last processes in that triple chain
have different values for the SUDO_UID environment variable.

Carlo
Junio C Hamano May 16, 2022, 4:25 p.m. UTC | #7
Carlo Marcelo Arenas Belón <carenas@gmail.com> writes:

> On Sun, May 15, 2022 at 10:27:04PM -0700, Junio C Hamano wrote:
>> Carlo Arenas <carenas@gmail.com> writes:
>> 
>> >> Hmph, it may not be needed, but it should still work, in which case
>> >> it probably is still worth testing, even with the optional patch #4.
>> >
>> > Just because it works, it doesn't mean we have to test it.
>> 
>> Yes.  It all depends on the answer to this question
>
> Not quite, after all this is part of the "git" testsuite and therefore will
> only apply if it would be testing git's functionality, and in this case it
> does not.

It is immaterial if the way how "sudo sudo git" behaves is "git's
functionality" or not, because what we care about is what the end
user sees as a whole and it does not matter all that much to them
where the observed behaviour comes from.

The rule is simple.  If we care about the behaviour to stay with us
over time, we ensure it with a test.  If we are certain that no
users will depend on such a behaviour and are willing to break them
(i.e. users who depend on how "sudo sudo git" behaves, which is an
empty set) when we need to update the code, then we don't.

And if that changes with and without the optional patch #4, it makes
it more important to have test (if we care, that is).  Later we may
find what patch #4 does is detrimental to user experience and decide
to tweak it out (not necessarily with a revert of #4, but doing an
equivalent of reverting of it only in the code part and not tests).

In any case, as I said in the beginning, this was merely "a bit
surprised" and "not a serious enough thing to trigger a reroll", so
I will stop wasting our time on this thread.

Thanks.
diff mbox series

Patch

diff --git a/t/lib-sudo.sh b/t/lib-sudo.sh
new file mode 100644
index 00000000000..b4d7788f4e5
--- /dev/null
+++ b/t/lib-sudo.sh
@@ -0,0 +1,15 @@ 
+# Helpers for running git commands under sudo.
+
+# Runs a scriplet passed through stdin under sudo.
+run_with_sudo () {
+	local ret
+	local RUN="$TEST_DIRECTORY/$$.sh"
+	write_script "$RUN" "$TEST_SHELL_PATH"
+	# avoid calling "$RUN" directly so sudo doesn't get a chance to
+	# override the shell, add aditional restrictions or even reject
+	# running the script because its security policy deem it unsafe
+	sudo "$TEST_SHELL_PATH" -c "\"$RUN\""
+	ret=$?
+	rm -f "$RUN"
+	return $ret
+}
diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh
index 6b8ea5357f6..a621f1ea5eb 100755
--- a/t/t0034-root-safe-directory.sh
+++ b/t/t0034-root-safe-directory.sh
@@ -3,6 +3,7 @@ 
 test_description='verify safe.directory checks while running as root'
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-sudo.sh
 
 if [ "$GIT_TEST_ALLOW_SUDO" != "YES" ]
 then
@@ -10,6 +11,12 @@  then
 	test_done
 fi
 
+if ! test_have_prereq NOT_ROOT
+then
+	skip_all="These tests do not support running as root"
+	test_done
+fi
+
 test_lazy_prereq SUDO '
 	sudo -n id -u >u &&
 	id -u root >r &&
@@ -19,6 +26,12 @@  test_lazy_prereq SUDO '
 	test_cmp u r
 '
 
+if ! test_have_prereq SUDO
+then
+	skip_all="Your sudo/system configuration is either too strict or unsupported"
+	test_done
+fi
+
 test_expect_success SUDO 'setup' '
 	sudo rm -rf root &&
 	mkdir -p root/r &&
@@ -36,6 +49,55 @@  test_expect_success SUDO 'sudo git status as original owner' '
 	)
 '
 
+test_expect_success SUDO 'setup root owned repository' '
+	sudo mkdir -p root/p &&
+	sudo git init root/p
+'
+
+test_expect_success 'cannot access if owned by root' '
+	(
+		cd root/p &&
+		test_must_fail git status
+	)
+'
+
+test_expect_success 'can access if addressed explicitly' '
+	(
+		cd root/p &&
+		GIT_DIR=.git GIT_WORK_TREE=. git status
+	)
+'
+
+test_expect_failure SUDO 'can access with sudo if root' '
+	(
+		cd root/p &&
+		sudo git status
+	)
+'
+
+test_expect_success SUDO 'can access with sudo if root by removing SUDO_UID' '
+	(
+		cd root/p &&
+		run_with_sudo <<-END
+			unset SUDO_UID &&
+			git status
+		END
+	)
+'
+
+test_lazy_prereq SUDO_SUDO '
+	sudo sudo id -u >u &&
+	id -u root >r &&
+	test_cmp u r
+'
+
+test_expect_success SUDO_SUDO 'can access with sudo abusing SUDO_UID' '
+	(
+		cd root/p &&
+		sudo sudo git status
+	)
+'
+
 # this MUST be always the last test
 test_expect_success SUDO 'cleanup' '
 	sudo rm -rf root