Merge branch 'cb/path-owner-check-with-sudo'
With a recent update to refuse access to repositories of other people by default, "sudo make install" and "sudo git describe" stopped working. This series intends to loosen it while keeping the safety. * cb/path-owner-check-with-sudo: t0034: add negative tests and allow git init to mostly work under sudo git-compat-util: avoid failing dir ownership checks if running privileged t: regression git needs safe.directory when using sudo Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
commit
b779214eaf
@ -26,3 +26,17 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`
|
||||
is set in system config and you want to re-enable this protection, then
|
||||
initialize your list with an empty value before listing the repositories
|
||||
that you deem safe.
|
||||
+
|
||||
As explained, Git only allows you to access repositories owned by
|
||||
yourself, i.e. the user who is running Git, by default. When Git
|
||||
is running as 'root' in a non Windows platform that provides sudo,
|
||||
however, git checks the SUDO_UID environment variable that sudo creates
|
||||
and will allow access to the uid recorded as its value in addition to
|
||||
the id from 'root'.
|
||||
This is to make it easy to perform a common sequence during installation
|
||||
"make && sudo make install". A git process running under 'sudo' runs as
|
||||
'root' but the 'sudo' command exports the environment variable to record
|
||||
which id the original user has.
|
||||
If that is not what you would prefer and want git to only trust
|
||||
repositories that are owned by root instead, then you can remove
|
||||
the `SUDO_UID` variable from root's environment before invoking git.
|
||||
|
@ -393,12 +393,68 @@ static inline int git_offset_1st_component(const char *path)
|
||||
#endif
|
||||
|
||||
#ifndef is_path_owned_by_current_user
|
||||
|
||||
#ifdef __TANDEM
|
||||
#define ROOT_UID 65535
|
||||
#else
|
||||
#define ROOT_UID 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do not use this function when
|
||||
* (1) geteuid() did not say we are running as 'root', or
|
||||
* (2) using this function will compromise the system.
|
||||
*
|
||||
* PORTABILITY WARNING:
|
||||
* This code assumes uid_t is unsigned because that is what sudo does.
|
||||
* If your uid_t type is signed and all your ids are positive then it
|
||||
* should all work fine.
|
||||
* If your version of sudo uses negative values for uid_t or it is
|
||||
* buggy and return an overflowed value in SUDO_UID, then git might
|
||||
* fail to grant access to your repository properly or even mistakenly
|
||||
* grant access to someone else.
|
||||
* In the unlikely scenario this happened to you, and that is how you
|
||||
* got to this message, we would like to know about it; so sent us an
|
||||
* email to git@vger.kernel.org indicating which platform you are
|
||||
* using and which version of sudo, so we can improve this logic and
|
||||
* maybe provide you with a patch that would prevent this issue again
|
||||
* in the future.
|
||||
*/
|
||||
static inline void extract_id_from_env(const char *env, uid_t *id)
|
||||
{
|
||||
const char *real_uid = getenv(env);
|
||||
|
||||
/* discard anything empty to avoid a more complex check below */
|
||||
if (real_uid && *real_uid) {
|
||||
char *endptr = NULL;
|
||||
unsigned long env_id;
|
||||
|
||||
errno = 0;
|
||||
/* silent overflow errors could trigger a bug here */
|
||||
env_id = strtoul(real_uid, &endptr, 10);
|
||||
if (!*endptr && !errno)
|
||||
*id = env_id;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int is_path_owned_by_current_uid(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
uid_t euid;
|
||||
|
||||
if (lstat(path, &st))
|
||||
return 0;
|
||||
return st.st_uid == geteuid();
|
||||
|
||||
euid = geteuid();
|
||||
if (euid == ROOT_UID)
|
||||
{
|
||||
if (st.st_uid == ROOT_UID)
|
||||
return 1;
|
||||
else
|
||||
extract_id_from_env("SUDO_UID", &euid);
|
||||
}
|
||||
|
||||
return st.st_uid == euid;
|
||||
}
|
||||
|
||||
#define is_path_owned_by_current_user is_path_owned_by_current_uid
|
||||
|
15
t/lib-sudo.sh
Normal file
15
t/lib-sudo.sh
Normal file
@ -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
|
||||
}
|
93
t/t0034-root-safe-directory.sh
Executable file
93
t/t0034-root-safe-directory.sh
Executable file
@ -0,0 +1,93 @@
|
||||
#!/bin/sh
|
||||
|
||||
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
|
||||
skip_all="You must set env var GIT_TEST_ALLOW_SUDO=YES in order to run this test"
|
||||
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 &&
|
||||
test_cmp u r &&
|
||||
command -v git >u &&
|
||||
sudo command -v git >r &&
|
||||
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 &&
|
||||
(
|
||||
cd root/r &&
|
||||
git init
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success SUDO 'sudo git status as original owner' '
|
||||
(
|
||||
cd root/r &&
|
||||
git status &&
|
||||
sudo git status
|
||||
)
|
||||
'
|
||||
|
||||
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_success 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
|
||||
)
|
||||
'
|
||||
|
||||
# this MUST be always the last test
|
||||
test_expect_success SUDO 'cleanup' '
|
||||
sudo rm -rf root
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user