{"thread":{"id":"57799","subject":"[RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","startedAt":"2022-04-26T18:31:47Z","lastAt":"2022-06-17T21:02:13Z","messageCount":170,"participants":["Carlo Marcelo Arenas Belón","Derrick Stolee","Junio C Hamano","rsbecker@nexbridge.com","Carlo Arenas","Phillip Wood","Bagas Sanjaya","Johannes Schindelin","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"454458","messageId":"20220426183105.99779-1-carenas@gmail.com","threadId":"57799","inReplyTo":null,"subject":"[RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-26T18:31:05Z","receivedAt":"2022-04-26T18:31:47Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that uid was\nroot (because git was invoked through sudo or doas) and the effetive id\nthat repositiry trusted for its config was different, therefore failing\nthe following common call:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nthose tools create to keep track of the original user id, and do the\nownership check using those instead.\n\nThis assumes the environment the user is running with after going\npriviledged can't be tampered with, and also does the check only for\nroot to keep the most common case less complicated, but as a side effect\nwill miss cases where sudo (or an equivalent) was used to change to\nanother unpriviledged user.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\nSent as an RFC as it has been only lightly tested and because some of\nthe assumptions I have to make, made me unconfortable.\n\nEx, in order to make the atoi() calls safe, I was originally doing\nis_digit(), but that would require this function to move further down\nto work.\n\nIt is also now big enough that would make sense for it to move into\nits own compat file and outside for git-compat-util.h, but if that is\ndone we might not keep the \"root uid is not always 0\" bits that seem\nuseful to have for the future.\n\ngetent() is not thread safe, so it might be worth to use an alternative\nbut that would require a bigger change.\n\nIMHO it should have a test added, but not sure where it would fit.\n\nOriginal discussion in :\n\n  https://lore.kernel.org/git/4ef9287b-6260-9538-7c89-cffb611520ee@maurel.de/\n\n git-compat-util.h | 24 +++++++++++++++++++++++-\n 1 file changed, 23 insertions(+), 1 deletion(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 58fd813bd01..2ed97b47979 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -437,12 +437,34 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID) {\n+\t\t/* we might have raised our priviledges with sudo or doas */\n+\t\tconst char *real_uid = getenv(\"SUDO_UID\");\n+\t\tif (real_uid && *real_uid)\n+\t\t\teuid = atoi(real_uid);\n+\t\telse {\n+\t\t\treal_uid = getenv(\"DOAS_UID\");\n+\t\t\tif (real_uid && *real_uid)\n+\t\t\t\teuid = atoi(real_uid);\n+\t\t}\n+\t}\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\n-- \n2.36.0.266.g59f845bde02\n\n"},{"id":"454460","messageId":"9658dea7-d421-b238-113d-c7b83eca4569@github.com","threadId":"57799","inReplyTo":"20220426183105.99779-1-carenas@gmail.com","subject":"Re: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"Derrick Stolee","fromEmail":"derrickstolee@github.com","sentAt":"2022-04-26T19:48:33Z","receivedAt":"2022-04-26T19:48:39Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/26/2022 2:31 PM, Carlo Marcelo Arenas Belón wrote:\n> bdc77d1d685 (Add a function to determine whether a path is owned by the\n> current user, 2022-03-02) checks for the effective uid of the running\n> process using geteuid() but didn't account for cases where that uid was\n> root (because git was invoked through sudo or doas) and the effetive id\n\ns/effetive/effective\n\n> that repositiry trusted for its config was different, therefore failing\n\ns/repositiry/repository\n\n> the following common call:\n> \n>   guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n>   [sudo] password for guy:\n>   fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n> \n> Attempt to detect those cases by using the environment variables that\n> those tools create to keep track of the original user id, and do the\n> ownership check using those instead.\n> \n> This assumes the environment the user is running with after going\n> priviledged can't be tampered with, and also does the check only for\n\ns/priviledged/privileged \n\n> root to keep the most common case less complicated, but as a side effect\n> will miss cases where sudo (or an equivalent) was used to change to\n> another unpriviledged user.\n\ns/unpriviledged/unpriviledged \n\n> Sent as an RFC as it has been only lightly tested and because some of\n> the assumptions I have to make, made me unconfortable.\n\n \n> Ex, in order to make the atoi() calls safe, I was originally doing\n> is_digit(), but that would require this function to move further down\n> to work.\n>\n> It is also now big enough that would make sense for it to move into\n> its own compat file and outside for git-compat-util.h, but if that is\n> done we might not keep the \"root uid is not always 0\" bits that seem\n> useful to have for the future.\n>\n> getent() is not thread safe, so it might be worth to use an alternative\n> but that would require a bigger change.\n\nThese points make sense. It would be worth taking our time and\ndoing some refactoring in advance of this functional change.\n \n> IMHO it should have a test added, but not sure where it would fit.\n\nI wonder how we could test a multi-user scenario. The tests I\nadded in e47363e5a (t0033: add tests for safe.directory, 2022-04-13)\npurposefully avoid the user-id functionality.\n\n> Original discussion in :\n> \n>   https://lore.kernel.org/git/4ef9287b-6260-9538-7c89-cffb611520ee@maurel.de/\n\nI agree that the idea behind this change is a good one. The escalation\nof privilege isn't a huge concern when the \"real\" user is the same.\nThe only way to trick the root user here is to set an environment\nvariable, in which case they might as well modify PATH and be done with\nit.\n\n> +\teuid = geteuid();\n> +\tif (euid == ROOT_UID) {\n> +\t\t/* we might have raised our priviledges with sudo or doas */\n\nSimilar spelling error here.\n\n> +\t\tconst char *real_uid = getenv(\"SUDO_UID\");\n> +\t\tif (real_uid && *real_uid)\n> +\t\t\teuid = atoi(real_uid);\n> +\t\telse {\n> +\t\t\treal_uid = getenv(\"DOAS_UID\");\n> +\t\t\tif (real_uid && *real_uid)\n> +\t\t\t\teuid = atoi(real_uid);\n> +\t\t}\n\nI imagine that something else could be added here to help Windows\nusers who have elevated to administrator privileges. It will use a\ncompletely different mechanism, though, if needed at all. We can\ndelay that for now.\n\nThanks,\n-Stolee\n"},{"id":"454461","messageId":"xmqqlevrr53n.fsf@gitster.g","threadId":"57799","inReplyTo":"9658dea7-d421-b238-113d-c7b83eca4569@github.com","subject":"Re: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-26T19:56:28Z","receivedAt":"2022-04-26T19:56:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Derrick Stolee <derrickstolee@github.com> writes:\n\n>> Original discussion in :\n>> \n>>   https://lore.kernel.org/git/4ef9287b-6260-9538-7c89-cffb611520ee@maurel.de/\n>\n> I agree that the idea behind this change is a good one. The escalation\n> of privilege isn't a huge concern when the \"real\" user is the same.\n> The only way to trick the root user here is to set an environment\n> variable, in which case they might as well modify PATH and be done with\n> it.\n\nHow much do we really want to trust SUDO_UID or DOSA_UID are telling\nthe truth, though?\n\n>> +\teuid = geteuid();\n>> +\tif (euid == ROOT_UID) {\n>> +\t\t/* we might have raised our priviledges with sudo or doas */\n>\n> Similar spelling error here.\n>\n>> +\t\tconst char *real_uid = getenv(\"SUDO_UID\");\n>> +\t\tif (real_uid && *real_uid)\n>> +\t\t\teuid = atoi(real_uid);\n>> +\t\telse {\n>> +\t\t\treal_uid = getenv(\"DOAS_UID\");\n>> +\t\t\tif (real_uid && *real_uid)\n>> +\t\t\t\teuid = atoi(real_uid);\n>> +\t\t}\n>\n> I imagine that something else could be added here to help Windows\n> users who have elevated to administrator privileges. It will use a\n> completely different mechanism, though, if needed at all. We can\n> delay that for now.\n>\n> Thanks,\n> -Stolee\n"},{"id":"454463","messageId":"04bb01d859a9$b759cb50$260d61f0$@nexbridge.com","threadId":"57799","inReplyTo":"xmqqlevrr53n.fsf@gitster.g","subject":"RE: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-26T20:10:40Z","receivedAt":"2022-04-26T20:11:21Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 26, 2022 3:56 PM, Junio C Hamano wrote:\n>Subject: Re: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if\n>running priviledged\n>\n>Derrick Stolee <derrickstolee@github.com> writes:\n>\n>>> Original discussion in :\n>>>\n>>>\n>>> https://lore.kernel.org/git/4ef9287b-6260-9538-7c89-cffb611520ee@maur\n>>> el.de/\n>>\n>> I agree that the idea behind this change is a good one. The escalation\n>> of privilege isn't a huge concern when the \"real\" user is the same.\n>> The only way to trick the root user here is to set an environment\n>> variable, in which case they might as well modify PATH and be done\n>> with it.\n>\n>How much do we really want to trust SUDO_UID or DOSA_UID are telling the\n>truth, though?\n>\n>>> +\teuid = geteuid();\n>>> +\tif (euid == ROOT_UID) {\n>>> +\t\t/* we might have raised our priviledges with sudo or doas */\n>>\n>> Similar spelling error here.\n>>\n>>> +\t\tconst char *real_uid = getenv(\"SUDO_UID\");\n>>> +\t\tif (real_uid && *real_uid)\n>>> +\t\t\teuid = atoi(real_uid);\n>>> +\t\telse {\n>>> +\t\t\treal_uid = getenv(\"DOAS_UID\");\n>>> +\t\t\tif (real_uid && *real_uid)\n>>> +\t\t\t\teuid = atoi(real_uid);\n\nThis should be strtol() instead of atoi(). Putting garbage into DOAS_UID might end up causing some unwanted effects since atoi() could then return 0 or some partial value. The result should also be checked for sanity and the end pointer should point to a '\\0'. My team has effectively banned the use of atoi() in new code and is migrating to strtol() or strtoll() as code is touched.\n\n>>> +\t\t}\n>>\n>> I imagine that something else could be added here to help Windows\n>> users who have elevated to administrator privileges. It will use a\n>> completely different mechanism, though, if needed at all. We can delay\n>> that for now.\n>>\n>> Thanks,\n>> -Stolee\n\n"},{"id":"454464","messageId":"CAPUEspizQ5hkhnNURNLyhzucUfD1tS99cfH5NhQKF+47NzKMPg@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqlevrr53n.fsf@gitster.g","subject":"Re: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-26T20:12:43Z","receivedAt":"2022-04-26T20:13:20Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, Apr 26, 2022 at 12:56 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> How much do we really want to trust SUDO_UID or DOSA_UID are telling\n> the truth, though?\n\nIMHO since we are only trusting this if the EUID is root it would require that\nthe root account was compromised already or running in a tampered environment.\n\nfor the absolutely paranoid we could trace back the process tree to make sure\nthe current session was indeed created by that tool, but if we are going that\nway I think that trusting the ownership of the pty as was proposed[1] originally\nwould be simpler and is indeed how other tools (like who) deal with\nthat problem.\n\nThe advantage of trusting these variables is that we can keep the more common\ncase simpler and avoid the reported regression.\n\nCarlo\n\n[1] https://lore.kernel.org/git/20220425084003.nf267feurpqyvmsd@carlos-mbp.lan/\n"},{"id":"454465","messageId":"CAPUEspitAQrEjMpUyw8e2pyT1MT+h_dO5wSU0wWDWTqSye5TwA@mail.gmail.com","threadId":"57799","inReplyTo":"9658dea7-d421-b238-113d-c7b83eca4569@github.com","subject":"Re: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-26T20:26:48Z","receivedAt":"2022-04-26T20:27:05Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, Apr 26, 2022 at 12:48 PM Derrick Stolee\n<derrickstolee@github.com> wrote:\n\n> These points make sense. It would be worth taking our time and\n> doing some refactoring in advance of this functional change.\n\nProblem with taking our time or making it a bigger change is that\nit is currently broken in the last maint versions so it would be ideal\nto backport quickly there as a \"regression\".\n\n> I wonder how we could test a multi-user scenario. The tests I\n> added in e47363e5a (t0033: add tests for safe.directory, 2022-04-13)\n> purposefully avoid the user-id functionality.\n\nIt would need to be a CI only test (where passwordless sudo is allowed)\n\n> I imagine that something else could be added here to help Windows\n> users who have elevated to administrator privileges. It will use a\n> completely different mechanism, though, if needed at all. We can\n> delay that for now.\n\nNote this function is *NIX only, there is another one for Windows where\na similar fix (if needed) could be implemented\n\nCarlo\n"},{"id":"454473","messageId":"CAPUEspi_mX1xj1Nu2DuE83U9jB6oeRd=8FDPgGXbSC76mGHroQ@mail.gmail.com","threadId":"57799","inReplyTo":"04bb01d859a9$b759cb50$260d61f0$@nexbridge.com","subject":"Re: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-26T20:45:16Z","receivedAt":"2022-04-26T20:45:34Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, Apr 26, 2022 at 1:10 PM <rsbecker@nexbridge.com> wrote:\n>\n> Putting garbage into DOAS_UID might end up causing some unwanted effects\n\nSince it was the root user who put garbage there, we will have to\ntrust it was not\nunwanted.  My proposal to use is_digit() was to make sure we didn't get garbage\nfrom the getenv() call (ex: \"\") that would confuse the logic, but if\nthere is some sudo\nversion that is saving the uid as \"ThisIsGarbage\" then that is a bug\nbetter handled\nsomewhere else.\n\nAgree with you that using strtol is better, but the added checks and\nlogic make it\nmore complicated and go against the assumption made in the commit message\nthat the environment CAN'T be tampered with.\n\nCarlo\n"},{"id":"454475","messageId":"xmqqilqvpn3u.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspi_mX1xj1Nu2DuE83U9jB6oeRd=8FDPgGXbSC76mGHroQ@mail.gmail.com","subject":"Re: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-26T21:10:29Z","receivedAt":"2022-04-26T21:10:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> Agree with you that using strtol is better, but the added checks\n> and logic make it more complicated and go against the assumption\n> made in the commit message that the environment CAN'T be tampered\n> with.\n\nI think we require strto*l() here, to relieve us from worrying about\n\"is int large enough?\" question.\n\n"},{"id":"454482","messageId":"20220427000522.15637-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220426183105.99779-1-carenas@gmail.com","subject":"[PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T00:05:22Z","receivedAt":"2022-04-27T00:05:38Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that uid was\nroot (because git was invoked through sudo or a compatible tool) and the\noriginal user that repository trusted for its config was different,\ntherefore failing the following common use case:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nsudo or compatible tools create to keep track of the original user id,\nand do the ownership check using that instead.\n\nThis assumes the environment the user is running with after going\nprivileged can't be tampered with, and also does the check only for\nroot to keep the most common case less complicated, but as a side effect\nwill miss cases where sudo (or an equivalent) was used to change to\nanother unprivileged user or where the equivalent tool used to raise\nprivileges didn't track the original id in a sudo compatible way.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\nChanges since RFC\n* Addresses all spelling errors, even the ones not reported and even if I\n  am sure \"priviledged\" is a nicer sounding word even if obsoleted.\n* Uses strtol instead of atoi as suggested by Randall and Junio, the extra\n  error checking was too much to handle inline so a new helper function\n  was added.\n* Removes checks for DOAS_UID, in an attempt to make the change smaller\n  and because that is part of an extention that might not be that common.\n  This means `doas` is still broken, but that was punted for now.\n* Has been tested a little more, but is still missing a test case, but\n  as Derrick pointed out doing so is not trivial, so punted for now.\n\n git-compat-util.h | 38 +++++++++++++++++++++++++++++++++++++-\n 1 file changed, 37 insertions(+), 1 deletion(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 58fd813bd01..9bb0eb5087a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -437,12 +437,48 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n+/*\n+ * this helper function overrides a ROOT_UID with the one provided by\n+ * an environment variable, do not use unless the original uid is\n+ * root\n+ */\n+static inline int extract_id_from_env(const char *env, uid_t *id)\n+{\n+\tconst char *real_uid = getenv(env);\n+\n+\tif (real_uid && *real_uid) {\n+\t\tchar *error;\n+\t\tlong extracted_id = strtol(real_uid, &error, 10);\n+\t\tif (!*error && LONG_MIN < extracted_id &&\n+\t\t\t\textracted_id < LONG_MAX) {\n+\t\t\t*id = (uid_t)extracted_id;\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID) {\n+\t\t/* we might have raised our privileges with sudo */\n+\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\t}\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\n-- \n2.36.0.266.g59f845bde02\n\n"},{"id":"454490","messageId":"6522673b-494a-951c-be5e-3ca01577c12b@gmail.com","threadId":"57799","inReplyTo":"20220427000522.15637-1-carenas@gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-27T09:33:04Z","receivedAt":"2022-04-27T10:59:14Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Carlo\n\nOn 27/04/2022 01:05, Carlo Marcelo Arenas Belón wrote:\n> bdc77d1d685 (Add a function to determine whether a path is owned by the\n> current user, 2022-03-02) checks for the effective uid of the running\n> process using geteuid() but didn't account for cases where that uid was\n> root (because git was invoked through sudo or a compatible tool) and the\n> original user that repository trusted for its config was different,\n> therefore failing the following common use case:\n> \n>    guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n>    [sudo] password for guy:\n>    fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n> \n> Attempt to detect those cases by using the environment variables that\n> sudo or compatible tools create to keep track of the original user id,\n> and do the ownership check using that instead.\n> \n> This assumes the environment the user is running with after going\n> privileged can't be tampered with, and also does the check only for\n> root to keep the most common case less complicated, but as a side effect\n> will miss cases where sudo (or an equivalent) was used to change to\n> another unprivileged user or where the equivalent tool used to raise\n> privileges didn't track the original id in a sudo compatible way.\n> \n> Reported-by: Guy Maurel <guy.j@maurel.de>\n> Helped-by: SZEDER Gábor <szeder.dev@gmail.com>\n> Helped-by: Randall Becker <rsbecker@nexbridge.com>\n> Suggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> ---\n> Changes since RFC\n> * Addresses all spelling errors, even the ones not reported and even if I\n>    am sure \"priviledged\" is a nicer sounding word even if obsoleted.\n> * Uses strtol instead of atoi as suggested by Randall and Junio, the extra\n>    error checking was too much to handle inline so a new helper function\n>    was added.\n> * Removes checks for DOAS_UID, in an attempt to make the change smaller\n>    and because that is part of an extention that might not be that common.\n>    This means `doas` is still broken, but that was punted for now.\n> * Has been tested a little more, but is still missing a test case, but\n>    as Derrick pointed out doing so is not trivial, so punted for now.\n> \n>   git-compat-util.h | 38 +++++++++++++++++++++++++++++++++++++-\n>   1 file changed, 37 insertions(+), 1 deletion(-)\n> \n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 58fd813bd01..9bb0eb5087a 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -437,12 +437,48 @@ static inline int git_offset_1st_component(const char *path)\n>   #endif\n>   \n>   #ifndef is_path_owned_by_current_user\n> +\n> +#ifdef __TANDEM\n> +#define ROOT_UID 65535\n> +#else\n> +#define ROOT_UID 0\n> +#endif\n> +\n> +/*\n> + * this helper function overrides a ROOT_UID with the one provided by\n> + * an environment variable, do not use unless the original uid is\n> + * root\n> + */\n> +static inline int extract_id_from_env(const char *env, uid_t *id)\n\nDo we really want this living in git-compat-util.h?\n\n> +{\n> +\tconst char *real_uid = getenv(env);\n> +\n> +\tif (real_uid && *real_uid) {\n> +\t\tchar *error;\n> +\t\tlong extracted_id = strtol(real_uid, &error, 10);\n> +\t\tif (!*error && LONG_MIN < extracted_id &&\n> +\t\t\t\textracted_id < LONG_MAX) {\n\nstrtol() returns a long so the last two checks are redundant. The \nstandard is silent on what happens to error when the value is out of \nrange. The way to check that all the string was consumed without \nunderflow/overflow is\n\n\terrno = 0;\n\tval = strtol(str, &endp, 10);\n\tif (errno || !*endp)\n\t\terror(...)\n\nIn this case I think negative values make no sense as I believe uids are \nalways positive integers so we should add a check for \"extracted_id < 0\"\n\n> +\t\t\t*id = (uid_t)extracted_id;\n\nThere is a potential integer truncation here which could lead to false \npositives. I'm not sure that there is a way to query the maximum valid \nuid but we could do\n\n\t#if sizeof(uid_t) == sizeof(int)\n\t\tif (extracted_id > INT_MAX)\n\t\t\terror(...)\n\t#endif\n\nUnfortunately I think we need to use #if rather than if to prevent \ncompilers complaining that the condition is always true or always false.\n\nChecking the real user id from an environment variable makes me feel a \nbit queasy but as others have pointed out if an attacker can mess with \nthe users environment then they can already override $PATH.\n\nBest Wishes\n\nPhillip\n\n> +\t\t\treturn 1;\n> +\t\t}\n> +\t}\n> +\treturn 0;\n> +}\n> +\n>   static inline int is_path_owned_by_current_uid(const char *path)\n>   {\n>   \tstruct stat st;\n> +\tuid_t euid;\n> +\n>   \tif (lstat(path, &st))\n>   \t\treturn 0;\n> -\treturn st.st_uid == geteuid();\n> +\n> +\teuid = geteuid();\n> +\tif (euid == ROOT_UID) {\n> +\t\t/* we might have raised our privileges with sudo */\n> +\t\textract_id_from_env(\"SUDO_UID\", &euid);\n> +\t}\n> +\treturn st.st_uid == euid;\n>   }\n>   \n>   #define is_path_owned_by_current_user is_path_owned_by_current_uid\n\n"},{"id":"454494","messageId":"fcd26e80-daee-2d66-cbdc-b004c478357d@gmail.com","threadId":"57799","inReplyTo":"6522673b-494a-951c-be5e-3ca01577c12b@gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-27T12:30:50Z","receivedAt":"2022-04-27T12:30:59Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 27/04/2022 10:33, Phillip Wood wrote:\n> Hi Carlo\n> \n> On 27/04/2022 01:05, Carlo Marcelo Arenas Belón wrote:\n\n> [...]\n>> +{\n>> +    const char *real_uid = getenv(env);\n>> +\n>> +    if (real_uid && *real_uid) {\n>> +        char *error;\n>> +        long extracted_id = strtol(real_uid, &error, 10);\n>> +        if (!*error && LONG_MIN < extracted_id &&\n>> +                extracted_id < LONG_MAX) {\n> \n> strtol() returns a long so the last two checks are redundant. The \n> standard is silent on what happens to error when the value is out of \n> range. The way to check that all the string was consumed without \n> underflow/overflow is\n> \n>      errno = 0;\n>      val = strtol(str, &endp, 10);\n>      if (errno || !*endp)\n\nSorry that should be \"if (errno || *endp)\" to check for an error\n\n > [...]\n >     #if sizeof(uid_t) == sizeof(int)\n >         if (extracted_id > INT_MAX)\n >             error(...)\n >     #endif\n\nI think we should probably check if uid_t is a short integer as well as\n\n > +#ifdef __TANDEM\n > +#define ROOT_UID 65535\n\nsuggests it may be an unsigned short on NonStop.\n\nNot knowing the size of uid_t or if it is signed or not (as far as I can \ntell posix just says it's an integer) makes the limit checks tricky - \nmaybe we make euid a long (or unsigned long) here and it the function \nbelow rather than casting it to uid_t and possibly truncating it.\n\n > [...]\n>> +\n>>   static inline int is_path_owned_by_current_uid(const char *path)\n>>   {\n>>       struct stat st;\n>> +    uid_t euid;\n>> +\n>>       if (lstat(path, &st))\n>>           return 0;\n>> -    return st.st_uid == geteuid();\n>> +\n>> +    euid = geteuid();\n>> +    if (euid == ROOT_UID) {\n>> +        /* we might have raised our privileges with sudo */\n>> +        extract_id_from_env(\"SUDO_UID\", &euid);\n\nYou are ignoring any errors when parsing the environment variable - that \nis not a good idea in a security check.\n\nBest Wishes\n\nPhillip\n\n>> +    }\n>> +    return st.st_uid == euid;\n>>   }\n>>   #define is_path_owned_by_current_user is_path_owned_by_current_uid\n> \n\n"},{"id":"454497","messageId":"006e01d85a41$4903f5c0$db0be140$@nexbridge.com","threadId":"57799","inReplyTo":"fcd26e80-daee-2d66-cbdc-b004c478357d@gmail.com","subject":"RE: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-27T14:15:38Z","receivedAt":"2022-04-27T14:16:10Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 27, 2022 8:31 AM, Phillip Wood wrote:\n>On 27/04/2022 10:33, Phillip Wood wrote:\n>> Hi Carlo\n>>\n>> On 27/04/2022 01:05, Carlo Marcelo Arenas Belón wrote:\n>\n>> [...]\n>>> +{\n>>> +    const char *real_uid = getenv(env);\n>>> +\n>>> +    if (real_uid && *real_uid) {\n>>> +        char *error;\n>>> +        long extracted_id = strtol(real_uid, &error, 10);\n>>> +        if (!*error && LONG_MIN < extracted_id &&\n>>> +                extracted_id < LONG_MAX) {\n>>\n>> strtol() returns a long so the last two checks are redundant. The\n>> standard is silent on what happens to error when the value is out of\n>> range. The way to check that all the string was consumed without\n>> underflow/overflow is\n>>\n>>      errno = 0;\n>>      val = strtol(str, &endp, 10);\n>>      if (errno || !*endp)\n>\n>Sorry that should be \"if (errno || *endp)\" to check for an error\n>\n> > [...]\n> >     #if sizeof(uid_t) == sizeof(int)\n> >         if (extracted_id > INT_MAX)\n> >             error(...)\n> >     #endif\n>\n>I think we should probably check if uid_t is a short integer as well as\n>\n> > +#ifdef __TANDEM\n> > +#define ROOT_UID 65535\n>\n>suggests it may be an unsigned short on NonStop.\n>\n>Not knowing the size of uid_t or if it is signed or not (as far as I can tell posix just\n>says it's an integer) makes the limit checks tricky - maybe we make euid a long (or\n>unsigned long) here and it the function below rather than casting it to uid_t and\n>possibly truncating it.\n\nIt depends on the compile. If LP64 is used - long file pointers, then it is a long (32-bit) or an int (also 32-bit). Not unsigned in either case, but specifying unsigned would be helpful. Nice catch.\n\n> > [...]\n>>> +\n>>>   static inline int is_path_owned_by_current_uid(const char *path)\n>>>   {\n>>>       struct stat st;\n>>> +    uid_t euid;\n>>> +\n>>>       if (lstat(path, &st))\n>>>           return 0;\n>>> -    return st.st_uid == geteuid();\n>>> +\n>>> +    euid = geteuid();\n>>> +    if (euid == ROOT_UID) {\n>>> +        /* we might have raised our privileges with sudo */\n>>> +        extract_id_from_env(\"SUDO_UID\", &euid);\n>\n>You are ignoring any errors when parsing the environment variable - that is not a\n>good idea in a security check.\n\n"},{"id":"454500","messageId":"CAPUEsphEymVE1HHeDZE+Fh50fr7DJSpM_YFNC-v=m9hFhgz-UA@mail.gmail.com","threadId":"57799","inReplyTo":"6522673b-494a-951c-be5e-3ca01577c12b@gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T15:38:46Z","receivedAt":"2022-04-27T15:39:02Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 2:33 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> On 27/04/2022 01:05, Carlo Marcelo Arenas Belón wrote:\n> > diff --git a/git-compat-util.h b/git-compat-util.h\n> > index 58fd813bd01..9bb0eb5087a 100644\n> > --- a/git-compat-util.h\n> > +++ b/git-compat-util.h\n> > @@ -437,12 +437,48 @@ static inline int git_offset_1st_component(const char *path)\n> >   #endif\n> >\n> >   #ifndef is_path_owned_by_current_user\n> > +\n> > +#ifdef __TANDEM\n> > +#define ROOT_UID 65535\n> > +#else\n> > +#define ROOT_UID 0\n> > +#endif\n> > +\n> > +/*\n> > + * this helper function overrides a ROOT_UID with the one provided by\n> > + * an environment variable, do not use unless the original uid is\n> > + * root\n> > + */\n> > +static inline int extract_id_from_env(const char *env, uid_t *id)\n>\n> Do we really want this living in git-compat-util.h?\n\nNo; but IMHO the same applies to is_path_owned_by_current_uid(), and\nas I mentioned in my original proposal refactoring this code to do so\nhas been punted until later since the objective here was to keep the\nchange as small as possible for clean backporting.\n\nMy intention with that comment was not only to warn people that might\nwant to reuse that helper but to indicate it was just a hack that\nshould be refactored ASAP.\n\nFWIW, I still think that using atoi with a check to skip \"\" is\nprobably as safe as doing all this extra checking as no one has shown\nyet a system where sizeof(uid_t) > sizeof(uint32_t), but agree with\nJunio that using long instead avoids issues with the systems where\nsizeof(uid_t) > sizeof(int) and unless sizeof(int) == sizeof(long)\n(ex: 32-bit Linux) which is then covered by the cast.\n\n> > +{\n> > +     const char *real_uid = getenv(env);\n> > +\n> > +     if (real_uid && *real_uid) {\n> > +             char *error;\n> > +             long extracted_id = strtol(real_uid, &error, 10);\n> > +             if (!*error && LONG_MIN < extracted_id &&\n> > +                             extracted_id < LONG_MAX) {\n>\n> strtol() returns a long so the last two checks are redundant.\n\nThe last two checks were to check for underflow or overflow and to\nmake sure that the bogus values this function returns in case of those\nerrors are not taken into consideration.\n\n>The standard is silent on what happens to error when the value is out of\n> range.\n\nWhich is why instead I was avoiding LONG_{MIN,MAX} which are\ndescribed[1] as the bogus values that will be used in that case\nAgree with you that we could also add a check for >=0 as uid_t is\nusually unsigned, but it is not warranted to be so, and that is I was\naiming for the wider possible range so we don't have to worry that\nmuch and let it be settled to a valid value through the cast.\n\nCarlo\n\n[1] https://pubs.opengroup.org/onlinepubs/007904875/functions/strtol.html\n"},{"id":"454502","messageId":"009d01d85a4e$79cfa570$6d6ef050$@nexbridge.com","threadId":"57799","inReplyTo":"CAPUEsphEymVE1HHeDZE+Fh50fr7DJSpM_YFNC-v=m9hFhgz-UA@mail.gmail.com","subject":"RE: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-27T15:50:04Z","receivedAt":"2022-04-27T15:50:18Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 27, 2022 11:39 AM, Carlo Arenas wrote:\n>On Wed, Apr 27, 2022 at 2:33 AM Phillip Wood <phillip.wood123@gmail.com>\n>wrote:\n>> On 27/04/2022 01:05, Carlo Marcelo Arenas Belón wrote:\n>> > diff --git a/git-compat-util.h b/git-compat-util.h index\n>> > 58fd813bd01..9bb0eb5087a 100644\n>> > --- a/git-compat-util.h\n>> > +++ b/git-compat-util.h\n>> > @@ -437,12 +437,48 @@ static inline int git_offset_1st_component(const char\n>*path)\n>> >   #endif\n>> >\n>> >   #ifndef is_path_owned_by_current_user\n>> > +\n>> > +#ifdef __TANDEM\n>> > +#define ROOT_UID 65535\n>> > +#else\n>> > +#define ROOT_UID 0\n>> > +#endif\n>> > +\n>> > +/*\n>> > + * this helper function overrides a ROOT_UID with the one provided\n>> > +by\n>> > + * an environment variable, do not use unless the original uid is\n>> > + * root\n>> > + */\n>> > +static inline int extract_id_from_env(const char *env, uid_t *id)\n>>\n>> Do we really want this living in git-compat-util.h?\n>\n>No; but IMHO the same applies to is_path_owned_by_current_uid(), and as I\n>mentioned in my original proposal refactoring this code to do so has been punted\n>until later since the objective here was to keep the change as small as possible for\n>clean backporting.\n>\n>My intention with that comment was not only to warn people that might want to\n>reuse that helper but to indicate it was just a hack that should be refactored ASAP.\n>\n>FWIW, I still think that using atoi with a check to skip \"\" is probably as safe as doing\n>all this extra checking as no one has shown yet a system where sizeof(uid_t) >\n>sizeof(uint32_t), but agree with Junio that using long instead avoids issues with\n>the systems where\n>sizeof(uid_t) > sizeof(int) and unless sizeof(int) == sizeof(long)\n>(ex: 32-bit Linux) which is then covered by the cast.\n>\n>> > +{\n>> > +     const char *real_uid = getenv(env);\n>> > +\n>> > +     if (real_uid && *real_uid) {\n>> > +             char *error;\n>> > +             long extracted_id = strtol(real_uid, &error, 10);\n>> > +             if (!*error && LONG_MIN < extracted_id &&\n>> > +                             extracted_id < LONG_MAX) {\n>>\n>> strtol() returns a long so the last two checks are redundant.\n>\n>The last two checks were to check for underflow or overflow and to make sure\n>that the bogus values this function returns in case of those errors are not taken\n>into consideration.\n>\n>>The standard is silent on what happens to error when the value is out\n>>of  range.\n>\n>Which is why instead I was avoiding LONG_{MIN,MAX} which are described[1] as\n>the bogus values that will be used in that case Agree with you that we could also\n>add a check for >=0 as uid_t is usually unsigned, but it is not warranted to be so,\n>and that is I was aiming for the wider possible range so we don't have to worry\n>that much and let it be settled to a valid value through the cast.\n\nSomehow, the root user id is a compat issue. Perhaps we need a uid_t getRootUid() in git-compat-util.h, and hide the details of the proc from the interface.\n\n"},{"id":"454503","messageId":"CAPUEspiHWTTAvNyqqLzcC854UccH=bkPLPBzPaPfzFKn_yt4aA@mail.gmail.com","threadId":"57799","inReplyTo":"fcd26e80-daee-2d66-cbdc-b004c478357d@gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T15:58:58Z","receivedAt":"2022-04-27T16:00:03Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 5:30 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> You are ignoring any errors when parsing the environment variable - that\n> is not a good idea in a security check.\n\nwhich errors are you concerned about?, if anything in this code\nworries me from a security point of view is the fact that we are\nrelying in getenv not being racy (as mentioned in the original RFC),\nbut there are no errors set there AFAIK.\n\nnot ignoring errno in strtol is an option, but as mentioned before I\ndecided instead to reject bogus values and therefore not the clobber a\nprevious errno, since I was using strtol as a wider version of atoi.\n\nCarlo\n"},{"id":"454505","messageId":"b0a80f47-f441-fc6e-3695-58ea83dea2b8@gmail.com","threadId":"57799","inReplyTo":"CAPUEspiHWTTAvNyqqLzcC854UccH=bkPLPBzPaPfzFKn_yt4aA@mail.gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-27T16:14:27Z","receivedAt":"2022-04-27T16:17:21Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 27/04/2022 16:58, Carlo Arenas wrote:\n> On Wed, Apr 27, 2022 at 5:30 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>> You are ignoring any errors when parsing the environment variable - that\n>> is not a good idea in a security check.\n> \n> which errors are you concerned about?, if anything in this code\n\nI was confused by the fact that the helper function returns a \nsuccess/failure value which we ignore. However euid is not overwritten \nif strtol fails so it is safe I think.\n\n> worries me from a security point of view is the fact that we are\n> relying in getenv not being racy (as mentioned in the original RFC),\n> but there are no errors set there AFAIK.\n> \n> not ignoring errno in strtol is an option, but as mentioned before I\n> decided instead to reject bogus values and therefore not the clobber a\n> previous errno,\n\nstrtol() will set errno if there is a range error ignoring it does not \nchange that. In any case is_path_owned_by_current_uid() already clobbers \nerrno if stat() fails.\n\nBest Wishes\n\nPhillip\n\n> since I was using strtol as a wider version of atoi.\n\n\n> Carlo\n\n"},{"id":"454506","messageId":"xmqqczh2o5xg.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEsphEymVE1HHeDZE+Fh50fr7DJSpM_YFNC-v=m9hFhgz-UA@mail.gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-27T16:19:07Z","receivedAt":"2022-04-27T16:23:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n>> > +     if (real_uid && *real_uid) {\n>> > +             char *error;\n>> > +             long extracted_id = strtol(real_uid, &error, 10);\n>> > +             if (!*error && LONG_MIN < extracted_id &&\n>> > +                             extracted_id < LONG_MAX) {\n>>\n>> strtol() returns a long so the last two checks are redundant.\n>\n> The last two checks were to check for underflow or overflow and to\n> make sure that the bogus values this function returns in case of those\n> errors are not taken into consideration.\n>\n>>The standard is silent on what happens to error when the value is out of\n>> range.\n\nActually the standard is is very clear what happens to endptr (no,\ndon't call it \"error\", that is not the point of the parameter).\n\n    A pointer to the final string shall be stored in the object\n    pointed to by endptr, provided that endptr is not a null\n    pointer.\n\nwhere \"final string\" has a precise definition much earlier:\n\n    First, they decompose the input string into three parts:\n\n    1. An initial, possibly empty, sequence of white-space\n       characters (as specified by isspace())\n\n    2. A subject sequence interpreted as an integer represented in\n       some radix determined by the value of base\n\n    3. A final string of one or more unrecognized characters,\n       including the terminating null byte of the input string.\n\n    Then they shall attempt to convert the subject sequence to an\n    integer, and return the result.\n\nSo, leading whitespace is stripped, then \"subject sequence\" that is\nthe sequence of digits (with optional +/- sign) to be turned into a\nlong is recognised, and what remains is the \"final string\".  endptr\nis made to point at that \"final string\", and it does not matter what\nkind of value the interpretation of \"subject sequence\" yields.\n\nAnd that is why it is wrong to call it \"error\".  It is not about\nerrors, but is about the shape of the input string, i.e. where the\nrun of digits ends.\n\n> Which is why instead I was avoiding LONG_{MIN,MAX} which are\n> described[1] as the bogus values that will be used in that case\n\nstrtol() is designed to return LONG_MIN and LONG_MAX when values\noverflow or underflow, but that does not mean it returns these two\nvalues only when the input overflows or underflows.  If it were\nstrtouint8(), giving it \"255\" will give 255, while you would get\nUCHAR_MAX when the input makes it overflow, e.g. \"1000\", and from\nthe returned value you cannot tell which is which because UCHAR_MAX\nis 255 ;-)\n\nIOW, you are reading the standard wrong.  It does not say that\nLONG_MIN and LONG_MAX are bogus values at all.\n\nAnd theree is this note:\n\n    Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX}\n    are returned on error and are also valid returns on success, an\n    application wishing to check for error situations should set errno\n    to 0, then call strtol() or strtoll(), then check errno.\n\nSo, no, I do not think the range check gives us anything\nmeaningful.\n\nAt this point, it is tempting to say that it is not worth trying to\ndo it right by avoiding atoi(), as we are bound to make more of this\nkind of mistakes X-<.  But at the same time, I hope we can learn\ntogether and get this right ;-).\n"},{"id":"454507","messageId":"57217c15-c6d1-32f1-a481-0003ba66e342@gmail.com","threadId":"57799","inReplyTo":"CAPUEsphEymVE1HHeDZE+Fh50fr7DJSpM_YFNC-v=m9hFhgz-UA@mail.gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-27T16:31:07Z","receivedAt":"2022-04-27T16:31:27Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 27/04/2022 16:38, Carlo Arenas wrote:\n> On Wed, Apr 27, 2022 at 2:33 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>> On 27/04/2022 01:05, Carlo Marcelo Arenas Belón wrote:\n> [...]\n> FWIW, I still think that using atoi with a check to skip \"\" is\n> probably as safe as doing all this extra checking as no one has shown\n> yet a system where sizeof(uid_t) > sizeof(uint32_t), but agree with\n> Junio that using long instead avoids issues with the systems where\n> sizeof(uid_t) > sizeof(int) and unless sizeof(int) == sizeof(long)\n> (ex: 32-bit Linux) which is then covered by the cast.\n\nif sizeof(uid_t) < sizeof(long) then the cast will truncate the value \nreturned by strtol() which means we are trusting that SUDO_UID is a \nvalid uid otherwise it will be truncated.\n\n>>> +{\n>>> +     const char *real_uid = getenv(env);\n>>> +\n>>> +     if (real_uid && *real_uid) {\n>>> +             char *error;\n>>> +             long extracted_id = strtol(real_uid, &error, 10);\n>>> +             if (!*error && LONG_MIN < extracted_id &&\n>>> +                             extracted_id < LONG_MAX) {\n>>\n>> strtol() returns a long so the last two checks are redundant.\n> \n> The last two checks were to check for underflow or overflow and to\n> make sure that the bogus values this function returns in case of those\n> errors are not taken into consideration.\n\nSorry I misread the code - this is checking if the value is valid, not \nif there is an error. On platforms where uid_t and long are the same \nsize (e.g. where int and long are both 32 bits) the \"< LONG_MAX\" check \nis rejecting a valid uid. The fact that we are doing these checks makes \nme think we should care about the possible truncation above.\n\nBest Wishes\n\nPhillip\n\n>> The standard is silent on what happens to error when the value is out of\n>> range.\n> \n> Which is why instead I was avoiding LONG_{MIN,MAX} which are\n> described[1] as the bogus values that will be used in that case\n> Agree with you that we could also add a check for >=0 as uid_t is\n> usually unsigned, but it is not warranted to be so, and that is I was\n> aiming for the wider possible range so we don't have to worry that\n> much and let it be settled to a valid value through the cast.\n> \n> Carlo\n> \n> [1] https://pubs.opengroup.org/onlinepubs/007904875/functions/strtol.html\n\n"},{"id":"454510","messageId":"CAPUEspgANqqEcqS31UbBTq+QB6R7TQ8TncZ8uMt778=kvrE=eQ@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqczh2o5xg.fsf@gitster.g","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T16:45:21Z","receivedAt":"2022-04-27T16:45:58Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 9:19 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> And that is why it is wrong to call it \"error\".  It is not about\n> errors, but is about the shape of the input string, i.e. where the\n> run of digits ends.\n\nI called it error, because I only cared about it to signal that the\nstring it converted was an erroneous one (ex: \"1a\" or \"a\")\n\n> And there is this note:\n>\n>     Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX}\n>     are returned on error and are also valid returns on success, an\n>     application wishing to check for error situations should set errno\n>     to 0, then call strtol() or strtoll(), then check errno.\n>\n> So, no, I do not think the range check gives us anything\n> meaningful.\n\nthe meaningful part of it was meant to be:\n\nthis function will try to get the value of an UID from SUDO_UID, if it\ngets anything insane like LONG_MIN or LONG_MAX or anything above or\nbelow that, it would consider you are just trying to play a bad joke\nwith it and ignore you.\n\n> At this point, it is tempting to say that it is not worth trying to\n> do it right by avoiding atoi(), as we are bound to make more of this\n> kind of mistakes X-<.  But at the same time, I hope we can learn\n> together and get this right ;-).\n\nexcept it wasn't a mistake, but maybe poorly documented since I was\nalready going over my quota of added lines for what should have been a\n3 line patch.\n\napologies for making the code so cryptic and thanks for spending so\nmuch time reviewing it and commenting on it, has been definitely very\ninstructive so far.\n\nany specific suggestions you would like to have in a reroll?\n\nCarlo\n"},{"id":"454511","messageId":"CAPUEsphumEJ=qBM9c9WLJ6fzL=mcK2+3fUViyHEvttaD-DsOgg@mail.gmail.com","threadId":"57799","inReplyTo":"57217c15-c6d1-32f1-a481-0003ba66e342@gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T16:54:52Z","receivedAt":"2022-04-27T16:55:09Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 9:31 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> On 27/04/2022 16:38, Carlo Arenas wrote:\n> > FWIW, I still think that using atoi with a check to skip \"\" is\n> > probably as safe as doing all this extra checking as no one has shown\n> > yet a system where sizeof(uid_t) > sizeof(uint32_t), but agree with\n> > Junio that using long instead avoids issues with the systems where\n> > sizeof(uid_t) > sizeof(int) and unless sizeof(int) == sizeof(long)\n> > (ex: 32-bit Linux) which is then covered by the cast.\n>\n> if sizeof(uid_t) < sizeof(long) then the cast will truncate the value\n> returned by strtol() which means we are trusting that SUDO_UID is a\n> valid uid otherwise it will be truncated.\n\ncorrect, this whole procedure relies on the fact that SUDO_UID is not\na bogus value (ex: it was produced by a non buggy sudo and hasn't been\ntampered with)\n\nin systems where sizeof(uid_t) < sizeof(long), it is expected that the\nid we got should be able to fit in an uid_t so no truncation will ever\nhappen.\n\nthe only thing that worries me is sign extension but that is why I put\na specific cast.  for all practical reasons I expect uid_t to be\nuint32_t and therefore using long should be better than using int\n(through atoi)\n\nCarlo\n"},{"id":"454516","messageId":"ed2cdc8f-1908-a095-ddf1-660ef8b5a90b@gmail.com","threadId":"57799","inReplyTo":"xmqqczh2o5xg.fsf@gitster.g","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-27T17:22:03Z","receivedAt":"2022-04-27T17:22:18Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 27/04/2022 17:19, Junio C Hamano wrote:\n> Carlo Arenas <carenas@gmail.com> writes:\n>>> The standard is silent on what happens to error when the value is out of\n>>> range.\n> \n> Actually the standard is is very clear what happens to endptr (no,\n> don't call it \"error\", that is not the point of the parameter).\n >\n>      A pointer to the final string shall be stored in the object\n>      pointed to by endptr, provided that endptr is not a null\n>      pointer.\n> \n> where \"final string\" has a precise definition much earlier:\n> \n>      First, they decompose the input string into three parts:\n> \n>      1. An initial, possibly empty, sequence of white-space\n>         characters (as specified by isspace())\n> \n>      2. A subject sequence interpreted as an integer represented in\n>         some radix determined by the value of base\n> \n>      3. A final string of one or more unrecognized characters,\n>         including the terminating null byte of the input string.\n> \n>      Then they shall attempt to convert the subject sequence to an\n>      integer, and return the result.\n> \n> So, leading whitespace is stripped, then \"subject sequence\" that is\n> the sequence of digits (with optional +/- sign) to be turned into a\n> long is recognised, and what remains is the \"final string\".  endptr\n> is made to point at that \"final string\", and it does not matter what\n> kind of value the interpretation of \"subject sequence\" yields.\n\nOh I think I misunderstood when I read the standard this morning. Just \nto check I do understand now, in the case of overflow entptr points to \nthe final string (i.e. to the character following the last digit) even \nthough the \"subject sequence\" cannot be successfully converted?\n\nThanks\n\nPhillip\n"},{"id":"454517","messageId":"6c3b447d-9419-982d-678c-6a6c0ff8cbc2@gmail.com","threadId":"57799","inReplyTo":"CAPUEsphumEJ=qBM9c9WLJ6fzL=mcK2+3fUViyHEvttaD-DsOgg@mail.gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-27T17:28:03Z","receivedAt":"2022-04-27T17:28:11Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 27/04/2022 17:54, Carlo Arenas wrote:\n> On Wed, Apr 27, 2022 at 9:31 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>> On 27/04/2022 16:38, Carlo Arenas wrote:\n>>> FWIW, I still think that using atoi with a check to skip \"\" is\n>>> probably as safe as doing all this extra checking as no one has shown\n>>> yet a system where sizeof(uid_t) > sizeof(uint32_t), but agree with\n>>> Junio that using long instead avoids issues with the systems where\n>>> sizeof(uid_t) > sizeof(int) and unless sizeof(int) == sizeof(long)\n>>> (ex: 32-bit Linux) which is then covered by the cast.\n>>\n>> if sizeof(uid_t) < sizeof(long) then the cast will truncate the value\n>> returned by strtol() which means we are trusting that SUDO_UID is a\n>> valid uid otherwise it will be truncated.\n> \n> correct, this whole procedure relies on the fact that SUDO_UID is not\n> a bogus value (ex: it was produced by a non buggy sudo and hasn't been\n> tampered with)\n> \n> in systems where sizeof(uid_t) < sizeof(long), it is expected that the\n> id we got should be able to fit in an uid_t so no truncation will ever\n> happen.\n> \n> the only thing that worries me is sign extension but that is why I put\n> a specific cast.  for all practical reasons I expect uid_t to be\n> uint32_t and therefore using long should be better than using int\n> (through atoi)\n\n\nIf we think uid_t is a uint32_t then should we be using strtoul() to \nmake sure we cover the whole uid range where sizeof(long) == \nsizeof(uint32_t)?\n\nBest Wishes\n\nPhillip\n\n> Carlo\n\n"},{"id":"454519","messageId":"00ab01d85a5f$2831e0a0$7895a1e0$@nexbridge.com","threadId":"57799","inReplyTo":"ed2cdc8f-1908-a095-ddf1-660ef8b5a90b@gmail.com","subject":"RE: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-27T17:49:28Z","receivedAt":"2022-04-27T17:49:47Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 27, 2022 1:22 PM, Phillip Wood wrote:\n>On 27/04/2022 17:19, Junio C Hamano wrote:\n>> Carlo Arenas <carenas@gmail.com> writes:\n>>>> The standard is silent on what happens to error when the value is\n>>>> out of range.\n>>\n>> Actually the standard is is very clear what happens to endptr (no,\n>> don't call it \"error\", that is not the point of the parameter).\n> >\n>>      A pointer to the final string shall be stored in the object\n>>      pointed to by endptr, provided that endptr is not a null\n>>      pointer.\n>>\n>> where \"final string\" has a precise definition much earlier:\n>>\n>>      First, they decompose the input string into three parts:\n>>\n>>      1. An initial, possibly empty, sequence of white-space\n>>         characters (as specified by isspace())\n>>\n>>      2. A subject sequence interpreted as an integer represented in\n>>         some radix determined by the value of base\n>>\n>>      3. A final string of one or more unrecognized characters,\n>>         including the terminating null byte of the input string.\n>>\n>>      Then they shall attempt to convert the subject sequence to an\n>>      integer, and return the result.\n>>\n>> So, leading whitespace is stripped, then \"subject sequence\" that is\n>> the sequence of digits (with optional +/- sign) to be turned into a\n>> long is recognised, and what remains is the \"final string\".  endptr is\n>> made to point at that \"final string\", and it does not matter what kind\n>> of value the interpretation of \"subject sequence\" yields.\n>\n>Oh I think I misunderstood when I read the standard this morning. Just to check I\n>do understand now, in the case of overflow entptr points to the final string (i.e. to\n>the character following the last digit) even though the \"subject sequence\" cannot\n>be successfully converted?\n\nI can confirm this on multiple 32-bit platforms. With strtol(\"123456789012345678\", &endptr, 10) returns 2147483647 and *endptr == '\\0' just beyond the last 8.\n\n"},{"id":"454520","messageId":"CAPUEspjoTYtv9K=rvpkFnyGnEz_uxefED820rx09b6qGG93SqA@mail.gmail.com","threadId":"57799","inReplyTo":"6c3b447d-9419-982d-678c-6a6c0ff8cbc2@gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T17:49:18Z","receivedAt":"2022-04-27T17:49:52Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 10:28 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> On 27/04/2022 17:54, Carlo Arenas wrote:\n> >\n> > the only thing that worries me is sign extension but that is why I put\n> > a specific cast.  for all practical reasons I expect uid_t to be\n> > uint32_t and therefore using long should be better than using int\n> > (through atoi)\n\nWell, just because I think that is the most likely option, doesn't\nmean it will be so since it is not defined as such in the standard.\nI should have documented though that I was (probably incorrectly)\nprioritizing the possibility of supporting negative uids instead of\npositive uids > INT_MAX.\n\nThis of course only matters in 32bit, but looking at sudo's sources\nthey use \"%u\" to set the UID in the environment and therefore we\nshould change our approach to match.\n\n> If we think uid_t is a uint32_t then should we be using strtoul() to\n> make sure we cover the whole uid range where sizeof(long) ==\n> sizeof(uint32_t)?\n\nstrtoul is sadly not very portable, but I think you are correct that\nit should be used instead\noriginally I thought it would be better to do strtoimax but that will\nalso require moving this function around.\n\nCarlo\n"},{"id":"454521","messageId":"CAPUEspjgMw2CwFCj4i+iH8phX_8mSRT0wPYhNrEA0E6avNTaTQ@mail.gmail.com","threadId":"57799","inReplyTo":"00ab01d85a5f$2831e0a0$7895a1e0$@nexbridge.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T17:54:10Z","receivedAt":"2022-04-27T17:54:25Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 10:49 AM <rsbecker@nexbridge.com> wrote:\n>\n> I can confirm this on multiple 32-bit platforms. With strtol(\"123456789012345678\", &endptr, 10) returns 2147483647 and *endptr == '\\0' just beyond the last 8.\n\ncan you also confirm that you have strtoul and works the same, before\nI break NON-STOP in my next reroll?\n\nCarlo\n"},{"id":"454522","messageId":"00b501d85a61$74130240$5c3906c0$@nexbridge.com","threadId":"57799","inReplyTo":"CAPUEspjgMw2CwFCj4i+iH8phX_8mSRT0wPYhNrEA0E6avNTaTQ@mail.gmail.com","subject":"RE: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-27T18:05:55Z","receivedAt":"2022-04-27T18:06:03Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 27, 2022 1:54 PM, Carlo Arenas wrote:\n>To: rsbecker@nexbridge.com\n>Cc: phillip.wood@dunelm.org.uk; Junio C Hamano <gitster@pobox.com>;\n>git@vger.kernel.org; philipoakley@iee.email; me@ttaylorr.com;\n>guy.j@maurel.de; szeder.dev@gmail.com; johannes.Schindelin@gmx.de;\n>derrickstolee@github.com\n>Subject: Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running\n>privileged\n>\n>On Wed, Apr 27, 2022 at 10:49 AM <rsbecker@nexbridge.com> wrote:\n>>\n>> I can confirm this on multiple 32-bit platforms. With\n>strtol(\"123456789012345678\", &endptr, 10) returns 2147483647 and *endptr == '\\0'\n>just beyond the last 8.\n>\n>can you also confirm that you have strtoul and works the same, before I break\n>NON-STOP in my next reroll?\n\nResults on NonStop: strtol(\"123456789012345678\", &endptr, 10) returns 4294967295 and *endptr == '\\0' just beyond the last 8.\n\n"},{"id":"454524","messageId":"CAPUEspgOwmQwqBjauKW=VYJjry3537Te4RLjB=ZuT=CU+rRA4A@mail.gmail.com","threadId":"57799","inReplyTo":"00b501d85a61$74130240$5c3906c0$@nexbridge.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T18:11:37Z","receivedAt":"2022-04-27T18:11:54Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 11:06 AM <rsbecker@nexbridge.com> wrote:\n> Results on NonStop: strtol(\"123456789012345678\", &endptr, 10) returns 4294967295 and *endptr == '\\0' just beyond the last 8.\n\nThanks and errno == ERANGE as POSIX requires, right?, the code\n(untested) I was planning to use instead looks like :\n\nstatic inline void extract_id_from_env(const char *env, uid_t *id)\n{\n        const char *real_uid = getenv(env);\n\n        /* discard any empty values */\n        if (real_uid && *real_uid) {\n                unsigned long extracted_id;\n                int saved_errno = errno;\n\n                errno = 0;\n                extracted_id = strtoul(real_uid, NULL, 10);\n                if (!errno)\n                        *id = (uid_t)extracted_id;\n                errno = saved_errno;\n        }\n        return 0;\n}\n\nCarlo\n"},{"id":"454533","messageId":"00bd01d85a62$ff56e7d0$fe04b770$@nexbridge.com","threadId":"57799","inReplyTo":"CAPUEspgOwmQwqBjauKW=VYJjry3537Te4RLjB=ZuT=CU+rRA4A@mail.gmail.com","subject":"RE: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-27T18:16:58Z","receivedAt":"2022-04-27T18:17:06Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 27, 2022 2:12 PM, Carlo Arenas wrote:\n>On Wed, Apr 27, 2022 at 11:06 AM <rsbecker@nexbridge.com> wrote:\n>> Results on NonStop: strtol(\"123456789012345678\", &endptr, 10) returns\n>4294967295 and *endptr == '\\0' just beyond the last 8.\n>\n>Thanks and errno == ERANGE as POSIX requires, right?, the code\n>(untested) I was planning to use instead looks like :\n>\n>static inline void extract_id_from_env(const char *env, uid_t *id) {\n>        const char *real_uid = getenv(env);\n>\n>        /* discard any empty values */\n>        if (real_uid && *real_uid) {\n>                unsigned long extracted_id;\n>                int saved_errno = errno;\n>\n>                errno = 0;\n>                extracted_id = strtoul(real_uid, NULL, 10);\n>                if (!errno)\n>                        *id = (uid_t)extracted_id;\n>                errno = saved_errno;\n>        }\n>        return 0;\n>}\n\nerrno = 4034 (Value out of range), which is the ERANGE #define.\n--Randall\n\n"},{"id":"454534","messageId":"xmqqzgk6l5ly.fsf@gitster.g","threadId":"57799","inReplyTo":"b0a80f47-f441-fc6e-3695-58ea83dea2b8@gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-27T18:54:17Z","receivedAt":"2022-04-27T19:04:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> On 27/04/2022 16:58, Carlo Arenas wrote:\n>> On Wed, Apr 27, 2022 at 5:30 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>> You are ignoring any errors when parsing the environment variable - that\n>>> is not a good idea in a security check.\n>> which errors are you concerned about?, if anything in this code\n>\n> I was confused by the fact that the helper function returns a\n> success/failure value which we ignore. However euid is not overwritten \n> if strtol fails so it is safe I think.\n>\n>> worries me from a security point of view is the fact that we are\n>> relying in getenv not being racy (as mentioned in the original RFC),\n>> but there are no errors set there AFAIK.\n>> not ignoring errno in strtol is an option, but as mentioned before I\n>> decided instead to reject bogus values and therefore not the clobber a\n>> previous errno,\n>\n> strtol() will set errno if there is a range error ignoring it does not\n> change that. In any case is_path_owned_by_current_uid() already\n> clobbers errno if stat() fails.\n\nIOW we are not preserving errno anyway, so ignoring errno (or\nresetting before calling strtol) does not by us anything.\n\nWe probably should step back a bit, take a deep breath and think\nwhat we are trying to protect our users against.  When I said early\nin the discussion how much we trust the value in SUDO_UID, I hoped\npeople would do so, and I was especially hoping such a discussion to\nhappen when they realized that the width of uid_t is unknown and\nthere can be truncations in either direction.\n\nSo let's start one now.\n\nIf we didn't trust the value in SUDO_UID, what valid use case do we\nhelp, and what avenue of attack do we open ourselves to?  This is\nnot a suggestion of an alternative, but is a discussion starter to\nillustrate the line along which we want to think about the issues.\n\nThe original \"sudo make install\" (which runs \"git describe\" inside)\nuse case does not really care.  The process running with SUDO_UID is\nnot spelunking into random directories uncontrollably without being\naware that there may be hostile repositories.  The directories they\nvisit are part of legitimate journey \"make install\" takes.\n\nThe \"sudo sh to get a shell, chdir to /var/tmp/foo to do something\"\nuse case does care---it needs to make sure that whereever it goes is\nnot part of a hostile repository.  So \"if SUDO_UID is there, anything\ngoes\" is not a good protection for such a use case.\n\nIf we read SUDO_UID into an int16_t and uid_t happens to be much\nwider than that type, then what happens?  Again, I am not advocating\nto deliberately use shorter type to cause truncation.  This is\nmerely to illustrate how much truncation matters.\n\nThe \"sudo make install\" use case may be harmed unless the comparison\nis done carefully.  If the repository owner's UID is beyond 32k then\nasking if (st.st_uid == SUDO_UID) would say \"no\" due to truncation\nand refuse access to the legitimate user.  If we compare both after\ncasting them to int16_t then the repository owner will be allowed in\nagain.  A friendly stranger who happens to share the low 16-bit of\nUID will also be allowed to install from the repository, but that is\nnot an intended consequence.\n\nThe \"sudo sh and go spelunking\" use case is weakend by truncation.\nIt is protected only if the victim's UID does not share the lower\n16-bit with the owner of hostile repository.\n\nSo what attack does this allow?  An attacker needs to learn their\nown UID, find another user whose UID is the same modulo 16-bit as a\npotential victim, and the victim has to be among those who can run\n\"sudo\".  Then the victim somehow has to be talked into running stuff\nin a repository the attacker prepares.\n\nPossible?  Yes.  Practical?  I dunno.  Especially if we do not\ndeliberately truncate by reading into int16_t but use \"int\" (32-bit\nalmost everywhere we care about) or \"long\".  Now how likely is uid_t\nnarrower than long?  If it is not likely, then we probably are OK to\nuse long and not worry about the truncation at all.  Or use strtoll()\nto make it even less likely.\n\nSo, in short, I think it is reasonable if we did:\n\n - do the extra \"if SUDO_UID exists, then...\" only when we are root.\n\n - use strtol to ensure SUDO_UID is in good shape (all digits) and\n   read into long; use errno=0 trick to notice overflows.  err on\n   the safe side and do not allow if the value cannot be read\n   correctly.\n\n - do the comparison between st.st_uid and strtol() result by\n   casting both to (long).  Without this, st.st_uid has a value that\n   needs wider than long, we cannot allow the owner of such a\n   repository in (and I somehow feel that is unlikely to happen).\n\n - or omit the third one --- tough luck for those whose UID is\n   beyond what a long can represent (and I somehow feel that this is\n   probably OK).\n\nAnother thing I'd suggest doing is to have a helper function to do\nthe \"we do a bit more than geteuid() to come up with the allowed\nowner of repositories we encounter\", and call that function instead\nof geteuid().\n\nThanks.\n"},{"id":"454547","messageId":"CAPUEsph9tUkm+JsvU6z0Wt7mtRcTCH1vbvYTEdWjNyXzdoU=vw@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqzgk6l5ly.fsf@gitster.g","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T20:59:33Z","receivedAt":"2022-04-27T20:59:52Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 11:54 AM Junio C Hamano <gitster@pobox.com> wrote:\n\n> The \"sudo sh to get a shell, chdir to /var/tmp/foo to do something\"\n> use case does care---it needs to make sure that whereever it goes is\n> not part of a hostile repository.  So \"if SUDO_UID is there, anything\n> goes\" is not a good protection for such a use case.\n\nFWIW that was never part of the proposal, indeed making git aware of\nSUDO_ID when it is running as only as root was part of the design to\navoid other users probably allowing repositories they don't control by\nhaving an evil SUDO_ID.\n\nas per the root user, I was expecting that he could be trusted more\nand that wouldn't accidentally get an evil SUDO_ID on their session\nbecause it is something that gets generated from their original\naccount and they should be aware of it and even might need to tweak it\n(ex: by un setting it if it gets in the way).\n\nTo make the `sudo make install` use case possible I think it make\nsense to trust SUDO_ID by default, but I would be open to add a\nconfiguration setting that would be required to enable it (it indeed\nmight become useful for root users that might want to disable it as an\nalternative to unset SUDO_ID).\n\n> Possible?  Yes.  Practical?  I dunno.  Especially if we do not\n> deliberately truncate by reading into int16_t but use \"int\" (32-bit\n> almost everywhere we care about) or \"long\".  Now how likely is uid_t\n> narrower than long?  If it is not likely, then we probably are OK to\n> use long and not worry about the truncation at all.  Or use strtoll()\n> to make it even less likely.\n\nstrtoll (or my suggested alternative of strtoimax) suffer from\nportability issues which are handled later in the git-compat-util.h\nfile, so while I think it is worth doing, I would prefer doing so\nlater as part of moving this code into a proper compat module.\n\nfor this iteration, the suggestion by Phillip to use strtoul makes\nmore sense (specially after confirmation by Randall that it works in\nNON-STOP), it is more portable and doesn't require later in the file\ngit-compat magic to work, it allows for the full range of 32bit that\nmight be needed in 32bit *NIX, it is should fit find even in 32bit\nenvironments with a 32bit unsigned uid_t (which is fairly common), it\ndoesn't sign extend if applied into a wider uid_t and would be likely\nable to be assigned even without a cast and without the risk of\ntruncation for most uid_t types.  Lastly, since now this code is\nfocused only in sudo compatibility, and sudo casts their uid to an\nunsigned int and prints it into that variable with \"%u\" it is the\nright \"API\".\n\nFor comparison, I would also think it is better to let the compiler\nwarn if needed so at least the users would know their uid_t type is\nnarrower than what we expect and sudo sets, and might work as a\nweather balloon to find those systems.\n\n>\n> So, in short, I think it is reasonable if we did:\n>\n>  - do the extra \"if SUDO_UID exists, then...\" only when we are root.\n\nalready in since the RFC, see discussion above for an option to\ntighten it further if really needed, but even in that case I would\nrather do it in the next iteration.\n\n>  - use strtol to ensure SUDO_UID is in good shape (all digits) and\n>    read into long; use errno=0 trick to notice overflows.  err on\n>    the safe side and do not allow if the value cannot be read\n>    correctly.\n\nalready implemented as part of v2, except it is using strtoul/unsigned long.\nalso in the line of \"err on the safe side\" I was also discarding any values\nthat would overflow an uid_t (which is assumed to be unsigned), which\naffect the next bullet point.\n\n>  - do the comparison between st.st_uid and strtol() result by\n>    casting both to (long).  Without this, st.st_uid has a value that\n>    needs wider than long, we cannot allow the owner of such a\n>    repository in (and I somehow feel that is unlikely to happen).\n\ndo you still want to cast both sides even if discarding values that would\noverflow an uid_t?\n\nFWIW, as Phillip reported, using long (or another signed type) would\nrestrict the valid ids in 32-bit *NIX to half of what the expected uint32_t\nrange most of them should have.\n\n>  - or omit the third one --- tough luck for those whose UID is\n>    beyond what a long can represent (and I somehow feel that this is\n>    probably OK).\n\nThat was what I proposed in the current RFC (at least in 32bit *NIX)\nbut I have to admit that i'd seen a lot more issues with uid larger than\nINT_MAX that I expected when doing google for it, so that is what I\nthought it would be safer to use the full 32-bit and an unsigned type\ninstead.\n\n> Another thing I'd suggest doing is to have a helper function to do\n> the \"we do a bit more than geteuid() to come up with the allowed\n> owner of repositories we encounter\", and call that function instead\n> of geteuid().\n\nI did this originally, but discarded it quickly because it was a\nlittle odd and easy to reuse, for something that I was hoping wouldn't\nstay in git-compat for too long.\n\nThe use of the current helper function covers that use case but is by\ndesign harder to reuse while keeping the overall logic of the 2\ncombined functions more visible.\n\nOnce we move this code into a proper compat module, I would be happy\nto add a geteuid_or_sudo() function but that would be probably after\nwe also fix doas.\n\nCarlo\n"},{"id":"454549","messageId":"00d301d85a7b$0af698c0$20e3ca40$@nexbridge.com","threadId":"57799","inReplyTo":"CAPUEsph9tUkm+JsvU6z0Wt7mtRcTCH1vbvYTEdWjNyXzdoU=vw@mail.gmail.com","subject":"RE: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-27T21:09:05Z","receivedAt":"2022-04-27T21:09:14Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 27, 2022 5:00 PM, Carlo Arenas wrote:\n>On Wed, Apr 27, 2022 at 11:54 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n>> The \"sudo sh to get a shell, chdir to /var/tmp/foo to do something\"\n>> use case does care---it needs to make sure that whereever it goes is\n>> not part of a hostile repository.  So \"if SUDO_UID is there, anything\n>> goes\" is not a good protection for such a use case.\n>\n>FWIW that was never part of the proposal, indeed making git aware of SUDO_ID\n>when it is running as only as root was part of the design to avoid other users\n>probably allowing repositories they don't control by having an evil SUDO_ID.\n>\n>as per the root user, I was expecting that he could be trusted more and that\n>wouldn't accidentally get an evil SUDO_ID on their session because it is something\n>that gets generated from their original account and they should be aware of it and\n>even might need to tweak it\n>(ex: by un setting it if it gets in the way).\n<snip>\n\nFor perspective, the root user is specifically only trusted so far my community. Mucking about with repositories is frowned upon except for special system configuration repositories (ones for /etc, ssl certs, for example, and they have to sign those). Commit signing is being deployed to detect and as much practical prevent root (or any other user, elevated or not) from inappropriate repo history operations.\n\nJust sharing a different POV.\n--Randall\n\n"},{"id":"454551","messageId":"xmqqy1zqjk0x.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEsph9tUkm+JsvU6z0Wt7mtRcTCH1vbvYTEdWjNyXzdoU=vw@mail.gmail.com","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-27T21:25:50Z","receivedAt":"2022-04-27T21:25:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> On Wed, Apr 27, 2022 at 11:54 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n>> The \"sudo sh to get a shell, chdir to /var/tmp/foo to do something\"\n>> use case does care---it needs to make sure that whereever it goes is\n>> not part of a hostile repository.  So \"if SUDO_UID is there, anything\n>> goes\" is not a good protection for such a use case.\n>\n> FWIW that was never part of the proposal, indeed making git aware of\n> SUDO_ID when it is running as only as root was part of the design to\n> avoid other users probably allowing repositories they don't control by\n> having an evil SUDO_ID.\n\nYou forgot to quote:\n\n    This is not a suggestion of an alternative, but is a discussion\n    starter to illustrate the line along which we want to think\n    about the issues.\n\nthat came before it.\n\n>>  - do the comparison between st.st_uid and strtol() result by\n>>    casting both to (long).  Without this, st.st_uid has a value that\n>>    needs wider than long, we cannot allow the owner of such a\n>>    repository in (and I somehow feel that is unlikely to happen).\n>\n> do you still want to cast both sides even if discarding values that would\n> overflow an uid_t?\n\nThe variable used with strtol (or strtoull or whatever) does not\nhave to be casted.  The \"both sides\" was primarily for the case\nwhere st.st_uid is wider than whatever integral type we used to\nparse and hold the value we took from the environment, to force\nthe same truncation on st.st_uid as the truncation the environment\nparsing may have caused.  But as I keep saying I do not think it is\nworth it, which means ...\n\n>>  - or omit the third one --- tough luck for those whose UID is\n>>    beyond what a long can represent (and I somehow feel that this is\n>>    probably OK).\n\n... this one.\n"},{"id":"454560","messageId":"20220427222649.63516-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220427000522.15637-1-carenas@gmail.com","subject":"[RFC PATCH v2] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-27T22:26:49Z","receivedAt":"2022-04-27T22:27:01Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that user was\nroot (because git was invoked through sudo or a compatible tool) and the\noriginal uid that repository trusted for its config was no longer known,\ntherefore failing the following common call:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nthose tools create to keep track of the original user id, and do the\nownership check using that instead.\n\nThis assumes the environment the user is running with after going\nprivileged can't be tampered with, and also does the check only for\nroot to keep the most common case less complicated, but as a side effect\nwill miss cases where sudo (or an equivalent) was used to change to\nanother unprivileged user or where the equivalent tool used to raise\nprivileges didn't track the original id in a sudo compatible way.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\nChanges since v1\n* The helper function was completely rewritten to include all feedback,\n  specially in areas that were too confusing and that include:\n  - removing the return type that was only useful when doas was also supported\n    and that is therefore no longer needed since v1.\n  - using strtoul instead of strtol and assumed uid_t is unsigned.  This is\n    a likely more popular configuration and allows up to 2^32 uids in 32bit\n    systems.\n  - using errno to check for errors in strtoul, this also includes saving and\n    restoring the previous errno even if that is not yet needed.\n  - avoiding truncation issues in systems where sizeof(long) > sizeof(uid_t)\n    by discarding any values that wouldn't fit in an uid_t.  sudo uses\n    unsigned int to represent the uids so no valid id should be affected.\n    This assumes an unsigned uid_t which is not guaranteed by the standard\n    and therefore might need adjusting later if some platform we support does\n    not provide that (it is expected to trigger a warning at build time)\n  - renaming variables that had confusing names\n* Improved comments and commit message, and spell checked twice.\n\nSent as an RFC to make sure it fits everyone expectations and since it doesn't\nfully implement all suggestions that were proposed about the same time it was\nready.\n\n git-compat-util.h | 40 +++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 39 insertions(+), 1 deletion(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 58fd813bd01..3c9883934f6 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -437,12 +437,50 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n+/*\n+ * this helper function overrides a ROOT_UID with the one provided by\n+ * an environment variable, do not use unless the original user is\n+ * root\n+ */\n+static inline void extract_id_from_env(const char *env, uid_t *id)\n+{\n+\tconst char *real_uid = getenv(env);\n+\n+\t/* discard any empty values */\n+\tif (real_uid && *real_uid) {\n+\t\tchar *endptr;\n+\t\tunsigned long env_id;\n+\t\tint saved_errno = errno;\n+\n+\t\terrno = 0;\n+\t\tenv_id = strtoul(real_uid, &endptr, 10);\n+\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n+\t\t\t*id = env_id;\n+\n+\t\terrno = saved_errno;\n+\t}\n+}\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID)\n+\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\n-- \n2.36.0.266.g59f845bde02\n\n"},{"id":"454561","messageId":"xmqqilqujgvs.fsf@gitster.g","threadId":"57799","inReplyTo":"20220427222649.63516-1-carenas@gmail.com","subject":"Re: [RFC PATCH v2] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-27T22:33:43Z","receivedAt":"2022-04-27T22:33:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 58fd813bd01..3c9883934f6 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -437,12 +437,50 @@ static inline int git_offset_1st_component(const char *path)\n>  #endif\n>  \n>  #ifndef is_path_owned_by_current_user\n> +\n> +#ifdef __TANDEM\n> +#define ROOT_UID 65535\n> +#else\n> +#define ROOT_UID 0\n> +#endif\n> +\n> +/*\n> + * this helper function overrides a ROOT_UID with the one provided by\n> + * an environment variable, do not use unless the original user is\n> + * root\n> + */\n> +static inline void extract_id_from_env(const char *env, uid_t *id)\n> +{\n> +\tconst char *real_uid = getenv(env);\n> +\n> +\t/* discard any empty values */\n> +\tif (real_uid && *real_uid) {\n> +\t\tchar *endptr;\n> +\t\tunsigned long env_id;\n> +\t\tint saved_errno = errno;\n> +\n> +\t\terrno = 0;\n> +\t\tenv_id = strtoul(real_uid, &endptr, 10);\n> +\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n> +\t\t\t*id = env_id;\n\nSo we refrain from touching *id when we cannot read from SUDO_UID;\nlet's make sure that the caller is prepared for that ...\n\n> +\t\terrno = saved_errno;\n> +\t}\n> +}\n> +\n>  static inline int is_path_owned_by_current_uid(const char *path)\n>  {\n>  \tstruct stat st;\n> +\tuid_t euid;\n> +\n>  \tif (lstat(path, &st))\n>  \t\treturn 0;\n> -\treturn st.st_uid == geteuid();\n> +\n> +\teuid = geteuid();\n> +\tif (euid == ROOT_UID)\n> +\t\textract_id_from_env(\"SUDO_UID\", &euid);\n\n... and it is.  euid is set to the real thing, and the tweak done by\nthe helper function may overwrite it only when the helper computed\na value without an error.\n\n> +\treturn st.st_uid == euid;\n\nOK.  Looking good.\n\nWill queue.\n\n>  }\n>  \n>  #define is_path_owned_by_current_user is_path_owned_by_current_uid\n"},{"id":"454564","messageId":"20220428033544.68188-2-carenas@gmail.com","threadId":"57799","inReplyTo":"20220428033544.68188-1-carenas@gmail.com","subject":"[PATCH 1/2] Documentation: explain how safe.directory works when running under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T03:35:43Z","receivedAt":"2022-04-28T03:35:58Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"In a previous patch, the behaviour of git was changed so it will be able\nto find the \"effective uid\" that is required when git was invoked with\nsudo to root, for example:\n\n  $ sudo make install\n\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n Documentation/config/safe.txt | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex 6d764fe0ccf..67f8ef5d766 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -26,3 +26,11 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n is set in system config and you want to re-enable this protection, then\n initialize your list with an empty value before listing the repositories\n that you deem safe.\n++\n+When git tries to check for ownership of git repositories it will obviously\n+use the user that is being used to run git itself, but if git is running\n+as root, it will first check if it might had been started through `sudo`,\n+and if that is the case, will use the user id that invoked sudo instead.\n+If that is not what you would prefer and want git to instead only trust\n+repositories that are owned by root, then you should remove the `SUDO_UID`\n+variable from root's environment.\n-- \n2.36.0.266.g59f845bde02\n\n"},{"id":"454565","messageId":"20220428033544.68188-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220427222649.63516-1-carenas@gmail.com","subject":"[PATCH 0/2] fix `sudo make install` regression in maint","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T03:35:42Z","receivedAt":"2022-04-28T03:36:00Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"The following series complement the recently queued[0] RFC that adds\nthe missing functionality to allow git to validate a git repository\nwhile running under sudo.\n\nThey could be squashed together if preferred, as they seem to be\nsmaller that I had originally assumed and also unlikely to conflict.\n\nThe test uses a function I stole from rs/t7812-pcre2-ws-bug-test that\ncould be alternatively moved to a common location and reused if that\nis preferred, but it is small enough that might be as well be done\nas part of some cleanup later.\n\nTried to change the documentation in a way that wouldn't conflict with\nother on the fly changes, but there is at least one pending change\nnot in seen AFAIK in the same file from Gábor which might[1], but the\nresolution should be to take both sides.\n\nCarlo Marcelo Arenas Belón (2):\n  Documentation: explain how safe.directory works when running under\n    sudo\n  t: add tests for safe.directory when running with sudo\n\n Documentation/config/safe.txt  |  8 ++++++\n t/t0034-root-safe-directory.sh | 51 ++++++++++++++++++++++++++++++++++\n 2 files changed, 59 insertions(+)\n create mode 100755 t/t0034-root-safe-directory.sh\n\n[0] https://lore.kernel.org/git/xmqqilqujgvs.fsf@gitster.g/\n[1] https://lore.kernel.org/git/xmqqee1il09v.fsf@gitster.g/\n-- \n2.36.0.266.g59f845bde02\n\n"},{"id":"454566","messageId":"20220428033544.68188-3-carenas@gmail.com","threadId":"57799","inReplyTo":"20220428033544.68188-1-carenas@gmail.com","subject":"[PATCH 2/2] t: add tests for safe.directory when running with sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T03:35:44Z","receivedAt":"2022-04-28T03:36:03Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"In a previous commit the functionality for fixing this regression was\nimplemented, so add a test for it and the relevant infrastructure.\n\nThis new test file is meant to be run in CI and checks for a SUDO\nprerequisite which requires a passwordless configuration if run\nlocally, but that is common there.\n\nIt could be run locally by first running sudo, so the credentials are\ntemporarily cached and then running it as :\n\n  $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n\nIt is slightly ackward as it needs to clean up after itself since the\ntest framework would fail to do its own cleanup otherwise, and for\nsimplicity creates its own subtree while ignoring the one provided by\nthe framework, but doing some better integration has been punted.\n\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/t0034-root-safe-directory.sh | 51 ++++++++++++++++++++++++++++++++++\n 1 file changed, 51 insertions(+)\n create mode 100755 t/t0034-root-safe-directory.sh\n\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nnew file mode 100755\nindex 00000000000..c62bf3777c0\n--- /dev/null\n+++ b/t/t0034-root-safe-directory.sh\n@@ -0,0 +1,51 @@\n+#!/bin/sh\n+\n+test_description='verify safe.directory checks while running as root'\n+\n+. ./test-lib.sh\n+\n+if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]; then\n+\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run thi\n+s test\"\n+\ttest_done\n+fi\n+\n+if ! test_have_prereq NOT_ROOT\n+then\n+\tskip_all=\"this test uses sudo to run as root\"\n+\ttest_done\n+fi\n+\n+doalarm () {\n+\tperl -e 'alarm shift; exec @ARGV' -- \"$@\"\n+}\n+\n+test_lazy_prereq SUDO '\n+\tdoalarm 1 sudo id -u >u &&\n+\tid -u root >r &&\n+\ttest_cmp u r\n+'\n+\n+test_expect_success SUDO 'setup' '\n+\tsudo rm -rf root &&\n+\tmkdir -p root/r &&\n+\tsudo chown root root &&\n+\t(\n+\t\tcd root/r &&\n+\t\tgit init\n+\t)\n+'\n+\n+test_expect_success SUDO 'sudo git status works' '\n+\t(\n+\t\tcd root/r &&\n+\t\tgit status &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'cleanup' '\n+\tsudo rm -rf root\n+'\n+\n+test_done\n-- \n2.36.0.266.g59f845bde02\n\n"},{"id":"454567","messageId":"xmqqy1zphkk6.fsf@gitster.g","threadId":"57799","inReplyTo":"20220428033544.68188-1-carenas@gmail.com","subject":"Re: [PATCH 0/2] fix `sudo make install` regression in maint","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T04:57:13Z","receivedAt":"2022-04-28T04:57:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> The following series complement the recently queued[0] RFC that adds\n> the missing functionality to allow git to validate a git repository\n> while running under sudo.\n>\n> They could be squashed together if preferred, as they seem to be\n> smaller that I had originally assumed and also unlikely to conflict.\n>\n> The test uses a function I stole from rs/t7812-pcre2-ws-bug-test that\n> could be alternatively moved to a common location and reused if that\n> is preferred, but it is small enough that might be as well be done\n> as part of some cleanup later.\n>\n> Tried to change the documentation in a way that wouldn't conflict with\n> other on the fly changes, but there is at least one pending change\n> not in seen AFAIK in the same file from Gábor which might[1], but the\n> resolution should be to take both sides.\n\nWe shouldn't have to worry too much about anything that is not in\n'master', as we can kick out things that conflict whose resolution\nis too cumbersome and ask contributors to rebase and come back if\nneeded.  Regression fixes are more urgent than anything not in\n'master' at this point, although of course we do not have to make\nconflicts deliberately ;)\n\nIt seems that these two apply cleanly on top of the other one that\nin turn applies cleanly on top of maint-2.30, which is very much\nsuitable base to build these fixes on.\n\nThanks, will queue.\n\nI've already read through them but additional set of eyes are\nappreciated as always and even more than usual.  Hint, hint...\n\n\n\n"},{"id":"454568","messageId":"xmqqlevphjmg.fsf@gitster.g","threadId":"57799","inReplyTo":"20220428033544.68188-2-carenas@gmail.com","subject":"Re: [PATCH 1/2] Documentation: explain how safe.directory works when running under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T05:17:27Z","receivedAt":"2022-04-28T05:17:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> In a previous patch, the behaviour of git was changed so it will be able\n> to find the \"effective uid\" that is required when git was invoked with\n> sudo to root, for example:\n>\n>   $ sudo make install\n>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> ---\n>  Documentation/config/safe.txt | 8 ++++++++\n>  1 file changed, 8 insertions(+)\n>\n> diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\n> index 6d764fe0ccf..67f8ef5d766 100644\n> --- a/Documentation/config/safe.txt\n> +++ b/Documentation/config/safe.txt\n> @@ -26,3 +26,11 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n>  is set in system config and you want to re-enable this protection, then\n>  initialize your list with an empty value before listing the repositories\n>  that you deem safe.\n> ++\n> +When git tries to check for ownership of git repositories it will obviously\n\nComma before \"it will obviously\".\n\n> +use the user that is being used to run git itself, but if git is running\n> +as root, it will first check if it might had been started through `sudo`,\n> +and if that is the case, will use the user id that invoked sudo instead.\n\nThis raises a design question.  In a repository is owned by root,\nshouldn't \"sudo git describe\" work?  IOW, I am wondering if the\n\"instead\" at the end of the description is what we want, or if we\nwant to check both the original user and \"root\".\n\nThere is not much point in protecting against a malicious repository\na repository that is owned by \"root\"---an attacker that can create\nsuch a repository and futz with its config or hooks can attack you\nmore directly, without social engineering you into using git on such\na repository.  So from that point of view, it may be reasonable to\nsay that we can trust repositories owned by \n\n - euid (both when euid is root and euid is not root)\n - SUDO_UID (when euid is root)\n\nI think.  And even if we adopt such a tweak, ...\n\n> +If that is not what you would prefer and want git to instead only trust\n> +repositories that are owned by root, then you should remove the `SUDO_UID`\n> +variable from root's environment.\n\n... this is still true.\n\nI guess the necessary tweak to the code, if we were to take that\nsuggestion, would be quite small.  We are happy when euid owns the\npath (regardless of who euid is), and in addition, only when euid\nis root, we check with SUDO_UID, too.\n\n git-compat-util.h | 22 ++++++++++++----------\n 1 file changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git c/git-compat-util.h w/git-compat-util.h\nindex dfdd3e4f81..18660553b3 100644\n--- c/git-compat-util.h\n+++ w/git-compat-util.h\n@@ -401,13 +401,13 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n /*\n- * this helper function overrides a ROOT_UID with the one provided by\n- * an environment variable, do not use unless the original user is\n- * root\n+ * The environment variable (e.g. SUDO_UID) gives an integer;\n+ * is it the same as the given uid_t id?\n  */\n-static inline void extract_id_from_env(const char *env, uid_t *id)\n+static inline int id_from_env_matches(const char *env, uid_t id)\n {\n \tconst char *real_uid = getenv(env);\n+\tint matches = 0;\n \n \t/* discard any empty values */\n \tif (real_uid && *real_uid) {\n@@ -417,11 +417,12 @@ static inline void extract_id_from_env(const char *env, uid_t *id)\n \n \t\terrno = 0;\n \t\tenv_id = strtoul(real_uid, &endptr, 10);\n-\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n-\t\t\t*id = env_id;\n-\n+\t\tif (!errno && !*endptr && env_id <= (uid_t)-1 &&\n+\t\t    (uid_t)env_id == id)\n+\t\t\tmatches = 1;\n \t\terrno = saved_errno;\n \t}\n+\treturn matches;\n }\n \n static inline int is_path_owned_by_current_uid(const char *path)\n@@ -433,10 +434,11 @@ static inline int is_path_owned_by_current_uid(const char *path)\n \t\treturn 0;\n \n \teuid = geteuid();\n+\tif (st.st_uid == euid)\n+\t\treturn 1;\n \tif (euid == ROOT_UID)\n-\t\textract_id_from_env(\"SUDO_UID\", &euid);\n-\n-\treturn st.st_uid == euid;\n+\t\treturn id_from_env_matches(\"SUDO_UID\", st.st_uid);\n+\treturn 0;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\n"},{"id":"454569","messageId":"xmqqsfpxg4a5.fsf@gitster.g","threadId":"57799","inReplyTo":"20220428033544.68188-3-carenas@gmail.com","subject":"Re: [PATCH 2/2] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T05:34:10Z","receivedAt":"2022-04-28T05:34:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> In a previous commit the functionality for fixing this regression was\n> implemented, so add a test for it and the relevant infrastructure.\n>\n> This new test file is meant to be run in CI and checks for a SUDO\n> prerequisite which requires a passwordless configuration if run\n> locally, but that is common there.\n>\n> It could be run locally by first running sudo, so the credentials are\n> temporarily cached and then running it as :\n>\n>   $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n>\n> It is slightly ackward as it needs to clean up after itself since the\n\n\"awkward\", I think.\n\n> test framework would fail to do its own cleanup otherwise, and for\n> simplicity creates its own subtree while ignoring the one provided by\n> the framework, but doing some better integration has been punted.\n>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> ---\n>  t/t0034-root-safe-directory.sh | 51 ++++++++++++++++++++++++++++++++++\n>  1 file changed, 51 insertions(+)\n>  create mode 100755 t/t0034-root-safe-directory.sh\n>\n> diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\n> new file mode 100755\n> index 00000000000..c62bf3777c0\n> --- /dev/null\n> +++ b/t/t0034-root-safe-directory.sh\n> @@ -0,0 +1,51 @@\n> +#!/bin/sh\n> +\n> +test_description='verify safe.directory checks while running as root'\n> +\n> +. ./test-lib.sh\n> +\n> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]; then\n> +\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run thi\n> +s test\"\n> +\ttest_done\n> +fi\n> +\n> +if ! test_have_prereq NOT_ROOT\n> +then\n> +\tskip_all=\"this test uses sudo to run as root\"\n\nAs a statement of fact, there is nothing wrong per-se in this\nmessage.  It may be an explanation why you should not run this as\nroot, but as an explanation of the reason why all tests in this\nscript are skipped, and more importantly, hint to testers what they\nneed to do to correct the situation, this is too cryptic to readers.\n\nPerhaps telling them\n\n\tskip_all=\"do not run this test as root\"\n\nis more important and useful.\n\n> +\ttest_done\n> +fi\n> +\n> +doalarm () {\n> +\tperl -e 'alarm shift; exec @ARGV' -- \"$@\"\n> +}\n> +\n> +test_lazy_prereq SUDO '\n> +\tdoalarm 1 sudo id -u >u &&\n> +\tid -u root >r &&\n> +\ttest_cmp u r\n> +'\n> +\n> +test_expect_success SUDO 'setup' '\n> +\tsudo rm -rf root &&\n> +\tmkdir -p root/r &&\n> +\tsudo chown root root &&\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit init\n> +\t)\n> +'\n> +\n> +test_expect_success SUDO 'sudo git status works' '\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit status &&\n> +\t\tsudo git status\n> +\t)\n> +'\n\nAll of the above are positive tests.  One possible negative test is\nto prepare a root-owned repository and see what \"git status\" as\nyourself in there does.  And also see what \"git status\" as root\nthere does.\n\ntest_expect_success SUDO 'in root owned repository' '\n\tmkdir root/p\n        sudo chown root root/p &&\n\tsudo git init root/p &&\n\n\t# owned by other person (root), do I see it as a repository?\n\t(\n\t\tcd root/p &&\n\t\ttest_must_fail git status\n\t) &&\n\n\t# owned by root, can I access it under sudo?\n\t(\n\t\tcd root/p &&\n\t\tsudo git status\n\t)\n'\n\n> +test_expect_success SUDO 'cleanup' '\n> +\tsudo rm -rf root\n> +'\n> +\n> +test_done\n"},{"id":"454570","messageId":"CAPUEsphE1PkZ_oZVAizUqeJRaA3muL1t8ONH=7bCqvxOksf2zg@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqlevphjmg.fsf@gitster.g","subject":"Re: [PATCH 1/2] Documentation: explain how safe.directory works when running under sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T05:58:07Z","receivedAt":"2022-04-28T05:58:25Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Apr 27, 2022 at 10:17 PM Junio C Hamano <gitster@pobox.com> wrote:\n> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n> > diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\n> > index 6d764fe0ccf..67f8ef5d766 100644\n> > --- a/Documentation/config/safe.txt\n> > +++ b/Documentation/config/safe.txt\n> > @@ -26,3 +26,11 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n> >  is set in system config and you want to re-enable this protection, then\n> >  initialize your list with an empty value before listing the repositories\n> >  that you deem safe.\n> > ++\n> > +When git tries to check for ownership of git repositories it will obviously\n>\n> Comma before \"it will obviously\".\n\nObviously my whole paragraph could be improved further, do you want\na reroll with this fix, or would instead fixup locally?\n\n> > +use the user that is being used to run git itself, but if git is running\n\n\"use the user that is being used\", is something my high school grammar\nteacher would label as a \"cacophony\", so feel free to provide an\nalternative as well there.\n\n> > +as root, it will first check if it might had been started through `sudo`,\n> > +and if that is the case, will use the user id that invoked sudo instead.\n>\n> This raises a design question.  In a repository is owned by root,\n> shouldn't \"sudo git describe\" work?  IOW, I am wondering if the\n> \"instead\" at the end of the description is what we want, or if we\n> want to check both the original user and \"root\".\n\nI think it makes sense to have both, and your implementation below\nseems like a good way to do it but it might not be as safe as it\nseems, since sometimes directories owned by root might be also world\nwritable and therefore not necessarily safe.\n\nThis is obviously not directly related to this code, but the original\nissue as reported in Windows for the original CVE could be traced back\nto the default policy to allow any authenticated user to write in the\nroot directory.\n\nCarlo\n"},{"id":"454571","messageId":"xmqqh76dg15d.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEsphE1PkZ_oZVAizUqeJRaA3muL1t8ONH=7bCqvxOksf2zg@mail.gmail.com","subject":"Re: [PATCH 1/2] Documentation: explain how safe.directory works when running under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T06:41:50Z","receivedAt":"2022-04-28T06:42:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> On Wed, Apr 27, 2022 at 10:17 PM Junio C Hamano <gitster@pobox.com> wrote:\n>> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n>> > diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\n>> > index 6d764fe0ccf..67f8ef5d766 100644\n>> > --- a/Documentation/config/safe.txt\n>> > +++ b/Documentation/config/safe.txt\n>> > @@ -26,3 +26,11 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n>> >  is set in system config and you want to re-enable this protection, then\n>> >  initialize your list with an empty value before listing the repositories\n>> >  that you deem safe.\n>> > ++\n>> > +When git tries to check for ownership of git repositories it will obviously\n>>\n>> Comma before \"it will obviously\".\n>\n> Obviously my whole paragraph could be improved further, do you want\n> a reroll with this fix, or would instead fixup locally?\n\nI think the patches (including the previous one) are still fluid and\nexpect them to be reworked; local fix-ups would be a bit premature\nand leads to waste.  At least not yet.\n\n>> This raises a design question.  In a repository is owned by root,\n>> shouldn't \"sudo git describe\" work?  IOW, I am wondering if the\n>> \"instead\" at the end of the description is what we want, or if we\n>> want to check both the original user and \"root\".\n>\n> I think it makes sense to have both, and your implementation below\n> seems like a good way to do it but it might not be as safe as it\n> seems, since sometimes directories owned by root might be also world\n> writable and therefore not necessarily safe.\n\nI am not quite following you; that logic applies to directories\nowned by euid (not necessarily root).  As we are loosening to make\n\"sudo\" usable again, the use case to visit root-owned repository as\nroot via \"sudo\" is worth discussing, if not worth immediately\nsupporting, I would think.  I do not think it is absolutely needed\nas there is an easy workaround (see below).\n\nAssuming we will go without \"same euid, whether it is root or not,\nplus SUDO_UID when run as root\", here a test addition, updated from\nthe one I gave you in the review of [2/2]\n\ntest_expect_success SUDO 'in root owned repository' '\n\tmkdir root/p\n        sudo chown root root/p &&\n\tsudo git init root/p &&\n\n\t# owned by other person (root), do I see it as a repository?\n\t(\n\t\tcd root/p &&\n\t\ttest_must_fail git status\n\t) &&\n\n\t# owned by root, can I access it under sudo?\n\t(\n\t\tcd root/p &&\n\t\ttest_must_fail sudo git status\n\t) &&\n\n\t# workaround #1, giving GIT_DIR explicitly\n\t(\n\t\tcd root/p &&\n\t\tsudo \"\n\t\t\tGIT_DIR=.git GIT_WORK_TREE=. git status\n\t\t\"\n\t) &&\n\n\t# workaround #2, discarding SUDO_UID\n\t(\n\t\tcd root/p &&\n\t\tsudo \"\n\t\t\tunset SUDO_UID;\n\t\t\tgit status\n\t\t\"\n\t)\n'\n\n\n"},{"id":"454573","messageId":"20220428105852.94449-2-carenas@gmail.com","threadId":"57799","inReplyTo":"20220428105852.94449-1-carenas@gmail.com","subject":"[PATCH v2 1/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T10:58:50Z","receivedAt":"2022-04-28T10:59:59Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that user was\nroot (because git was invoked through sudo or a compatible tool) and the\noriginal uid that repository trusted for its config was no longer known,\ntherefore failing the following otherwise safe call:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nthose tools create to keep track of the original user id, and do the\nownership check using that instead.\n\nThis assumes the environment the user is running with after going\nprivileged can't be tampered with, and also does the check only for\nroot to keep the most common case less complicated, but as a side effect\nwill miss cases where sudo (or an equivalent) was used to change to\nanother unprivileged user or where the equivalent tool used to raise\nprivileges didn't track the original id in a sudo compatible way.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n git-compat-util.h | 40 +++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 39 insertions(+), 1 deletion(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 63ba89dd31d..dfdd3e4f81a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -393,12 +393,50 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n+/*\n+ * this helper function overrides a ROOT_UID with the one provided by\n+ * an environment variable, do not use unless the original user is\n+ * root\n+ */\n+static inline void extract_id_from_env(const char *env, uid_t *id)\n+{\n+\tconst char *real_uid = getenv(env);\n+\n+\t/* discard any empty values */\n+\tif (real_uid && *real_uid) {\n+\t\tchar *endptr;\n+\t\tunsigned long env_id;\n+\t\tint saved_errno = errno;\n+\n+\t\terrno = 0;\n+\t\tenv_id = strtoul(real_uid, &endptr, 10);\n+\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n+\t\t\t*id = env_id;\n+\n+\t\terrno = saved_errno;\n+\t}\n+}\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID)\n+\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454574","messageId":"20220428105852.94449-3-carenas@gmail.com","threadId":"57799","inReplyTo":"20220428105852.94449-1-carenas@gmail.com","subject":"[PATCH v2 2/3] Documentation: explain how safe.directory works when running under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T10:58:51Z","receivedAt":"2022-04-28T11:00:01Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"In a previous patch, the behavior of git was changed so it will be able\nto find the \"effective uid\" that is required when git was invoked with\nsudo to root, for example the internal calls made to git when calling\nthe following in git's own repository:\n\n  $ sudo make install\n\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/config/safe.txt | 9 +++++++++\n 1 file changed, 9 insertions(+)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex 6d764fe0ccf..ee558ced8c7 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -26,3 +26,12 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n is set in system config and you want to re-enable this protection, then\n initialize your list with an empty value before listing the repositories\n that you deem safe.\n++\n+When git tries to check for ownership of git repositories, it will\n+obviously do so with the uid of the user that is running git itself,\n+but if git is running as root, it will check first if it might have\n+been started through `sudo`, and if that is the case, will instead\n+use the uid of the user that did so.\n+If that is not what you would prefer and want git to only trust\n+repositories that are owned by root instead, then you should remove\n+the `SUDO_UID` variable from root's environment.\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454575","messageId":"20220428105852.94449-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220428033544.68188-1-carenas@gmail.com","subject":"[PATCH v2 0/3] fix `sudo make install` regression in maint","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T10:58:49Z","receivedAt":"2022-04-28T11:00:03Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Mainly documentation (both in the manual and commit messages) and\nextended/cleaner tests with the following considerations :\n\n * able to run as root, and therefore removed reported issue with message\n * remove perl function for a sudo native alternative and a more reliable\n   execution by making sure to avoid its PATH interceptions.\n * would likely need more changes to the test framework to avoid odities\n   but the deficiencies are clearly visible until then, and so safe for\n   backporting.\n\nCarlo Marcelo Arenas Belón (3):\n  git-compat-util: avoid failing dir ownership checks if running privileged\n  Documentation: explain how safe.directory works when running under sudo\n  t: add tests for safe.directory when running with sudo\n\n Documentation/config/safe.txt  |  9 ++++\n git-compat-util.h              | 40 +++++++++++++++-\n t/t0034-root-safe-directory.sh | 87 ++++++++++++++++++++++++++++++++++\n 3 files changed, 135 insertions(+), 1 deletion(-)\n create mode 100755 t/t0034-root-safe-directory.sh\n\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454576","messageId":"20220428105852.94449-4-carenas@gmail.com","threadId":"57799","inReplyTo":"20220428105852.94449-1-carenas@gmail.com","subject":"[PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T10:58:52Z","receivedAt":"2022-04-28T11:00:05Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"In a previous commit the functionality for fixing this regression was\nimplemented, so add the basic infrastructure needed to run sudo and\nimplement some tests with it.\n\nThis new test is meant to be mainly run in CI and therefore assumes\nthat the system where it runs provides passwordless sudo to root and\ndoesn't sanitize the path.\n\nAll tests should depend on the new SUDO prerequisite which validates\nthat setup is available but it could also run locally, with the right\nconfiguration and maybe making use of the sudo credential cache by\nfirst invoking sudo, entering your password if needed, and then\ninvoking the test by doing:\n\n  $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n\nIt is slightly awkward as it needs to run its own clean up task at\nthe end to remove the root owned directories and that the test\nframework can't yet manage, can't use the library inside sudo and\nit creates its own subtree and repositories while ignoring the one\nprovided by the framework, but improving that has been punted for now.\n\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t0034-root-safe-directory.sh | 87 ++++++++++++++++++++++++++++++++++\n 1 file changed, 87 insertions(+)\n create mode 100755 t/t0034-root-safe-directory.sh\n\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nnew file mode 100755\nindex 00000000000..fb54a2fb851\n--- /dev/null\n+++ b/t/t0034-root-safe-directory.sh\n@@ -0,0 +1,87 @@\n+#!/bin/sh\n+\n+test_description='verify safe.directory checks while running as root'\n+\n+. ./test-lib.sh\n+\n+if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]; then\n+\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run this test\"\n+\ttest_done\n+fi\n+\n+is_root() {\n+\ttest -n \"$1\" && CMD=\"sudo -n\"\n+\ttest $($CMD id -u) = $(id -u root)\n+}\n+\n+test_lazy_prereq SUDO '\n+\tis_root sudo &&\n+\t! sudo grep -E '^[^#].*secure_path' /etc/sudoers\n+'\n+\n+test_lazy_prereq ROOT '\n+\tis_root\n+'\n+\n+test_expect_success SUDO 'setup' '\n+\tsudo rm -rf root &&\n+\tmkdir -p root/r &&\n+\tsudo chown root root &&\n+\t(\n+\t\tcd root/r &&\n+\t\tgit init\n+\t)\n+'\n+\n+test_expect_success SUDO 'sudo git status as original owner' '\n+\t(\n+\t\tcd root/r &&\n+\t\tgit status &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'setup root owned repository' '\n+\tsudo mkdir -p root/p &&\n+\tsudo git init root/p\n+'\n+\n+test_expect_success SUDO,!ROOT 'can access if owned by root' '\n+\t(\n+\t\tcd root/p &&\n+\t\ttest_must_fail git status\n+\t)\n+'\n+\n+test_expect_success SUDO,!ROOT 'can access with sudo' '\n+\t# fail to access using sudo\n+\t(\n+\t\t# TODO: test_must_fail missing functionality\n+\t\tcd root/p &&\n+\t\t! sudo git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'can access with workaround' '\n+\t# provide explicit GIT_DIR\n+\t(\n+\t\tcd root/p &&\n+\t\tsudo sh -c \"\n+\t\t\tGIT_DIR=.git GIT_WORK_TREE=. git status\n+\t\t\"\n+\t) &&\n+\t# discard SUDO_UID\n+\t(\n+\t\tcd root/p &&\n+\t\tsudo sh -c \"\n+\t\t\tunset SUDO_UID &&\n+\t\t\tgit status\n+\t\t\"\n+\t)\n+'\n+\n+test_expect_success SUDO 'cleanup' '\n+\tsudo rm -rf root\n+'\n+\n+test_done\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454577","messageId":"xmqq7d79du6c.fsf@gitster.g","threadId":"57799","inReplyTo":"20220428105852.94449-4-carenas@gmail.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T16:55:23Z","receivedAt":"2022-04-28T16:55:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> +test_description='verify safe.directory checks while running as root'\n> +\n> +. ./test-lib.sh\n> +\n> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]; then\n\nStyle.\n\n\tif test \"$IKNOWWHATIAMDOING\" != \"YES\"\n\tthen\n\n> +is_root() {\n> +\ttest -n \"$1\" && CMD=\"sudo -n\"\n> +\ttest $($CMD id -u) = $(id -u root)\n> +}\n\nStyle.\n\n\tis_root () {\n\t\t... body ..\n\nBut more importantly, why do we need this in the first place?\nSANITY prerequisite checks if the user is running as root or\nnon-root---can't we use it here?\n\nOr perhaps my reading is wrong?  I assumed from its name that it was\njust \"see if we are running as user 'root' and return 0 or non-zero\nto answer\", but if it does more than that, like priming \"sudo\", then\nprobably it is misnamed.\n\n> +test_lazy_prereq SUDO '\n> +\tis_root sudo &&\n> +\t! sudo grep -E '^[^#].*secure_path' /etc/sudoers\n> +'\n\nOK.\n\n> +test_lazy_prereq ROOT '\n> +\tis_root\n> +'\n> +\n> +test_expect_success SUDO 'setup' '\n> +\tsudo rm -rf root &&\n> +\tmkdir -p root/r &&\n> +\tsudo chown root root &&\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit init\n> +\t)\n> +'\n\nWe have a root-owned directory \"root\" with a subdirectory \"r\" owned\nby us.  We want to be able to use our \"root/r\" directory as a\nrepository.  OK.\n\nThe prerequisite allows this test to be started as root, but I do\nnot quite see the point.  It may pass when started as root, but it\nis not testing what this test is designed to check (i.e. an ordinary\nuser who has repository at root/r can do things there).\n\n> +test_expect_success SUDO 'sudo git status as original owner' '\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit status &&\n> +\t\tsudo git status\n> +\t)\n> +'\n\nAnd the directory can be used by the user under \"sudo\", too.  Good.\n\nThe same \"this is allowed to run as root, but why?\" question\napplies.  If this was started by 'root', root, root/r and\nroot/r/.git all are owned by 'root' and we are checking if 'root'\ncan run 'git status' as 'root' (or 'root' via sudo) there.  Such a\ntest may well pass, but it is not catching a future regression on\nthe code you wrote for this series.\n\n> +test_expect_success SUDO 'setup root owned repository' '\n> +\tsudo mkdir -p root/p &&\n> +\tsudo git init root/p\n> +'\n\nNow we go on to create root owned repository at root/p\n\n> +test_expect_success SUDO,!ROOT 'can access if owned by root' '\n> +\t(\n> +\t\tcd root/p &&\n> +\t\ttest_must_fail git status\n> +\t)\n> +'\n\nAnd as an ordinary user, we fail to access a repository that is\nowned by a wrong person (i.e. root).  !ROOT (or SANITY) prereq\nshould be there NOT because the test written here would fail if run\nby root, but because running it as root, even if passed, is totally\npointless, because we are *not* testing \"person A has a repository,\nperson B cannot access it\" combination.\n\nThe other side of the same coin is that the lack of !ROOT (or\nSANITY) prereq in earlier tests I pointed out above misses the point\nof why we have prerequisite mechanism in the first place.  It is not\nto mark a test that fails when the precondition is not met.  It is\nto avoid running code that would NOT test what we want to test.\n\nThe difference is that a test that passes for a wrong reason\n(e.g. we wanted to see of person A can access a repository of their\nown even when the user identity is tentatively switched to 'root'\nvia 'sudo'---if person A is 'root', the access will be granted even\nif the special code to handle 'sudo' situation we have is broken)\nshould also be excluded with prerequisite.\n\n> +test_expect_success SUDO,!ROOT 'can access with sudo' '\n> +\t# fail to access using sudo\n> +\t(\n> +\t\t# TODO: test_must_fail missing functionality\n\nCare to explain a bit in the log message or in this comment the\nreason why we do not use test_must_fail but use ! here?  Are we\nover-eager to reject anything non \"git\" be fed, or something?\n\n> +\t\tcd root/p &&\n> +\t\t! sudo git status\n> +\t)\n> +'\n\nThe repository is owned by 'root', but because of the 'sudo'\n\"support\", you cannot access the repository with \"sudo git\".\n\nThe test title needs updating.  We expect that the repository cannot\nbe accessed under sudo.\n\n> +test_expect_success SUDO 'can access with workaround' '\n\n\"workarounds\", I think.\n\n> +\t# provide explicit GIT_DIR\n> +\t(\n> +\t\tcd root/p &&\n> +\t\tsudo sh -c \"\n> +\t\t\tGIT_DIR=.git GIT_WORK_TREE=. git status\n> +\t\t\"\n> +\t) &&\n> +\t# discard SUDO_UID\n> +\t(\n> +\t\tcd root/p &&\n> +\t\tsudo sh -c \"\n> +\t\t\tunset SUDO_UID &&\n> +\t\t\tgit status\n> +\t\t\"\n> +\t)\n> +'\n\nAgain, this lack !ROOT (or SANITY) because tests pass for a wrong\nreason.\n\nOverall, I like the simplicity and clarity of \"do not start this\ntest as 'root'\" in the previous round much better.\n\nBut other than that, the test coverage given by this patch looks\nquite sensible.\n\nThanks.\n\n> +\n> +test_expect_success SUDO 'cleanup' '\n> +\tsudo rm -rf root\n> +'\n> +\n> +test_done\n"},{"id":"454579","messageId":"fabb3940-7d6d-efb4-dba0-07531caf9d5e@gmail.com","threadId":"57799","inReplyTo":"xmqqzgk6l5ly.fsf@gitster.g","subject":"Re: [PATCH] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-28T17:56:35Z","receivedAt":"2022-04-28T17:56:42Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 27/04/2022 19:54, Junio C Hamano wrote:\n\n[ I've trimmed your discussion for brevity but thanks for taking the \ntime to write it out, it was helpful in clarifying what we're trying to \nprotect ourselves against]\n\n> So, in short, I think it is reasonable if we did:\n> \n>   - do the extra \"if SUDO_UID exists, then...\" only when we are root.\n> \n>   - use strtol to ensure SUDO_UID is in good shape (all digits) and\n>     read into long; use errno=0 trick to notice overflows.  err on\n>     the safe side and do not allow if the value cannot be read\n>     correctly.\n> \n>   - do the comparison between st.st_uid and strtol() result by\n>     casting both to (long).  Without this, st.st_uid has a value that\n>     needs wider than long, we cannot allow the owner of such a\n>     repository in (and I somehow feel that is unlikely to happen).\n> \n>   - or omit the third one --- tough luck for those whose UID is\n>     beyond what a long can represent (and I somehow feel that this is\n>     probably OK).\n\nI think that unsigned long should be wide enough. On x86 linux uid_t is \nuint32_t for both 32 & 64 bit processors. That means that we could \ntruncate the value we read from SUDO_UID when long is 64 bits if it is \ncast to uid_t but we're supposed to be able to trust that SUDO_UID is a \nvalid id so that shouldn't be a problem. If an attacker can change \nwhat's in SUDO_UID we're doomed anyway.\n\nBest Wishes\n\nPhillip\n"},{"id":"454580","messageId":"225d0f01-89d5-f2b4-36f2-097b915d66c5@gmail.com","threadId":"57799","inReplyTo":"20220428105852.94449-2-carenas@gmail.com","subject":"Re: [PATCH v2 1/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-28T18:02:45Z","receivedAt":"2022-04-28T18:02:51Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Carlo\n\nOn 28/04/2022 11:58, Carlo Marcelo Arenas Belón wrote:\n> bdc77d1d685 (Add a function to determine whether a path is owned by the\n> current user, 2022-03-02) checks for the effective uid of the running\n> process using geteuid() but didn't account for cases where that user was\n> root (because git was invoked through sudo or a compatible tool) and the\n> original uid that repository trusted for its config was no longer known,\n> therefore failing the following otherwise safe call:\n> \n>    guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n>    [sudo] password for guy:\n>    fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n> \n> Attempt to detect those cases by using the environment variables that\n> those tools create to keep track of the original user id, and do the\n> ownership check using that instead.\n> \n> This assumes the environment the user is running with after going\n> privileged can't be tampered with, and also does the check only for\n> root to keep the most common case less complicated, but as a side effect\n> will miss cases where sudo (or an equivalent) was used to change to\n> another unprivileged user or where the equivalent tool used to raise\n> privileges didn't track the original id in a sudo compatible way.\n> \n> Reported-by: Guy Maurel <guy.j@maurel.de>\n> Helped-by: SZEDER Gábor <szeder.dev@gmail.com>\n> Helped-by: Randall Becker <rsbecker@nexbridge.com>\n> Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n> Suggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>   git-compat-util.h | 40 +++++++++++++++++++++++++++++++++++++++-\n>   1 file changed, 39 insertions(+), 1 deletion(-)\n> \n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 63ba89dd31d..dfdd3e4f81a 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -393,12 +393,50 @@ static inline int git_offset_1st_component(const char *path)\n>   #endif\n>   \n>   #ifndef is_path_owned_by_current_user\n> +\n> +#ifdef __TANDEM\n> +#define ROOT_UID 65535\n> +#else\n> +#define ROOT_UID 0\n> +#endif\n> +\n> +/*\n> + * this helper function overrides a ROOT_UID with the one provided by\n> + * an environment variable, do not use unless the original user is\n> + * root\n> + */\n> +static inline void extract_id_from_env(const char *env, uid_t *id)\n> +{\n> +\tconst char *real_uid = getenv(env);\n> +\n> +\t/* discard any empty values */\n> +\tif (real_uid && *real_uid) {\n> +\t\tchar *endptr;\n> +\t\tunsigned long env_id;\n> +\t\tint saved_errno = errno;\n\nI still don't understand why you're worried about preserving errno - am \nI missing something? It's not wrong to save it but I'm not sure why we \nneed to. is_path_owned_by_current_uid() does not save it around the stat \ncall so why do we need to do this here?\n\n> +\n> +\t\terrno = 0;\n> +\t\tenv_id = strtoul(real_uid, &endptr, 10);\n> +\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n\nThinking out loud:\n\"!errno && !*endptr\" ensures we have read a valid integer from SUDO_UID. \nIf uid_t is unsigned then \"env_id <= (uid_t)-1\" ensures the value we \nread fits into a uid_t. If uid_t is signed then this test is always true \nand we could truncate the value we read. However if we don't trust \nSUDO_UID then we shouldn't be doing any of this so we are trusting that \nthe truncation never happens which means we probably don't need this \ntest in the first place.\n\nBest Wishes\n\nPhillip\n\n> +\t\t\t*id = env_id;\n> +\n> +\t\terrno = saved_errno;\n> +\t}\n> +}\n> +\n>   static inline int is_path_owned_by_current_uid(const char *path)\n>   {\n>   \tstruct stat st;\n> +\tuid_t euid;\n> +\n>   \tif (lstat(path, &st))\n>   \t\treturn 0;\n> -\treturn st.st_uid == geteuid();\n> +\n> +\teuid = geteuid();\n> +\tif (euid == ROOT_UID)\n> +\t\textract_id_from_env(\"SUDO_UID\", &euid);\n> +\n> +\treturn st.st_uid == euid;\n>   }\n>   \n>   #define is_path_owned_by_current_user is_path_owned_by_current_uid\n"},{"id":"454581","messageId":"5493b2f1-e59d-d91d-ac21-47c93d2996f2@gmail.com","threadId":"57799","inReplyTo":"xmqq7d79du6c.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-04-28T18:08:46Z","receivedAt":"2022-04-28T18:08:53Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 28/04/2022 17:55, Junio C Hamano wrote:\n> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n> \n>> +test_description='verify safe.directory checks while running as root'\n>> +\n>> +. ./test-lib.sh\n>> +\n>> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]; then\n> \n> Style.\n> \n> \tif test \"$IKNOWWHATIAMDOING\" != \"YES\"\n> \tthen\n\nAlso naming - we normally prefix test environment variables with \nGIT_TEST_. IKNOWWHATIAMDOING does not tell us what we are allowing by \nsetting the variable. Something like GIT_TEST_ALLOW_SUDO would tell us \nwhat we're letting ourselves in for by setting it.\n\n>> +is_root() {\n>> +\ttest -n \"$1\" && CMD=\"sudo -n\"\n>> +\ttest $($CMD id -u) = $(id -u root)\n>> +}\n> \n> Style.\n> \n> \tis_root () {\n> \t\t... body ..\n> \n> But more importantly, why do we need this in the first place?\n> SANITY prerequisite checks if the user is running as root or\n> non-root---can't we use it here?\n> \n> Or perhaps my reading is wrong?  I assumed from its name that it was\n> just \"see if we are running as user 'root' and return 0 or non-zero\n> to answer\", but if it does more than that, like priming \"sudo\", then\n> probably it is misnamed.\n\nI'm confused by this as well. Also if $1 is empty we run whatever \nhappens to be in $CMD.\n\nBest Wishes\n\nPhillip\n\n>> +test_lazy_prereq SUDO '\n>> +\tis_root sudo &&\n>> +\t! sudo grep -E '^[^#].*secure_path' /etc/sudoers\n>> +'\n> \n> OK.\n> \n>> +test_lazy_prereq ROOT '\n>> +\tis_root\n>> +'\n>> +\n>> +test_expect_success SUDO 'setup' '\n>> +\tsudo rm -rf root &&\n>> +\tmkdir -p root/r &&\n>> +\tsudo chown root root &&\n>> +\t(\n>> +\t\tcd root/r &&\n>> +\t\tgit init\n>> +\t)\n>> +'\n> \n> We have a root-owned directory \"root\" with a subdirectory \"r\" owned\n> by us.  We want to be able to use our \"root/r\" directory as a\n> repository.  OK.\n> \n> The prerequisite allows this test to be started as root, but I do\n> not quite see the point.  It may pass when started as root, but it\n> is not testing what this test is designed to check (i.e. an ordinary\n> user who has repository at root/r can do things there).\n> \n>> +test_expect_success SUDO 'sudo git status as original owner' '\n>> +\t(\n>> +\t\tcd root/r &&\n>> +\t\tgit status &&\n>> +\t\tsudo git status\n>> +\t)\n>> +'\n> \n> And the directory can be used by the user under \"sudo\", too.  Good.\n> \n> The same \"this is allowed to run as root, but why?\" question\n> applies.  If this was started by 'root', root, root/r and\n> root/r/.git all are owned by 'root' and we are checking if 'root'\n> can run 'git status' as 'root' (or 'root' via sudo) there.  Such a\n> test may well pass, but it is not catching a future regression on\n> the code you wrote for this series.\n> \n>> +test_expect_success SUDO 'setup root owned repository' '\n>> +\tsudo mkdir -p root/p &&\n>> +\tsudo git init root/p\n>> +'\n> \n> Now we go on to create root owned repository at root/p\n> \n>> +test_expect_success SUDO,!ROOT 'can access if owned by root' '\n>> +\t(\n>> +\t\tcd root/p &&\n>> +\t\ttest_must_fail git status\n>> +\t)\n>> +'\n> \n> And as an ordinary user, we fail to access a repository that is\n> owned by a wrong person (i.e. root).  !ROOT (or SANITY) prereq\n> should be there NOT because the test written here would fail if run\n> by root, but because running it as root, even if passed, is totally\n> pointless, because we are *not* testing \"person A has a repository,\n> person B cannot access it\" combination.\n> \n> The other side of the same coin is that the lack of !ROOT (or\n> SANITY) prereq in earlier tests I pointed out above misses the point\n> of why we have prerequisite mechanism in the first place.  It is not\n> to mark a test that fails when the precondition is not met.  It is\n> to avoid running code that would NOT test what we want to test.\n> \n> The difference is that a test that passes for a wrong reason\n> (e.g. we wanted to see of person A can access a repository of their\n> own even when the user identity is tentatively switched to 'root'\n> via 'sudo'---if person A is 'root', the access will be granted even\n> if the special code to handle 'sudo' situation we have is broken)\n> should also be excluded with prerequisite.\n> \n>> +test_expect_success SUDO,!ROOT 'can access with sudo' '\n>> +\t# fail to access using sudo\n>> +\t(\n>> +\t\t# TODO: test_must_fail missing functionality\n> \n> Care to explain a bit in the log message or in this comment the\n> reason why we do not use test_must_fail but use ! here?  Are we\n> over-eager to reject anything non \"git\" be fed, or something?\n> \n>> +\t\tcd root/p &&\n>> +\t\t! sudo git status\n>> +\t)\n>> +'\n> \n> The repository is owned by 'root', but because of the 'sudo'\n> \"support\", you cannot access the repository with \"sudo git\".\n> \n> The test title needs updating.  We expect that the repository cannot\n> be accessed under sudo.\n> \n>> +test_expect_success SUDO 'can access with workaround' '\n> \n> \"workarounds\", I think.\n> \n>> +\t# provide explicit GIT_DIR\n>> +\t(\n>> +\t\tcd root/p &&\n>> +\t\tsudo sh -c \"\n>> +\t\t\tGIT_DIR=.git GIT_WORK_TREE=. git status\n>> +\t\t\"\n>> +\t) &&\n>> +\t# discard SUDO_UID\n>> +\t(\n>> +\t\tcd root/p &&\n>> +\t\tsudo sh -c \"\n>> +\t\t\tunset SUDO_UID &&\n>> +\t\t\tgit status\n>> +\t\t\"\n>> +\t)\n>> +'\n> \n> Again, this lack !ROOT (or SANITY) because tests pass for a wrong\n> reason.\n> \n> Overall, I like the simplicity and clarity of \"do not start this\n> test as 'root'\" in the previous round much better.\n> \n> But other than that, the test coverage given by this patch looks\n> quite sensible.\n> \n> Thanks.\n> \n>> +\n>> +test_expect_success SUDO 'cleanup' '\n>> +\tsudo rm -rf root\n>> +'\n>> +\n>> +test_done\n\n"},{"id":"454582","messageId":"xmqq7d79gjre.fsf@gitster.g","threadId":"57799","inReplyTo":"5493b2f1-e59d-d91d-ac21-47c93d2996f2@gmail.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T18:12:05Z","receivedAt":"2022-04-28T18:12:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> On 28/04/2022 17:55, Junio C Hamano wrote:\n>> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n>> \n>>> +test_description='verify safe.directory checks while running as root'\n>>> +\n>>> +. ./test-lib.sh\n>>> +\n>>> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]; then\n>> Style.\n>> \tif test \"$IKNOWWHATIAMDOING\" != \"YES\"\n>> \tthen\n>\n> Also naming - we normally prefix test environment variables with\n> GIT_TEST_. IKNOWWHATIAMDOING does not tell us what we are allowing by \n> setting the variable. Something like GIT_TEST_ALLOW_SUDO would tell us\n> what we're letting ourselves in for by setting it.\n\nIf this weren't \"let's reuse the same mechanism as already used in\n1509\", I would have had the same reaction.  Renaming would be better\ndone outside the topic, I would think.\n\nThanks.\n"},{"id":"454586","messageId":"CAPUEsphFb-=BcV-mxS5RZpJQ8UVq23ni0Lo8tQ4J3TP04B4KQg@mail.gmail.com","threadId":"57799","inReplyTo":"225d0f01-89d5-f2b4-36f2-097b915d66c5@gmail.com","subject":"Re: [PATCH v2 1/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T18:57:53Z","receivedAt":"2022-04-28T18:58:07Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, Apr 28, 2022 at 11:02 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> On 28/04/2022 11:58, Carlo Marcelo Arenas Belón wrote:\n>\n> I still don't understand why you're worried about preserving errno - am\n> I missing something?\n\nI don't think so, you are correct that doing so is useless now and\ncould be dropped, I even said so in my message.\n\n> It's not wrong to save it but I'm not sure why we\n> need to. is_path_owned_by_current_uid() does not save it around the stat\n> call so why do we need to do this here?\n\nbecause the errno from is_path_owned_by_current_uid() is useful and\nunlike this one is not being handled, so a caller of that function\nmight later use it to distinguish between a \"dunno\" and \"no\" answer to\nthe \"is path owned by current uid\" question and more importantly\nunderstand better why \"dunno\" was the answer (ex: path has a loop, or\nnot accessible or whatever).\n\nit also documents (in the code) that this function won't report any\nissues it might have getting that information from the environment\n(which extra checks on top to make sure anything suspicious is\nignored), so you can trust that if you get an answer it was a valid\none.\n\n> > +             errno = 0;\n> > +             env_id = strtoul(real_uid, &endptr, 10);\n> > +             if (!errno && !*endptr && env_id <= (uid_t)-1)\n>\n> Thinking out loud:\n> \"!errno && !*endptr\" ensures we have read a valid integer from SUDO_UID.\n> If uid_t is unsigned then \"env_id <= (uid_t)-1\" ensures the value we\n> read fits into a uid_t. If uid_t is signed then this test is always true\n\nand you hopefully got a warning at build time.\n\n> and we could truncate the value we read. However if we don't trust\n> SUDO_UID then we shouldn't be doing any of this so we are trusting that\n> the truncation never happens which means we probably don't need this\n> test in the first place.\n\nit is there to protect us against a system where uid_t is unsigned but\nstill narrower than long, and so we don't accidentally assume uid = 0\nif we somehow get (the obviously tampered with) SUDO_UID = UINT_MAX +\n1\n\nCarlo\n"},{"id":"454588","messageId":"000001d85b39$9d5cfc90$d816f5b0$@nexbridge.com","threadId":"57799","inReplyTo":"xmqq7d79du6c.fsf@gitster.g","subject":"RE: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-28T19:53:12Z","receivedAt":"2022-04-28T19:53:29Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 28, 2022 12:55 PM, Junio C Hamano wrote:\n>Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n>\n>> +test_description='verify safe.directory checks while running as root'\n>> +\n>> +. ./test-lib.sh\n>> +\n>> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]; then\n>\n>Style.\n>\n>\tif test \"$IKNOWWHATIAMDOING\" != \"YES\"\n>\tthen\n>\n>> +is_root() {\n>> +\ttest -n \"$1\" && CMD=\"sudo -n\"\n>> +\ttest $($CMD id -u) = $(id -u root)\n>> +}\n>\n>Style.\n>\n>\tis_root () {\n>\t\t... body ..\n>\n>But more importantly, why do we need this in the first place?\n>SANITY prerequisite checks if the user is running as root or non-root---can't we\n>use it here?\n>\n>Or perhaps my reading is wrong?  I assumed from its name that it was just \"see if\n>we are running as user 'root' and return 0 or non-zero to answer\", but if it does\n>more than that, like priming \"sudo\", then probably it is misnamed.\n>\n>> +test_lazy_prereq SUDO '\n>> +\tis_root sudo &&\n>> +\t! sudo grep -E '^[^#].*secure_path' /etc/sudoers '\n\n/etc/sudoers is not standard although usual. This path should come from a knob somewhere. We can't run this test on our x86 system anyway - no access to root or sudo even though it is installed. Also, /etc/sudoers is typically secured 0600 so the grep will fail even if is_root passes - and I'm worried about the portability of is_root, which is mostly Linux.\n\n>OK.\n>\n>> +test_lazy_prereq ROOT '\n>> +\tis_root\n>> +'\n>> +\n>> +test_expect_success SUDO 'setup' '\n>> +\tsudo rm -rf root &&\n>> +\tmkdir -p root/r &&\n>> +\tsudo chown root root &&\n>> +\t(\n>> +\t\tcd root/r &&\n>> +\t\tgit init\n>> +\t)\n>> +'\n>\n>We have a root-owned directory \"root\" with a subdirectory \"r\" owned by us.  We\n>want to be able to use our \"root/r\" directory as a repository.  OK.\n>\n>The prerequisite allows this test to be started as root, but I do not quite see the\n>point.  It may pass when started as root, but it is not testing what this test is\n>designed to check (i.e. an ordinary user who has repository at root/r can do things\n>there).\n>\n>> +test_expect_success SUDO 'sudo git status as original owner' '\n>> +\t(\n>> +\t\tcd root/r &&\n>> +\t\tgit status &&\n>> +\t\tsudo git status\n>> +\t)\n>> +'\n>\n>And the directory can be used by the user under \"sudo\", too.  Good.\n>\n>The same \"this is allowed to run as root, but why?\" question applies.  If this was\n>started by 'root', root, root/r and root/r/.git all are owned by 'root' and we are\n>checking if 'root'\n>can run 'git status' as 'root' (or 'root' via sudo) there.  Such a test may well pass, but\n>it is not catching a future regression on the code you wrote for this series.\n>\n>> +test_expect_success SUDO 'setup root owned repository' '\n>> +\tsudo mkdir -p root/p &&\n>> +\tsudo git init root/p\n>> +'\n>\n>Now we go on to create root owned repository at root/p\n>\n>> +test_expect_success SUDO,!ROOT 'can access if owned by root' '\n>> +\t(\n>> +\t\tcd root/p &&\n>> +\t\ttest_must_fail git status\n>> +\t)\n>> +'\n>\n>And as an ordinary user, we fail to access a repository that is owned by a wrong\n>person (i.e. root).  !ROOT (or SANITY) prereq should be there NOT because the\n>test written here would fail if run by root, but because running it as root, even if\n>passed, is totally pointless, because we are *not* testing \"person A has a\n>repository, person B cannot access it\" combination.\n>\n>The other side of the same coin is that the lack of !ROOT (or\n>SANITY) prereq in earlier tests I pointed out above misses the point of why we\n>have prerequisite mechanism in the first place.  It is not to mark a test that fails\n>when the precondition is not met.  It is to avoid running code that would NOT test\n>what we want to test.\n>\n>The difference is that a test that passes for a wrong reason (e.g. we wanted to see\n>of person A can access a repository of their own even when the user identity is\n>tentatively switched to 'root'\n>via 'sudo'---if person A is 'root', the access will be granted even if the special code\n>to handle 'sudo' situation we have is broken) should also be excluded with\n>prerequisite.\n>\n>> +test_expect_success SUDO,!ROOT 'can access with sudo' '\n>> +\t# fail to access using sudo\n>> +\t(\n>> +\t\t# TODO: test_must_fail missing functionality\n>\n>Care to explain a bit in the log message or in this comment the reason why we do\n>not use test_must_fail but use ! here?  Are we over-eager to reject anything non\n>\"git\" be fed, or something?\n>\n>> +\t\tcd root/p &&\n>> +\t\t! sudo git status\n>> +\t)\n>> +'\n>\n>The repository is owned by 'root', but because of the 'sudo'\n>\"support\", you cannot access the repository with \"sudo git\".\n>\n>The test title needs updating.  We expect that the repository cannot be accessed\n>under sudo.\n>\n>> +test_expect_success SUDO 'can access with workaround' '\n>\n>\"workarounds\", I think.\n>\n>> +\t# provide explicit GIT_DIR\n>> +\t(\n>> +\t\tcd root/p &&\n>> +\t\tsudo sh -c \"\n>> +\t\t\tGIT_DIR=.git GIT_WORK_TREE=. git status\n>> +\t\t\"\n>> +\t) &&\n>> +\t# discard SUDO_UID\n>> +\t(\n>> +\t\tcd root/p &&\n>> +\t\tsudo sh -c \"\n>> +\t\t\tunset SUDO_UID &&\n>> +\t\t\tgit status\n>> +\t\t\"\n>> +\t)\n>> +'\n>\n>Again, this lack !ROOT (or SANITY) because tests pass for a wrong reason.\n>\n>Overall, I like the simplicity and clarity of \"do not start this test as 'root'\" in the\n>previous round much better.\n>\n>But other than that, the test coverage given by this patch looks quite sensible.\n>\n>Thanks.\n>\n>> +\n>> +test_expect_success SUDO 'cleanup' '\n>> +\tsudo rm -rf root\n>> +'\n>> +\n>> +test_done\n\n"},{"id":"454590","messageId":"CAPUEsph+p-fD8vMOMU4Djkc8cFUmm=9JVFdgaxkQ4-CpKZgnCA@mail.gmail.com","threadId":"57799","inReplyTo":"000001d85b39$9d5cfc90$d816f5b0$@nexbridge.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T20:22:42Z","receivedAt":"2022-04-28T20:22:57Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, Apr 28, 2022 at 12:53 PM <rsbecker@nexbridge.com> wrote:\n> /etc/sudoers is not standard although usual. This path should come from a knob somewhere. We can't run this test on our x86 system anyway - no access to root or sudo even though it is installed.\n\ncorrect and note that the test would succeed if the file doesn't exist\nbecause what we are really interested on, is to make sure that sudo\nwon't mess with our path when invoking git, and if there is a chance\nit would (because that setting is enabled in a different file for\nexample) then we will just skip these tests.\n\nObviously the target I had in mind when I built this test was my own\nworkstation and our public CI, but feel free to provide a fixup that\nwould also make it work for your private runs if you are interested in\nalso running this test.\n\n> Also, /etc/sudoers is typically secured 0600 so the grep will fail even if is_root passes\n\nIt won't, because it is running with sudo ;).  note that as stated in\nthe commit message, this requires a fairly open sudo setup (like the\none github provides with their actions).\n\n> - and I'm worried about the portability of is_root, which is mostly Linux.\n\nI actually made sure that is_root was posix shell compatible, but got\na little carried away when refactoring it to accomodate for reuse;\neitherway it is gone in v3.\n\nCarlo\n"},{"id":"454591","messageId":"xmqqbkwleypf.fsf@gitster.g","threadId":"57799","inReplyTo":"000001d85b39$9d5cfc90$d816f5b0$@nexbridge.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T20:32:12Z","receivedAt":"2022-04-28T20:32:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"<rsbecker@nexbridge.com> writes:\n\n>>> +test_lazy_prereq SUDO '\n>>> +\tis_root sudo &&\n>>> +\t! sudo grep -E '^[^#].*secure_path' /etc/sudoers '\n>\n> /etc/sudoers is not standard although usual. This path should come\n> from a knob somewhere. We can't run this test on our x86 system\n> anyway - no access to root or sudo even though it is\n> installed. Also, /etc/sudoers is typically secured 0600 so the\n> grep will fail even if is_root passes - and I'm worried about the\n> portability of is_root, which is mostly Linux.\n\nTrue.\n\nOn a box I happen to be using, the grep gives me\n\n    Defaults secure_path=/usr/sbin:/usr/bin:/sbin:/bin\n\nand makes the prereq fail.  Which is sort-of expected, and I\nunderstand why this check is here, but I suspect that any sane and\nsensible installations would reinitialize the path to a fairly\nrestricted one with the mechanism, so we wouldn't be testing this on\nmajority of places, I am afraid.\n\nWhat we really care is that we use the same PATH as the test\nenvironment uses, including \"we want to test the binary we just\nbuilt\" (or \"at the specified path\", when GIT_TEST_INSTALLED is in\neffect).  I wonder what the right way to carry $PATH and other\nenvironment variables down to whatever \"sudo\" in the test runs.\n\n    $ foo=foobla; export foo\n    $ sudo sh -c set | grep foo; echo $?\n    1\n\nso resetting PATH from an environment we export, e.g.\n\n    USE_THIS_PATH=$PATH sudo sh -c '\n\tPATH=$USE_THIS_PATH\n\t... invoke our git normally here  ...\n\tgit status\n    '\n\nwould not work X-<.  Worse yet, other environment variables such as\nGIT_TEST_DEFAULT_INITIAL_BRANCH_NAME that we set in our tests may\nprobably be cleared before \"sudo\" runs any test command, so rejecting\nan installaion whose \"sudo\" resets PATH with the above check is probably\ninsufficient to give our tests a reasonable envionment to run in.\n\n>>Overall, I like the simplicity and clarity of \"do not start this test as 'root'\" in the\n>>previous round much better.\n>>\n>>But other than that, the test coverage given by this patch looks quite sensible.\n\nSo, I unfortunately have to strike the last sentence from my earlier\nresponse.  The tests do mean well, but I doubt they would work in\nthe way the good intentions planned them to work.\n\n"},{"id":"454592","messageId":"000701d85b40$4819baf0$d84d30d0$@nexbridge.com","threadId":"57799","inReplyTo":"xmqqbkwleypf.fsf@gitster.g","subject":"RE: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-28T20:40:59Z","receivedAt":"2022-04-28T20:41:11Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 28, 2022 4:32 PM, Junio C Hamano wrote:\n>To: rsbecker@nexbridge.com\n>Cc: 'Carlo Marcelo Arenas Belón' <carenas@gmail.com>; git@vger.kernel.org\n>Subject: Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo\n>\n><rsbecker@nexbridge.com> writes:\n>\n>>>> +test_lazy_prereq SUDO '\n>>>> +\tis_root sudo &&\n>>>> +\t! sudo grep -E '^[^#].*secure_path' /etc/sudoers '\n>>\n>> /etc/sudoers is not standard although usual. This path should come\n>> from a knob somewhere. We can't run this test on our x86 system anyway\n>> - no access to root or sudo even though it is installed. Also,\n>> /etc/sudoers is typically secured 0600 so the grep will fail even if\n>> is_root passes - and I'm worried about the portability of is_root,\n>> which is mostly Linux.\n>\n>True.\n>\n>On a box I happen to be using, the grep gives me\n>\n>    Defaults secure_path=/usr/sbin:/usr/bin:/sbin:/bin\n>\n>and makes the prereq fail.  Which is sort-of expected, and I understand why this\n>check is here, but I suspect that any sane and sensible installations would\n>reinitialize the path to a fairly restricted one with the mechanism, so we wouldn't\n>be testing this on majority of places, I am afraid.\n>\n>What we really care is that we use the same PATH as the test environment uses,\n>including \"we want to test the binary we just built\" (or \"at the specified path\",\n>when GIT_TEST_INSTALLED is in effect).  I wonder what the right way to carry\n>$PATH and other environment variables down to whatever \"sudo\" in the test\n>runs.\n>\n>    $ foo=foobla; export foo\n>    $ sudo sh -c set | grep foo; echo $?\n>    1\n>\n>so resetting PATH from an environment we export, e.g.\n>\n>    USE_THIS_PATH=$PATH sudo sh -c '\n>\tPATH=$USE_THIS_PATH\n>\t... invoke our git normally here  ...\n>\tgit status\n>    '\n>\n>would not work X-<.  Worse yet, other environment variables such as\n>GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME that we set in our tests may\n>probably be cleared before \"sudo\" runs any test command, so rejecting an\n>installaion whose \"sudo\" resets PATH with the above check is probably insufficient\n>to give our tests a reasonable envionment to run in.\n>\n>>>Overall, I like the simplicity and clarity of \"do not start this test\n>>>as 'root'\" in the previous round much better.\n>>>\n>>>But other than that, the test coverage given by this patch looks quite sensible.\n>\n>So, I unfortunately have to strike the last sentence from my earlier response.  The\n>tests do mean well, but I doubt they would work in the way the good intentions\n>planned them to work.\n\nsudo on my machines is very specific that it does not preserve much of the environment. This causes all kinds of DLL load issues too. We rarely can build regression test suites that include sudo testing. More than that, it is general policy that password-less sudo is frowned upon, so I'm pretty sure we cannot run this test. When we run the git test suite, it is done by a user who is, by design, excluded from the sudoers file because regression tests happen in a sandbox.\n\n"},{"id":"454593","messageId":"000801d85b40$ac11ec80$0435c580$@nexbridge.com","threadId":"57799","inReplyTo":"CAPUEsph+p-fD8vMOMU4Djkc8cFUmm=9JVFdgaxkQ4-CpKZgnCA@mail.gmail.com","subject":"RE: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-28T20:43:47Z","receivedAt":"2022-04-28T20:43:58Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 28, 2022 4:23 PM, Carlo Arenas wrote:\n>On Thu, Apr 28, 2022 at 12:53 PM <rsbecker@nexbridge.com> wrote:\n>> /etc/sudoers is not standard although usual. This path should come from a knob\n>somewhere. We can't run this test on our x86 system anyway - no access to root\n>or sudo even though it is installed.\n>\n>correct and note that the test would succeed if the file doesn't exist because what\n>we are really interested on, is to make sure that sudo won't mess with our path\n>when invoking git, and if there is a chance it would (because that setting is enabled\n>in a different file for\n>example) then we will just skip these tests.\n>\n>Obviously the target I had in mind when I built this test was my own workstation\n>and our public CI, but feel free to provide a fixup that would also make it work for\n>your private runs if you are interested in also running this test.\n>\n>> Also, /etc/sudoers is typically secured 0600 so the grep will fail\n>> even if is_root passes\n>\n>It won't, because it is running with sudo ;).  note that as stated in the commit\n>message, this requires a fairly open sudo setup (like the one github provides with\n>their actions).\n>\n>> - and I'm worried about the portability of is_root, which is mostly Linux.\n>\n>I actually made sure that is_root was posix shell compatible, but got a little carried\n>away when refactoring it to accomodate for reuse; eitherway it is gone in v3.\n\nI tried to find is_root in POSIX but could not. Do you have a reference? It is not in bash 4.3.48, which is on our older system.\n\n"},{"id":"454594","messageId":"xmqq4k2dey2b.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEsph+p-fD8vMOMU4Djkc8cFUmm=9JVFdgaxkQ4-CpKZgnCA@mail.gmail.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T20:46:04Z","receivedAt":"2022-04-28T20:46:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> It won't, because it is running with sudo ;).  note that as stated in\n> the commit message, this requires a fairly open sudo setup (like the\n> one github provides with their actions).\n\nAhh, OK.  So this is pretty much only for CI environment and such,\nnot on a typical developer and end-user box.\n\nOK, but the potential issues that I raised about cleansed\nenvironment, not limited to $PATH, still exists.  Perhaps\nthe prereq check can be tightened to something like:\n\n    GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=no-no-name \\\n    PATH=no-such-path:$PATH \\\n    sudo sh -c \"echo '\\$PATH \\$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME'\" |\n    grep \"^no-such-path.* no-no-name$\"\n\ni.e. we export an envionment with a known value that is unlikely\nvalue for the variable in tester's environment, prepend a known\nstring that unlikely begins the tester's $PATH, and ask sudo what\nvalues, if any, the process sudo spawned sees in these two\nenvironment variables.  An environment that does not molest PATH and\npasses environment variables we set in the tests to affect execution\nof \"git\" being tested will pass the above test.  Otherwise the\nenvironment would silently be breaking our expectation.\n\n"},{"id":"454595","messageId":"CAPUEspgu4wNsgh_8JNENEYG9g5BWsef-5OGoSF3DQuem1BnijA@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqbkwleypf.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T20:48:45Z","receivedAt":"2022-04-28T20:48:59Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, Apr 28, 2022 at 1:32 PM Junio C Hamano <gitster@pobox.com> wrote:\n> On a box I happen to be using, the grep gives me\n>\n>     Defaults secure_path=/usr/sbin:/usr/bin:/sbin:/bin\n>\n> and makes the prereq fail.  Which is sort-of expected, and I\n> understand why this check is here, but I suspect that any sane and\n> sensible installations would reinitialize the path to a fairly\n> restricted one with the mechanism, so we wouldn't be testing this on\n> majority of places, I am afraid.\n\nour CI runs with macOS should still work, and any place that does is\nbetter that none IMHO\n\n> What we really care is that we use the same PATH as the test\n> environment uses, including \"we want to test the binary we just\n> built\" (or \"at the specified path\", when GIT_TEST_INSTALLED is in\n> effect).  I wonder what the right way to carry $PATH and other\n> environment variables down to whatever \"sudo\" in the test runs.\n\nsadly the issue is even more insidious because the PATH is not\nchanged, but sudo ignores it when going to look for a binary to run\n\n>     $ foo=foobla; export foo\n>     $ sudo sh -c set | grep foo; echo $?\n>     1\n>\n> so resetting PATH from an environment we export, e.g.\n>\n>     USE_THIS_PATH=$PATH sudo sh -c '\n>         PATH=$USE_THIS_PATH\n>         ... invoke our git normally here  ...\n>         git status\n>     '\n>\n> would not work X-<.  Worse yet, other environment variables such as\n> GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME that we set in our tests may\n> probably be cleared before \"sudo\" runs any test command, so rejecting\n> an installaion whose \"sudo\" resets PATH with the above check is probably\n> insufficient to give our tests a reasonable envionment to run in.\n\nI think we are confusing, running the whole suite with sudo vs running\na specific command inside a test with it.  We obviously will need to\nadapt our suite a lot more before it will natively support sudo and\nthat might never happen as well, since there are conflicting\nobjectives there.  IMHO that doesn't mean we shouldn't try.\n\nMaybe I should document better what I meant with \"awkward\", but yes I\nwas serious when I said \"minimal support\" for running things through\nsudo, but I should mention the ones you provided almost worked AS-IS\nso it is not that bad IMHO.\n\nCarlo\n"},{"id":"454596","messageId":"xmqqzgk5dj8n.fsf@gitster.g","threadId":"57799","inReplyTo":"000801d85b40$ac11ec80$0435c580$@nexbridge.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T20:51:36Z","receivedAt":"2022-04-28T20:51:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"<rsbecker@nexbridge.com> writes:\n\n>>I actually made sure that is_root was posix shell compatible, but got a little carried\n>>away when refactoring it to accomodate for reuse; eitherway it is gone in v3.\n>\n> I tried to find is_root in POSIX but could not. Do you have a reference? It is not in bash 4.3.48, which is on our older system.\n\nWhat he meant was the implementation of is_root shell function he\nwrote in the patch uses construct from POSIX.\n\n        is_root() {\n                test -n \"$1\" && CMD=\"sudo -n\"\n                test $($CMD id -u) = $(id -u root)\n        }\n\nBesides, as somebody else already pointed out, this will run random\ncommand that is in $CMD (perhaps from tester's environment) when it\nis run without $1 or an empty string in $1.  But other than that,\n\"id\" being in POSIX.1, that looks fairly safe.  Of course, sudo and\nsudo -n would not be in POSIX, but that is what this one is testing\navailablity for, so it is to be expected ;-)\n"},{"id":"454597","messageId":"CAPUEspgcd1CYTfL=ug3WtnOrJscWbyQXeF-2SQ_24KcCTkuRkA@mail.gmail.com","threadId":"57799","inReplyTo":"000801d85b40$ac11ec80$0435c580$@nexbridge.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T20:56:00Z","receivedAt":"2022-04-28T20:56:15Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, Apr 28, 2022 at 1:43 PM <rsbecker@nexbridge.com> wrote:\n> I tried to find is_root in POSIX but could not. Do you have a reference? It is not in bash 4.3.48, which is on our older system.\n\nmy bad; is_root is a helper function i provided as part of this file;\nthe latest version which should work in your posix system AND was\nspecifically written to hopefully not break with NON-STOP based on\nwhat you told us about it looks like (hand edited and not tested) :\n\nis_root() {\n  id -u >u\n  id -u root >r\n  cmp u r\n}\n"},{"id":"454599","messageId":"CAPUEspiCjQRiaOcvSVgS5cZ9q=o6YeZgjp5s3BRZEByD=9Un2Q@mail.gmail.com","threadId":"57799","inReplyTo":"xmqq7d79du6c.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-04-28T21:02:24Z","receivedAt":"2022-04-28T21:02:41Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, Apr 28, 2022 at 9:55 AM Junio C Hamano <gitster@pobox.com> wrote:\n> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n> > +is_root() {\n> > +     test -n \"$1\" && CMD=\"sudo -n\"\n> > +     test $($CMD id -u) = $(id -u root)\n> > +}\n>\n> Style.\n>\n>         is_root () {\n>                 ... body ..\n>\n> But more importantly, why do we need this in the first place?\n> SANITY prerequisite checks if the user is running as root or\n> non-root---can't we use it here?\n\nmy bad; tried first to use NON_ROOT but it didn't work and SANITY\nseems way too complicated for what is really needed, plus this can be\nshared by both prerequisites, and more importantly allows me to\nintroduce an exploit with that CMD trick, but Phillip's eagle eyes\nalready blocked me so it is gone and replaced with SANITY for v3\n\n> Or perhaps my reading is wrong?  I assumed from its name that it was\n> just \"see if we are running as user 'root' and return 0 or non-zero\n> to answer\", but if it does more than that, like priming \"sudo\", then\n> probably it is misnamed.\n\nit does both indeed, and is also why I am pulling the SUDO\nprerequisite on each test instead of checking once at the beginning of\nthe file and being done with it.\n\nI would rather have some tests skipped if sudo can't get root without\npassword than a failed test, and want sudo to always work and not\n\"possibly hang, waiting for a password\" during each run, not to block\nCI either.\n\n> We have a root-owned directory \"root\" with a subdirectory \"r\" owned\n> by us.  We want to be able to use our \"root/r\" directory as a\n> repository.  OK.\n>\n> The prerequisite allows this test to be started as root, but I do\n> not quite see the point.\n\nI have to agree that I was looking at it the other way, my concern\nwith allowing root to call this was to make sure that none of my\nchanges (or any future ones) prevent them to do what they should\nnormally do, hence why I only disabled for root the tests that\ncouldn't work because make no sense (just like is done for tests that\nrely on a case insensitive filesystem, for example)\n\nMore on that in the next test.\n\n> It may pass when started as root, but it\n> is not testing what this test is designed to check (i.e. an ordinary\n> user who has a repository at root/r can do things there).\n\nIMHO these tests should validate that ANY user can do what is\nexpected, and that includes root (the two versions of it), not only\n\"regular users\"\n\n> > +test_expect_success SUDO 'sudo git status as original owner' '\n> > +     (\n> > +             cd root/r &&\n> > +             git status &&\n> > +             sudo git status\n> > +     )\n> > +'\n> If this was started by 'root', root, root/r and\n> root/r/.git all are owned by 'root' and we are checking if 'root'\n> can run 'git status' as 'root' (or 'root' via sudo) there.  Such a\n> test may well pass, but it is not catching a future regression on\n> the code you wrote for this series.\n\nIt is subtle but it does, when run as a real root it will pass, but if\nwe run it through sudo it fails because of the change that was\nintroduced in this series.\n\n> > +test_expect_success SUDO,!ROOT 'can access if owned by root' '\n> > +     (\n> > +             cd root/p &&\n> > +             test_must_fail git status\n> > +     )\n> > +'\n>\n> And as an ordinary user, we fail to access a repository that is\n> owned by a wrong person (i.e. root).  !ROOT (or SANITY) prereq\n> should be there NOT because the test written here would fail if run\n> by root, but because running it as root, even if passed, is totally\n> pointless, because we are *not* testing \"person A has a repository,\n> person B cannot access it\" combination.\n>\n> The other side of the same coin is that the lack of !ROOT (or\n> SANITY) prereq in earlier tests I pointed out above misses the point\n> of why we have prerequisite mechanism in the first place.  It is not\n> to mark a test that fails when the precondition is not met.  It is\n> to avoid running code that would NOT test what we want to test.\n>\n> The difference is that a test that passes for a wrong reason\n> (e.g. we wanted to see of person A can access a repository of their\n> own even when the user identity is tentatively switched to 'root'\n> via 'sudo'---if person A is 'root', the access will be granted even\n> if the special code to handle 'sudo' situation we have is broken)\n> should also be excluded with prerequisite.\n\nAgree I am abusing the prerequisites, I am instead removing the tests\nsince they are pointless when run as root in v3, which would have been\npart of the first proposal, even if slightly more complicated.\n\n> > +test_expect_success SUDO,!ROOT 'can access with sudo' '\n> > +     # fail to access using sudo\n> > +     (\n> > +             # TODO: test_must_fail missing functionality\n>\n> Care to explain a bit in the log message or in this comment the\n> reason why we do not use test_must_fail but use ! here?  Are we\n> over-eager to reject anything non \"git\" be fed, or something?\n\ncorrect since 6a67c759489 (test-lib-functions: restrict test_must_fail\nusage, 2020-07-07) using anything but git fails, and improving that\nnow is IMHO not worth it.\n\nThe only protection we get from using test_must_fail instead would be\nto know if we introduced a crash, but the same command has run several\ntimes already so IMHO it is unlikely.\n\nwill obviously not miss the opportunity to enhance test_must_fail and\nremove the TODO otherwise ASAP.\n\n> Overall, I like the simplicity and clarity of \"do not start this\n> test as 'root'\" in the previous round much better.\n\nI disagree, and think that the fact that the second test changes\nbehaviour with this series proves my point.\n\nI agree I was abusing the prerequisites, but was in the name of making\nthis change simpler, I am hoping\nand slightly more complicated version that doesn't abuse them would be\nbetter than having a simpler one where those issues are hidden and\neven if we currently have no \"run as root CI jobs\" and last time I\ntried one found it is broken somewhere else.\n\nEither Way those issues are orthogonal to this change and would be\nhappy to discuss again after v3 which is still not ready and will be\nposted most likely as an RFC including as much as can from the\nfeedback provided so far.\n\nCarlo\n"},{"id":"454600","messageId":"xmqqv8usex1v.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspiCjQRiaOcvSVgS5cZ9q=o6YeZgjp5s3BRZEByD=9Un2Q@mail.gmail.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T21:07:56Z","receivedAt":"2022-04-28T21:08:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n>> Overall, I like the simplicity and clarity of \"do not start this\n>> test as 'root'\" in the previous round much better.\n>\n> I disagree, and think that the fact that the second test changes\n> behaviour with this series proves my point.\n\nI do not know which second test you are talking about, but anyway.\n\n> Either Way those issues are orthogonal to this change and would be\n> happy to discuss again after v3 which is still not ready and will be\n> posted most likely as an RFC including as much as can from the\n> feedback provided so far.\n\nSure. Looking forward to seeing a version that does *NOT* abuse\nprerequisite mechanism.  We are interested in testing an ordinary\nuser becoming root via sudo in these tests, so reject whoever starts\nthe test under 'root' upfront like in the earlier round.\n\nThanks.\n"},{"id":"454602","messageId":"000f01d85b4a$af8c3aa0$0ea4afe0$@nexbridge.com","threadId":"57799","inReplyTo":"CAPUEspgcd1CYTfL=ug3WtnOrJscWbyQXeF-2SQ_24KcCTkuRkA@mail.gmail.com","subject":"RE: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-28T21:55:28Z","receivedAt":"2022-04-28T21:55:56Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 28, 2022 4:56 PM, Carlo Arenas wrote:\n>On Thu, Apr 28, 2022 at 1:43 PM <rsbecker@nexbridge.com> wrote:\n>> I tried to find is_root in POSIX but could not. Do you have a reference? It is not in\n>bash 4.3.48, which is on our older system.\n>\n>my bad; is_root is a helper function i provided as part of this file; the latest version\n>which should work in your posix system AND was specifically written to hopefully\n>not break with NON-STOP based on what you told us about it looks like (hand\n>edited and not tested) :\n>\n>is_root() {\n>  id -u >u\n>  id -u root >r\n>  cmp u r\n>}\n\nThis is about as portable as I can find and works even in ksh. It could be optimized.\n\nis_root() {\n  id -u >u\n  id -u root >r\n  cmp -s u r\n  if [ $? -ne 0 ]; then\n    echo 0\n  else\n    echo 1\n  fi\n}\n\nif [ `is_root` -ne 0 ]; then\n        echo root\nelse\n        echo Not root\nfi\n\n"},{"id":"454603","messageId":"xmqqczh0etmt.fsf@gitster.g","threadId":"57799","inReplyTo":"000f01d85b4a$af8c3aa0$0ea4afe0$@nexbridge.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-28T22:21:46Z","receivedAt":"2022-04-28T22:21:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"<rsbecker@nexbridge.com> writes:\n\n>>is_root() {\n>>  id -u >u\n>>  id -u root >r\n>>  cmp u r\n>>}\n>\n> This is about as portable as I can find and works even in ksh. It could be optimized.\n>\n> is_root() {\n>   id -u >u\n>   id -u root >r\n>   cmp -s u r\n>   if [ $? -ne 0 ]; then\n>     echo 0\n>   else\n>     echo 1\n>   fi\n> }\n>\n> if [ `is_root` -ne 0 ]; then\n>         echo root\n> else\n>         echo Not root\n> fi\n\nThe above looks very roundabout way.  With the first three in\nis_root that ends with \"cmp\", we already know from its exit status\nif \"id -u\" output for ourselves matches that for root, i.e. if we\nare root then cmp would have exited with 0.\n\nSo with the first one I quoted from your quote, the caller can say\n\n\tif is_root\n\tthen\n\t\techo root\n\telse\n\t\techo not root\n\tfi\n\nwithout turning the exit status into string \"0\" or \"1\" and comparing\nthat string with \"[ `cmd` -ne 0 ]\".  And the first one is just as\nportable.  I agree that running cmp with \"-s\" is probably a good\nidea.\n\nWhat I used to often use in my previous life (in previous century)\nis technically incorrect, but is a lot more succinct and works well\nin practice on any sanely installed systems.  Just see if the root\ndirectory is writable.  No sane system makes it writable by anybody\nbut root.\n\nI.e.\n\n\tif test -w /\n\tthen\n\t\t... we are running as root ...\n\telse\n\t\t... we are not running as root ...\n\tfi\n"},{"id":"454604","messageId":"001901d85b51$b5333420$1f999c60$@nexbridge.com","threadId":"57799","inReplyTo":"xmqqczh0etmt.fsf@gitster.g","subject":"RE: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-04-28T22:45:44Z","receivedAt":"2022-04-28T22:45:57Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On April 28, 2022 6:22 PM, Junio C Hamano wrote:\n><rsbecker@nexbridge.com> writes:\n>\n>>>is_root() {\n>>>  id -u >u\n>>>  id -u root >r\n>>>  cmp u r\n>>>}\n>>\n>> This is about as portable as I can find and works even in ksh. It could\nbe\n>optimized.\n>>\n>> is_root() {\n>>   id -u >u\n>>   id -u root >r\n>>   cmp -s u r\n>>   if [ $? -ne 0 ]; then\n>>     echo 0\n>>   else\n>>     echo 1\n>>   fi\n>> }\n>>\n>> if [ `is_root` -ne 0 ]; then\n>>         echo root\n>> else\n>>         echo Not root\n>> fi\n>\n>The above looks very roundabout way.  With the first three in is_root that\nends\n>with \"cmp\", we already know from its exit status if \"id -u\" output for\nourselves\n>matches that for root, i.e. if we are root then cmp would have exited with\n0.\n>\n>So with the first one I quoted from your quote, the caller can say\n>\n>\tif is_root\n>\tthen\n>\t\techo root\n>\telse\n>\t\techo not root\n>\tfi\n>\n>without turning the exit status into string \"0\" or \"1\" and comparing that\nstring with\n>\"[ `cmd` -ne 0 ]\".  And the first one is just as portable.  I agree that\nrunning cmp\n>with \"-s\" is probably a good idea.\n>\n>What I used to often use in my previous life (in previous century) is\ntechnically\n>incorrect, but is a lot more succinct and works well in practice on any\nsanely\n>installed systems.  Just see if the root directory is writable.  No sane\nsystem makes\n>it writable by anybody but root.\n>\n>I.e.\n>\n>\tif test -w /\n>\tthen\n>\t\t... we are running as root ...\n>\telse\n>\t\t... we are not running as root ...\n>\tfi\n\nI agree. I think my ksh is rather broken. But we use bash for git testing\nand can never go back to ksh, so no worries on that score. Thanks.\n\n"},{"id":"454608","messageId":"20220429012438.37o4uaxsrfdu2b6x@carlos-mbp.lan","threadId":"57799","inReplyTo":"xmqqv8usex1v.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-29T01:24:38Z","receivedAt":"2022-04-29T01:24:55Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, Apr 28, 2022 at 02:07:56PM -0700, Junio C Hamano wrote:\n> Carlo Arenas <carenas@gmail.com> writes:\n> \n> >> Overall, I like the simplicity and clarity of \"do not start this\n> >> test as 'root'\" in the previous round much better.\n> >\n> > I disagree, and think that the fact that the second test changes\n> > behavior with this series proves my point.\n> \n> I do not know which second test you are talking about, but anyway.\n\nMy bad; by \"second test\" I was referring to the one that I introduced to\ntrack the regression and its fix and which has its behavior changed, but\nyou would only notice if looking at it from all angles (and yes, that\nincludes as a regular user, as well as root, with and without sudo :\n\nIf we do :\n\n  [0] login as regular user || sudo to root || login as root\n  [1] % mkdir -p root/r\n  [2] % git init root/r\n  [3] % cd root/r && git status\n\nwe get\n\n  step \\ type | regular user | sudo to root | root\n--------------------------------------------------\n            1 |    work      |     work     | work\n  before    2 |    work      |     work     | work\n            3 |    work      |     work     | work\n---------------------------------------------------\n            1 |    work      |     work     | work\n   after    2 |    work      |     work     | work\n            3 |    work      |     fail     | work\n\nthe reason why it fails is expected (git now finds the SUDO_UID variable\nand rejects the repository because it is NOT owned by that id (it was created\nby root anyway, even if there is no way for git to know that it was done\nat a different time and with a different session, and therefore the SUDO_UID\nvariable it is honoring could be considered irrelevant in the current context.\n\nin the documentation patch (which I think would be better to squash with the\nfix) I explain what to do as a workaround, and I expect this use case to be\nless common than the currently broken one (so a net positive)\n\nCarlo\n"},{"id":"454622","messageId":"484187d6-5bbd-c238-a922-95411e80322e@github.com","threadId":"57799","inReplyTo":"9658dea7-d421-b238-113d-c7b83eca4569@github.com","subject":"Re: [RFC PATCH] git-compat-util: avoid failing dir ownership checks if running priviledged","fromName":"Derrick Stolee","fromEmail":"derrickstolee@github.com","sentAt":"2022-04-29T16:16:57Z","receivedAt":"2022-04-29T16:17:04Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/26/2022 3:48 PM, Derrick Stolee wrote:\n> On 4/26/2022 2:31 PM, Carlo Marcelo Arenas Belón wrote:\n\n>> +\t\tconst char *real_uid = getenv(\"SUDO_UID\");\n>> +\t\tif (real_uid && *real_uid)\n>> +\t\t\teuid = atoi(real_uid);\n>> +\t\telse {\n>> +\t\t\treal_uid = getenv(\"DOAS_UID\");\n>> +\t\t\tif (real_uid && *real_uid)\n>> +\t\t\t\teuid = atoi(real_uid);\n>> +\t\t}\n> \n> I imagine that something else could be added here to help Windows\n> users who have elevated to administrator privileges. It will use a\n> completely different mechanism, though, if needed at all. We can\n> delay that for now.\n\nJust chiming in to say that the way we do this check on Windows,\nthere is no difference between a user and the same user with\nelevated privileges (the \"Security Identifier (SID)\" is the same\nin both cases).\n\nThanks,\n-Stolee\n"},{"id":"454631","messageId":"xmqqee1fbu67.fsf@gitster.g","threadId":"57799","inReplyTo":"20220429012438.37o4uaxsrfdu2b6x@carlos-mbp.lan","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-29T18:50:40Z","receivedAt":"2022-04-29T18:50:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón <carenas@gmail.com> writes:\n\n> If we do :\n>\n>   [0] login as regular user || sudo to root || login as root\n\nAmong these three, the last one is equivalent to \"sudo and then\nunset the environment\", right?\n\nAs many installations no longer allow direct \"login\" as \"root\",\nclarifying how users can get the behaviour for the third column\nwould help our documentation, and that is the reason behind the\nquestion.  IOW, this is merely a simple yes-or-no question to\nsanity-check our mutual understanding, and no need to get overly\ndefensive about being asked.\n\n>   [1] % mkdir -p root/r\n>   [2] % git init root/r\n>   [3] % cd root/r && git status\n>\n>   step \\ type | regular user | sudo to root | root\n> --------------------------------------------------\n>             1 |    work      |     work     | work\n>   before    2 |    work      |     work     | work\n>             3 |    work      |     work     | work\n> ---------------------------------------------------\n>             1 |    work      |     work     | work\n>    after    2 |    work      |     work     | work\n>             3 |    work      |     fail     | work\n\nSo the only difference is that in a repository created by a user who\ndid \"sudo mkdir; sudo git init\".  It used to be that the same user\ncan read the repository with \"sudo git status\" (because we did not\ncare about how we become 'root', we only saw the owner of the repo\nand the current euid).  Now, such an access is no longer allowed.\n\nAnd a workaround is to use the third-column behaviour, i.e. either\nlogin as root (which is probably too cumbersome as a step in a\ntypical \"make && make test && make install\" sequence where at least\nthe last step need to be done as a privileged user) or use \"sudo\"\nand drop the SUDO_UID environment, for which, the documentation was\nadded in this series.\n\nBut I do not see what relevance the above has to the argument you\nwere making, against \"if you start these tests as 'root' (instead of\nstarting as an ordinary user), some tests may succeed but for a\nwrong reason, and some tests may fail because they are not prepared\nfor it; it is wrong to mark only the latter with prerequisite and\nnot the former\".  The change in the behaviour we see above is for\nthose who start as an ordinary user and uses \"sudo\" without dropping\nSUDO_UID.  How is it relevant to allow those who start the test as\n'root' (not an ordinary user) to try that?  Tests done under such\ncondition will see 'root' in euid, SUDO_UID, and st.st_uid, so there\nis no way for them to detect any mismatch and behave differently,\nso the transition from \"it used to work\" to \"now it is forbidden\"\nis not even tested.\n\n> and rejects the repository because it is NOT owned by that id (it was created\n> by root anyway, even if there is no way for git to know that it was done\n> at a different time and with a different session, and therefore the SUDO_UID\n> variable it is honoring could be considered irrelevant in the current context.\n>\n> in the documentation patch (which I think would be better to squash with the\n> fix) I explain what to do as a workaround, and I expect this use case to be\n> less common than the currently broken one (so a net positive)\n\nBoth of these two paragraphs speak truth, but there is no relevance\nto, and it does not justify, your \"I disagree, and think that the\nfact ... proves my point\".\n\nFor example, this is the 'setup' step.\n\n> +test_expect_success SUDO 'setup' '\n> +\tsudo rm -rf root &&\n> +\tmkdir -p root/r &&\n> +\tsudo chown root root &&\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit init\n> +\t)\n> +'\n\nIf the test was started by an ordinary user, root/r is owned by the\nuser who is not 'root'.  If the test was started by 'root',\neverything is owned by 'root'.  Either way, 'root' is owned by\n'root'.  In such a repository, we see this test:\n\n+test_expect_success SUDO 'sudo git status as original owner' '\n+\t(\n+\t\tcd root/r &&\n+\t\tgit status &&\n+\t\tsudo git status\n+\t)\n+'\n\nThe behaviour we are trying to ensure is that, even though root/r is\nowned by non-root, accessing it with \"git status\" as the original\nuser and \"git status\" as root work, as long as if you used \"sudo\" in\nthe second \"git status\", so that \"git status\" can take SUDO_UID into\naccount.  The test is making sure that our \"pay attention to\nSUDO_UID\" mechanism has not been broken by future changes.\n\nIf we start this test as 'root', we cannot test for that.  The setup\nstep made everything owned by 'root', and we go there as 'root' and\nrun \"git status\", which should succceed, but with \"sudo git status\",\neven we broke SUDO_UID mechanism and compared euid with st.st_uid,\nwe'll allow an access.\n\nSo the test may succeed but it succeeds for a wrong reason even\nafter we break the mechanism added by this series.\n"},{"id":"454637","messageId":"20220429200544.p7ggvccdnksmhvxt@carlos-mbp.lan","threadId":"57799","inReplyTo":"xmqqee1fbu67.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-29T20:05:44Z","receivedAt":"2022-04-29T20:05:53Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Fri, Apr 29, 2022 at 11:50:40AM -0700, Junio C Hamano wrote:\n> Carlo Marcelo Arenas Belón <carenas@gmail.com> writes:\n> \n> > If we do :\n> >\n> >   [0] login as regular user || sudo to root || login as root\n> \n> Among these three, the last one is equivalent to \"sudo and then\n> unset the environment\", right?\n\nCorrect, the differences from the most likely sequence of commands\nof a potential tester on their workstation (which as you point,\nmost of the time doesn't allow login in as root) is :\n\n  $ sudo -s -H\n  # unset SUDO_UID\n  # IKNOWWHATIAMDOING=yes ./t0034-root-safe-directory.sh\n\nthe unset only relevant for the third option, of course.\n\n> As many installations no longer allow direct \"login\" as \"root\",\n> clarifying how users can get the behaviour for the third column\n> would help our documentation, and that is the reason behind the\n> question.  IOW, this is merely a simple yes-or-no question to\n> sanity-check our mutual understanding, and no need to get overly\n> defensive about being asked.\n\nApologies if sounding otherwise, but I can assure I am not offended\nby any of this questions, and looking forward to improve in the\ndocumentation with the help you had provided on reviewing it.\n\nI would also like to thank you personally, since I am well aware\nthat as a not native English speaker, and because Spanish is my\nmother's tongue I usually write things in a way that is not natural\nor expected and also overly verbose and without expected pauses.  So\nhaving a second set of eyes on it is specially appreciated.\n\n> >   [1] % mkdir -p root/r\n> >   [2] % git init root/r\n> >   [3] % cd root/r && git status\n> >\n> >   step \\ type | regular user | sudo to root | root\n> > --------------------------------------------------\n> >             1 |    work      |     work     | work\n> >   before    2 |    work      |     work     | work\n> >             3 |    work      |     work     | work\n> > ---------------------------------------------------\n> >             1 |    work      |     work     | work\n> >    after    2 |    work      |     work     | work\n> >             3 |    work      |     fail     | work\n> \n> So the only difference is that in a repository created by a user who\n> did \"sudo mkdir; sudo git init\".  It used to be that the same user\n> can read the repository with \"sudo git status\" (because we did not\n> care about how we become 'root', we only saw the owner of the repo\n> and the current euid).  Now, such an access is no longer allowed.\n\nCorrect, but more importantly we now allow the sequence documented\nin the test case which is also IMHO more comnon and useful, where the\nlast step might need to run through sudo (unlike the previous ones)\n\n> But I do not see what relevance the above has to the argument you\n> were making, against \"if you start these tests as 'root' (instead of\n> starting as an ordinary user), some tests may succeed but for a\n> wrong reason, and some tests may fail because they are not prepared\n> for it; it is wrong to mark only the latter with prerequisite and\n> not the former\".  The change in the behaviour we see above is for\n> those who start as an ordinary user and uses \"sudo\" without dropping\n> SUDO_UID.  How is it relevant to allow those who start the test as\n> 'root' (not an ordinary user) to try that?  Tests done under such\n> condition will see 'root' in euid, SUDO_UID, and st.st_uid, so there\n> is no way for them to detect any mismatch and behave differently,\n> so the transition from \"it used to work\" to \"now it is forbidden\"\n> is not even tested.\n\nCorrect again; guess my intention wasn't clear.  My concern was that by\nblocking root, we don't allow for such a test (if it can be written,\nsince as you pointed out is challenging) to be added and we also lose\nthe currently failing run which can be used as an \"explanation\" of sorts\nto the question of \"is this supported and expected to work?\" which I\nthink the tests help answer and regardless of what is in the documentation.\n\n> > and rejects the repository because it is NOT owned by that id (it was created\n> > by root anyway, even if there is no way for git to know that it was done\n> > at a different time and with a different session, and therefore the SUDO_UID\n> > variable it is honoring could be considered irrelevant in the current context.\n> >\n> > in the documentation patch (which I think would be better to squash with the\n> > fix) I explain what to do as a workaround, and I expect this use case to be\n> > less common than the currently broken one (so a net positive)\n> \n> Both of these two paragraphs speak truth, but there is no relevance\n> to, and it does not justify, your \"I disagree, and think that the\n> fact ... proves my point\".\n\nI ended up doing a bigger refactoring with v3 that split the tests in two and\nwhich I think will help also in the long run, but kept the Documentation patch\nindependent since it already has your SO and don't want to waste your time\nfurther by having to re-review it.\n\nAssuming that there are no more improvements (or even if they are) to be made\nto the documentation would be OK if I follow my own advice and squash it\ntogether with the code change that introduces the change?\n\nApologies for not doing it earlier, but in my defense I would say that I sent\nthe currently applied version originally as an RFC ;)\n\n> For example, this is the 'setup' step.\n> \n> > +test_expect_success SUDO 'setup' '\n> > +\tsudo rm -rf root &&\n> > +\tmkdir -p root/r &&\n> > +\tsudo chown root root &&\n> > +\t(\n> > +\t\tcd root/r &&\n> > +\t\tgit init\n> > +\t)\n> > +'\n> \n> If the test was started by an ordinary user, root/r is owned by the\n> user who is not 'root'.  If the test was started by 'root',\n> everything is owned by 'root'.  Either way, 'root' is owned by\n> 'root'.  In such a repository, we see this test:\n> \n> +test_expect_success SUDO 'sudo git status as original owner' '\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit status &&\n> +\t\tsudo git status\n> +\t)\n> +'\n> \n> The behaviour we are trying to ensure is that, even though root/r is\n> owned by non-root, accessing it with \"git status\" as the original\n> user and \"git status\" as root work, as long as if you used \"sudo\" in\n> the second \"git status\", so that \"git status\" can take SUDO_UID into\n> account.  The test is making sure that our \"pay attention to\n> SUDO_UID\" mechanism has not been broken by future changes.\n> \n> If we start this test as 'root', we cannot test for that.  The setup\n> step made everything owned by 'root', and we go there as 'root' and\n> run \"git status\", which should succceed, but with \"sudo git status\",\n> even we broke SUDO_UID mechanism and compared euid with st.st_uid,\n> we'll allow an access.\n\nDepending of the way you become 'root' the test could fail as well,\nbut IMHO the failing should be expected (and as shown in the table\nabove) was introduced with this change.\n\nThe gist is that if we started the whole test with sudo, there is\nno way for git (with the current implementation) to differenciate if that\nSUDO_UID is relevant only to its current run or to the environment and\nmore importantly what the intentions are from the user that is running\non that environment.\n\nAlternatively we could ammend the code to allow for such logic but I\ndon't think that would be easier to implement and I don't see much of\na benefit.\n\nMy thinking is that if we are going to let sudo tells us who the user is\nthen we must trust that SUDO_UID indicates also the intention of the user\nbehind that environment and therefore it is correct in this case to fail.\n\nIf the user really meant to not trust its SUDO_UID and instead use the\nid we are running as, then he should have removed it from the environment\nbefore invoking git as documented.\n\nLong term, as you proposed, if we are running as root we might ALSO\nconsider that any root owned repositories should be fine to trust but\nthat change is orthogonal to fixing the 'sudo git <command> in my own\nrepository doesn't work after the last maint release'\n\nIt should also be important to note that starting the whole test with\nsudo is not trivial, neither expected, and will also block because of\nsudo most likely removing the IKNOWWHATIAMDOING environment variable,\nso whichever way we decide we shouldn't expect someone accidentally\nfailing this test.\n\n> So the test may succeed but it succeeds for a wrong reason even\n> after we break the mechanism added by this series.\n\nthe test as root without a SUDO_UID would succeed for the wrong reasons\nso I agree (and again apologize for suggesting it) that using a\nprerequisite to squash that run (as done in the other tests) was wrong.\n\nwhat I am still not sure about is if it is worth complicating the test\nby adding logic that differenciate a root user with and without SUDO_UID\nthat might run it, and I have to admit that the current draft I have of\nv3 does follow your advice of blocking root from even being able to run\nit as suggested (and which is also what I am leaning for).\n\nCarlo\n\nPS. I apologize for not trimming on your responses more aggresively to\nsave some bytes as I would normally do, but wanted to make sure you\nunderstand that by trimming those parts I wasn't implying they weren't\nread or relevant, but just not strictly neccesary and implictly agreed\nupon for further discussion\n"},{"id":"454674","messageId":"YmzUirQlDR1942rH@debian.me","threadId":"57799","inReplyTo":"20220428105852.94449-3-carenas@gmail.com","subject":"Re: [PATCH v2 2/3] Documentation: explain how safe.directory works when running under sudo","fromName":"Bagas Sanjaya","fromEmail":"bagasdotme@gmail.com","sentAt":"2022-04-30T06:17:46Z","receivedAt":"2022-04-30T06:17:59Z","isPatch":true,"sender":{"key":"bagasdotme@gmail.com","avatar":"https://avatars.githubusercontent.com/u/40219486?v=4"},"body":"On Thu, Apr 28, 2022 at 03:58:51AM -0700, Carlo Marcelo Arenas Belón wrote:\n> In a previous patch, the behavior of git was changed so it will be able\n> to find the \"effective uid\" that is required when git was invoked with\n> sudo to root, for example the internal calls made to git when calling\n> the following in git's own repository:\n> \n>   $ sudo make install\n>\n\nThat is building Git, right?\n\n-- \nAn old man doll... just what I always wanted! - Clara\n"},{"id":"454675","messageId":"xmqqbkwj847c.fsf@gitster.g","threadId":"57799","inReplyTo":"YmzUirQlDR1942rH@debian.me","subject":"Re: [PATCH v2 2/3] Documentation: explain how safe.directory works when running under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-04-30T06:39:51Z","receivedAt":"2022-04-30T06:40:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bagas Sanjaya <bagasdotme@gmail.com> writes:\n\n> On Thu, Apr 28, 2022 at 03:58:51AM -0700, Carlo Marcelo Arenas Belón wrote:\n>> In a previous patch, the behavior of git was changed so it will be able\n>> to find the \"effective uid\" that is required when git was invoked with\n>> sudo to root, for example the internal calls made to git when calling\n>> the following in git's own repository:\n>> \n>>   $ sudo make install\n>>\n>\n> That is building Git, right?\n\nWhy do you want to know?  In other words, if Carlo answers \"yes\" (or\n\"no\" for that matter), what are you going to do with that piece of\ninformation?  E-mailed communications with people on other\ncontinents are inherently high latency, so it is more efficient to\ntry reducing number of round trips.  One trick is to make sure that\nother side does not have to wonder \"what do you need to know it\nfor?\" by telling them upfront why you want to know.  Then they can\nguess better what kind of information to what detail you need, in\norder to move forward.  If they agree where you want to go with the\ninformation is a good thing, it may even give them an incentive to\ngive as high quality information as they can as quickly as they can\nto you.\n\nHaving said all that.\n\nIf you re-read the sentence before that sample command line, it\nwould be clear that the answer is \"yes, as that sentence said, it is\nbuilding and installing Git\".  Especially \"when calling the\nfollowing in Git's own repository\".\n\nBut Git in that message is merely an example.  Any piece of software\nthat wants to run \"git\" as part of the \"make install\" procedure\n(e.g. to compute the version number, it may run \"git describe\", when\nit knows the build is being run in a Git managed repository, instead\nof being in a tarball extract) is affected.\n"},{"id":"454679","messageId":"20220430141516.u5yeznmmbxwaki44@carlos-mbp.lan","threadId":"57799","inReplyTo":"YmzUirQlDR1942rH@debian.me","subject":"Re: [PATCH v2 2/3] Documentation: explain how safe.directory works when running under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-04-30T14:15:16Z","receivedAt":"2022-04-30T14:15:23Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Sat, Apr 30, 2022 at 01:17:46PM +0700, Bagas Sanjaya wrote:\n> On Thu, Apr 28, 2022 at 03:58:51AM -0700, Carlo Marcelo Arenas Belón wrote:\n> > In a previous patch, the behavior of git was changed so it will be able\n> > to find the \"effective uid\" that is required when git was invoked with\n> > sudo to root, for example the internal calls made to git when calling\n> > the following in git's own repository:\n> > \n> >   $ sudo make install\n> >\n> \n> That is building Git, right?\n\nTechnically, installing it.  The full report is more informative of what the\nspecific impact is, which I obviously forgot to link to:\n\n  https://lore.kernel.org/git/20220412180510.GA2173@szeder.dev/\n\nAnother example of it (which started this whole regression fix) is available\nin:\n\n  https://lore.kernel.org/git/4ef9287b-6260-9538-7c89-cffb611520ee@maurel.de/\n\nCarlo\n"},{"id":"454739","messageId":"20220502183920.88982-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220428105852.94449-1-carenas@gmail.com","subject":"[RFC PATCH v3 0/3] fix `sudo make install` regression in maint","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-02T18:39:17Z","receivedAt":"2022-05-02T18:39:35Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"A more involved refactoring, but mainly for the benefit of long term\nmaintanability, by making the code and documentation changes together\nand splitting the tests into pre/post sections, which should hopefully\nalso make all deficiences of the approach taken clear but still be\nuseful enough to support the current usecases and allow for future\nextensions.\n\nCarlo Marcelo Arenas Belón (3):\n  t: document regression git safe.directory when using sudo\n  git-compat-util: avoid failing dir ownership checks if running\n    privileged\n  t0034: enhance framework to allow testing more commands under sudo\n\n Documentation/config/safe.txt  |   9 +++\n git-compat-util.h              |  40 ++++++++++++-\n t/lib-sudo.sh                  |  31 ++++++++++\n t/t0034-root-safe-directory.sh | 100 +++++++++++++++++++++++++++++++++\n 4 files changed, 179 insertions(+), 1 deletion(-)\n create mode 100644 t/lib-sudo.sh\n create mode 100755 t/t0034-root-safe-directory.sh\n\nA range-diff from the previous version (in case someone finds it\nuseful) shown below:\n\n-:  ----------- > 1:  51d0d485b5f t: document regression git safe.directory when using sudo\n1:  b0436d4a50a ! 2:  4928ad698e2 git-compat-util: avoid failing dir ownership checks if running privileged\n    @@ Commit message\n         those tools create to keep track of the original user id, and do the\n         ownership check using that instead.\n     \n    -    This assumes the environment the user is running with after going\n    -    privileged can't be tampered with, and also does the check only for\n    -    root to keep the most common case less complicated, but as a side effect\n    -    will miss cases where sudo (or an equivalent) was used to change to\n    -    another unprivileged user or where the equivalent tool used to raise\n    +    This assumes the environment the user is running on after going\n    +    privileged can't be tampered with, and also adds code to restrict that\n    +    the new behavior only applies if running as root, therefore keeping the\n    +    most common case, which runs unprivileged, from changing, but because of\n    +    that, it will miss cases where sudo (or an equivalent) was used to change\n    +    to another unprivileged user or where the equivalent tool used to raise\n         privileges didn't track the original id in a sudo compatible way.\n     \n         Reported-by: Guy Maurel <guy.j@maurel.de>\n    @@ Commit message\n         Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n         Suggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n         Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n    +\n    + ## Documentation/config/safe.txt ##\n    +@@ Documentation/config/safe.txt: directory was listed in the `safe.directory` list. If `safe.directory=*`\n    + is set in system config and you want to re-enable this protection, then\n    + initialize your list with an empty value before listing the repositories\n    + that you deem safe.\n    +++\n    ++When git tries to check for ownership of git repositories, it will\n    ++obviously do so with the uid of the user that is running git itself,\n    ++but if git is running as root, it will check first if it might have\n    ++been started through `sudo`, and if that is the case, will instead\n    ++use the uid of the user that did so.\n    ++If that is not what you would prefer and want git to only trust\n    ++repositories that are owned by root instead, then you should remove\n    ++the `SUDO_UID` variable from root's environment.\n     \n      ## git-compat-util.h ##\n     @@ git-compat-util.h: static inline int git_offset_1st_component(const char *path)\n    @@ git-compat-util.h: static inline int git_offset_1st_component(const char *path)\n      }\n      \n      #define is_path_owned_by_current_user is_path_owned_by_current_uid\n    +\n    + ## t/t0034-root-safe-directory.sh ##\n    +@@ t/t0034-root-safe-directory.sh: test_expect_success SUDO 'setup' '\n    + \t)\n    + '\n    + \n    +-test_expect_failure SUDO 'sudo git status as original owner' '\n    ++test_expect_success SUDO 'sudo git status as original owner' '\n    + \t(\n    + \t\tcd root/r &&\n    + \t\tgit status &&\n2:  d05e886d394 < -:  ----------- Documentation: explain how safe.directory works when running under sudo\n3:  10ec03d71e4 < -:  ----------- t: add tests for safe.directory when running with sudo\n-:  ----------- > 3:  98aae872efd t0034: enhance framework to allow testing more commands under sudo\n\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454740","messageId":"20220502183920.88982-2-carenas@gmail.com","threadId":"57799","inReplyTo":"20220502183920.88982-1-carenas@gmail.com","subject":"[RFC PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-02T18:39:18Z","receivedAt":"2022-05-02T18:39:36Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Originally reported after release of v2.35.2 (and other maint branches)\nfor CVE-2022-24765 and blocking otherwise harmless commands that were\ndone using sudo in a repository that was owned by the user.\n\nAdd a new test script with very basic support to allow running git\ncommands through sudo, so a reproduction could be implemented and that\nuses only `git status` as a proxy of the issue reported.\n\nNote that because of the way sudo interacts with the system, a much\nmore complete integration with the test framework will require a lot\nmore work and that was therefore intentionally punted for now.\n\nThe current implementation requires the execution of a special cleanup\nfunction which should always be kept as the last \"test\" or otherwise\nthe standard cleanup functions will fail because they can't remove\nthe root owned directories that are used.  This also means that if\nfailures are found while running the specifics of the failure might\nnot be kept for further debugging and if the test was interrupted, it\nwill be necessary to clean the working directory manually before\nrestarting by running:\n\n  $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n\nThe test file also uses at least one initial \"setup\" test that creates\na parallel execution directory, while ignoring the repository created\nby the test framework, and special care should be taken when invoking\ncommands through sudo, since the environment is otherwise independent\nfrom what the test framework expects.  Indeed `git status` was used\nas a proxy because it doesn't even require commits in the repository\nto work.\n\nA new SUDO prerequisite is provided that does some sanity checking\nto make sure the sudo command that will be used allows for passwordless\nexecution as root and doesn't mess with git execution paths, but\notherwise additional work will be required to ensure additional\ncommands behave as expected and that will be addressed in a later patch.\n\nMost of those characteristics make this test mostly suitable only for\nCI, but it could be executed locally if special care is taken to provide\nfor some of them in the local configuration and maybe making use of the\nsudo credential cache by first invoking sudo, entering your password if\nneeded, and then invoking the test by doing:\n\n  $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n\nReported-by: SZEDER Gábor <szeder.dev@gmail.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/t0034-root-safe-directory.sh | 42 ++++++++++++++++++++++++++++++++++\n 1 file changed, 42 insertions(+)\n create mode 100755 t/t0034-root-safe-directory.sh\n\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nnew file mode 100755\nindex 00000000000..bec73fe3c10\n--- /dev/null\n+++ b/t/t0034-root-safe-directory.sh\n@@ -0,0 +1,42 @@\n+#!/bin/sh\n+\n+test_description='verify safe.directory checks while running as root'\n+\n+. ./test-lib.sh\n+\n+# this prerequisite should be added to all the tests, it not only prevents\n+# the test from failing but also warms up any authentication cache sudo\n+# might need to avoid asking for a password\n+test_lazy_prereq SUDO '\n+\tsudo -n id -u >u &&\n+\tid -u root >r &&\n+\ttest_cmp u r &&\n+\tcommand -v git >u &&\n+\tsudo command -v git >r &&\n+\ttest_cmp u r\n+'\n+\n+test_expect_success SUDO 'setup' '\n+\tsudo rm -rf root &&\n+\tmkdir -p root/r &&\n+\tsudo chown root root &&\n+\t(\n+\t\tcd root/r &&\n+\t\tgit init\n+\t)\n+'\n+\n+test_expect_failure SUDO 'sudo git status as original owner' '\n+\t(\n+\t\tcd root/r &&\n+\t\tgit status &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+# this MUST be always the last test\n+test_expect_success SUDO 'cleanup' '\n+\tsudo rm -rf root\n+'\n+\n+test_done\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454741","messageId":"20220502183920.88982-3-carenas@gmail.com","threadId":"57799","inReplyTo":"20220502183920.88982-1-carenas@gmail.com","subject":"[RFC PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-02T18:39:19Z","receivedAt":"2022-05-02T18:39:39Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that user was\nroot (because git was invoked through sudo or a compatible tool) and the\noriginal uid that repository trusted for its config was no longer known,\ntherefore failing the following otherwise safe call:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nthose tools create to keep track of the original user id, and do the\nownership check using that instead.\n\nThis assumes the environment the user is running on after going\nprivileged can't be tampered with, and also adds code to restrict that\nthe new behavior only applies if running as root, therefore keeping the\nmost common case, which runs unprivileged, from changing, but because of\nthat, it will miss cases where sudo (or an equivalent) was used to change\nto another unprivileged user or where the equivalent tool used to raise\nprivileges didn't track the original id in a sudo compatible way.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n Documentation/config/safe.txt  |  9 ++++++++\n git-compat-util.h              | 40 +++++++++++++++++++++++++++++++++-\n t/t0034-root-safe-directory.sh |  2 +-\n 3 files changed, 49 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex 6d764fe0ccf..ee558ced8c7 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -26,3 +26,12 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n is set in system config and you want to re-enable this protection, then\n initialize your list with an empty value before listing the repositories\n that you deem safe.\n++\n+When git tries to check for ownership of git repositories, it will\n+obviously do so with the uid of the user that is running git itself,\n+but if git is running as root, it will check first if it might have\n+been started through `sudo`, and if that is the case, will instead\n+use the uid of the user that did so.\n+If that is not what you would prefer and want git to only trust\n+repositories that are owned by root instead, then you should remove\n+the `SUDO_UID` variable from root's environment.\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 63ba89dd31d..dfdd3e4f81a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -393,12 +393,50 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n+/*\n+ * this helper function overrides a ROOT_UID with the one provided by\n+ * an environment variable, do not use unless the original user is\n+ * root\n+ */\n+static inline void extract_id_from_env(const char *env, uid_t *id)\n+{\n+\tconst char *real_uid = getenv(env);\n+\n+\t/* discard any empty values */\n+\tif (real_uid && *real_uid) {\n+\t\tchar *endptr;\n+\t\tunsigned long env_id;\n+\t\tint saved_errno = errno;\n+\n+\t\terrno = 0;\n+\t\tenv_id = strtoul(real_uid, &endptr, 10);\n+\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n+\t\t\t*id = env_id;\n+\n+\t\terrno = saved_errno;\n+\t}\n+}\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID)\n+\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex bec73fe3c10..67dd96b9321 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -26,7 +26,7 @@ test_expect_success SUDO 'setup' '\n \t)\n '\n \n-test_expect_failure SUDO 'sudo git status as original owner' '\n+test_expect_success SUDO 'sudo git status as original owner' '\n \t(\n \t\tcd root/r &&\n \t\tgit status &&\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454742","messageId":"20220502183920.88982-4-carenas@gmail.com","threadId":"57799","inReplyTo":"20220502183920.88982-1-carenas@gmail.com","subject":"[RFC PATCH v3 3/3] t0034: enhance framework to allow testing more commands under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-02T18:39:20Z","receivedAt":"2022-05-02T18:39:41Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"When running under sudo, the environment gets altered in significant\nways, so make sure that PATH is respected by comparing the full path\nto git outside and inside sudo and disabling the tests if they don't\nmatch.\n\nAdditionally, invent a way to inject environment variables into that\nenvironment and create a helper function to facilitate running more\nthan one command under sudo, while using those variables.\n\nAdd additional negative tests as suggested by Junio and export the\nGIT_TEST_DEFAULT_INITIAL_BRANCH_NAME variable that will be used when\nrunning init in one of those.\n\nNote that in order to be able to call `test_must_fail sudo git status`\nor an equivalent test_must_fail will need to be enhanced or be able\nto run under sudo, so fixing that has been punted, since the only\nprotection it affords is for `git status` not crashing, and that is\ncovered already by other tests.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/lib-sudo.sh                  | 31 ++++++++++++++++++\n t/t0034-root-safe-directory.sh | 58 ++++++++++++++++++++++++++++++++++\n 2 files changed, 89 insertions(+)\n create mode 100644 t/lib-sudo.sh\n\ndiff --git a/t/lib-sudo.sh b/t/lib-sudo.sh\nnew file mode 100644\nindex 00000000000..60046927f3b\n--- /dev/null\n+++ b/t/lib-sudo.sh\n@@ -0,0 +1,31 @@\n+# Helpers for running git commands under sudo.\n+\n+# Runs a scriplet passed through stdin under sudo.\n+run_with_sudo () {\n+\tlocal ret\n+\tlocal SH=${1-\"$TEST_SHELL_PATH\"}\n+\tlocal RUN=\"$HOME/$$.sh\"\n+\t{\n+\t\techo \"#!$SH\"\n+\t\techo \"set -e\"\n+\t\techo \". \\\"$HOME/env\\\"\"\n+\t\tcat\n+\t} >\"$RUN\" &&\n+\tchmod +x \"$RUN\" &&\n+\tsudo \"$SH\" -c \"\\\"$RUN\\\"\"\n+\tret=$?\n+\trm -f \"$RUN\"\n+\treturn $ret\n+}\n+\n+# Makes all variables passed as parameters available to the scriplet that\n+# run under sudo with run_with_sudo\n+export_to_sudo () {\n+\twhile test -n \"$1\"\n+\tdo\n+\t\tlocal v\n+\t\teval v=\"\\$$1\"\n+\t\techo \"$1=$v\" >>\"$HOME/env\"\n+\t\tshift\n+\tdone\n+}\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex 67dd96b9321..0f79648a2fb 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -3,6 +3,19 @@\n test_description='verify safe.directory checks while running as root'\n \n . ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-sudo.sh\n+\n+if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]\n+then\n+\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run this test\"\n+\ttest_done\n+fi\n+\n+if ! test_have_prereq NOT_ROOT\n+then\n+\tskip_all=\"No, you don't; these tests can't run as root\"\n+\ttest_done\n+fi\n \n # this prerequisite should be added to all the tests, it not only prevents\n # the test from failing but also warms up any authentication cache sudo\n@@ -19,6 +32,7 @@ test_lazy_prereq SUDO '\n test_expect_success SUDO 'setup' '\n \tsudo rm -rf root &&\n \tmkdir -p root/r &&\n+\texport_to_sudo GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME &&\n \tsudo chown root root &&\n \t(\n \t\tcd root/r &&\n@@ -34,6 +48,50 @@ test_expect_success SUDO 'sudo git status as original owner' '\n \t)\n '\n \n+test_expect_success SUDO 'setup root owned repository' '\n+\tsudo mkdir -p root/p &&\n+\trun_with_sudo <<-END\n+\t\tgit init root/p\n+\tEND\n+'\n+\n+test_expect_success SUDO 'cannot access if owned by root' '\n+\t(\n+\t\tcd root/p &&\n+\t\ttest_must_fail git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'cannot access with sudo' '\n+\t(\n+\t\t# TODO: test_must_fail needs additional functionality\n+\t\t# 6a67c759489 blocks its use with sudo\n+\t\tcd root/p &&\n+\t\t! sudo git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'can access using a workaround' '\n+\t# provide explicit GIT_DIR\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tGIT_DIR=.git\n+\t\t\tGIT_WORK_TREE=.\n+\t\t\texport GIT_DIR GIT_WORK_TREE\n+\t\t\tgit status\n+\t\tEND\n+\t) &&\n+\t# discard SUDO_UID\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tunset SUDO_UID\n+\t\t\tgit status\n+\t\tEND\n+\t)\n+'\n+\n # this MUST be always the last test\n test_expect_success SUDO 'cleanup' '\n \tsudo rm -rf root\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454750","messageId":"xmqqy1zjwrbu.fsf@gitster.g","threadId":"57799","inReplyTo":"20220502183920.88982-2-carenas@gmail.com","subject":"Re: [RFC PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-02T21:35:33Z","receivedAt":"2022-05-02T21:35:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> +test_lazy_prereq SUDO '\n> +\tsudo -n id -u >u &&\n> +\tid -u root >r &&\n> +\ttest_cmp u r &&\n\nOK.  We make sure we can become root with \"sudo\".\n\n> +\tcommand -v git >u &&\n> +\tsudo command -v git >r &&\n> +\ttest_cmp u r\n\nWhile this is not as thorough as the \"make sure we see the\nenvironment intact\" that I alluded to during the previous review, it\nat least makes sure PATH (which our test framework tweaks) is\npropagated down to \"sudo\" environment intact, which should be good\nenough to run just \"init\" and \"status\".  Keeping things simple is\ngood.\n\nWe may have to exclude this from tests that require specialized\nenvironment like valgrind tests, but that is not of immediate\nconcern.\n\nWill queue.\n\n> +'\n> +\n> +test_expect_success SUDO 'setup' '\n> +\tsudo rm -rf root &&\n> +\tmkdir -p root/r &&\n> +\tsudo chown root root &&\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit init\n> +\t)\n> +'\n> +\n> +test_expect_failure SUDO 'sudo git status as original owner' '\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit status &&\n> +\t\tsudo git status\n> +\t)\n> +'\n> +\n> +# this MUST be always the last test\n> +test_expect_success SUDO 'cleanup' '\n> +\tsudo rm -rf root\n> +'\n> +\n> +test_done\n"},{"id":"454752","messageId":"xmqqo80fvb5q.fsf@gitster.g","threadId":"57799","inReplyTo":"20220502183920.88982-4-carenas@gmail.com","subject":"Re: [RFC PATCH v3 3/3] t0034: enhance framework to allow testing more commands under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-02T22:10:09Z","receivedAt":"2022-05-02T22:10:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> +# Runs a scriplet passed through stdin under sudo.\n> +run_with_sudo () {\n> +\tlocal ret\n> +\tlocal SH=${1-\"$TEST_SHELL_PATH\"}\n> +\tlocal RUN=\"$HOME/$$.sh\"\n> +\t{\n> +\t\techo \"#!$SH\"\n> +\t\techo \"set -e\"\n> +\t\techo \". \\\"$HOME/env\\\"\"\n> +\t\tcat\n> +\t} >\"$RUN\" &&\n> +\tchmod +x \"$RUN\" &&\n> +\tsudo \"$SH\" -c \"\\\"$RUN\\\"\"\n> +\tret=$?\n> +\trm -f \"$RUN\"\n> +\treturn $ret\n> +}\n\nI wonder if write_script can be used for better readability.  It is\nespecially true as I am going to suggest ripping out $HOME/env stuff\nthat is not absolutely needed (and its support with this patch looks\ninadequate when we do need one).\n\n\tlocal RUN=$HOME/$$.sh &&\n\twrite_script \"$RUN\" \"$TEST_SHELL_PATH\" &&\n\tsudo \"$RUN\"\n\nor something?\n\n> +# Makes all variables passed as parameters available to the scriplet that\n> +# run under sudo with run_with_sudo\n> +export_to_sudo () {\n> +\twhile test -n \"$1\"\n> +\tdo\n> +\t\tlocal v\n> +\t\teval v=\"\\$$1\"\n> +\t\techo \"$1=$v\" >>\"$HOME/env\"\n> +\t\tshift\n> +\tdone\n> +}\n\nTwo potential issues:\n\n - This forces the caller to list _all_ the relevant environment\n   variables that would ever matter, which would not be feasible and\n   would not be maintainable.  For example, by forgetting to export\n   GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS, \"git\" commands run in the\n   sudo tests change their behaviour.  Whoever writing a new test\n   need to see what obscure GIT_TEST_* thing may affect the test\n   they want to write, and whoever enhancing the test framework to\n   add new GIT_TEST_* knob need to pay attention to the users of\n   export_to_sudo if their new knob need to be exported.\n\n - I think the assignment to $v under eval is correct, but I am not\n   sure the string accumulated in the $HOME/env file is safe to\n   eval.  We can pass TEST_DIRECTORY via this mechanism, where the\n   value deliberately has a whitespace in it, but if the leading\n   path to our source directory had a single-quote in it, it\n   probably would not work well.  Of course, any variable that has\n   LF in its value would not work without proper quoting.\n\nI think both are not impossible but are hard to do right.  Because I\ndo not see anything that absolutely needs the $HOME/env mechanism to\nwork in the rest of the tests in this patch, I am inclined to say\nthat I'd prefer keeping things simple and only make sure we use the\nright $SHELL to run our script (which write_script may help).\n\n> diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\n> index 67dd96b9321..0f79648a2fb 100755\n> --- a/t/t0034-root-safe-directory.sh\n> +++ b/t/t0034-root-safe-directory.sh\n> @@ -3,6 +3,19 @@\n>  test_description='verify safe.directory checks while running as root'\n>  \n>  . ./test-lib.sh\n> +. \"$TEST_DIRECTORY\"/lib-sudo.sh\n> +\n> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]\n> +then\n> +\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run this test\"\n> +\ttest_done\n> +fi\n> +\n> +if ! test_have_prereq NOT_ROOT\n> +then\n> +\tskip_all=\"No, you don't; these tests can't run as root\"\n> +\ttest_done\n> +fi\n\nOK.\n\n> @@ -19,6 +32,7 @@ test_lazy_prereq SUDO '\n>  test_expect_success SUDO 'setup' '\n>  \tsudo rm -rf root &&\n>  \tmkdir -p root/r &&\n> +\texport_to_sudo GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME &&\n>  \tsudo chown root root &&\n>  \t(\n>  \t\tcd root/r &&\n\nI know I brought up the \"git init\" during the previous review, but\nas long as the test does not depend on the GIT_TEST_* knob\n(i.e. either we say \"git init --initial-branch\" explicitly, or we do\nnot rely on the initial branch having a certain name), we do not\nhave to worry.  We do not check what branch we are on after we do\nthis test, we do not check what branch \"git status\" reports that we\nare on in later tests, we obviously do not care between main and\nmaster in this test script.\n\nI am tempted to suggest dropping the whole $HOME/env business.\n\n> @@ -34,6 +48,50 @@ test_expect_success SUDO 'sudo git status as original owner' '\n>  \t)\n>  '\n>  \n> +test_expect_success SUDO 'setup root owned repository' '\n> +\tsudo mkdir -p root/p &&\n> +\trun_with_sudo <<-END\n> +\t\tgit init root/p\n> +\tEND\n> +'\n\nOK.\n\n> +test_expect_success SUDO 'cannot access if owned by root' '\n> +\t(\n> +\t\tcd root/p &&\n> +\t\ttest_must_fail git status\n> +\t)\n> +'\n\nOK, but strictly speaking, we do not need the SUDO prerequisite for\nthis one.  It still need it for the test directories prepared in\nprevious steps anyway, so perhaps we want one check upfront, just\nlike we do for NOT_ROOT?\n\n\tif ! test_have_prereq SUDO\n\tthen\n\t\tskip_all=\"You do not seem to have a working 'sudo'\"\n\t\ttest_done\n\tfi\n\n> +test_expect_success SUDO 'cannot access with sudo' '\n> +\t(\n> +\t\t# TODO: test_must_fail needs additional functionality\n> +\t\t# 6a67c759489 blocks its use with sudo\n> +\t\tcd root/p &&\n> +\t\t! sudo git status\n> +\t)\n> +'\n\nOK.  So we cannot by default access root-owned repository by\ndefault, which is OK.  I wonder what happens if we did \"sudo sudo\ngit status\".  Perhaps the inner sudo will notice that SUDO_UID is\nset in its environment and does not update it to 0?\n\n\t... goes and checks ...\n\t$ sudo sudo sh -c 'echo $SUDO_UID; whoami'\n\t0\n\troot\n\nSo that gives us another workaround, I guess, which might be even\nsimpler.\n\n> +test_expect_success SUDO 'can access using a workaround' '\n> +\t# provide explicit GIT_DIR\n> +\t(\n> +\t\tcd root/p &&\n> +\t\trun_with_sudo <<-END\n> +\t\t\tGIT_DIR=.git\n> +\t\t\tGIT_WORK_TREE=.\n> +\t\t\texport GIT_DIR GIT_WORK_TREE\n> +\t\t\tgit status\n> +\t\tEND\n> +\t) &&\n> +\t# discard SUDO_UID\n> +\t(\n> +\t\tcd root/p &&\n> +\t\trun_with_sudo <<-END\n> +\t\t\tunset SUDO_UID\n> +\t\t\tgit status\n> +\t\tEND\n> +\t)\n\n\t# double sudo\n\t(\n\t\tcd root/p &&\n\t\tsudo sudo git status\n\t)\n\nI do not know if it is worth adding this third workaround.\n\n> +'\n> +\n>  # this MUST be always the last test\n>  test_expect_success SUDO 'cleanup' '\n>  \tsudo rm -rf root\n\nLooking much better otherwise.\n"},{"id":"454755","messageId":"CAPUEspj9YPFttgf+W604PAUuabDCSOOaOdik9Z+cPbQRDk7e2g@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqy1zjwrbu.fsf@gitster.g","subject":"Re: [RFC PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-02T23:07:53Z","receivedAt":"2022-05-02T23:08:07Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Mon, May 2, 2022 at 2:35 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n>\n> > +     command -v git >u &&\n> > +     sudo command -v git >r &&\n> > +     test_cmp u r\n>\n> While this is not as thorough as the \"make sure we see the\n> environment intact\" that I alluded to during the previous review, it\n> at least makes sure PATH (which our test framework tweaks) is\n> propagated down to \"sudo\" environment intact, which should be good\n> enough to run just \"init\" and \"status\".  Keeping things simple is\n> good.\n\nSorry, I should have mentioned that explicitly in my response.\n\nThat is not possible.  sudo by design will try to minimize the\nenvironment that root is running on, so the only way to make sure git\nstill works as expected there, is to add to that environment\neverything else we might need.\n\nThat is why I have to invent that ugly looking \"env\" file and the\nfunction to import variables with it, and I was assuming that for it\nto be useful in the end we might need to maybe import everything\n\"GIT*\" too, but obviously I didn't want to do that now, and that is\nwhy I only did the branch name (more as an example, than as something\nthat was strictly needed) since you mentioned that in your review and\nI could see how it was related to `git init` being added to the tests\nin the next commit.\n\nGuess I botched it in my refactoring anyway, since it also makes sense\nfor it to be added in the next commit together with `git init`instead\nof here.\n\n> may have to exclude this from tests that require specialized\n> environment like valgrind tests, but that is not of immediate\n> concern.\n\nI didn't test valgrind, but I would assume it is probably broken now,\nas well as anything else that relies on extra environmental things.\n\nCarlo\n"},{"id":"454757","messageId":"CAPUEspi+2ZA3jxfggiwp43XJ2+LmzymVeNBFFnWtyptZ8Tj41w@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqo80fvb5q.fsf@gitster.g","subject":"Re: [RFC PATCH v3 3/3] t0034: enhance framework to allow testing more commands under sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-03T00:00:07Z","receivedAt":"2022-05-03T00:02:19Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Mon, May 2, 2022 at 3:10 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n>\n> > +# Runs a scriplet passed through stdin under sudo.\n> > +run_with_sudo () {\n> > +     local ret\n> > +     local SH=${1-\"$TEST_SHELL_PATH\"}\n> > +     local RUN=\"$HOME/$$.sh\"\n> > +     {\n> > +             echo \"#!$SH\"\n> > +             echo \"set -e\"\n> > +             echo \". \\\"$HOME/env\\\"\"\n> > +             cat\n> > +     } >\"$RUN\" &&\n> > +     chmod +x \"$RUN\" &&\n> > +     sudo \"$SH\" -c \"\\\"$RUN\\\"\"\n> > +     ret=$?\n> > +     rm -f \"$RUN\"\n> > +     return $ret\n> > +}\n>\n> I wonder if write_script can be used for better readability.  It is\n> especially true as I am going to suggest ripping out $HOME/env stuff\n> that is not absolutely needed (and its support with this patch looks\n> inadequate when we do need one).\n>\n>         local RUN=$HOME/$$.sh &&\n>         write_script \"$RUN\" \"$TEST_SHELL_PATH\" &&\n>         sudo \"$RUN\"\n>\n> or something?\n\ncorrect, I tried to use write_script initially, but I thought that\nsince I needed to inject code at the beginning for env, I could also\ninject \"set -e\" and make sure that any scriplet used would work (and\nmore importantly fail when not) even without the \"&&\".\n\nso the scriptlets themselves would be more readable.\n\nMy function is just a slightly modified version of wrte_script for\nthat reason, as making write_script do that seemed more complicated\nthan what I ended up doing.\n\n> +# Makes all variables passed as parameters available to the scriplet that\n> > +# run under sudo with run_with_sudo\n> > +export_to_sudo () {\n> > +     while test -n \"$1\"\n> > +     do\n> > +             local v\n> > +             eval v=\"\\$$1\"\n> > +             echo \"$1=$v\" >>\"$HOME/env\"\n> > +             shift\n> > +     done\n> > +}\n>\n> Two potential issues:\n>\n>  - This forces the caller to list _all_ the relevant environment\n>    variables that would ever matter, which would not be feasible and\n>    would not be maintainable.  For example, by forgetting to export\n>    GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS, \"git\" commands run in the\n>    sudo tests change their behaviour.  Whoever writing a new test\n>    need to see what obscure GIT_TEST_* thing may affect the test\n>    they want to write, and whoever enhancing the test framework to\n>    add new GIT_TEST_* knob need to pay attention to the users of\n>    export_to_sudo if their new knob need to be exported.\n>\n>  - I think the assignment to $v under eval is correct, but I am not\n>    sure the string accumulated in the $HOME/env file is safe to\n>    eval.  We can pass TEST_DIRECTORY via this mechanism, where the\n>    value deliberately has a whitespace in it, but if the leading\n>    path to our source directory had a single-quote in it, it\n>    probably would not work well.  Of course, any variable that has\n>    LF in its value would not work without proper quoting.\n>\n> I think both are not impossible but are hard to do right.  Because I\n> do not see anything that absolutely needs the $HOME/env mechanism to\n> work in the rest of the tests in this patch, I am inclined to say\n> that I'd prefer keeping things simple and only make sure we use the\n> right $SHELL to run our script (which write_script may help).\n\nmakes sense, would prepare a formal v3 with those changes and that\nshould be safe to queue.\n\n> > +test_expect_success SUDO 'cannot access if owned by root' '\n> > +     (\n> > +             cd root/p &&\n> > +             test_must_fail git status\n> > +     )\n> > +'\n>\n> OK, but strictly speaking, we do not need the SUDO prerequisite for\n> this one.  It still need it for the test directories prepared in\n> previous steps anyway, so perhaps we want one check upfront, just\n> like we do for NOT_ROOT?\n>\n>         if ! test_have_prereq SUDO\n>         then\n>                 skip_all=\"You do not seem to have a working 'sudo'\"\n>                 test_done\n>         fi\n\nmy only concern doing that would be that then could confuse people\nadding new tests later that might also not need SUDO and that would be\nskipped because they were added at the end, but I agree it is overall\ncleaner so would also include in the reroll\n\n> > +test_expect_success SUDO 'cannot access with sudo' '\n> > +     (\n> > +             # TODO: test_must_fail needs additional functionality\n> > +             # 6a67c759489 blocks its use with sudo\n> > +             cd root/p &&\n> > +             ! sudo git status\n> > +     )\n> > +'\n>\n> OK.  So we cannot by default access root-owned repository by\n> default, which is OK.  I wonder what happens if we did \"sudo sudo\n> git status\".  Perhaps the inner sudo will notice that SUDO_UID is\n> set in its environment and does not update it to 0?\n\nfunny enough sudo itself doesn't honour SUDO_UID.\n\n>       ... goes and checks ...\n>         $ sudo sudo sh -c 'echo $SUDO_UID; whoami'\n>         0\n>         root\n>\n> So that gives us another workaround, I guess, which might be even\n> simpler.\n\ncorrect.\n\n> > +test_expect_success SUDO 'can access using a workaround' '\n> > +     # provide explicit GIT_DIR\n> > +     (\n> > +             cd root/p &&\n> > +             run_with_sudo <<-END\n> > +                     GIT_DIR=.git\n> > +                     GIT_WORK_TREE=.\n> > +                     export GIT_DIR GIT_WORK_TREE\n> > +                     git status\n> > +             END\n> > +     ) &&\n> > +     # discard SUDO_UID\n> > +     (\n> > +             cd root/p &&\n> > +             run_with_sudo <<-END\n> > +                     unset SUDO_UID\n> > +                     git status\n> > +             END\n> > +     )\n>\n>         # double sudo\n>         (\n>                 cd root/p &&\n>                 sudo sudo git status\n>         )\n>\n> I do not know if it is worth adding this third workaround.\n\nI think it is, as it helps document them, and makes sure they remain\nviable, but still think that the one added to the documentation is\n\"better\", because it is direct and not an implementation detail\n\nremoving SUDO_UID from your environment \"means\" you want to be\nidentified as root by git from then on, and that the fact that you\nmight have become root through sudo is no longer relevant.\n\nCarlo\n"},{"id":"454766","messageId":"20220503065442.95699-3-carenas@gmail.com","threadId":"57799","inReplyTo":"20220503065442.95699-1-carenas@gmail.com","subject":"[PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-03T06:54:41Z","receivedAt":"2022-05-03T06:55:50Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that user was\nroot (because git was invoked through sudo or a compatible tool) and the\noriginal uid that repository trusted for its config was no longer known,\ntherefore failing the following otherwise safe call:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nthose tools create to keep track of the original user id, and do the\nownership check using that instead.\n\nThis assumes the environment the user is running on after going\nprivileged can't be tampered with, and also adds code to restrict that\nthe new behavior only applies if running as root, therefore keeping the\nmost common case, which runs unprivileged, from changing, but because of\nthat, it will miss cases where sudo (or an equivalent) was used to change\nto another unprivileged user or where the equivalent tool used to raise\nprivileges didn't track the original id in a sudo compatible way.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n Documentation/config/safe.txt  |  9 ++++++++\n git-compat-util.h              | 40 +++++++++++++++++++++++++++++++++-\n t/t0034-root-safe-directory.sh |  2 +-\n 3 files changed, 49 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex 6d764fe0ccf..ee558ced8c7 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -26,3 +26,12 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n is set in system config and you want to re-enable this protection, then\n initialize your list with an empty value before listing the repositories\n that you deem safe.\n++\n+When git tries to check for ownership of git repositories, it will\n+obviously do so with the uid of the user that is running git itself,\n+but if git is running as root, it will check first if it might have\n+been started through `sudo`, and if that is the case, will instead\n+use the uid of the user that did so.\n+If that is not what you would prefer and want git to only trust\n+repositories that are owned by root instead, then you should remove\n+the `SUDO_UID` variable from root's environment.\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 63ba89dd31d..dfdd3e4f81a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -393,12 +393,50 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n+/*\n+ * this helper function overrides a ROOT_UID with the one provided by\n+ * an environment variable, do not use unless the original user is\n+ * root\n+ */\n+static inline void extract_id_from_env(const char *env, uid_t *id)\n+{\n+\tconst char *real_uid = getenv(env);\n+\n+\t/* discard any empty values */\n+\tif (real_uid && *real_uid) {\n+\t\tchar *endptr;\n+\t\tunsigned long env_id;\n+\t\tint saved_errno = errno;\n+\n+\t\terrno = 0;\n+\t\tenv_id = strtoul(real_uid, &endptr, 10);\n+\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n+\t\t\t*id = env_id;\n+\n+\t\terrno = saved_errno;\n+\t}\n+}\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID)\n+\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex 6dac7a05cfd..dd659aed4e1 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -32,7 +32,7 @@ test_expect_success SUDO 'setup' '\n \t)\n '\n \n-test_expect_failure SUDO 'sudo git status as original owner' '\n+test_expect_success SUDO 'sudo git status as original owner' '\n \t(\n \t\tcd root/r &&\n \t\tgit status &&\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454767","messageId":"20220503065442.95699-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220428105852.94449-1-carenas@gmail.com","subject":"[PATCH v3 0/3] fix `sudo make install` regression in maint","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-03T06:54:39Z","receivedAt":"2022-05-03T06:55:55Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Changes since RFC v3:\n* Cleaner split of tests so patch1 will not break if called under sudo\n  and will be less likely to break any CI by restricting its runs to\n  IKNOWWHATIAMDOING=YES\n* Simplified patch3 with all requested enhancements, except that it is\n  still keeping the (currently unused) possibility to override the shell\n  used in run_with_sudo with an optional first parameter.\n\nCarlo Marcelo Arenas Belón (3):\n  t: document regression git safe.directory when using sudo\n  git-compat-util: avoid failing dir ownership checks if running\n    privileged\n  t0034: enhance framework to allow testing more commands under sudo\n\n Documentation/config/safe.txt  |   9 +++\n git-compat-util.h              |  40 +++++++++++-\n t/lib-sudo.sh                  |  13 ++++\n t/t0034-root-safe-directory.sh | 115 +++++++++++++++++++++++++++++++++\n 4 files changed, 176 insertions(+), 1 deletion(-)\n create mode 100644 t/lib-sudo.sh\n create mode 100755 t/t0034-root-safe-directory.sh\n\nA range-diff against RFC v3 shown below to easy review:\n\n1:  51d0d485b5f ! 1:  27192634476 t: document regression git safe.directory when using sudo\n    @@ t/t0034-root-safe-directory.sh (new)\n     +\n     +. ./test-lib.sh\n     +\n    ++if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]\n    ++then\n    ++\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run this test\"\n    ++\ttest_done\n    ++fi\n    ++\n     +# this prerequisite should be added to all the tests, it not only prevents\n     +# the test from failing but also warms up any authentication cache sudo\n     +# might need to avoid asking for a password\n    @@ t/t0034-root-safe-directory.sh (new)\n     +\t)\n     +'\n     +\n    -+# this MUST be always the last test\n    ++# this MUST be always the last test, if used more than once, the next\n    ++# test should do a full setup again.\n     +test_expect_success SUDO 'cleanup' '\n     +\tsudo rm -rf root\n     +'\n2:  4928ad698e2 = 2:  58b4671b9ef git-compat-util: avoid failing dir ownership checks if running privileged\n3:  98aae872efd < -:  ----------- t0034: enhance framework to allow testing more commands under sudo\n-:  ----------- > 3:  7c029c66666 t0034: enhance framework to allow testing more commands under sudo\n\nAlbeit not ideal, if needef patches 1 and 2 could be fastracked to close the\nregression while patch 3 goes through further iterations.\n\nCarlo\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454768","messageId":"20220503065442.95699-2-carenas@gmail.com","threadId":"57799","inReplyTo":"20220503065442.95699-1-carenas@gmail.com","subject":"[PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-03T06:54:40Z","receivedAt":"2022-05-03T06:55:57Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Originally reported after release of v2.35.2 (and other maint branches)\nfor CVE-2022-24765 and blocking otherwise harmless commands that were\ndone using sudo in a repository that was owned by the user.\n\nAdd a new test script with very basic support to allow running git\ncommands through sudo, so a reproduction could be implemented and that\nuses only `git status` as a proxy of the issue reported.\n\nNote that because of the way sudo interacts with the system, a much\nmore complete integration with the test framework will require a lot\nmore work and that was therefore intentionally punted for now.\n\nThe current implementation requires the execution of a special cleanup\nfunction which should always be kept as the last \"test\" or otherwise\nthe standard cleanup functions will fail because they can't remove\nthe root owned directories that are used.  This also means that if\nfailures are found while running the specifics of the failure might\nnot be kept for further debugging and if the test was interrupted, it\nwill be necessary to clean the working directory manually before\nrestarting by running:\n\n  $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n\nThe test file also uses at least one initial \"setup\" test that creates\na parallel execution directory, while ignoring the repository created\nby the test framework, and special care should be taken when invoking\ncommands through sudo, since the environment is otherwise independent\nfrom what the test framework expects.  Indeed `git status` was used\nas a proxy because it doesn't even require commits in the repository\nto work.\n\nA new SUDO prerequisite is provided that does some sanity checking\nto make sure the sudo command that will be used allows for passwordless\nexecution as root and doesn't mess with git execution paths, but\notherwise additional work will be required to ensure additional\ncommands behave as expected and that will be addressed in a later patch.\n\nMost of those characteristics make this test mostly suitable only for\nCI, but it could be executed locally if special care is taken to provide\nfor some of them in the local configuration and maybe making use of the\nsudo credential cache by first invoking sudo, entering your password if\nneeded, and then invoking the test by doing:\n\n  $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n\nReported-by: SZEDER Gábor <szeder.dev@gmail.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/t0034-root-safe-directory.sh | 49 ++++++++++++++++++++++++++++++++++\n 1 file changed, 49 insertions(+)\n create mode 100755 t/t0034-root-safe-directory.sh\n\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nnew file mode 100755\nindex 00000000000..6dac7a05cfd\n--- /dev/null\n+++ b/t/t0034-root-safe-directory.sh\n@@ -0,0 +1,49 @@\n+#!/bin/sh\n+\n+test_description='verify safe.directory checks while running as root'\n+\n+. ./test-lib.sh\n+\n+if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]\n+then\n+\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run this test\"\n+\ttest_done\n+fi\n+\n+# this prerequisite should be added to all the tests, it not only prevents\n+# the test from failing but also warms up any authentication cache sudo\n+# might need to avoid asking for a password\n+test_lazy_prereq SUDO '\n+\tsudo -n id -u >u &&\n+\tid -u root >r &&\n+\ttest_cmp u r &&\n+\tcommand -v git >u &&\n+\tsudo command -v git >r &&\n+\ttest_cmp u r\n+'\n+\n+test_expect_success SUDO 'setup' '\n+\tsudo rm -rf root &&\n+\tmkdir -p root/r &&\n+\tsudo chown root root &&\n+\t(\n+\t\tcd root/r &&\n+\t\tgit init\n+\t)\n+'\n+\n+test_expect_failure SUDO 'sudo git status as original owner' '\n+\t(\n+\t\tcd root/r &&\n+\t\tgit status &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+# this MUST be always the last test, if used more than once, the next\n+# test should do a full setup again.\n+test_expect_success SUDO 'cleanup' '\n+\tsudo rm -rf root\n+'\n+\n+test_done\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454769","messageId":"20220503065442.95699-4-carenas@gmail.com","threadId":"57799","inReplyTo":"20220503065442.95699-1-carenas@gmail.com","subject":"[PATCH v3 3/3] t0034: enhance framework to allow testing more commands under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-03T06:54:42Z","receivedAt":"2022-05-03T06:55:59Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Add a support library that provides one function that can be used\nto run a \"scriplet\" of commands through sudo and that has an\noptional parameter (currently unused) to indicate which shell to\nuse to do so.\n\nAdd additional negative tests as suggested by Junio and that use\nnew workspace that is owned by root.\n\nNote that in order to be able to call `test_must_fail sudo git status`\nor an equivalent, test_must_fail will need to be enhanced or be able\nto run under sudo, so fixing that has been punted, since the only\nprotection it affords is for `git status` not crashing, and that is\ncovered already by other tests.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/lib-sudo.sh                  | 13 +++++++\n t/t0034-root-safe-directory.sh | 70 +++++++++++++++++++++++++++++++++-\n 2 files changed, 81 insertions(+), 2 deletions(-)\n create mode 100644 t/lib-sudo.sh\n\ndiff --git a/t/lib-sudo.sh b/t/lib-sudo.sh\nnew file mode 100644\nindex 00000000000..9ebb30fc82b\n--- /dev/null\n+++ b/t/lib-sudo.sh\n@@ -0,0 +1,13 @@\n+# Helpers for running git commands under sudo.\n+\n+# Runs a scriplet passed through stdin under sudo.\n+run_with_sudo () {\n+\tlocal ret\n+\tlocal SH=${1-\"$TEST_SHELL_PATH\"}\n+\tlocal RUN=\"$HOME/$$.sh\"\n+\twrite_script \"$RUN\" \"$SH\"\n+\tsudo \"$SH\" -c \"\\\"$RUN\\\"\"\n+\tret=$?\n+\trm -f \"$RUN\"\n+\treturn $ret\n+}\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex dd659aed4e1..a68e1d7602b 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -3,6 +3,7 @@\n test_description='verify safe.directory checks while running as root'\n \n . ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-sudo.sh\n \n if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]\n then\n@@ -10,6 +11,12 @@ then\n \ttest_done\n fi\n \n+if ! test_have_prereq NOT_ROOT\n+then\n+\tskip_all=\"No, you don't; these tests can't run as root\"\n+\ttest_done\n+fi\n+\n # this prerequisite should be added to all the tests, it not only prevents\n # the test from failing but also warms up any authentication cache sudo\n # might need to avoid asking for a password\n@@ -40,8 +47,67 @@ test_expect_success SUDO 'sudo git status as original owner' '\n \t)\n '\n \n-# this MUST be always the last test, if used more than once, the next\n-# test should do a full setup again.\n+# this destroys the test environment used above\n+test_expect_success SUDO 'cleanup regression' '\n+\tsudo rm -rf root\n+'\n+\n+if ! test_have_prereq SUDO\n+then\n+\tskip_all=\"You need sudo to root for all remaining tests\"\n+\ttest_done\n+fi\n+\n+test_expect_success SUDO 'setup root owned repository' '\n+\tsudo mkdir -p root/p &&\n+\tsudo git init root/p\n+'\n+\n+test_expect_success 'cannot access if owned by root' '\n+\t(\n+\t\tcd root/p &&\n+\t\ttest_must_fail git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'cannot access with sudo' '\n+\t(\n+\t\t# TODO: test_must_fail needs additional functionality\n+\t\t# 6a67c759489 blocks its use with sudo\n+\t\tcd root/p &&\n+\t\t! sudo git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'can access using a workaround' '\n+\t# run sudo twice\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tsudo git status\n+\t\tEND\n+\t) &&\n+\t# provide explicit GIT_DIR\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tGIT_DIR=.git &&\n+\t\t\tGIT_WORK_TREE=. &&\n+\t\t\texport GIT_DIR GIT_WORK_TREE &&\n+\t\t\tgit status\n+\t\tEND\n+\t) &&\n+\t# discard SUDO_UID\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tunset SUDO_UID &&\n+\t\t\tgit status\n+\t\tEND\n+\t)\n+'\n+\n+# this MUST be always the last test\n test_expect_success SUDO 'cleanup' '\n \tsudo rm -rf root\n '\n-- \n2.36.0.352.g0cd7feaf86f\n\n"},{"id":"454789","messageId":"9b92b380-1da1-b76d-1eb4-469aba289694@gmail.com","threadId":"57799","inReplyTo":"20220503065442.95699-2-carenas@gmail.com","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-03T14:03:59Z","receivedAt":"2022-05-03T14:04:09Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Carlo\n\nOn 03/05/2022 07:54, Carlo Marcelo Arenas Belón wrote:\n> Originally reported after release of v2.35.2 (and other maint branches)\n> for CVE-2022-24765 and blocking otherwise harmless commands that were\n> done using sudo in a repository that was owned by the user.\n> \n> Add a new test script with very basic support to allow running git\n> commands through sudo, so a reproduction could be implemented and that\n> uses only `git status` as a proxy of the issue reported.\n> \n> Note that because of the way sudo interacts with the system, a much\n> more complete integration with the test framework will require a lot\n> more work and that was therefore intentionally punted for now.\n> \n> The current implementation requires the execution of a special cleanup\n> function which should always be kept as the last \"test\" or otherwise\n> the standard cleanup functions will fail because they can't remove\n> the root owned directories that are used.  This also means that if\n> failures are found while running the specifics of the failure might\n> not be kept for further debugging and if the test was interrupted, it\n> will be necessary to clean the working directory manually before\n> restarting by running:\n> \n>    $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n> \n> The test file also uses at least one initial \"setup\" test that creates\n> a parallel execution directory, while ignoring the repository created\n> by the test framework, and special care should be taken when invoking\n> commands through sudo, since the environment is otherwise independent\n> from what the test framework expects.  Indeed `git status` was used\n> as a proxy because it doesn't even require commits in the repository\n> to work.\n> \n> A new SUDO prerequisite is provided that does some sanity checking\n> to make sure the sudo command that will be used allows for passwordless\n> execution as root and doesn't mess with git execution paths, but\n> otherwise additional work will be required to ensure additional\n> commands behave as expected and that will be addressed in a later patch.\n> \n> Most of those characteristics make this test mostly suitable only for\n> CI, but it could be executed locally if special care is taken to provide\n> for some of them in the local configuration and maybe making use of the\n> sudo credential cache by first invoking sudo, entering your password if\n> needed, and then invoking the test by doing:\n> \n>    $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n> \n> Reported-by: SZEDER Gábor <szeder.dev@gmail.com>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> ---\n>   t/t0034-root-safe-directory.sh | 49 ++++++++++++++++++++++++++++++++++\n>   1 file changed, 49 insertions(+)\n>   create mode 100755 t/t0034-root-safe-directory.sh\n> \n> diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\n> new file mode 100755\n> index 00000000000..6dac7a05cfd\n> --- /dev/null\n> +++ b/t/t0034-root-safe-directory.sh\n> @@ -0,0 +1,49 @@\n> +#!/bin/sh\n> +\n> +test_description='verify safe.directory checks while running as root'\n> +\n> +. ./test-lib.sh\n> +\n> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]\n> +then\n> +\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run this test\"\n> +\ttest_done\n> +fi\n> +\n> +# this prerequisite should be added to all the tests, it not only prevents\n> +# the test from failing but also warms up any authentication cache sudo\n> +# might need to avoid asking for a password\n\nIf this is required for all the tests then it would be simpler just to \nskip all the tests if it is not satisfied as you do above.\n\nRunning \"sudo env\" shows that it sets $HOME to /root which means that \nthese tests will pick up /root/.gitconfig if it exists. Normally when \nrunning the tests we set $HOME to $TEST_DIRECTORY so they are run in a \npredictable environment. At least anything pointed to by core.hooksPath \nor core.fsmontior in that file is expecting to be run as root. I think \nit is worth spelling this out explicitly in the commit message \n(currently it is a bit vague about what the implications of not having \nbetter integration with the test framework are) and the top of the test \nfile. Note that t1509 sources test-lib.sh as the root user so does not \nhave this issue.\n\n> +test_lazy_prereq SUDO '\n> +\tsudo -n id -u >u &&\n> +\tid -u root >r &&\n> +\ttest_cmp u r &&\n> +\tcommand -v git >u &&\n> +\tsudo command -v git >r &&\n> +\ttest_cmp u r\n> +'\n> +\n> +test_expect_success SUDO 'setup' '\n> +\tsudo rm -rf root &&\n> +\tmkdir -p root/r &&\n> +\tsudo chown root root &&\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit init\n\nUsing git -C <directory> would eliminate a lot of the sub shells in this \nfile\n\nBest Wishes\n\nPhillip\n\n> +\t)\n> +'\n> +\n> +test_expect_failure SUDO 'sudo git status as original owner' '\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit status &&\n> +\t\tsudo git status\n> +\t)\n> +'\n> +\n> +# this MUST be always the last test, if used more than once, the next\n> +# test should do a full setup again.\n> +test_expect_success SUDO 'cleanup' '\n> +\tsudo rm -rf root\n> +'\n> +\n> +test_done\n"},{"id":"454790","messageId":"af4dd56d-f301-9c3d-2fc3-929a24596e82@gmail.com","threadId":"57799","inReplyTo":"20220503065442.95699-4-carenas@gmail.com","subject":"Re: [PATCH v3 3/3] t0034: enhance framework to allow testing more commands under sudo","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-03T14:12:30Z","receivedAt":"2022-05-03T14:12:39Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Carlo\n\nOn 03/05/2022 07:54, Carlo Marcelo Arenas Belón wrote:\n> Add a support library that provides one function that can be used\n> to run a \"scriplet\" of commands through sudo and that has an\n> optional parameter (currently unused) to indicate which shell to\n> use to do so.\n> \n> Add additional negative tests as suggested by Junio and that use\n> new workspace that is owned by root.\n> \n> Note that in order to be able to call `test_must_fail sudo git status`\n> or an equivalent, test_must_fail will need to be enhanced or be able\n> to run under sudo, so fixing that has been punted, since the only\n> protection it affords is for `git status` not crashing, and that is\n> covered already by other tests.\n> \n> Helped-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> ---\n>   t/lib-sudo.sh                  | 13 +++++++\n>   t/t0034-root-safe-directory.sh | 70 +++++++++++++++++++++++++++++++++-\n>   2 files changed, 81 insertions(+), 2 deletions(-)\n>   create mode 100644 t/lib-sudo.sh\n> \n> diff --git a/t/lib-sudo.sh b/t/lib-sudo.sh\n> new file mode 100644\n> index 00000000000..9ebb30fc82b\n> --- /dev/null\n> +++ b/t/lib-sudo.sh\n> @@ -0,0 +1,13 @@\n> +# Helpers for running git commands under sudo.\n> +\n> +# Runs a scriplet passed through stdin under sudo.\n> +run_with_sudo () {\n> +\tlocal ret\n> +\tlocal SH=${1-\"$TEST_SHELL_PATH\"}\n\nWhat use do you envisage for this? It would be simpler just to use \n$TEST_SHELL_PATH directly below\n\n> +\tlocal RUN=\"$HOME/$$.sh\"\n\nCan we used a fixed name for the script? That would make things simpler \nespecially debugging as one would know what file to look for. Also using \n$TEST_DIRECTORY rather than $HOME would make it clear where the file \nends up.\n\n> +\twrite_script \"$RUN\" \"$SH\"\n> +\tsudo \"$SH\" -c \"\\\"$RUN\\\"\"\n\nI think using write_script means we can just do 'sudo \"$RUN\"'\n\n> +\tret=$?\n> +\trm -f \"$RUN\" > +\treturn $ret\n> +}\n> diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\n> index dd659aed4e1..a68e1d7602b 100755\n> --- a/t/t0034-root-safe-directory.sh\n> +++ b/t/t0034-root-safe-directory.sh\n> @@ -3,6 +3,7 @@\n>   test_description='verify safe.directory checks while running as root'\n>   \n>   . ./test-lib.sh\n> +. \"$TEST_DIRECTORY\"/lib-sudo.sh\n>   \n>   if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]\n>   then\n> @@ -10,6 +11,12 @@ then\n>   \ttest_done\n>   fi\n>   \n> +if ! test_have_prereq NOT_ROOT\n> +then\n> +\tskip_all=\"No, you don't; these tests can't run as root\"\n\nI think the message would be friendlier without the \"No, you don't\" and \njust said that the tests cannot be run as root.\n\n> +\ttest_done\n> +fi\n> +\n>   # this prerequisite should be added to all the tests, it not only prevents\n>   # the test from failing but also warms up any authentication cache sudo\n>   # might need to avoid asking for a password\n> @@ -40,8 +47,67 @@ test_expect_success SUDO 'sudo git status as original owner' '\n>   \t)\n>   '\n>   \n> -# this MUST be always the last test, if used more than once, the next\n> -# test should do a full setup again.\n\nWhy is the comment being changed? If you want the shorter version at the \nend of this patch can't we just use that wording in patch 1?\n\n\n> +# this destroys the test environment used above\n> +test_expect_success SUDO 'cleanup regression' '\n> +\tsudo rm -rf root\n> +'\n> +\n> +if ! test_have_prereq SUDO\n> +then\n> +\tskip_all=\"You need sudo to root for all remaining tests\"\n> +\ttest_done\n> +fi\n> +\n> +test_expect_success SUDO 'setup root owned repository' '\n> +\tsudo mkdir -p root/p &&\n> +\tsudo git init root/p\n> +'\n> +\n> +test_expect_success 'cannot access if owned by root' '\n> +\t(\n> +\t\tcd root/p &&\n> +\t\ttest_must_fail git status\n> +\t)\n> +'\n> +\n> +test_expect_success SUDO 'cannot access with sudo' '\n> +\t(\n> +\t\t# TODO: test_must_fail needs additional functionality\n> +\t\t# 6a67c759489 blocks its use with sudo\n> +\t\tcd root/p &&\n> +\t\t! sudo git status\n> +\t)\n> +'\n\nI think Junio suggested that this should work and showed it was simple \nto make it work. It seems funny that if sudo is started as root it does \nnot work.\n\n> +test_expect_success SUDO 'can access using a workaround' '\n> +\t# run sudo twice\n> +\t(\n> +\t\tcd root/p &&\n> +\t\trun_with_sudo <<-END\n> +\t\t\tsudo git status\n> +\t\tEND\n> +\t) &&\n> +\t# provide explicit GIT_DIR\n> +\t(\n> +\t\tcd root/p &&\n> +\t\trun_with_sudo <<-END\n> +\t\t\tGIT_DIR=.git &&\n> +\t\t\tGIT_WORK_TREE=. &&\n> +\t\t\texport GIT_DIR GIT_WORK_TREE &&\n> +\t\t\tgit status\n\nI'm confused by this. Does this mean we don't do the ownership checks if \nGIT_DIR and or GIT_WORK_TREE are set in the environment?\n\n\nThanks for working on this\n\nBest Wishes\n\nPhillip\n\n\n> +\t\tEND\n> +\t) &&\n> +\t# discard SUDO_UID\n> +\t(\n> +\t\tcd root/p &&\n> +\t\trun_with_sudo <<-END\n> +\t\t\tunset SUDO_UID &&\n> +\t\t\tgit status\n> +\t\tEND\n> +\t)\n> +'\n> +\n> +# this MUST be always the last test\n>   test_expect_success SUDO 'cleanup' '\n>   \tsudo rm -rf root\n>   '\n"},{"id":"454794","messageId":"xmqqv8umr5zr.fsf@gitster.g","threadId":"57799","inReplyTo":"af4dd56d-f301-9c3d-2fc3-929a24596e82@gmail.com","subject":"Re: [PATCH v3 3/3] t0034: enhance framework to allow testing more commands under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-03T15:27:36Z","receivedAt":"2022-05-03T15:27:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n(I'd be brief as it is my day-off today).\n\n>> +test_expect_success SUDO 'cannot access with sudo' '\n>> +\t(\n>> +\t\t# TODO: test_must_fail needs additional functionality\n>> +\t\t# 6a67c759489 blocks its use with sudo\n>> +\t\tcd root/p &&\n>> +\t\t! sudo git status\n>> +\t)\n>> +'\n>\n> I think Junio suggested that this should work and showed it was simple\n> to make it work. It seems funny that if sudo is started as root it\n> does not work.\n\nIt does feel odd.  Any attacker who can prepare a root-owned trap do\nnot have to trick \"sudo git\" to fall there, so I personally do not\nsee much value in stopping this particular pattern, but since\nworkarounds are easy (like double sudo), I do not mind if this does\nnot work *IF* there is a good reason to stop this.\n\n>> +test_expect_success SUDO 'can access using a workaround' '\n>> +\t# run sudo twice\n>> +\t(\n>> +\t\tcd root/p &&\n>> +\t\trun_with_sudo <<-END\n>> +\t\t\tsudo git status\n>> +\t\tEND\n>> +\t) &&\n>> +\t# provide explicit GIT_DIR\n>> +\t(\n>> +\t\tcd root/p &&\n>> +\t\trun_with_sudo <<-END\n>> +\t\t\tGIT_DIR=.git &&\n>> +\t\t\tGIT_WORK_TREE=. &&\n>> +\t\t\texport GIT_DIR GIT_WORK_TREE &&\n>> +\t\t\tgit status\n>\n> I'm confused by this. Does this mean we don't do the ownership checks\n> if GIT_DIR and or GIT_WORK_TREE are set in the environment?\n\nThat's by design.  Remember, we are protecting people from \"cd\"ing\ninto a (sub)directory, unknowingly, that happens to be controled by\na Git repository somebody else prepared as a trap.  So we try to\nensure who owns such a repository when we do the discovery.  Users\nwho set these environment variables to tell Git that they are aware\nthat they are working with that directory are different from the\ntarget audience.\n\n> Thanks for working on this\n\nDitto.  And thanks for reviewing and raising questions.  I agree\nwith all the things you said in the part of the message I did not\ntouch in this reply.\n\n"},{"id":"454796","messageId":"20220503155649.b4ehcez2ytfwyq6e@carlos-mbp.lan","threadId":"57799","inReplyTo":"9b92b380-1da1-b76d-1eb4-469aba289694@gmail.com","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-03T15:56:49Z","receivedAt":"2022-05-03T15:56:57Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, May 03, 2022 at 03:03:59PM +0100, Phillip Wood wrote:\n> > +\n> > +# this prerequisite should be added to all the tests, it not only prevents\n> > +# the test from failing but also warms up any authentication cache sudo\n> > +# might need to avoid asking for a password\n> \n> If this is required for all the tests then it would be simpler just to skip\n> all the tests if it is not satisfied as you do above.\n\nit is obviously not required (as shown by some tests in patch 3 not having\nit and by my choice if the word \"should\"), but it still recommended, which\nI was hoping would be explained by that comment since if sudo to root is\nonly allowed \"temporarily\" by someone typing their password, then sudo keeps\nthat authentication in a cache, that could probably expire otherwise.\n\nIronically, this comment was meant to explain why it was not checked once\nat the beginning and being used instead in almost every test, but presume\nI wasn't clear enough, not sure if worth resubmitting either.\n\n> Running \"sudo env\" shows that it sets $HOME to /root which means that these\n> tests will pick up /root/.gitconfig if it exists.\n\nI think this depends on how sudo is configured, but yes ANY environment\nvariables could be set to unsafe values that would confuse git if it assumes\nit is still running as part of the test suite.\n\nMy approach was to make sure (with the prerequisite) that at least we have\nPATH set to the right value, so we won't start accidentally running the\nsystem provided git, but you are correct that at least for patch1, the only\nthing I can WARRANT to work is `git status`, but it should be also clear\nto whoever writes tests using sudo, that it can't be otherwise since git it\nis not only running as root, but it is running in the environment that sudo\nprovides when doing so.\n\n> Normally when running the\n> tests we set $HOME to $TEST_DIRECTORY so they are run in a predictable\n> environment. At least anything pointed to by core.hooksPath or\n> core.fsmontior in that file is expecting to be run as root.\n\nwhich should be the same expectation of anyone running `sudo make install`\nin their own repository, so we are just mimicking the use case we care\nabout.\n\ncore.hooksPath or core.fsmonitor might be relevant now, but there is no way\nfor me to predict what else might be in the future, and then again `sudo -H`\nwill behave differently than `sudo` and there is nothing git can do to\nprevent that, so I keep thinking $HOME is not that special eitherway.\n\nit might be worth adding that as well as a constrain into the prerequisite\nthough, so if your sudo does change HOME then we skip these tests, or we\ntry harder to call sudo in a way that doesn't change HOME instead.\n\n> I think it is\n> worth spelling this out explicitly in the commit message (currently it is a\n> bit vague about what the implications of not having better integration with\n> the test framework are) and the top of the test file. Note that t1509\n> sources test-lib.sh as the root user so does not have this issue.\n\nAs explained below, there is no way to \"explictly\" document all things that\nmight be relevant, and being vague was therefore by design.\n\nt1509 has also a different objective AFAIK, which is to test in an environment\nwhere everything is running as root, which is not what we want to do here.\n\nroot is relevant only when we got it through sudo, hence I don't think that\njust reading test-lib.sh through sudo as well would be a \"solution\" in this\ncase, but I agree with you that for a full integration a lot more would be\nneeded, which was again documented and punted explicitly.\n\n> > +test_lazy_prereq SUDO '\n> > +\tsudo -n id -u >u &&\n> > +\tid -u root >r &&\n> > +\ttest_cmp u r &&\n> > +\tcommand -v git >u &&\n> > +\tsudo command -v git >r &&\n> > +\ttest_cmp u r\n> > +'\n> > +\n> > +test_expect_success SUDO 'setup' '\n> > +\tsudo rm -rf root &&\n> > +\tmkdir -p root/r &&\n> > +\tsudo chown root root &&\n> > +\t(\n> > +\t\tcd root/r &&\n> > +\t\tgit init\n> \n> Using git -C <directory> would eliminate a lot of the sub shells in this\n> file\n\nMy assumption (and help me understand if it was incorrect) is that these\ntests should document the expected use cases, so you are correct that\nboth cd and -C accomplish the same in the end, but I think that cd is what\nusers would more normally use, and by writing with it (specially since it\nrequires a subshell) is also more easy to spot and understand that an\ninvocation of git with -C.\n\nI have to admit I didn't even thought of using -C originally because of\nthat, but if you think that makes the test easier to understand and better\nI am sure happy to include that in a reroll.\n\nCarlo\n"},{"id":"454808","messageId":"d54b7672-36ab-a2b8-1a73-7d1a444a5936@gmail.com","threadId":"57799","inReplyTo":"20220503155649.b4ehcez2ytfwyq6e@carlos-mbp.lan","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-04T11:15:29Z","receivedAt":"2022-05-04T11:15:43Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Carlo\n\nOn 03/05/2022 16:56, Carlo Marcelo Arenas Belón wrote:\n> On Tue, May 03, 2022 at 03:03:59PM +0100, Phillip Wood wrote:\n>>> +\n>>> +# this prerequisite should be added to all the tests, it not only prevents\n>>> +# the test from failing but also warms up any authentication cache sudo\n>>> +# might need to avoid asking for a password\n>>\n>> If this is required for all the tests then it would be simpler just to skip\n>> all the tests if it is not satisfied as you do above.\n> \n> it is obviously not required (as shown by some tests in patch 3 not having\n> it and by my choice if the word \"should\"),\n\nI'm afraid it is not obvious to me. As far as I can see the only test \nthat does not have this prerequisite is 'cannot access if owned by root' \nadded in patch 3. That test needs a setup test to run first which \nrequires sudo so there is no point running it if this prerequisite is \nnot satisfied.\n\n> but it still recommended, which\n> I was hoping would be explained by that comment since if sudo to root is\n> only allowed \"temporarily\" by someone typing their password, then sudo keeps\n> that authentication in a cache, that could probably expire otherwise.\n> \n> Ironically, this comment was meant to explain why it was not checked once\n> at the beginning and being used instead in almost every test, but presume\n> I wasn't clear enough, not sure if worth resubmitting either.\n\nThat was not clear to me. Prerequisites are evaluated once and the \nresult is cached. Making it lazy just means it is evaluated when it is \nfirst required rather than when it is defined. You're right that we want \nto avoid sudo hanging because it is waiting for a password. We should \ndefine something like\n\nsudo () {\n\tcommand sudo -n \"$@\"\n}\n\nto avoid that.\n\n>> Running \"sudo env\" shows that it sets $HOME to /root which means that these\n>> tests will pick up /root/.gitconfig if it exists.\n> \n> I think this depends on how sudo is configured, but yes ANY environment\n> variables could be set to unsafe values that would confuse git if it assumes\n> it is still running as part of the test suite.\n\nI think I'm using the default configuration for that setting (or at \nleast the default configured by the linux distribution I'm using).\n\n> My approach was to make sure (with the prerequisite) that at least we have\n> PATH set to the right value, so we won't start accidentally running the\n> system provided git, but you are correct that at least for patch1, the only\n> thing I can WARRANT to work is `git status`, but it should be also clear\n> to whoever writes tests using sudo, that it can't be otherwise since git it\n> is not only running as root, but it is running in the environment that sudo\n> provides when doing so.\n> \n>> Normally when running the\n>> tests we set $HOME to $TEST_DIRECTORY so they are run in a predictable\n>> environment. At least anything pointed to by core.hooksPath or\n>> core.fsmontior in that file is expecting to be run as root.\n> \n> which should be the same expectation of anyone running `sudo make install`\n> in their own repository, so we are just mimicking the use case we care\n> about.\n\nTwo of the most important promises the suite makes are that (i) tests do \nnot write outside $TEST_DIRECTORY and (ii) the tests are not affected by \nthe user's or system's git config files. By having $HOME point to /root \nwe are clearly violating the second promise and making it much easier to \naccidentally violate the first by inadvertently writing to $HOME.\n\n> core.hooksPath or core.fsmonitor might be relevant now, but there is no way\n> for me to predict what else might be in the future,\n\nexactly, they are just examples and show why setting HOME=root is a bad idea\n\n> and then again `sudo -H`\n> will behave differently than `sudo` and there is nothing git can do to\n> prevent that, so I keep thinking $HOME is not that special eitherway.\n\nI think $HOME is important enough to worry about because the test suite \ndeliberately resets to avoid reading the user's config. Whether some \nother random variable such as GIT_COMMITTER_DATE is set or not does not \nmatter in the same way.\n\n> it might be worth adding that as well as a constrain into the prerequisite\n> though, so if your sudo does change HOME then we skip these tests, or we\n> try harder to call sudo in a way that doesn't change HOME instead.\n\nIt would be better to call git via a wrapper that sets HOME correctly\n\n>> I think it is\n>> worth spelling this out explicitly in the commit message (currently it is a\n>> bit vague about what the implications of not having better integration with\n>> the test framework are) and the top of the test file. Note that t1509\n>> sources test-lib.sh as the root user so does not have this issue.\n> \n> As explained below, there is no way to \"explictly\" document all things that\n> might be relevant, and being vague was therefore by design.\n\nBeing vague by design is unhelpful, just because it is difficult to list \nall the possible implications of a changes does not mean that one should \nnot list the important known issues. Commit messages should be \ntransparent about the known implications of the changes the commit \nintroduces and whether there are likely to be other unanticipated \nimplications.\n\n> t1509 has also a different objective AFAIK, which is to test in an environment\n> where everything is running as root, which is not what we want to do here.\n\nIndeed - I brought it up because we're reusing IKNOWWHATIAMDOING but not \ndocumenting that we using it in a different way.\n\n> root is relevant only when we got it through sudo, hence I don't think that\n> just reading test-lib.sh through sudo as well would be a \"solution\" in this\n> case, but I agree with you that for a full integration a lot more would be\n> needed, which was again documented and punted explicitly.\n> \n>>> +test_lazy_prereq SUDO '\n>>> +\tsudo -n id -u >u &&\n>>> +\tid -u root >r &&\n>>> +\ttest_cmp u r &&\n>>> +\tcommand -v git >u &&\n>>> +\tsudo command -v git >r &&\n>>> +\ttest_cmp u r\n>>> +'\n>>> +\n>>> +test_expect_success SUDO 'setup' '\n>>> +\tsudo rm -rf root &&\n>>> +\tmkdir -p root/r &&\n>>> +\tsudo chown root root &&\n>>> +\t(\n>>> +\t\tcd root/r &&\n>>> +\t\tgit init\n>>\n>> Using git -C <directory> would eliminate a lot of the sub shells in this\n>> file\n> \n> My assumption (and help me understand if it was incorrect) is that these\n> tests should document the expected use cases, so you are correct that\n> both cd and -C accomplish the same in the end, but I think that cd is what\n> users would more normally use, and by writing with it (specially since it\n> requires a subshell) is also more easy to spot and understand that an\n> invocation of git with -C.\n> \n> I have to admit I didn't even thought of using -C originally because of\n> that, but if you think that makes the test easier to understand and better\n> I am sure happy to include that in a reroll.\n\nI think it's pretty common to use -C in the test suite when running git \nin a repository that is a subdirectory of $TEST_DIRECTORY.\n\nBest Wishes\n\nPhillip\n\n> Carlo\n"},{"id":"454810","messageId":"CAPUEsphJrD5VUp+QiDFr+rp7MiRrPQO8vO++O-ibXZ+BhC43HQ@mail.gmail.com","threadId":"57799","inReplyTo":"d54b7672-36ab-a2b8-1a73-7d1a444a5936@gmail.com","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-04T13:02:54Z","receivedAt":"2022-05-04T13:03:10Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, May 4, 2022 at 4:15 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> On 03/05/2022 16:56, Carlo Marcelo Arenas Belón wrote:\n> > On Tue, May 03, 2022 at 03:03:59PM +0100, Phillip Wood wrote:\n> >>> +\n> >>> +# this prerequisite should be added to all the tests, it not only prevents\n> >>> +# the test from failing but also warms up any authentication cache sudo\n> >>> +# might need to avoid asking for a password\n> >>\n> >> If this is required for all the tests then it would be simpler just to skip\n> >> all the tests if it is not satisfied as you do above.\n> >\n> > it is obviously not required (as shown by some tests in patch 3 not having\n> > it and by my choice if the word \"should\"),\n>\n> I'm afraid it is not obvious to me. As far as I can see the only test\n> that does not have this prerequisite is 'cannot access if owned by root'\n> added in patch 3. That test needs a setup test to run first which\n> requires sudo so there is no point running it if this prerequisite is\n> not satisfied.\n\nWe are in violent agreement here, but again (and don't take it wrong,\nsince it is most likely my fault for not being clear enough in my\nrequest), the issue is I can't figure out how to make it obvious to\nyou since just the use of the world \"should\" made it obvious to me.\n\nDo you have any suggestion I could include in a v4 reroll?, which will\nbe also sent as an RFC, so hopefully this time, we get at least\nagreement in patches 1 and 2, so we could move forward and unblock the\ndevelopment pipeline.\n\n> > but it still recommended, which\n> > I was hoping would be explained by that comment since if sudo to root is\n> > only allowed \"temporarily\" by someone typing their password, then sudo keeps\n> > that authentication in a cache, that could probably expire otherwise.\n> >\n> > Ironically, this comment was meant to explain why it was not checked once\n> > at the beginning and being used instead in almost every test, but presume\n> > I wasn't clear enough, not sure if worth rerolling either.\n>\n> That was not clear to me. Prerequisites are evaluated once and the\n> result is cached.\n\nThis is indeed a bug, my intention was that it will be called in every\nrequest so I need to at least make it \"not lazy\"\n\n> Making it lazy just means it is evaluated when it is\n> first required rather than when it is defined. You're right that we want\n> to avoid sudo hanging because it is waiting for a password. We should\n> define something like\n>\n> sudo () {\n>         command sudo -n \"$@\"\n> }\n\nThis gets us half way to what is needed.  Indeed I explicitly use sudo\n-n in the \"prerequisite\" for this reason, and originally I used a perl\nfunction that called sudo with a timeout and then killed it after a\nfixed time.\n\nThe problem is we ALSO don't want the tests to fail if sudo suddenly\ndecides to ask for a password, so by design I wanted to detect that\nissue in the prerequisite and disable the test instead, which I\nobviously didn't get right.\n\n> >> Running \"sudo env\" shows that it sets $HOME to /root which means that these\n> >> tests will pick up /root/.gitconfig if it exists.\n> >\n> > I think this depends on how sudo is configured, but yes ANY environment\n> > variables could be set to unsafe values that would confuse git if it assumes\n> > it is still running as part of the test suite.\n>\n> I think I'm using the default configuration for that setting (or at\n> least the default configured by the linux distribution I'm using).\n\nAs Junio pointed out in the discussion, this is likely not going to\nrun in a lot of places because of issues like that.\nIndeed in Debian 10 (and therefore most likely all our Ubuntu based\nCI) the prerequisite fails probably because of the same reason it\nfails in your workstation.\n\nsudo is configured to do '-H' by default (which we can't disable\nunless we change the configuration AFAIK) and also doesn't run with\n'-s' which means that even the following shows an error\n\n  sudo command -v git\n\nmy hope was that it will at least run in the macOS part of the CI\nwhich is better than nothing, or alternatively we could define an\nalias as you suggested and force -s on it.\n\nThe problem of doing that though, is that then sudo might run the\nwrong shell, which is also part of the reason why I was forcing it by\ncalling the script explicitly through the shell we want to use\ninstead.\n\n> > My approach was to make sure (with the prerequisite) that at least we have\n> > PATH set to the right value, so we won't start accidentally running the\n> > system provided git, but you are correct that at least for patch1, the only\n> > thing I can WARRANT to work is `git status`, but it should be also clear\n> > to whoever writes tests using sudo, that it can't be otherwise since git it\n> > is not only running as root, but it is running in the environment that sudo\n> > provides when doing so.\n> >\n> >> Normally when running the\n> >> tests we set $HOME to $TEST_DIRECTORY so they are run in a predictable\n> >> environment. At least anything pointed to by core.hooksPath or\n> >> core.fsmontior in that file is expecting to be run as root.\n> >\n> > which should be the same expectation of anyone running `sudo make install`\n> > in their own repository, so we are just mimicking the use case we care\n> > about.\n>\n> Two of the most important promises the suite makes are that (i) tests do\n> not write outside $TEST_DIRECTORY and (ii) the tests are not affected by\n> the user's or system's git config files. By having $HOME point to /root\n> we are clearly violating the second promise and making it much easier to\n> accidentally violate the first by inadvertently writing to $HOME.\n\nWhile I think I'd seen my fair set of violations of those 2 principles\nbefore, I agree that not violating them here would be a good option,\nbut I also consider this as part of the \"integration with the\nframework\" that was explicitly punted.\n\nPatch 1 only concerns with making an accurate reproduction of the\nproblem that was presented as a regression, so having the wrong shell\nor having root's HOME if your sudo so prefers is by design what we\nshould do as well, and my ONLY warranty is that I would be able to\ncall the `git status` command I am trying to test by making sure that\nat least sudo will (mostly) respect the PATH the test suite provides,\nand which is also why I would rather have the prerequisite fail than\nto make it work where it does not by default create a shell.\n\nFWIW I don't think even that is perfect because a sufficiently evil\nsudo configuration could force git to call a different status builtin,\nbut I thought calling the builtin directly by using git-status was\nprobably too much and also likely to fail in places where that binary\ndoesn't get created.\n\nPatch 3 got what would be the beginnings of that \"integration with the\nframework\", with an ugly and minimal \"this is how we can inject\nenvironment variables we care about\" implementation that got of course\ndiscarded in the RFC because it wasn't good enough and not strictly\nneeded.\n\nI think your suggestion makes sense as an enhancement to patch3, but I\nam not sure of how to get it done without reintroducing the\nenvironment I got wrong already in the previous round.\n\n> > core.hooksPath or core.fsmonitor might be relevant now, but there is no way\n> > for me to predict what else might be in the future,\n>\n> exactly, they are just examples and show why setting HOME=root is a bad idea\n\nI think that the current prerequisite prevents that already by failing\nto work as I described before, is the prerequisite working on your\nsetup and still changing HOME?\n\nthis is what I get in macOS 11:\n\n  $ sudo 'env' | grep HOME\n  HOME=/Users/carlo\n  $ sudo -H 'env' | grep HOME\n  HOME=/var/root\n\n> > and then again `sudo -H`\n> > will behave differently than `sudo` and there is nothing git can do to\n> > prevent that, so I keep thinking $HOME is not that special eitherway.\n>\n> I think $HOME is important enough to worry about because the test suite\n> deliberately resets to avoid reading the user's config. Whether some\n> other random variable such as GIT_COMMITTER_DATE is set or not does not\n> matter in the same way.\n\nI meant not important to our concerns that it will negatively impact\nrunning these tests, I cannot provide any warranties that the sudo\nenvironment provided wouldn't be evil enough, for example by setting\nthe path where git looks for its builtins.\n\nbut then again, I think that worrying about that is a stretch.\n\nIf root in a system we are running can change the sudoers\nconfigurations or put configurations in root's home, that system has\nmore things to worry about than having this test running.\n\n> > it might be worth adding that as well as a constraint into the prerequisite\n> > though, so if your sudo does change HOME then we skip these tests, or we\n> > try harder to call sudo in a way that doesn't change HOME instead.\n>\n> It would be better to call git via a wrapper that sets HOME correctly\n\nI would rather make sure the prerequisite fails and all these tests\nare skipped in that system.\n\nGetting a wrapper that fixes THIS specific case won't protect against\nmany others\n\n> >> I think it is\n> >> worth spelling this out explicitly in the commit message (currently it is a\n> >> bit vague about what the implications of not having better integration with\n> >> the test framework are) and the top of the test file. Note that t1509\n> >> sources test-lib.sh as the root user so does not have this issue.\n> >\n> > As explained before, there is no way to \"explicitly\" document all things that\n> > might be relevant, and being vague was therefore by design.\n>\n> Being vague by design is unhelpful, just because it is difficult to list\n> all the possible implications of a changes does not mean that one should\n> not list the important known issues. Commit messages should be\n> transparent about the known implications of the changes the commit\n> introduces and whether there are likely to be other unanticipated\n> implications.\n\nfair enough, care to come with a suggestion?\nagain I think the \"we are running things as root folks!!\" is enough to\ntrigger a \"better do not set that IKNOWWHATIAMDOING\" variable on me,\nbut it might be my sysadmin experience talking.\n\n> > t1509 has also a different objective AFAIK, which is to test in an environment\n> > where everything is running as root, which is not what we want to do here.\n>\n> Indeed - I brought it up because we're reusing IKNOWWHATIAMDOING but not\n> documenting that we using it in a different way.\n\nIt is not used in a different way.\n\nIKNOWWHATIAMDOING is meant to keep developers from running potentially\ndangerous stuff, that yes could mess with your system badly and which\nalso applies here.\n\nBTW while trying to test this in CI, I realized it is not set there,\nso might as well be changed to something different that will be and\nthat would ease your concerns.\n\n> >>> +test_lazy_prereq SUDO '\n> >>> +   sudo -n id -u >u &&\n> >>> +   id -u root >r &&\n> >>> +   test_cmp u r &&\n> >>> +   command -v git >u &&\n> >>> +   sudo command -v git >r &&\n> >>> +   test_cmp u r\n> >>> +'\n> >>> +\n> >>> +test_expect_success SUDO 'setup' '\n> >>> +   sudo rm -rf root &&\n> >>> +   mkdir -p root/r &&\n> >>> +   sudo chown root root &&\n> >>> +   (\n> >>> +           cd root/r &&\n> >>> +           git init\n> >>\n> >> Using git -C <directory> would eliminate a lot of the sub shells in this\n> >> file\n> >\n> > My assumption (and help me understand if it was incorrect) is that these\n> > tests should document the expected use cases, so you are correct that\n> > both cd and -C accomplish the same in the end, but I think that cd is what\n> > users would more normally use, and by writing with it (specially since it\n> > requires a subshell) is also more easy to spot and understand that an\n> > invocation of git with -C.\n> >\n> > I have to admit I didn't even thought of using -C originally because of\n> > that, but if you think that makes the test easier to understand and better\n> > I am sure happy to include that in a reroll.\n>\n> I think it's pretty common to use -C in the test suite when running git\n> in a repository that is a subdirectory of $TEST_DIRECTORY.\n\nI get that, but do you think that in this case makes the tests simpler\nand more importantly more recognizable?\n\nI'll try to use it more in the reroll, but examples where it actually\nimprove the tests would be useful.\n\nCarlo\n"},{"id":"454812","messageId":"1e5c95cb-74b7-011f-7597-1639b84e56ff@gmail.com","threadId":"57799","inReplyTo":"CAPUEsphJrD5VUp+QiDFr+rp7MiRrPQO8vO++O-ibXZ+BhC43HQ@mail.gmail.com","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-04T14:11:11Z","receivedAt":"2022-05-04T14:11:28Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Carlo\n\nJust a quick reply for now with some brief thoughts - I'll try and \nanswer more fully tomorrow.\n\nOn 04/05/2022 14:02, Carlo Arenas wrote:\n >[...]\n> \n> This is indeed a bug, my intention was that it will be called in every\n> request so I need to at least make it \"not lazy\"\n\nUnfortunately don't think that will work, it just evaluates the \nprerequisite when you define it and uses the cached result for each \ntest. (The lazy one evaluates the prerequisite on its first use and then \ncaches the result)\n\n>> Making it lazy just means it is evaluated when it is\n>> first required rather than when it is defined. You're right that we want\n>> to avoid sudo hanging because it is waiting for a password. We should\n>> define something like\n>>\n>> sudo () {\n>>          command sudo -n \"$@\"\n>> }\n> \n> This gets us half way to what is needed.  Indeed I explicitly use sudo\n> -n in the \"prerequisite\" for this reason, and originally I used a perl\n> function that called sudo with a timeout and then killed it after a\n> fixed time.\n> \n> The problem is we ALSO don't want the tests to fail if sudo suddenly\n> decides to ask for a password, so by design I wanted to detect that\n> issue in the prerequisite and disable the test instead, which I\n> obviously didn't get right.\n\nI don't think we have a mechanism to do that. I think the best we can do \nis just to skip the whole file if the SUDO prerequisite fails. Depending \non the configuration sudo will delay the expiration of the cache \npassword each time it is called. In any case this test file is not going \nto take much time to run so if the prerequisite passes the tests should \nhopefully run before the cached password expires.\n\nAnother possibility is to call a function at the start of each test that \nskips the test if 'sudo -n' fails.\n\n> [...] \n> again I think the \"we are running things as root folks!!\" is enough to\n> trigger a \"better do not set that IKNOWWHATIAMDOING\" variable on me,\n> but it might be my sysadmin experience talking.\n\nIt is the fact that we're not just changing the uid that is used to run \nthe tests but we're changing the environment as well that I think we \nneed to call out. It is not obvious that running the tests with a \ndifferent uid will stop $HOME pointing to $TEST_DIRECTORY.\n\n\nI'll try and get back to you on the other points tomorrow\n\nBest Wishes\n\nPhillip\n"},{"id":"454856","messageId":"nycvar.QRO.7.76.6.2205051439290.355@tvgsbejvaqbjf.bet","threadId":"57799","inReplyTo":"20220503065442.95699-2-carenas@gmail.com","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-05-05T13:44:34Z","receivedAt":"2022-05-05T13:44:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Carlo,\n\nOn Mon, 2 May 2022, Carlo Marcelo Arenas Belón wrote:\n\n> Originally reported after release of v2.35.2 (and other maint branches)\n> for CVE-2022-24765 and blocking otherwise harmless commands that were\n> done using sudo in a repository that was owned by the user.\n>\n> Add a new test script with very basic support to allow running git\n> commands through sudo, so a reproduction could be implemented and that\n> uses only `git status` as a proxy of the issue reported.\n>\n> Note that because of the way sudo interacts with the system, a much\n> more complete integration with the test framework will require a lot\n> more work and that was therefore intentionally punted for now.\n>\n> The current implementation requires the execution of a special cleanup\n> function which should always be kept as the last \"test\" or otherwise\n> the standard cleanup functions will fail because they can't remove\n> the root owned directories that are used.  This also means that if\n> failures are found while running the specifics of the failure might\n> not be kept for further debugging and if the test was interrupted, it\n> will be necessary to clean the working directory manually before\n> restarting by running:\n>\n>   $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n>\n> The test file also uses at least one initial \"setup\" test that creates\n> a parallel execution directory, while ignoring the repository created\n> by the test framework, and special care should be taken when invoking\n> commands through sudo, since the environment is otherwise independent\n> from what the test framework expects.  Indeed `git status` was used\n> as a proxy because it doesn't even require commits in the repository\n> to work.\n>\n> A new SUDO prerequisite is provided that does some sanity checking\n> to make sure the sudo command that will be used allows for passwordless\n> execution as root and doesn't mess with git execution paths, but\n> otherwise additional work will be required to ensure additional\n> commands behave as expected and that will be addressed in a later patch.\n>\n> Most of those characteristics make this test mostly suitable only for\n> CI, but it could be executed locally if special care is taken to provide\n> for some of them in the local configuration and maybe making use of the\n> sudo credential cache by first invoking sudo, entering your password if\n> needed, and then invoking the test by doing:\n>\n>   $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n\nHmm. I would like to suggest that we can side-step all of these issues\n(and the ones I outline below) by considering a similar approach to the\none Stolee took in t0033: use one or more `GIT_TEST_*` environment\nvariables to pretend the exact scenario we want to test for.\n\n>\n> Reported-by: SZEDER Gábor <szeder.dev@gmail.com>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> ---\n>  t/t0034-root-safe-directory.sh | 49 ++++++++++++++++++++++++++++++++++\n>  1 file changed, 49 insertions(+)\n>  create mode 100755 t/t0034-root-safe-directory.sh\n>\n> diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\n> new file mode 100755\n> index 00000000000..6dac7a05cfd\n> --- /dev/null\n> +++ b/t/t0034-root-safe-directory.sh\n> @@ -0,0 +1,49 @@\n> +#!/bin/sh\n> +\n> +test_description='verify safe.directory checks while running as root'\n> +\n> +. ./test-lib.sh\n> +\n> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]\n> +then\n> +\tskip_all=\"You must set env var IKNOWWHATIAMDOING=YES in order to run this test\"\n> +\ttest_done\n> +fi\n> +\n> +# this prerequisite should be added to all the tests, it not only prevents\n> +# the test from failing but also warms up any authentication cache sudo\n> +# might need to avoid asking for a password\n> +test_lazy_prereq SUDO '\n> +\tsudo -n id -u >u &&\n> +\tid -u root >r &&\n> +\ttest_cmp u r &&\n> +\tcommand -v git >u &&\n> +\tsudo command -v git >r &&\n\nIn my Ubuntu setup, `/bin/sh` is a symbolic link to `/bin/dash`, which\ndoes not understand the `command`. It might make more sense to use `type`\nhere, but it is quite possible that `type git` uses a different output\nformat than `sudo type git` if they use different shells.\n\nAnother complication is that the `/etc/sudoers` I have over here specifies\na `secure_path`, which prevents the directory with the just-built `git`\nexecutable from being left in `PATH`. I had to edit `/etc/sudoers` _and_\nchange the script to using `sudo -sE` to fix these woes.\n\nIt took me a good chunk of time to figure out how to run these tests, and\nI will have to remember to revert the temporary edit of `/etc/sudoers`\nfile. This is definitely not something I plan on doing often, so I wonder\nhow these regression tests can guarantee that no regressions are\nintroduced if they are so hard to run ;-)\n\n> +\ttest_cmp u r\n> +'\n> +\n> +test_expect_success SUDO 'setup' '\n> +\tsudo rm -rf root &&\n> +\tmkdir -p root/r &&\n> +\tsudo chown root root &&\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit init\n> +\t)\n> +'\n> +\n> +test_expect_failure SUDO 'sudo git status as original owner' '\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit status &&\n> +\t\tsudo git status\n> +\t)\n> +'\n> +\n> +# this MUST be always the last test, if used more than once, the next\n> +# test should do a full setup again.\n> +test_expect_success SUDO 'cleanup' '\n> +\tsudo rm -rf root\n\nThis would be more canonical as `test_when_finished \"sudo rm -rf root\"` in\nthe preceding test cases.\n\nBut as I said above, I would prefer it if we could figure out a way to\npretend a specific scenario via `GIT_TEST_*`. That would ensure not only\nthat those tests are easy to run, but also that they run whenever the test\nsuite runs.\n\nThank you for working on this!\nDscho\n\n> +'\n> +\n> +test_done\n> --\n> 2.36.0.352.g0cd7feaf86f\n>\n>\n"},{"id":"454858","messageId":"nycvar.QRO.7.76.6.2205051545370.355@tvgsbejvaqbjf.bet","threadId":"57799","inReplyTo":"20220503065442.95699-3-carenas@gmail.com","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-05-05T14:01:21Z","receivedAt":"2022-05-05T14:01:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Carlo,\n\nOn Mon, 2 May 2022, Carlo Marcelo Arenas Belón wrote:\n\n> bdc77d1d685 (Add a function to determine whether a path is owned by the\n> current user, 2022-03-02) checks for the effective uid of the running\n> process using geteuid() but didn't account for cases where that user was\n> root (because git was invoked through sudo or a compatible tool) and the\n> original uid that repository trusted for its config was no longer known,\n> therefore failing the following otherwise safe call:\n>\n>   guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n>   [sudo] password for guy:\n>   fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n>\n> Attempt to detect those cases by using the environment variables that\n> those tools create to keep track of the original user id, and do the\n> ownership check using that instead.\n>\n> This assumes the environment the user is running on after going\n> privileged can't be tampered with, and also adds code to restrict that\n> the new behavior only applies if running as root, therefore keeping the\n> most common case, which runs unprivileged, from changing, but because of\n> that, it will miss cases where sudo (or an equivalent) was used to change\n> to another unprivileged user or where the equivalent tool used to raise\n> privileges didn't track the original id in a sudo compatible way.\n\nHmm. I do realize that this is a quite common scenario, and I wish we\nwould not need to rush for a fix here: Otherwise we could carefully design\nan \"untrusted\" mode in which Git errors out on spawning user-specified\ncommands and on writing files (and avoids refreshing the index to avoid\nhaving to write a file), but runs normally if none of that is needed.\n\n> diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\n> index 6d764fe0ccf..ee558ced8c7 100644\n> --- a/Documentation/config/safe.txt\n> +++ b/Documentation/config/safe.txt\n> @@ -26,3 +26,12 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n>  is set in system config and you want to re-enable this protection, then\n>  initialize your list with an empty value before listing the repositories\n>  that you deem safe.\n> ++\n> +When git tries to check for ownership of git repositories, it will\n> +obviously do so with the uid of the user that is running git itself,\n> +but if git is running as root, it will check first if it might have\n> +been started through `sudo`, and if that is the case, will instead\n> +use the uid of the user that did so.\n> +If that is not what you would prefer and want git to only trust\n> +repositories that are owned by root instead, then you should remove\n> +the `SUDO_UID` variable from root's environment.\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 63ba89dd31d..dfdd3e4f81a 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -393,12 +393,50 @@ static inline int git_offset_1st_component(const char *path)\n>  #endif\n>\n>  #ifndef is_path_owned_by_current_user\n> +\n> +#ifdef __TANDEM\n> +#define ROOT_UID 65535\n> +#else\n> +#define ROOT_UID 0\n> +#endif\n\nI do wonder whether we have to play this kind of fragile game. Why not\nsimply respect `SUDO_UID` if it is set? It's not like we expect attackers\nto have control over the environment and could set this malicously.\n\n> +\n> +/*\n> + * this helper function overrides a ROOT_UID with the one provided by\n> + * an environment variable, do not use unless the original user is\n> + * root\n> + */\n> +static inline void extract_id_from_env(const char *env, uid_t *id)\n> +{\n> +\tconst char *real_uid = getenv(env);\n> +\n> +\t/* discard any empty values */\n> +\tif (real_uid && *real_uid) {\n> +\t\tchar *endptr;\n> +\t\tunsigned long env_id;\n> +\t\tint saved_errno = errno;\n> +\n> +\t\terrno = 0;\n> +\t\tenv_id = strtoul(real_uid, &endptr, 10);\n> +\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n\nWe should not look at `errno` here unless the return value of `strtoul()`\nindicates that there might have been an error (i.e. when it is\n`ULONG_MAX`).\n\nLikewise, we need to either initialize `endptr` or only look at it when\n`strtoul()` succeeded.\n\nWe could side-step all of this, of course, if we simply did this:\n\n\teuid = getuid();\n\tif (euid == ROOT_UID)\n\t\teuid = git_env_ulong(\"SUDO_UID\", euid);\n\n> +\t\t\t*id = env_id;\n> +\n> +\t\terrno = saved_errno;\n> +\t}\n\n> +}\n> +\n>  static inline int is_path_owned_by_current_uid(const char *path)\n>  {\n>  \tstruct stat st;\n> +\tuid_t euid;\n> +\n>  \tif (lstat(path, &st))\n>  \t\treturn 0;\n> -\treturn st.st_uid == geteuid();\n> +\n> +\teuid = geteuid();\n> +\tif (euid == ROOT_UID)\n> +\t\textract_id_from_env(\"SUDO_UID\", &euid);\n> +\n> +\treturn st.st_uid == euid;\n\nSince this code is not even compiled on Windows, I believe we need to\nadjust the documentation accordingly (\"On systems other than Windows,\nwhere `sudo` is available, ...\").\n\n>  }\n>\n>  #define is_path_owned_by_current_user is_path_owned_by_current_uid\n> diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\n> index 6dac7a05cfd..dd659aed4e1 100755\n> --- a/t/t0034-root-safe-directory.sh\n> +++ b/t/t0034-root-safe-directory.sh\n> @@ -32,7 +32,7 @@ test_expect_success SUDO 'setup' '\n>  \t)\n>  '\n>\n> -test_expect_failure SUDO 'sudo git status as original owner' '\n> +test_expect_success SUDO 'sudo git status as original owner' '\n>  \t(\n>  \t\tcd root/r &&\n>  \t\tgit status &&\n> --\n> 2.36.0.352.g0cd7feaf86f\n\nAgain, thank you for working on this!\nDscho\n"},{"id":"454860","messageId":"c9fc0fc6-c688-022d-9476-aaa87c66d295@gmail.com","threadId":"57799","inReplyTo":"nycvar.QRO.7.76.6.2205051545370.355@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-05T14:32:03Z","receivedAt":"2022-05-05T14:32:12Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Dscho\n\nOn 05/05/2022 15:01, Johannes Schindelin wrote:\n> [...]\n>> +\n>> +/*\n>> + * this helper function overrides a ROOT_UID with the one provided by\n>> + * an environment variable, do not use unless the original user is\n>> + * root\n>> + */\n>> +static inline void extract_id_from_env(const char *env, uid_t *id)\n>> +{\n>> +\tconst char *real_uid = getenv(env);\n>> +\n>> +\t/* discard any empty values */\n>> +\tif (real_uid && *real_uid) {\n>> +\t\tchar *endptr;\n>> +\t\tunsigned long env_id;\n>> +\t\tint saved_errno = errno;\n>> +\n>> +\t\terrno = 0;\n>> +\t\tenv_id = strtoul(real_uid, &endptr, 10);\n>> +\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n> \n> We should not look at `errno` here unless the return value of `strtoul()`\n> indicates that there might have been an error (i.e. when it is\n> `ULONG_MAX`). >\n> Likewise, we need to either initialize `endptr` or only look at it when\n> `strtoul()` succeeded.\n\nI don't think we need to do either of those, and indeed the function you \nsuggest below does not do them. The standard guarantees that endptr is \nalways set and there is no harm in unconditionally checking errno.\n\n> We could side-step all of this, of course, if we simply did this:\n> \n> \teuid = getuid();\n> \tif (euid == ROOT_UID)\n> \t\teuid = git_env_ulong(\"SUDO_UID\", euid);\n\nThat's a nice suggestion, I didn't know that function existed. It means \nwe would die() if we could not parse SUDO_UID which I think is \nreasonable (we'd also accept a units suffix an the uid)\n\nBest Wishes\n\nPhillip\n"},{"id":"454861","messageId":"06d8719c-1732-c40f-61ec-e010f208cb5d@gmail.com","threadId":"57799","inReplyTo":"nycvar.QRO.7.76.6.2205051439290.355@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-05T14:34:37Z","receivedAt":"2022-05-05T14:34:47Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Dscho\n\nOn 05/05/2022 14:44, Johannes Schindelin wrote:\n>> A new SUDO prerequisite is provided that does some sanity checking\n>> to make sure the sudo command that will be used allows for passwordless\n>> execution as root and doesn't mess with git execution paths, but\n>> otherwise additional work will be required to ensure additional\n>> commands behave as expected and that will be addressed in a later patch.\n>>\n>> Most of those characteristics make this test mostly suitable only for\n>> CI, but it could be executed locally if special care is taken to provide\n>> for some of them in the local configuration and maybe making use of the\n>> sudo credential cache by first invoking sudo, entering your password if\n>> needed, and then invoking the test by doing:\n>>\n>>    $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n> \n> Hmm. I would like to suggest that we can side-step all of these issues\n> (and the ones I outline below) by considering a similar approach to the\n> one Stolee took in t0033: use one or more `GIT_TEST_*` environment\n> variables to pretend the exact scenario we want to test for.\n\nThat's an excellent suggestion. Trying to use sudo in the tests leads to \nall sorts of issues, if we can use a GIT_TEST_* approach instead that \nwould be much better.\n\nBest Wishes\n\nPhillip\n"},{"id":"454864","messageId":"xmqqsfpof06a.fsf@gitster.g","threadId":"57799","inReplyTo":"nycvar.QRO.7.76.6.2205051439290.355@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-05T15:50:53Z","receivedAt":"2022-05-05T15:51:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> A new SUDO prerequisite is provided that does some sanity checking\n>> to make sure the sudo command that will be used allows for passwordless\n>> execution as root and doesn't mess with git execution paths, but\n>> otherwise additional work will be required to ensure additional\n>> commands behave as expected and that will be addressed in a later patch.\n\nThis part probably needs to be stressed, not just here but near the\npart where we require IKNOWWHATIAMDOING=YES to be set.  For regular\ninteractive boxes, this test should pretty much be useless, as on a\nnormally configured machine with human users, it is likely that\n\"sudo\" updates/restricts PATH to a limited set of directories and\nexclude the path to our just-built-and-being-tested \"git\".\n\nIOW, this is primarily (and likely to be solely) for a specialized\nCI job in a very controlled environment.\n\n>> +# this prerequisite should be added to all the tests, it not only prevents\n>> +# the test from failing but also warms up any authentication cache sudo\n>> +# might need to avoid asking for a password\n>> +test_lazy_prereq SUDO '\n>> +\tsudo -n id -u >u &&\n>> +\tid -u root >r &&\n>> +\ttest_cmp u r &&\n>> +\tcommand -v git >u &&\n>> +\tsudo command -v git >r &&\n>\n> In my Ubuntu setup, `/bin/sh` is a symbolic link to `/bin/dash`, which\n> does not understand the `command`. It might make more sense to use `type`\n> here, but it is quite possible that `type git` uses a different output\n> format than `sudo type git` if they use different shells.\n\nSo with that in mind, shell portability is still an issue, but ...\n\n> Another complication is that the `/etc/sudoers` I have over here specifies\n\n... /etc/sudoers (both people allowed to use and how environments\nare futzed with) is not.  If your /etc/sudoers do not allow SUDO\nprereq here to pass, then that is OK.\n"},{"id":"454866","messageId":"xmqqilqkezav.fsf@gitster.g","threadId":"57799","inReplyTo":"nycvar.QRO.7.76.6.2205051545370.355@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-05T16:09:44Z","receivedAt":"2022-05-05T16:10:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> We could side-step all of this, of course, if we simply did this:\n>\n> \teuid = getuid();\n> \tif (euid == ROOT_UID)\n> \t\teuid = git_env_ulong(\"SUDO_UID\", euid);\n\nYes, that is not \"side-stepping\" at all.  It is \"we already have a\nfunction that knows how to use strto*l() correctly\" ;-)\n\nVery good suggestion.  Thanks.\n"},{"id":"454872","messageId":"xmqqlevfesnu.fsf@gitster.g","threadId":"57799","inReplyTo":"nycvar.QRO.7.76.6.2205051439290.355@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-05T18:33:09Z","receivedAt":"2022-05-05T18:42:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hmm. I would like to suggest that we can side-step all of these issues\n> (and the ones I outline below) by considering a similar approach to the\n> one Stolee took in t0033: use one or more `GIT_TEST_*` environment\n> variables to pretend the exact scenario we want to test for.\n\nI like the GIT_TEST_ASSUME_DIFFERENT_OWNER because it is fairly\nclear that it cannot be used as a new attack vector, even with\nsocial engineering.\n\nIt would be nice if we can do something similar, but I am coming up\nempty while trying to think of \"we are testing; pretend that ...\"\nthat is good for testing this SUDO_UID special case *and* clearly\ncannot be used as an attack target.\n\nSo I very much like the suggestion in principle, but I am not sure\nhow useful the suggestion would be to make the resulting code better\nin practice.\n\nPerhaps this may be a way to pretend we are running a command under\n'sudo'?\n\n\ttest_pretend_sudo () {\t\n            GIT_TEST_PRETEND_GETEUID_RETURNING_ROOT=1 \\\n\t    GIT_TEST_PRETEND_LSTAT_RETURNING_ROOT=root/p \\\n                SUDO_UID=0 \"$@\"\n\t}\n\n\ttest_expect_success 'access root-owned repository as root' '\n\t\tmkdir root/p &&\n\t\tgit init root/p &&\n\t\ttest_pretend_sudo git status\n\t'\n\nThat way we can avoid having to run \"chown\" while preparing for the\ntest fixture, and running \"git status\" under root, but I am not sure\nif we want our shipped production binaries to have these \"pretend\"\nknobs.\n\nThanks.\n"},{"id":"454879","messageId":"xmqqczgrdb0j.fsf@gitster.g","threadId":"57799","inReplyTo":"xmqqlevfesnu.fsf@gitster.g","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-05T19:39:40Z","receivedAt":"2022-05-05T19:39:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I like the GIT_TEST_ASSUME_DIFFERENT_OWNER because it is fairly\n> clear that it cannot be used as a new attack vector, even with\n> social engineering.\n>\n> It would be nice if we can do something similar, but I am coming up\n> empty while trying to think of \"we are testing; pretend that ...\"\n> that is good for testing this SUDO_UID special case *and* clearly\n> cannot be used as an attack target.\n>\n> So I very much like the suggestion in principle, but I am not sure\n> how useful the suggestion would be to make the resulting code better\n> in practice.\n> ...\n\nThe worst part is that the SUDO_UID stuff is about _loosening_ the\nprotection the other parts of the mechanism implements.  We do not\nallow access when euid does not match st_uid, but with SUDO_UID, we\ninstead use that for checking when euid is root.  So setting for\ntesting such a feature works to loosen the protection, which would\nmake the attack surface larger.  So I am not so optimistic that we\ncan invent a GIT_TEST_* knob as good as ASSUME_DIFFERENT_OWNER for\nthat.\n\nThanks.\n"},{"id":"454922","messageId":"CAPUEspjjapB1u=_obNFE1gvrsCjFN3oVfPV=7mBG+aGDqnPR1Q@mail.gmail.com","threadId":"57799","inReplyTo":"af4dd56d-f301-9c3d-2fc3-929a24596e82@gmail.com","subject":"Re: [PATCH v3 3/3] t0034: enhance framework to allow testing more commands under sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T16:54:32Z","receivedAt":"2022-05-06T16:54:50Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, May 3, 2022 at 7:12 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> > diff --git a/t/lib-sudo.sh b/t/lib-sudo.sh\n> > new file mode 100644\n> > index 00000000000..9ebb30fc82b\n> > --- /dev/null\n> > +++ b/t/lib-sudo.sh\n> > @@ -0,0 +1,13 @@\n> > +# Helpers for running git commands under sudo.\n> > +\n> > +# Runs a scriplet passed through stdin under sudo.\n> > +run_with_sudo () {\n> > +     local ret\n> > +     local SH=${1-\"$TEST_SHELL_PATH\"}\n>\n> What use do you envisage for this? It would be simpler just to use\n> $TEST_SHELL_PATH directly below\n\nSince this function is a ripoff of write_script which has this feature\n(except I changed the shell used), I thought it might come handy later\nand that getting the first version with a hardcoded value wasn't\nelegant enough, but you are right it is not needed, so is gone in the\nnext RFC.\n\n> > +     local RUN=\"$HOME/$$.sh\"\n>\n> Can we use a fixed name for the script? That would make things simpler\n> especially debugging as one would know what file to look for. Also using\n> $TEST_DIRECTORY rather than $HOME would make it clear where the file\n> ends up.\n\nFrankly (and speaking by experience because this broke a lot for me),\ndebugging is painful enough already that having to find the shell\nscript would be the least of your concerns.\n\nThe main reason why it is not hardcoded to a known name is that by\nadding a slightly more random name, it makes it slightly more\ndifficult for someone to try to trick us into running something else\nthey prepared instead, and the fact that it will be run as root makes\nit much more enticing.\n\nSorry about not using TEST_DIRECTORY to begin with, they are set to\nthe same value and thought HOME was clearer and shorter, but has been\nfixed in the next RFC.\n\n> > +     write_script \"$RUN\" \"$SH\"\n> > +     sudo \"$SH\" -c \"\\\"$RUN\\\"\"\n>\n> I think using write_script means we can just do 'sudo \"$RUN\"'\n\nWe could, but by doing it this way we ensure:\n* we specifically require sudo to allow running a shell, and that\nshell is the one we want it to run (a strict sudo wouldn't do that)\n* we obscure a little bit what sudo is running from it and rely more\nin the shell, so it won't try to be helpful and block it (running\nshell scripts is something a strict sudo might not allow as well)\n\nOn that last point I am still debating if the prerequisite should be\nenhanced to detect that case and fail, but since it is restrictive\nenough already it might not be worth doing now.\n\n> > -# this MUST be always the last test, if used more than once, the next\n> > -# test should do a full setup again.\n>\n> Why is the comment being changed? If you want the shorter version at the\n> end of this patch can't we just use that wording in patch 1?\n\nIt was my failed attempt to document better how they are used, since\nthey are tricky enough to use already, but it is no longer needed and\nis gone in the next RFC.\n\n> > +test_expect_success SUDO 'cannot access with sudo' '\n> > +     (\n> > +             # TODO: test_must_fail needs additional functionality\n> > +             # 6a67c759489 blocks its use with sudo\n> > +             cd root/p &&\n> > +             ! sudo git status\n> > +     )\n> > +'\n>\n> I think Junio suggested that this should work and showed it was simple\n> to make it work. It seems funny that if sudo is started as root it does\n> not work.\n\nIt is not when sudo is started as root, but when the user runs `sudo\n-s` to get a shell and then LATER tries to use git with that shell.\n\nI make a better attempt to explain it in a different thread[1], and is\ntied to the documentation patch which might need further improvements\nto make clear (hopefully not as extensive as my attempts to do so)\n\nI am instead marking it as a known bug for the next RFC\n\nCarlo\n\n[1] https://lore.kernel.org/git/20220429012438.37o4uaxsrfdu2b6x@carlos-mbp.lan/\n"},{"id":"454928","messageId":"CAPUEspiNpNSiasswXK_SWPUPR=m8Hq2vq3b_XisnVz3zbTy8MA@mail.gmail.com","threadId":"57799","inReplyTo":"nycvar.QRO.7.76.6.2205051439290.355@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T17:39:12Z","receivedAt":"2022-05-06T17:39:29Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, May 5, 2022 at 6:44 AM Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n>\n> On Mon, 2 May 2022, Carlo Marcelo Arenas Belón wrote:\n> >\n> >   $ IKNOWWHATIAMDOING=YES ./t0034-root-safe-directory.sh\n>\n> Hmm. I would like to suggest that we can side-step all of these issues\n> (and the ones I outline below) by considering a similar approach to the\n> one Stolee took in t0033: use one or more `GIT_TEST_*` environment\n> variables to pretend the exact scenario we want to test for.\n\nI wish we could, but I think it is not possible in principle because\nit would break the trust chain that we are relying on here to make\nthis work.\n\nAs explained in the commit message from the next patch, for this to be\nuseful as well as safe our ONLY chance is to trust SUDO_UID hasn't\nbeen tampered with, which also requires that we run through sudo so\ngit is running as root and not as the regular user the test suite\nwould use.\n\nIf we remove the (I am really root, before I trust SUDO_UID)\nrequirement from our code, we have just opened ourselves to a way to\nweaken the protections that were added with CVE-2022-24765.\n\nto be frank while Junio mention this \"weakens\" the checks, I consider\nI was strengthened them by introducing a mechanism the user could use\n(only when he is root) to safely tell us that he wants to trust a\nrepository that is not owned by him without having to create an\nexception, and also improving the usability of it, but \"magically\"\ndetecting which uid they are most likely to trust.\n\n> It took me a good chunk of time to figure out how to run these tests, and\n> I will have to remember to revert the temporary edit of `/etc/sudoers`\n> file. This is definitely not something I plan on doing often, so I wonder\n> how these regression tests can guarantee that no regressions are\n> introduced if they are so hard to run ;-)\n\nby running in the CI (at least the macOS hosts, and maybe others if we\ndecide later to butcher their sudoers config as well)\nI am adding more instructions in the commit message from the next RFC\nto help anyone that might want to run this locally (which I\nwouldn't recommend myself)\n\n> This would be more canonical as `test_when_finished \"sudo rm -rf root\"` in\n> the preceding test cases.\n\ncorrect, but I was attempting not to do that to make it less of a pain\nto write more tests since (probably incorrectly) I assumed it would be\nsimpler to remember that there is a test at the end that does the\ncleanup and at least one at the beginning that does the setup than\nprobably having to take care of those 2 things on each test that you\nwrite.\n\nIdeally, the test framework would be able to know that this test\ncreates files as root and cleanup itself, but that was specifically\npunted.\n\nI am keeping this for the next RFC, but I am open to changing it to\nwhatever you would prefer, until a proper integration could be written\nto clean that mess up.\n\nCarlo\n"},{"id":"454929","messageId":"CAPUEspibV6LKVAGpUPBoDYWvF7cjBJUJOSMDzLY6ErMF8s-Eng@mail.gmail.com","threadId":"57799","inReplyTo":"xmqq7d79gjre.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T17:50:04Z","receivedAt":"2022-05-06T17:50:58Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, Apr 28, 2022 at 11:12 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Phillip Wood <phillip.wood123@gmail.com> writes:\n>\n> > On 28/04/2022 17:55, Junio C Hamano wrote:\n> >> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n> >>\n> >>> +test_description='verify safe.directory checks while running as root'\n> >>> +\n> >>> +. ./test-lib.sh\n> >>> +\n> >>> +if [ \"$IKNOWWHATIAMDOING\" != \"YES\" ]; then\n> >> Style.\n> >>      if test \"$IKNOWWHATIAMDOING\" != \"YES\"\n> >>      then\n> >\n> > Also naming - we normally prefix test environment variables with\n> > GIT_TEST_. IKNOWWHATIAMDOING does not tell us what we are allowing by\n> > setting the variable. Something like GIT_TEST_ALLOW_SUDO would tell us\n> > what we're letting ourselves in for by setting it.\n>\n> If this weren't \"let's reuse the same mechanism as already used in\n> 1509\", I would have had the same reaction.  Renaming would be better\n> done outside the topic, I would think.\n\nSince I am renaming it anyway as part of this topic with RFC v4, would\nit be a good idea to require both?\n\nI see the \"IKNOWHATIAMDOING\" not as a normal GIT_TEST flag, but as a\n\"here be dragons!\" warning, and I later found that I either\nmisremembered it being enabled in the CI, or it was dropped with one\nof those refactors we do often there.\n\nMy RFC v4 includes a new nice looking GIT_TEST variable as suggested\nby Phillip which I am also enabling in the CI to hopefully make it\neven more clear that this is only meant to run there, but sadly that\nalso means that this patch will likely have a conflict when merged\nupwards.\n\nAlternatively I could not enable the CI in this series that is aimed\nat maint or at least do it in an independent patch so it could be\ndropped where it is not strictly needed?\n\nCarlo\n"},{"id":"454937","messageId":"CAPUEspiMsvNhQF-RjW5eu3Xco9gU7TFt4w9dOOcF1PGM4Z+ceQ@mail.gmail.com","threadId":"57799","inReplyTo":"c9fc0fc6-c688-022d-9476-aaa87c66d295@gmail.com","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T19:15:06Z","receivedAt":"2022-05-06T19:15:27Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, May 5, 2022 at 7:32 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> On 05/05/2022 15:01, Johannes Schindelin wrote:\n> > [...]\n> >> +\n> >> +/*\n> >> + * this helper function overrides a ROOT_UID with the one provided by\n> >> + * an environment variable, do not use unless the original user is\n> >> + * root\n> >> + */\n> >> +static inline void extract_id_from_env(const char *env, uid_t *id)\n> >> +{\n> >> +    const char *real_uid = getenv(env);\n> >> +\n> >> +    /* discard any empty values */\n> >> +    if (real_uid && *real_uid) {\n> >> +            char *endptr;\n> >> +            unsigned long env_id;\n> >> +            int saved_errno = errno;\n> >> +\n> >> +            errno = 0;\n> >> +            env_id = strtoul(real_uid, &endptr, 10);\n> >> +            if (!errno && !*endptr && env_id <= (uid_t)-1)\n> >\n> > We should not look at `errno` here unless the return value of `strtoul()`\n> > indicates that there might have been an error (i.e. when it is\n> > `ULONG_MAX`). >\n> > Likewise, we need to either initialize `endptr` or only look at it when\n> > `strtoul()` succeeded.\n>\n> I don't think we need to do either of those, and indeed the function you\n> suggest below does not do them. The standard guarantees that endptr is\n> always set and there is no harm in unconditionally checking errno.\n\nI think the point dscho was trying to make is that while you are\ncorrect that the standard guarantees those two things and\nimplementation might decide to not do them, we obviously support\nsystems that are not POSIX.\n\nThe irony is that my first confusing attempt to implement this did\nthat before by explicitly ignoring errno and instead relying in the\n\"expected overflow/underflow\" values to detect the cases we care for\n(which is valid UID numbers that are most likely to be uint32_t) and\nwhich was the same thing we got from my original (but hated) atoi.\n\n> > We could side-step all of this, of course, if we simply did this:\n> >\n> >       euid = getuid();\n> >       if (euid == ROOT_UID)\n> >               euid = git_env_ulong(\"SUDO_UID\", euid);\n>\n> That's a nice suggestion, I didn't know that function existed. It means\n> we would die() if we could not parse SUDO_UID which I think is\n> reasonable (we'd also accept a units suffix an the uid)\n\nwhich is also why we can't use it, any possibly bogus or suspicious\nvalue we get from SUDO_UID MUST be ignored.\n\nCarlo\n"},{"id":"454939","messageId":"xmqq35hml9cs.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspiMsvNhQF-RjW5eu3Xco9gU7TFt4w9dOOcF1PGM4Z+ceQ@mail.gmail.com","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-06T20:00:35Z","receivedAt":"2022-05-06T20:00:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> which is also why we can't use it, any possibly bogus or suspicious\n> value we get from SUDO_UID MUST be ignored.\n\nI do not think I agree.  If we have strange value in SUDO_UID, it\nwould be much better and safer to err on the safe side.  \n\nInstead of ignoring, in the situation where we care about the value\nwe read from SUDO_UID (i.e. when euid==0), we should die loudly when\nit has a strange value.\n"},{"id":"454940","messageId":"CAPUEsphcyTDq1djqBMD3kX9eBK0exW-m8SGpjKBoGYaHuL-80g@mail.gmail.com","threadId":"57799","inReplyTo":"nycvar.QRO.7.76.6.2205051545370.355@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T20:02:03Z","receivedAt":"2022-05-06T20:02:21Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, May 5, 2022 at 7:01 AM Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> On Mon, 2 May 2022, Carlo Marcelo Arenas Belón wrote:\n> > bdc77d1d685 (Add a function to determine whether a path is owned by the\n> > current user, 2022-03-02) checks for the effective uid of the running\n> > process using geteuid() but didn't account for cases where that user was\n> > root (because git was invoked through sudo or a compatible tool) and the\n> > original uid that repository trusted for its config was no longer known,\n> > therefore failing the following otherwise safe call:\n> >\n> >   guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n> >   [sudo] password for guy:\n> >   fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n> >\n> > Attempt to detect those cases by using the environment variables that\n> > those tools create to keep track of the original user id, and do the\n> > ownership check using that instead.\n> >\n> > This assumes the environment the user is running on after going\n> > privileged can't be tampered with, and also adds code to restrict that\n> > the new behavior only applies if running as root, therefore keeping the\n> > most common case, which runs unprivileged, from changing, but because of\n> > that, it will miss cases where sudo (or an equivalent) was used to change\n> > to another unprivileged user or where the equivalent tool used to raise\n> > privileges didn't track the original id in a sudo compatible way.\n>\n> Hmm. I do realize that this is a quite common scenario, and I wish we\n> would not need to rush for a fix here:\n\nnot sure what are you referring by \"this\", and I read the whole snip\njust in case, but assuming is about the last paragraph\n\n* sudo between unprivileged users is still safe because we only look\nif we are running as root, my comment doesn't imply a regression\nthere, but just that the \"feature\" wouldn't work for them.\n* doas is a common tool that is used sometimes as a sudo alternative\nand I can see there might be even a version of it that would probably\nprovide a SUDO_UID for compatibility, once word goes out of how useful\nthat is for working with git, but until then only sudo is supported.\n\n> Otherwise we could carefully design\n> an \"untrusted\" mode in which Git errors out on spawning user-specified\n> commands and on writing files (and avoids refreshing the index to avoid\n> having to write a file), but runs normally if none of that is needed.\n\nThis seems like a useful feature to have, and would definitely make\nthis solution irrelevant, but this one is already implemented and I\ndon't see yet why there is concern, probably until \"this\" could be\nclarified.\n\n> > diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\n> > index 6d764fe0ccf..ee558ced8c7 100644\n> > --- a/Documentation/config/safe.txt\n> > +++ b/Documentation/config/safe.txt\n> > @@ -26,3 +26,12 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n> >  is set in system config and you want to re-enable this protection, then\n> >  initialize your list with an empty value before listing the repositories\n> >  that you deem safe.\n> > ++\n> > +When git tries to check for ownership of git repositories, it will\n> > +obviously do so with the uid of the user that is running git itself,\n> > +but if git is running as root, it will check first if it might have\n> > +been started through `sudo`, and if that is the case, will instead\n> > +use the uid of the user that did so.\n> > +If that is not what you would prefer and want git to only trust\n> > +repositories that are owned by root instead, then you should remove\n> > +the `SUDO_UID` variable from root's environment.\n> > diff --git a/git-compat-util.h b/git-compat-util.h\n> > index 63ba89dd31d..dfdd3e4f81a 100644\n> > --- a/git-compat-util.h\n> > +++ b/git-compat-util.h\n> > @@ -393,12 +393,50 @@ static inline int git_offset_1st_component(const char *path)\n> >  #endif\n> >\n> >  #ifndef is_path_owned_by_current_user\n> > +\n> > +#ifdef __TANDEM\n> > +#define ROOT_UID 65535\n> > +#else\n> > +#define ROOT_UID 0\n> > +#endif\n>\n> I do wonder whether we have to play this kind of fragile game. Why not\n> simply respect `SUDO_UID` if it is set? It's not like we expect attackers\n> to have control over the environment and could set this maliciously.\n\nThe problem is that it indeed would lower the bar on how this feature\nmight weaken the current protections.\n\nGetting an environment variable set \"maliciously\" is not that hard\nwith some social engineering, so making sure only root would have that\nescape hatch, and knowing that there is a way to infer from the\nenvironment what the relevant user is, is a powerful way to solve this\nregression without making the protections weaker.\n\nMy original implementation did not use SUDO_UID but the owner of the\npty as that is harder to fake, and therefore safer even for non root\nusers, but it makes it much more intrusive for the same reason.\n\nIf your concern is the introduced regression where `sudo git` will no\nlonger work without adding a safe.directory exception or removing\nSUDO_UID from the environment (or another of the workaround documented\nin the test case), I would actually argue that it instead increases\nthe security of the original solution by implementing a mechanism that\nuser can use to communicate their intention and that would prefer the\nlower privilege by default.\n\nStill I am considering it as a \"known bug\" which will hopefully be\nfixed soon, since Junio already provided the code to improve this one\nso that a root user can access both repositories owned by them and by\ntheir SUDO_UID.\n\nCarlo\n"},{"id":"454942","messageId":"CAPUEspj98i9oTECSvSp4c-sDQ=hrxJHCY3Nn6QwqdAf9Ntnahw@mail.gmail.com","threadId":"57799","inReplyTo":"xmqq35hml9cs.fsf@gitster.g","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T20:22:49Z","receivedAt":"2022-05-06T20:23:07Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Fri, May 6, 2022 at 1:00 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Arenas <carenas@gmail.com> writes:\n>\n> > which is also why we can't use it, any possibly bogus or suspicious\n> > value we get from SUDO_UID MUST be ignored.\n>\n> I do not think I agree.  If we have a strange value in SUDO_UID, it\n> would be much better and safer to err on the safe side.\n\nignoring it is the safe side; for example if we replace the current\nfunction with the proposed one then some user lucky enough to have\naccess to the latest linux supercomputer that has been patched to have\na 64-bit uid_t (because who makes 32-bit supercomputers nowadays)\nwould get root[1] access by simply faking his SUDO_UID to be UINT_MAX\n+ 1.\n\nWe will also honour probably SUDO_UID=0M as root instead of the\ncurrent action which is to ignore that nonsense and most likely die by\ntelling the pranker that he still can't run `git status` on that root\nowned repository he got access to even after he managed to get sudo to\ngenerate that as a SUDO_UID.\n\n> Instead of ignoring, in the situation where we care about the value\n> we read from SUDO_UID (i.e. when euid==0), we should die loudly when\n> it has a strange value.\n\nthat is fair, but then it would then make this feature into a denial\nof service attack target ;)\n\nThe current implementation instead keeps git running under the UID it\nwas started as, which should be root if it gets to use this code under\nthe current implementation.\n\nI am still open to changing it if you would rather let git be the last\nline of defense, I just think that the current implementation of\nignoring it is more user friendly and better at punking would be\nattackers.\n\nCarlo\n\n[1] https://lwn.net/Articles/727490/\n"},{"id":"454946","messageId":"xmqqh762js1j.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspj98i9oTECSvSp4c-sDQ=hrxJHCY3Nn6QwqdAf9Ntnahw@mail.gmail.com","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-06T20:59:52Z","receivedAt":"2022-05-06T21:00:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> On Fri, May 6, 2022 at 1:00 PM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> Carlo Arenas <carenas@gmail.com> writes:\n>>\n>> > which is also why we can't use it, any possibly bogus or suspicious\n>> > value we get from SUDO_UID MUST be ignored.\n>>\n>> I do not think I agree.  If we have a strange value in SUDO_UID, it\n>> would be much better and safer to err on the safe side.\n>\n> ignoring it is the safe side; for example if we replace the current\n> function with the proposed one then some user lucky enough to have\n> access to the latest linux supercomputer that has been patched to have\n> a 64-bit uid_t (because who makes 32-bit supercomputers nowadays)\n> would get root[1] access by simply faking his SUDO_UID to be UINT_MAX\n> + 1.\n\nSince we do not pay attention to SUDO_UID unless euid is root,\nanybody who can attack by faking SUDO_UID to affect what Git does\ncan already become root on the box.  So such an attacker would\nalready have root access without our help, or they would not.\n\nIn any case, if we notice that SUDO_UID is not a valid number and\ndie(), we deny the access anyway, so there is no need to write more\ncode to ignore.\n\n"},{"id":"454947","messageId":"CAPUEspjugusSzuLJkuHdN-TsfVpqcyAGnTaKEGu9qtwUAghwmw@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqczgrdb0j.fsf@gitster.g","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T21:03:49Z","receivedAt":"2022-05-06T21:04:08Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, May 5, 2022 at 12:39 PM Junio C Hamano <gitster@pobox.com> wrote:\n> So I am not so optimistic that we\n> can invent a GIT_TEST_* knob as good as ASSUME_DIFFERENT_OWNER for\n> that.\n\nthe only option I can think of (if the pain point is running git\nthrough sudo is just too cumbersome) AND we don't want to weaken our\nimplementation by allowing the SUDO_UID escape hatch to non-root would\nbe to still use sudo to change the ownership of the git binaries we\nare testing with to root and SUID them.\n\nbut at that point we are likely to deal with similar platform specific\nissues for why running git as root is still problematic regardless,\nand for whatever reason I feel even more compelled to ever run that\nscript in my workstation since at least with the current\nimplementation I know exactly which commands are running as root.  It\nalso makes this functionality slightly more dangerous since it will be\nincluded as part of the production binaries as you pointed out.\n\nMy hope to broaden its visibility was to instead (since this was\nmainly meant to be a CI only test as explained[1] originally) was to\nadd to our CI setup ways to fix the agents sudoers configuration to\nfit what we need, but I won't do that now, and will probably wait for\na while until the on the fly CI changes settle.\n\nCarlo\n\n[1] https://lore.kernel.org/git/CAPUEspitAQrEjMpUyw8e2pyT1MT+h_dO5wSU0wWDWTqSye5TwA@mail.gmail.com/\n"},{"id":"454949","messageId":"025801d8618d$50890670$f19b1350$@nexbridge.com","threadId":"57799","inReplyTo":"CAPUEspj98i9oTECSvSp4c-sDQ=hrxJHCY3Nn6QwqdAf9Ntnahw@mail.gmail.com","subject":"RE: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-05-06T21:07:31Z","receivedAt":"2022-05-06T21:07:41Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On May 6, 2022 4:23 PM, Carlo Arenas wrote:\n>On Fri, May 6, 2022 at 1:00 PM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> Carlo Arenas <carenas@gmail.com> writes:\n>>\n>> > which is also why we can't use it, any possibly bogus or suspicious\n>> > value we get from SUDO_UID MUST be ignored.\n>>\n>> I do not think I agree.  If we have a strange value in SUDO_UID, it\n>> would be much better and safer to err on the safe side.\n>\n>ignoring it is the safe side; for example if we replace the current function with the\n>proposed one then some user lucky enough to have access to the latest linux\n>supercomputer that has been patched to have a 64-bit uid_t (because who makes\n>32-bit supercomputers nowadays) would get root[1] access by simply faking his\n>SUDO_UID to be UINT_MAX\n>+ 1.\n>\n>We will also honour probably SUDO_UID=0M as root instead of the current action\n>which is to ignore that nonsense and most likely die by telling the pranker that he\n>still can't run `git status` on that root owned repository he got access to even after\n>he managed to get sudo to generate that as a SUDO_UID.\n>\n>> Instead of ignoring, in the situation where we care about the value we\n>> read from SUDO_UID (i.e. when euid==0), we should die loudly when it\n>> has a strange value.\n>\n>that is fair, but then it would then make this feature into a denial of service attack\n>target ;)\n>\n>The current implementation instead keeps git running under the UID it was\n>started as, which should be root if it gets to use this code under the current\n>implementation.\n>\n>I am still open to changing it if you would rather let git be the last line of defense, I\n>just think that the current implementation of ignoring it is more user friendly and\n>better at punking would be attackers.\n\nPlease keep in mind the uid_t == 65535 on __TANDEM. uid_t == 0 actually means \"not logged in\".\n\nThanks,\nRandall\n\n"},{"id":"454953","messageId":"CAPUEsphoG75eY-SmRfFvv-sfo7pwxtaWoeWN0QbsYK7M01XyVA@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqh762js1j.fsf@gitster.g","subject":"Re: [PATCH v3 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T21:40:05Z","receivedAt":"2022-05-06T21:40:26Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Fri, May 6, 2022 at 2:00 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Arenas <carenas@gmail.com> writes:\n>\n> > On Fri, May 6, 2022 at 1:00 PM Junio C Hamano <gitster@pobox.com> wrote:\n> >>\n> >> Carlo Arenas <carenas@gmail.com> writes:\n> >>\n> >> > which is also why we can't use it, any possibly bogus or suspicious\n> >> > value we get from SUDO_UID MUST be ignored.\n> >>\n> >> I do not think I agree.  If we have a strange value in SUDO_UID, it\n> >> would be much better and safer to err on the safe side.\n> >\n> > ignoring it is the safe side; for example if we replace the current\n> > function with the proposed one then some user lucky enough to have\n> > access to the latest linux supercomputer that has been patched to have\n> > a 64-bit uid_t (because who makes 32-bit supercomputers nowadays)\n> > would get root[1] access by simply faking his SUDO_UID to be UINT_MAX\n> > + 1.\n>\n> Since we do not pay attention to SUDO_UID unless euid is root,\n> anybody who can attack by faking SUDO_UID to affect what Git does\n> can already become root on the box.\n\nNormally yes, but they just might be too clever and found instead a way to\nfool sudo into generating a bogus SUDO_UID with the hopes that whoever\nimplemented this forgot to check for bogus values and used atoi() and\ntherefore grants them uid = 0 for whatever nefarious objective they\nmight have.\n\nWhile we can't protect against a buggy sudo, we can't do the next best\nthing and that is to NOT let a would-be attacker still get their 5 min\nof fame by reporting a vulnerability in git, because they just made it\ncrash through sudo.\n\nEspecially when the impact of just ignoring them and going our merry\nway is that (with the current code) we will use the euid of the user\nthat started sudo and \"do the right thing\" (tm).\n\n> In any case, if we notice that SUDO_UID is not a valid number and\n> die(), we deny the access anyway, so there is no need to write more\n> code to ignore.\n\nnot sure which additional code you are referring to here, but\ncurrently the only code to ignore is embedded in the one that is\nneeded to read the value, so it is not additional, except maybe for\nthe (uid_t)-1 check that was discussed before[1] and that is what\nprotects us from overflows when sizeof(long) > sizeof(uid_t) &&\nUID_T_MIN >= 0, which are likely most of the systems we are expected\nto run on.\n\nif you are referring to the whole function that could be replaced by\nusing instead git_env_ulong() as dscho suggested, additional code\nwould be needed anyway to make sure that we truncate it appropriately\nas what we really need is a git_env_uint32() which I am really glad to\nadd if you would rather go that way, but is definitely going to\nrequire more code than what we have right now.\n\nNote also that we will need to add a flag to it, so it doesn't try to\nbe helpful and allow SUDO_UID=0M to sneak in.\n\nCarlo\n\n[1] https://lore.kernel.org/git/CAPUEsphFb-=BcV-mxS5RZpJQ8UVq23ni0Lo8tQ4J3TP04B4KQg@mail.gmail.com/\n"},{"id":"454954","messageId":"xmqq1qx6jq0b.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspibV6LKVAGpUPBoDYWvF7cjBJUJOSMDzLY6ErMF8s-Eng@mail.gmail.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-06T21:43:48Z","receivedAt":"2022-05-06T21:43:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> Since I am renaming it anyway as part of this topic with RFC v4, would\n> it be a good idea to require both?\n>\n> I see the \"IKNOWHATIAMDOING\" not as a normal GIT_TEST flag, but as a\n> \"here be dragons!\" warning, and I later found that I either\n> misremembered it being enabled in the CI, or it was dropped with one\n> of those refactors we do often there.\n>\n> My RFC v4 includes a new nice looking GIT_TEST variable as suggested\n> by Phillip which I am also enabling in the CI to hopefully make it\n> even more clear that this is only meant to run there, but sadly that\n> also means that this patch will likely have a conflict when merged\n> upwards.\n\nThis must build from the older mainteance tracks like maint-2.30, so\nlet's keep the changes to absolute minimum, especially since that\nwill become the base for any further usability tweaks (in an earlier\nround you suggested to cover \"doas\", and other changes may want to\nbe applied but all of them should be deferred to later changes).\n\nI actually think 1/3 and 3/3 are OK.  Are there remaining issues in\nthese two patches (which only are tests)?\n\nAs to 2/3, I think the code is basically already fine, but a\nsimplification like the following on top would be a good idea.\n\n * The callers do not care how errno is modified by the call made\n   into extract_id_from_env(); we are potentially clobbering errno\n   by calling getenv(), lstat(), geteuid(), etc, and we have no\n   \"preserve errno as the caller had\" around them.  So let's lose\n   the saved_errno thing.\n\n * We clear errno before making strtoul() call, so any non-zero\n   errno must have happeneed in strtoul(), which includes ERANGE.\n   There is no point chekcing the returned value env_id; if it is\n   ULONG_MAX but errno is 0, then the SUDO_UID legitimately is\n   naming a user whose UID is that special value, and it is not an\n   indication of an overflow.\n\nWith the change squashed in, [2/3] can have \n\nReviewed-by: Junio C Hamano <gitster@pobox.com>\n\nThanks.\n\n git-compat-util.h | 5 +----\n 1 file changed, 1 insertion(+), 4 deletions(-)\n\ndiff --git c/git-compat-util.h w/git-compat-util.h\nindex dfdd3e4f81..43c9cd0b48 100644\n--- c/git-compat-util.h\n+++ w/git-compat-util.h\n@@ -413,14 +413,11 @@ static inline void extract_id_from_env(const char *env, uid_t *id)\n \tif (real_uid && *real_uid) {\n \t\tchar *endptr;\n \t\tunsigned long env_id;\n-\t\tint saved_errno = errno;\n \n \t\terrno = 0;\n \t\tenv_id = strtoul(real_uid, &endptr, 10);\n-\t\tif (!errno && !*endptr && env_id <= (uid_t)-1)\n+\t\tif (!*endptr && !errno)\n \t\t\t*id = env_id;\n-\n-\t\terrno = saved_errno;\n \t}\n }\n \n"},{"id":"454957","messageId":"CAPUEspjOPNTMrBdLQMKcbXYY7G+Vm1br++7C3rq6Bs+5xZ4yHg@mail.gmail.com","threadId":"57799","inReplyTo":"xmqq1qx6jq0b.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-06T22:57:13Z","receivedAt":"2022-05-06T22:57:32Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Fri, May 6, 2022 at 2:43 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Arenas <carenas@gmail.com> writes:\n>\n> > Since I am renaming it anyway as part of this topic with RFC v4, would\n> > it be a good idea to require both?\n> >\n> > I see the \"IKNOWHATIAMDOING\" not as a normal GIT_TEST flag, but as a\n> > \"here be dragons!\" warning, and I later found that I either\n> > misremembered it being enabled in the CI, or it was dropped with one\n> > of those refactors we do often there.\n> >\n> > My RFC v4 includes a new nice looking GIT_TEST variable as suggested\n> > by Phillip which I am also enabling in the CI to hopefully make it\n> > even more clear that this is only meant to run there, but sadly that\n> > also means that this patch will likely have a conflict when merged\n> > upwards.\n>\n> This must build from the older mainteance tracks like maint-2.30, so\n> let's keep the changes to absolute minimum\n\nmakes sense, but I still unsure about the two questions I had above:\n\n* would it make sense to make it run ONLY if both variables are set to\nYES or is it enough to use one (most likely the GIT_TEST one) that we\nwould enable independently in CI?\n\nthe advantage I see of having both variables is that it is even less\nlikely to even run accidentally in a desktop somewhere and maybe break\nthat test, and also keeps the meaning I wanted to attach to it with\nthat ugly looking flag that no one should ever try to enable in their\nworkstations unless they really know what they are doing.\n\nThe advantage of ONLY having the GIT_TEST one is that it will be\neasier to enable in CI and for whoever wants to play with it on their\nworkstation as well, but might still encourage people trying to make\nit work and wasting their time.\n\n* since we have to enable CI for these to be useful, would that be\nsomething to be done in an additional patch as part of this topic\nbranch and you will only pull the commits before it to maint to avoid\nconflicts, or should it be done completely independently as a mini\nfeature branch that depends on this one that will be pulled to seen\nand merged downwards from it?\n\nsomehow offtopic but just curious about your process, presume that if\nwe go with a single topic branch adding it instead as 2/4 would break\nyour flow/scripts since the only way to get that merged would be to\ncherry-pick, right?\n\n> I actually think 1/3 and 3/3 are OK.  Are there remaining issues in\n> these two patches (which only are tests)?\n\nThe versions of them in RFCv4 have more documentation and are cleaner\nsince they mostly include most of the feedback that was collected on\nthem (even if I am still unsure because it is spread around and\ndifficult to track, hence why I was planning an RFC)\n\nI don't think there is anything significantly different though but\nthey are and will need another review (which I am hoping would be\nuncontroversial)\n\n> As to 2/3, I think the code is basically already fine, but a\n> simplification like the following on top would be a good idea.\n>\n>  * We clear errno before making strtoul() call, so any non-zero\n>    errno must have happeneed in strtoul(), which includes ERANGE.\n>    There is no point checking the returned value env_id; if it is\n>    ULONG_MAX but errno is 0, then the SUDO_UID legitimately is\n>    naming a user whose UID is that special value, and it is not an\n>    indication of an overflow.\n\ntrue, but the apparent check for ULONG_MAX (which should have a\ncomment added) was really a check not to overflow when assigning the\nvalue we got into uid_t, by sacrificing an unlikely to be valid\nULONG_MAX as an uid.\n\nit also has the intentional side effect of breaking this code if uid_t\nis signed and hopefully triggering a warning in the process since it\nwould be always false, that way whoever has a system where this type\nis signed will have to carry their own version of the code and we\ndon't have to deal with the portability of it.\n\nlastly (since it really made me proud and would be sad to see it go)\nit ALSO avoids someone trying to sneak a value that would overflow in\none of the most common configurations we will run where sizeof(long) >\nsizeof(uid_t) && MIN_UID_T >=0, by using an equivalent to MAX_UID_T\n(which only exists in a few systems and therefore can't be relied on)\nto discard values that would overflow the range uid_t has.\n\nwithout it, we would probably find ourselves in the future having to\ndeal with an embarrassing bug that others before us had suffered.\n\nCarlo\n"},{"id":"454958","messageId":"xmqqfslmi5c7.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspjOPNTMrBdLQMKcbXYY7G+Vm1br++7C3rq6Bs+5xZ4yHg@mail.gmail.com","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-06T23:55:36Z","receivedAt":"2022-05-06T23:55:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> makes sense, but I still unsure about the two questions I had above:\n>\n> * would it make sense to make it run ONLY if both variables are set to\n> YES or is it enough to use one (most likely the GIT_TEST one) that we\n> would enable independently in CI?\n>\n> the advantage I see of having both variables is that it is even less\n> likely to even run accidentally in a desktop somewhere and maybe break\n> that test, and also keeps the meaning I wanted to attach to it with\n> that ugly looking flag that no one should ever try to enable in their\n> workstations unless they really know what they are doing.\n>\n> The advantage of ONLY having the GIT_TEST one is that it will be\n> easier to enable in CI and for whoever wants to play with it on their\n> workstation as well, but might still encourage people trying to make\n> it work and wasting their time.\n\nThose who want to use it in CI would need to be told (or have to\nfigure it out) by the patch that adds either IKNOWWHATIAMDOING or\nGIT_TEST_WHATEVER, and as long as the patch does its job well\nenough, I do not see much difference either way.  The only possible\ndifference is if we use IKNOWWHATIAMDOING then a special CI job that\nmay run with tweaked /etc/sudoers would run the test in this series\n*and* the other test we borrowed IKNOWWHATIAMDOING from, which may\nnot necessarily be what we want to do.\n\n> * since we have to enable CI for these to be useful, would that be\n> something to be done in an additional patch as part of this topic\n> branch and you will only pull the commits before it to maint to avoid\n> conflicts, or should it be done completely independently as a mini\n> feature branch that depends on this one that will be pulled to seen\n> and merged downwards from it?\n\nI'd expect that nobody pays attention to GitHub CI runs on\nmaint-2.30 - maint-2.35 branches when I push out.  I am hoping that\nthese fixes are built on maint-2.30 _without_ CI integration (i.e.\nthe SUDO tests won't be run due to lack of IKNOWWHATIAMDOING in the\nCI environment).\n\nA single branch, without CI integration, based on maint-2.30 would\nbe prepared.  Let's call that cb/path-owner-check-with-sudo topic.\n\nIt is merged to another branch, based on v2.36.0.  Let's call that\ncb/test-path-owner-check-with-sudo-in-ci.\n\nOn that latter branch, changes to CI to tweak /etc/sudoers and set\nIKNOWWHATIAMDOING would be created.  That latter branch will\npercolate down starting at 'seen', through 'next', 'master' and\nfinally to 'maint'.\n\nAfter all that happens to prove the primary topic (sans CI) is\nsound, the tip of maint-2.30 would be updated by merging it, i.e.\ncb/path-owner-check-with-sudo, and then the result would be merged\nto maint-2.31, ..., percolating upwards to maint-2.35.  The\nresulting maint-2.35 may be merged to 'maint' after that but that\nshould become a \"already up-to-date\" merge, I would expect, because\n'maint' by that time would have got cb/path-owner-check-with-sudo as\npart of merging cb/test-path-owner-check-with-sudo-in-ci already,\nand the merge of cb/path-owner-check-with-sudo is the only thing\n'maint-2.35' has that hasn't merged to 'maint' at that point.\n\n> true, but the apparent check for ULONG_MAX (which should have a\n> comment added) was really a check not to overflow when assigning the\n> value we got into uid_t, by sacrificing an unlikely to be valid\n> ULONG_MAX as an uid.\n\nAre you worried about uid_t wider than ulong?  strtoul() with !errno\ntest covers the case, doesn't it?  SUDO_UID cannot have any integer\nthat cannot be represented in uid_t and if strtoul() does not say\nERANGE, we know whatever value in SUID_UID did not overflow ulong.\n\n> it ALSO avoids someone trying to sneak a value that would overflow in\n> one of the most common configurations we will run where sizeof(long) >\n> sizeof(uid_t) && MIN_UID_T >=0, by using an equivalent to MAX_UID_T\n\nSorry, -ECANNOTPARSE.  If strtoul() can parse everything in uid_t\nthen where is the room for overflowing?  We are trying to protect an\nunsuspecting user who temporary has become 'root' via sudo, and not\nsomebody deliberately hurt themselves or others by setting SUDO_UID\ndeliberately to strange values (once you are 'root', you have easier\nways to hurt other people).\n"},{"id":"454969","messageId":"20220507115701.nozz53t4j52r2xon@carlos-mbp.lan","threadId":"57799","inReplyTo":"xmqqfslmi5c7.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] t: add tests for safe.directory when running with sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-07T11:57:01Z","receivedAt":"2022-05-07T11:57:10Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Fri, May 06, 2022 at 04:55:36PM -0700, Junio C Hamano wrote:\n> Carlo Arenas <carenas@gmail.com> writes:\n> \n> > true, but the apparent check for ULONG_MAX (which should have a\n> > comment added) was really a check not to overflow when assigning the\n> > value we got into uid_t, by sacrificing an unlikely to be valid\n> > ULONG_MAX as an uid.\n> \n> Are you worried about uid_t wider than ulong?  strtoul() with !errno\n> test covers the case, doesn't it?\n\nNo, I am worried about uid_t narrower than ulong, which is also the\nmost likely scenatio with a typeof(uid_t) == uint32_t\n\n> SUDO_UID cannot have any integer\n> that cannot be represented in uid_t and if strtoul() does not say\n> ERANGE, we know whatever value in SUID_UID did not overflow ulong.\n\nIt is a little subtle, but strtoul doesn't warrant always an ERANGE\nbecause it tries to be helpful when given a negative integer and returns\ninstead an equivalent unsigned long as per spec[1] (or in this case the\ncommentary from OpenBSD man page which is also easier to link)\n\n\"If the minus sign was part of the input sequence, the numeric value calculated from the sequence of digits is negated as if by unary minus in the result type, which applies unsigned integer wraparound rules.\"\n\n> > it ALSO avoids someone trying to sneak a value that would overflow in\n> > one of the most common configurations we will run where sizeof(long) >\n> > sizeof(uid_t) && MIN_UID_T >=0, by using an equivalent to MAX_UID_T\n> \n> Sorry, -ECANNOTPARSE.  If strtoul() can parse everything in uid_t\n> then where is the room for overflowing?\n\nSo lets assume a 32bit unsigned uid_t, that wraparounds at 2^32+1, if we\nget a negative value that is equivalent to something bigger than it, or\neven a positive value bigger than it, then the assignment will overflow\nunless we keep it in check by that obviously too clever condition that\nwas removed and we MIGHT even assume an uid_t of 0, which is embarrasing[0].\n\n> We are trying to protect an\n> unsuspecting user who temporary has become 'root' via sudo, and not\n> somebody deliberately hurt themselves or others by setting SUDO_UID\n> deliberately to strange values (once you are 'root', you have easier\n> ways to hurt other people).\n\nYou are correct for the current code that even has a big warning telling\npeople NEVER to run that function for anyone other than root, but who\nknows how this will evolve in the future.\n\nRemoving it also has other sideeffect, like making this code work in\nincorrect ways if uid_t is signed, which I mentioned before but probably\nshould had been added as a comment, but that was part of the requirements[2]\nwe had when Phillip argued correctly that I was restricting the valid uid\nto only half was possible in 32bit systems.\n\nFWIW, sudo prints the uid using \"%u\" so using unsigned long makes more\nsense and all these problems are unlikely to be practical issues now so\nI am ok taking your code if you insist, but I still think that the original\none was safer in case things change in the future or if there is a platform\nwe currently run on with has signed uid_t, so I will keep it in the RFC with\nhopefully enough comments to convince you.\n\nCarlo\n\n[0] https://github.com/systemd/systemd/issues/11026\n[1] https://man.openbsd.org/strtoul.3\n[2] https://lore.kernel.org/git/CAPUEspjoTYtv9K=rvpkFnyGnEz_uxefED820rx09b6qGG93SqA@mail.gmail.com/\n"},{"id":"454972","messageId":"20220507163508.78459-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220503065442.95699-1-carenas@gmail.com","subject":"[RFC PATCH v4 0/3] fix `sudo make install` regression in maint","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-07T16:35:05Z","receivedAt":"2022-05-07T16:35:34Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"A reroll for cb/path-owner-check-with-sudo with most of the suggestions\nincluded but planned originally as an RFC, because I am frankly not sure\nthat I read and addressed all of it, but also because after seeing how\nmy only chance to get an official Reviewed-by: Junio vanished I also\nrealized that I wasn't been clear enough and careful enough from the\nbeginning to explain the code correctly and therefore had maybe wasted\nmore of the review quota this change should require.\n\nImportant changes (eventhough most are not affecting the logic)\n* Document hopefully better which environments are supported and what\n  to do if you want to test it in one that is not (thanks to dscho)\n* Removed the arguably premature optimization to try to keep the sudo\n  cache warm which was actually buggy, as it was also not needed.\n  The CI does passwordless sudo unconditionally and even when running\n  it locally it will go so fast that is shouldn't be an issue (thanks\n  to Philip)\n* No longer using the ugly and controversial variable name so now it\n  will need GIT_TEST_ENABLE_SUDO to be used to enable it on CI (which\n  is not done in this series, but a run with it enabled on top of\n  seen is available[1])\n* Stop the arguing about what is or not a regression worth fixing and\n  instead document it as one through a test, which would be easy to\n  fix in a follow up since the code was already provided by Junio\n\nLastly I am little concerned by the fact this is going to maint but\nhas a \"weather balloon\" of sorts, which might not be wise, since it\nmight prevent people that might be affected from upgrading if they\nhave a -Werror policy.\n\nThe effect is minor though, as worst case, if someone has a system\nwith a signed uid_t then this \"feature\" wouldn't work for them and\nnothing has changed but I think it is worth to consider the alternatives\nwhich are (in my own order of preference)\n\n* Revert the change to use unsigned long and strtoul()\n\n  This will mean that people running in a 32bit system with an uid bigger\n  than INT_MAX wouldn't be able to use the feature\n\n* Move the code out (which is indeed an artificial restriction) so that\n  we can use intmax_t and strtoimax() instead and a cast to compare the\n  uid_t.\n\n  This avoids all issues and restrictions but means more code changes\n\n* Throw away the custom function and expand the API ones to be used\n  instead as dscho suggested.\n\n  Even more code changes, but maybe less risk as we will be building\n  on top of battle tested code.\n\n[1] https://github.com/carenas/git/actions/runs/2286452160\n\nCarlo Marcelo Arenas Belón (3):\n  t: regression git needs safe.directory when using sudo\n  git-compat-util: avoid failing dir ownership checks if running\n    privileged\n  t0034: add negative tests and allow git init to mostly work under sudo\n\n Documentation/config/safe.txt  |  10 ++++\n git-compat-util.h              |  49 +++++++++++++++-\n t/lib-sudo.sh                  |  12 ++++\n t/t0034-root-safe-directory.sh | 103 +++++++++++++++++++++++++++++++++\n 4 files changed, 173 insertions(+), 1 deletion(-)\n create mode 100644 t/lib-sudo.sh\n create mode 100755 t/t0034-root-safe-directory.sh\n\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"454973","messageId":"20220507163508.78459-2-carenas@gmail.com","threadId":"57799","inReplyTo":"20220507163508.78459-1-carenas@gmail.com","subject":"[RFC PATCH v4 1/3] t: regression git needs safe.directory when using sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-07T16:35:06Z","receivedAt":"2022-05-07T16:35:40Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Originally reported after release of v2.35.2 (and other maint branches)\nfor CVE-2022-24765 and blocking otherwise harmless commands that were\ndone using sudo in a repository that was owned by the user.\n\nAdd a new test script with very basic support to allow running git\ncommands through sudo, so a reproduction could be implemented and that\nuses only `git status` as a proxy of the issue reported.\n\nNote that because of the way sudo interacts with the system, a much\nmore complete integration with the test framework will require a lot\nmore work and that was therefore intentionally punted for now.\n\nThe current implementation requires the execution of a special cleanup\nfunction which should always be kept as the last \"test\" or otherwise\nthe standard cleanup functions will fail because they can't remove\nthe root owned directories that are used.  This also means that if\nfailures are found while running, the specifics of the failure might\nnot be kept for further debugging and if the test was interrupted, it\nwill be necessary to clean the working directory manually before\nrestarting by running:\n\n  $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n\nThe test file also uses at least one initial \"setup\" test that creates\na parallel execution directory, while ignoring the repository created\nby the test framework, and special care should be taken when invoking\ncommands through sudo, since the environment is otherwise independent\nfrom what the test framework expects.  Indeed `git status` was used\nas a proxy because it doesn't even require commits in the repository\nto work.\n\nA new SUDO prerequisite is provided that does some sanity checking\nto make sure the sudo command that will be used allows for passwordless\nexecution as root without restrictions and doesn't mess with git's\nexecution path.  This matches what is provided by the macOS agents that\nare used as part of GitHub actions and probably nowhere else.\n\nMost of those characteristics make this test mostly suitable only for\nCI, but it might be executed locally if special care is taken to provide\nfor some of them in the local configuration and maybe making use of the\nsudo credential cache by first invoking sudo, entering your password if\nneeded, and then invoking the test with:\n\n  $ GIT_TEST_ALLOW_SUDO=YES ./t0034-root-safe-directory.sh\n\nIf it fails to run, then it means your local setup wouldn't work for the\ntest and things that might help is to comment out sudo's secure_path config\nand make sure your account has similar privileges than what the CI\nprovides (for example an entry in /etc/sudoers for the user marta like)\n\n  marta\tALL=(ALL:ALL) NOPASSWD: ALL\n\nReported-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/t0034-root-safe-directory.sh | 45 ++++++++++++++++++++++++++++++++++\n 1 file changed, 45 insertions(+)\n create mode 100755 t/t0034-root-safe-directory.sh\n\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nnew file mode 100755\nindex 0000000000..2e4492a66d\n--- /dev/null\n+++ b/t/t0034-root-safe-directory.sh\n@@ -0,0 +1,45 @@\n+#!/bin/sh\n+\n+test_description='verify safe.directory checks while running as root'\n+\n+. ./test-lib.sh\n+\n+if [ \"$GIT_TEST_ALLOW_SUDO\" != \"YES\" ]\n+then\n+\tskip_all=\"You must set env var GIT_TEST_ALLOW_SUDO=YES in order to run this test\"\n+\ttest_done\n+fi\n+\n+test_lazy_prereq SUDO '\n+\tsudo -n id -u >u &&\n+\tid -u root >r &&\n+\ttest_cmp u r &&\n+\tcommand -v git >u &&\n+\tsudo command -v git >r &&\n+\ttest_cmp u r\n+'\n+\n+test_expect_success SUDO 'setup' '\n+\tsudo rm -rf root &&\n+\tmkdir -p root/r &&\n+\tsudo chown root root &&\n+\t(\n+\t\tcd root/r &&\n+\t\tgit init\n+\t)\n+'\n+\n+test_expect_failure SUDO 'sudo git status as original owner' '\n+\t(\n+\t\tcd root/r &&\n+\t\tgit status &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+# this MUST be always the last test\n+test_expect_success SUDO 'cleanup' '\n+\tsudo rm -rf root\n+'\n+\n+test_done\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"454974","messageId":"20220507163508.78459-3-carenas@gmail.com","threadId":"57799","inReplyTo":"20220507163508.78459-1-carenas@gmail.com","subject":"[RFC PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-07T16:35:07Z","receivedAt":"2022-05-07T16:35:48Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that user was\nroot (because git was invoked through sudo or a compatible tool) and the\noriginal uid that repository trusted for its config was no longer known,\ntherefore failing the following otherwise safe call:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nthose tools create to keep track of the original user id, and do the\nownership check using that instead.\n\nThis assumes the environment the user is running on after going\nprivileged can't be tampered with, and also adds code to restrict that\nthe new behavior only applies if running as root, therefore keeping the\nmost common case, which runs unprivileged, from changing, but because of\nthat, it will miss cases where sudo (or an equivalent) was used to change\nto another unprivileged user or where the equivalent tool used to raise\nprivileges didn't track the original id in a sudo compatible way.\n\nBecause of compatibility with sudo, the code assumes that uid_t is an\nunsigned integer type, but adds additional logic to protect itself\nagainst possibly malicious ids outside the expected range and ignore\nthem.\n\nA warning should be generated if uid_t is signed and the code would\nneed to be locally patched to work correctly, but this is also a\nweather balloon of sorts so we will then now which systems those are\nand whether we should accommodate for their portability in our codebase.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/config/safe.txt  | 10 +++++++\n git-compat-util.h              | 49 +++++++++++++++++++++++++++++++++-\n t/t0034-root-safe-directory.sh |  2 +-\n 3 files changed, 59 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex 6d764fe0cc..a6b81f6cfc 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -26,3 +26,13 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n is set in system config and you want to re-enable this protection, then\n initialize your list with an empty value before listing the repositories\n that you deem safe.\n++\n+When git tries to check for ownership of git repositories, it will\n+obviously do so with the uid of the user that is running git itself,\n+but if git is running as root, in a platform that provides sudo and is\n+not Windows, it will check first if it might have been started through\n+it, and if that is the case, will instead use the uid of the user that\n+did invoke that instead.\n+If that is not what you would prefer and want git to only trust\n+repositories that are owned by root instead, then you should remove\n+the `SUDO_UID` variable from root's environment.\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 63ba89dd31..409df99463 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -393,12 +393,59 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n+/*\n+ * this helper function overrides a ROOT_UID with the one provided by\n+ * an environment variable, do not use unless the original user is\n+ * root\n+ * WARNING: this function assumes uid_t is unsigned, if you got here\n+ *          because of a warning or a bug will need a patch and would\n+ *          be nice if you let us know\n+ */\n+static inline void extract_id_from_env(const char *env, uid_t *id)\n+{\n+\tconst char *real_uid = getenv(env);\n+\n+\t/* discard any empty values */\n+\tif (real_uid && *real_uid) {\n+\t\tchar *endptr = NULL;\n+\t\tunsigned long env_id;\n+\n+\t\terrno = 0;\n+\t\tenv_id = strtoul(real_uid, &endptr, 10);\n+\t\t/*\n+\t\t * env_id could underflow/overflow in the previous call\n+\t\t * and if it will still fit in a long it will not report\n+\t\t * it as error with ERANGE, instead silently using an\n+\t\t * equivalent positive number that might be bogus.\n+\t\t * if uid_t is narrower than long, it might not fit,\n+\t\t * hence why we  need to check it against the maximum\n+\t\t * possible uid_t value before accepting it.\n+\t\t */\n+\t\tif (!*endptr && !errno && env_id <= (uid_t)-1)\n+\t\t\t*id = env_id;\n+\t}\n+}\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID)\n+\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex 2e4492a66d..ecd9dca6b3 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -29,7 +29,7 @@ test_expect_success SUDO 'setup' '\n \t)\n '\n \n-test_expect_failure SUDO 'sudo git status as original owner' '\n+test_expect_success SUDO 'sudo git status as original owner' '\n \t(\n \t\tcd root/r &&\n \t\tgit status &&\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"454975","messageId":"20220507163508.78459-4-carenas@gmail.com","threadId":"57799","inReplyTo":"20220507163508.78459-1-carenas@gmail.com","subject":"[RFC PATCH v4 3/3] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-07T16:35:08Z","receivedAt":"2022-05-07T16:35:49Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Add a support library that provides one function that can be used\nto run a \"scriplet\" of commands through sudo and that helps invoking\nsudo in the slightly awkward way that is required to ensure it doesn't\nblock the call (if shell was allowed as tested in the prerequisite)\nand it doesn't run the command through a different shell than the one\nwe intended.\n\nAdd additional negative tests as suggested by Junio and that use a\nnew workspace that is owned by root.\n\nNote that the specific test that documents that after the previous\nchanges, it is no longer possible for root (if obtained through sudo)\nto NOT add an exception or need a \"workaround\" to be able to run git\ncommands in a repository owned by thyself, is marked as a regression\nand is expected to be fixed with a future change, which hasn't been\nprovided yet and that is not part of this series.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/lib-sudo.sh                  | 12 +++++++\n t/t0034-root-safe-directory.sh | 58 ++++++++++++++++++++++++++++++++++\n 2 files changed, 70 insertions(+)\n create mode 100644 t/lib-sudo.sh\n\ndiff --git a/t/lib-sudo.sh b/t/lib-sudo.sh\nnew file mode 100644\nindex 0000000000..d8a88fb9db\n--- /dev/null\n+++ b/t/lib-sudo.sh\n@@ -0,0 +1,12 @@\n+# Helpers for running git commands under sudo.\n+\n+# Runs a scriplet passed through stdin under sudo.\n+run_with_sudo () {\n+\tlocal ret\n+\tlocal RUN=\"$TEST_DIRECTORY/$$.sh\"\n+\twrite_script \"$RUN\" \"$TEST_SHELL_PATH\"\n+\tsudo \"$TEST_SHELL_PATH\" -c \"\\\"$RUN\\\"\"\n+\tret=$?\n+\trm -f \"$RUN\"\n+\treturn $ret\n+}\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex ecd9dca6b3..5bc416ab81 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -3,6 +3,7 @@\n test_description='verify safe.directory checks while running as root'\n \n . ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-sudo.sh\n \n if [ \"$GIT_TEST_ALLOW_SUDO\" != \"YES\" ]\n then\n@@ -10,6 +11,12 @@ then\n \ttest_done\n fi\n \n+if ! test_have_prereq NOT_ROOT\n+then\n+\tskip_all=\"These tests do not support running as root\"\n+\ttest_done\n+fi\n+\n test_lazy_prereq SUDO '\n \tsudo -n id -u >u &&\n \tid -u root >r &&\n@@ -19,6 +26,12 @@ test_lazy_prereq SUDO '\n \ttest_cmp u r\n '\n \n+if ! test_have_prereq SUDO\n+then\n+\tskip_all=\"Your sudo/system configuration is either too strict or unsupported\"\n+\ttest_done\n+fi\n+\n test_expect_success SUDO 'setup' '\n \tsudo rm -rf root &&\n \tmkdir -p root/r &&\n@@ -37,6 +50,51 @@ test_expect_success SUDO 'sudo git status as original owner' '\n \t)\n '\n \n+test_expect_success SUDO 'setup root owned repository' '\n+\tsudo mkdir -p root/p &&\n+\tsudo git init root/p\n+'\n+\n+test_expect_success 'cannot access if owned by root' '\n+\t(\n+\t\tcd root/p &&\n+\t\ttest_must_fail git status\n+\t)\n+'\n+\n+test_expect_failure SUDO 'can access with sudo if root' '\n+\t(\n+\t\tcd root/p &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'can access with sudo using a workaround' '\n+\t# run sudo twice; would fail is root is not in the sudoers\n+\t(\n+\t\tcd root/p &&\n+\t\tsudo sudo git status\n+\t) &&\n+\t# provide explicit GIT_DIR\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tGIT_DIR=.git &&\n+\t\t\tGIT_WORK_TREE=. &&\n+\t\t\texport GIT_DIR GIT_WORK_TREE &&\n+\t\t\tgit status\n+\t\tEND\n+\t) &&\n+\t# discard SUDO_UID\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tunset SUDO_UID &&\n+\t\t\tgit status\n+\t\tEND\n+\t)\n+'\n+\n # this MUST be always the last test\n test_expect_success SUDO 'cleanup' '\n \tsudo rm -rf root\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"454976","messageId":"xmqqv8uhgsaz.fsf@gitster.g","threadId":"57799","inReplyTo":"20220507163508.78459-3-carenas@gmail.com","subject":"Re: [RFC PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-07T17:34:44Z","receivedAt":"2022-05-07T17:35:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> +\t\t/*\n> +\t\t * env_id could underflow/overflow in the previous call\n> +\t\t * and if it will still fit in a long it will not report\n> +\t\t * it as error with ERANGE, instead silently using an\n> +\t\t * equivalent positive number that might be bogus.\n> +\t\t * if uid_t is narrower than long, it might not fit,\n> +\t\t * hence why we  need to check it against the maximum\n> +\t\t * possible uid_t value before accepting it.\n> +\t\t */\n> +\t\tif (!*endptr && !errno && env_id <= (uid_t)-1)\n> +\t\t\t*id = env_id;\n\nThanks for very clearly spelling out why you care.  It makes it much\neasier to explain why I disagree with the line of reasoning ;-)\n\nThis code may be exercised by a potential attacker, but we know that\nthe codepath is entered only when euid==ROOT_UID.  The attacker may\nor may not have used 'sudo', and we cannot trust the value of\nSUDO_UID at all.  But that is OK.  If the attacker already is root\non the box, they do not have to use \"git\" or exercise this new code\nin order to attack anybody on the box already.  This requires us to\nexclude social engineering attack to tell a victim to run \"sudo\",\nset SUDO_UID to a specific value, and run something, but at last I\nhave been excluding that from the beginning.  There are easier\nthings you can tell the potential victim to cause harm while being\nroot.\n\nNow the whole point of adding this new code to _weaken_ the existing\ncheck is to help legitimate users who are authorised to become root\nvia \"sudo\" on the box.  Making it easier for them to use \"git\" while\ntentatively gaining root priviledge so that they can do \"make\ninstall\" in a repository they own.\n\nWe know that this code is meant to be exercised after a potential\nvictim gained euid==ROOT_UID via 'sudo', and SUDO_UID is exported by\nthe command for the original user.  If uid_t is narrower than ulong\n(e.g. 16-bit uid_t vs 64-bit ulong), and if it is unsigned, the only\neffect the extra check is doing is to exclude the unfortunate user\nwith uid==65535 from using \"sudo git describe\".\n\nIn exchange, the only attack scenario the code prevents is this,\nIIUC.\n\n * You, the aspiring cracker, are a user not allowed to run \"sudo\" on\n   the box, and you know your uid is 1000\n\n * You look for another user, a potential victim, whose uid is 1000\n   modulo 65536 (if your uid_t is 16-bit) and who can run \"sudo\" on\n   the box.\n\n * You prepare a malicious repository, invite that user there and\n   ask them to run \"sudo something\" there.\n\nI'd say such an attack vector is not likely, and a user with maximum\nallowed uid_t value is equally not that likely, so I do not care too\ndeeply either way---and in such a case, I do prefer a simpler code.\n"},{"id":"454982","messageId":"20220507185624.k5n6xihvzcuuj3vt@carlos-mbp.lan","threadId":"57799","inReplyTo":"xmqqv8uhgsaz.fsf@gitster.g","subject":"Re: [RFC PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-07T18:56:24Z","receivedAt":"2022-05-07T18:56:30Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Sat, May 07, 2022 at 10:34:44AM -0700, Junio C Hamano wrote:\n> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n> \n> > +\t\t/*\n> > +\t\t * env_id could underflow/overflow in the previous call\n> > +\t\t * and if it will still fit in a long it will not report\n> > +\t\t * it as error with ERANGE, instead silently using an\n> > +\t\t * equivalent positive number that might be bogus.\n> > +\t\t * if uid_t is narrower than long, it might not fit,\n> > +\t\t * hence why we  need to check it against the maximum\n> > +\t\t * possible uid_t value before accepting it.\n> > +\t\t */\n> > +\t\tif (!*endptr && !errno && env_id <= (uid_t)-1)\n> > +\t\t\t*id = env_id;\n> \n> Thanks for very clearly spelling out why you care.  It makes it much\n> easier to explain why I disagree with the line of reasoning ;-)\n\nFunny enough the comment doesn't even scratch the surface on the genius\nof that (uid_t)-1 and how it also prevents people with a signed uid_t\nto misuse this code as well, while still allowing uid_t > INT_MAX.\n\nAs mentioned in the cover letter, the code without this is indeed broken\nand unsafe to use in that case, so we will need to do something else (as\nspelled there as well), I we were to proceed with it, which as I said\nbefore I am totally OK with (granted we do that something else, and\npromess not to misuse this somewhere later and open us to a potentially\nembarrasing bug.\n\n> This code may be exercised by a potential attacker, but we know that\n> the codepath is entered only when euid==ROOT_UID.  The attacker may\n> or may not have used 'sudo', and we cannot trust the value of\n> SUDO_UID at all.  But that is OK.  If the attacker already is root\n> on the box, they do not have to use \"git\" or exercise this new code\n> in order to attack anybody on the box already.  This requires us to\n> exclude social engineering attack to tell a victim to run \"sudo\",\n> set SUDO_UID to a specific value, and run something, but at last I\n> have been excluding that from the beginning.  There are easier\n> things you can tell the potential victim to cause harm while being\n> root.\n\nAgree, but even if I put a scary looking warning and tried to make this\ncode harder to use than it needs to be, is fairly visible and there had\nbeen already suggestions of removing that restriction.\n\nWhich is why I said this is more a defensive programming solution than\nreal protection under the current constrains.\n\n> Now the whole point of adding this new code to _weaken_ the existing\n> check is to help legitimate users who are authorised to become root\n> via \"sudo\" on the box.  Making it easier for them to use \"git\" while\n> tentatively gaining root priviledge so that they can do \"make\n> install\" in a repository they own.\n> \n> We know that this code is meant to be exercised after a potential\n> victim gained euid==ROOT_UID via 'sudo', and SUDO_UID is exported by\n> the command for the original user.  If uid_t is narrower than ulong\n> (e.g. 16-bit uid_t vs 64-bit ulong), and if it is unsigned, the only\n> effect the extra check is doing is to exclude the unfortunate user\n> with uid==65535 from using \"sudo git describe\".\n\nnot quite, the check does \"<=\" so excludes no legitimate users, what\nis excludes is bit multiplers of those valid users ids to work, so\nif an obviously impossible to get legitimately and therefore bogus if\nuid_t is 16bit value of 65536 even gets here we will not assume it was\nroot instead, which I would find personally embarrasing.\n\n> In exchange, the only attack scenario the code prevents is this,\n> IIUC.\n> \n>  * You, the aspiring cracker, are a user not allowed to run \"sudo\" on\n>    the box, and you know your uid is 1000\n> \n>  * You look for another user, a potential victim, whose uid is 1000\n>    modulo 65536 (if your uid_t is 16-bit) and who can run \"sudo\" on\n>    the box.\n> \n>  * You prepare a malicious repository, invite that user there and\n>    ask them to run \"sudo something\" there.\n> \n> I'd say such an attack vector is not likely, and a user with maximum\n> allowed uid_t value is equally not that likely, so I do not care too\n> deeply either way---and in such a case, I do prefer a simpler code.\n\nas I do as well, but this is only 4 characters long and getting rid of\nit means we now have to do either of :\n\n  * hope nobody has a signed uid_t as this code is broken in that case\n    and will misbehave widly, more importantly we also lost our only\n    way to find them and warn them ahead of time that they need to patch\n    it.\n  * add some aditional way to detect it and avoid this code and maybe\n    even provide an alternative.\n\nand also :\n\n  * move back to strtol and potentially break the feature for half the\n    valid users if uid_t is 32-bit unsigned as it is most likely to be\n    in 32-bit systems.\n  * move to an even wider integer so it will be always wider than uid_t\n    which means we have to move a lot more code around at least.\n\nCarlo\n"},{"id":"454993","messageId":"4314bf6d-d76c-bc5b-a7f9-e59c7c181c7c@gmail.com","threadId":"57799","inReplyTo":"xmqqlevfesnu.fsf@gitster.g","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-09T08:21:25Z","receivedAt":"2022-05-09T08:53:20Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Junio\n\nOn 05/05/2022 19:33, Junio C Hamano wrote:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n>> Hmm. I would like to suggest that we can side-step all of these issues\n>> (and the ones I outline below) by considering a similar approach to the\n>> one Stolee took in t0033: use one or more `GIT_TEST_*` environment\n>> variables to pretend the exact scenario we want to test for.\n> \n> I like the GIT_TEST_ASSUME_DIFFERENT_OWNER because it is fairly\n> clear that it cannot be used as a new attack vector, even with\n> social engineering.\n> \n> It would be nice if we can do something similar, but I am coming up\n> empty while trying to think of \"we are testing; pretend that ...\"\n> that is good for testing this SUDO_UID special case *and* clearly\n> cannot be used as an attack target.\n> \n> So I very much like the suggestion in principle, but I am not sure\n> how useful the suggestion would be to make the resulting code better\n> in practice.\n> \n> Perhaps this may be a way to pretend we are running a command under\n> 'sudo'?\n> \n> \ttest_pretend_sudo () {\t\n>              GIT_TEST_PRETEND_GETEUID_RETURNING_ROOT=1 \\\n> \t    GIT_TEST_PRETEND_LSTAT_RETURNING_ROOT=root/p \\\n>                  SUDO_UID=0 \"$@\"\n> \t}\n> \n> \ttest_expect_success 'access root-owned repository as root' '\n> \t\tmkdir root/p &&\n> \t\tgit init root/p &&\n> \t\ttest_pretend_sudo git status\n> \t'\n> \n> That way we can avoid having to run \"chown\" while preparing for the\n> test fixture, and running \"git status\" under root, but I am not sure\n> if we want our shipped production binaries to have these \"pretend\"\n> knobs.\n\nLets ask ourselves \"How could an attacker use these knobs to facilitate \nan attack?\". They need to either (a) set these variables in the user's \nenvironment themselves or (b) persuade the user to set them. For (a) if \nan attacker can set them in the user's environment then they can change \nthe user's $PATH or $GIT_DIR and $GIT_WORK_TREE so this does not open up \na new way to compromise the user. For (b) I'm not sure it is easier to \nsocially engineer the user to set these new variables rather than \nGIT_DIR and GIT_WORK_TREE which will also bypass the check.\n\nBest Wishes\n\nPhillip\n\n\n> Thanks.\n"},{"id":"455003","messageId":"CAPUEspiX4FJc4-1DGCek1iWMYL7M7Xir9PSXbFAwQy7xTFKxYg@mail.gmail.com","threadId":"57799","inReplyTo":"4314bf6d-d76c-bc5b-a7f9-e59c7c181c7c@gmail.com","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-09T14:51:36Z","receivedAt":"2022-05-09T14:51:55Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Mon, May 9, 2022 at 1:21 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> On 05/05/2022 19:33, Junio C Hamano wrote:\n> > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >\n> >> Hmm. I would like to suggest that we can side-step all of these issues\n> >> (and the ones I outline below) by considering a similar approach to the\n> >> one Stolee took in t0033: use one or more `GIT_TEST_*` environment\n> >> variables to pretend the exact scenario we want to test for.\n> >\n> > Perhaps this may be a way to pretend we are running a command under\n> > 'sudo'?\n> >\n> >       test_pretend_sudo () {\n> >              GIT_TEST_PRETEND_GETEUID_RETURNING_ROOT=1 \\\n> >           GIT_TEST_PRETEND_LSTAT_RETURNING_ROOT=root/p \\\n> >                  SUDO_UID=0 \"$@\"\n> >       }\n> >\n> >       test_expect_success 'access root-owned repository as root' '\n> >               mkdir root/p &&\n> >               git init root/p &&\n> >               test_pretend_sudo git status\n> >       '\n> >\n> > That way we can avoid having to run \"chown\" while preparing for the\n> > test fixture, and running \"git status\" under root, but I am not sure\n> > if we want our shipped production binaries to have these \"pretend\"\n> > knobs.\n>\n> Lets ask ourselves \"How could an attacker use these knobs to facilitate\n> an attack?\".\n\nThat is not the question raised by having those \"pretend\" knobs in the\nproduction binary, but instead how can an attacker abuse them to get\nthemself and UID he doesn't have and therefore additional access.\n\nThe fact that the current code requires you to be root to even enable\nthe logic makes it more difficult to use SUDO_UID that way, because if\nyou already got root, you don't really need them, but take into\nconsideration that this discussion starts with (how can we run these\nthings as a the test user and avoid sudo, hence root).\n\nCarlo\n"},{"id":"455005","messageId":"8b7e0af4-7b6b-8891-edc1-81d6b0f3b412@gmail.com","threadId":"57799","inReplyTo":"CAPUEspiX4FJc4-1DGCek1iWMYL7M7Xir9PSXbFAwQy7xTFKxYg@mail.gmail.com","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-09T15:18:37Z","receivedAt":"2022-05-09T15:18:48Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Carlo\n\nOn 09/05/2022 15:51, Carlo Arenas wrote:\n> On Mon, May 9, 2022 at 1:21 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>> On 05/05/2022 19:33, Junio C Hamano wrote:\n>>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>>>\n>>>> Hmm. I would like to suggest that we can side-step all of these issues\n>>>> (and the ones I outline below) by considering a similar approach to the\n>>>> one Stolee took in t0033: use one or more `GIT_TEST_*` environment\n>>>> variables to pretend the exact scenario we want to test for.\n>>>\n>>> Perhaps this may be a way to pretend we are running a command under\n>>> 'sudo'?\n>>>\n>>>        test_pretend_sudo () {\n>>>               GIT_TEST_PRETEND_GETEUID_RETURNING_ROOT=1 \\\n>>>            GIT_TEST_PRETEND_LSTAT_RETURNING_ROOT=root/p \\\n>>>                   SUDO_UID=0 \"$@\"\n>>>        }\n>>>\n>>>        test_expect_success 'access root-owned repository as root' '\n>>>                mkdir root/p &&\n>>>                git init root/p &&\n>>>                test_pretend_sudo git status\n>>>        '\n>>>\n>>> That way we can avoid having to run \"chown\" while preparing for the\n>>> test fixture, and running \"git status\" under root, but I am not sure\n>>> if we want our shipped production binaries to have these \"pretend\"\n>>> knobs.\n>>\n>> Lets ask ourselves \"How could an attacker use these knobs to facilitate\n>> an attack?\".\n> \n> That is not the question raised by having those \"pretend\" knobs in the\n> production binary, but instead how can an attacker abuse them to get\n> themself and UID he doesn't have and therefore additional access.\n\nMaybe I'm missing something but I thought the idea was that these knobs \nwere only for the safe.directory check and the normal file permissions \nwould apply to all the other code.\n\nBest Wishes\n\nPhillip\n\n> The fact that the current code requires you to be root to even enable\n> the logic makes it more difficult to use SUDO_UID that way, because if\n> you already got root, you don't really need them, but take into\n> consideration that this discussion starts with (how can we run these\n> things as a the test user and avoid sudo, hence root).\n> \n> Carlo\n"},{"id":"455016","messageId":"xmqq35hig0fr.fsf@gitster.g","threadId":"57799","inReplyTo":"4314bf6d-d76c-bc5b-a7f9-e59c7c181c7c@gmail.com","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-09T16:01:12Z","receivedAt":"2022-05-09T16:01:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n>> That way we can avoid having to run \"chown\" while preparing for the\n>> test fixture, and running \"git status\" under root, but I am not sure\n>> if we want our shipped production binaries to have these \"pretend\"\n>> knobs.\n>\n> Lets ask ourselves \"How could an attacker use these knobs to\n> facilitate an attack?\". They need to either (a) set these variables in\n> the user's environment themselves or (b) persuade the user to set\n> them.\n\nI actually was not worried about the scenario where an attacker\nfools potential victims, who are more privileged than the attacker,\ninto doing stupid things to hurt themselves.  I mentioned that the\nexisting knob for testing, \"pretend that euid and st_uid are\ndifferent\", because it tightens the check (even if you are trying\nthe code with your own directory, euid==st.st_uid check would not\ngive you an access and you are forced to rely on the safe.directory\ncofniguration allowing you in), not loosens it, and it felt much\nless risky than \"pretend we are root\" or \"pretend the directory is\nowned by root\", which just felt much riskier things to allow people\nto have us pretend.\n\nBut I was totally wrong ;-)  No matter what a unprivileged attacker\ndoes with these knobs, the actual access will be done by a process\nrun by the attacker, and the actual security at the filesystem level\nstill kicks in to prevent the attacker from doing anything that the\nattacker cannot normally do.  So the only qualm about the proliferation\nof these GIT_TEST_* environment variable checks in the production code\nis that it makes the logic ugly with more code.\n\nThanks.\n\n"},{"id":"455018","messageId":"CAPUEspj-74PQwWNXnd0PgQ1NYyvvaqdoZ6ki7=2Q0NOcrZGFwg@mail.gmail.com","threadId":"57799","inReplyTo":"xmqq35hig0fr.fsf@gitster.g","subject":"Re: [PATCH v3 1/3] t: document regression git safe.directory when using sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-09T16:21:08Z","receivedAt":"2022-05-09T16:21:28Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Mon, May 9, 2022 at 9:01 AM Junio C Hamano <gitster@pobox.com> wrote:\n\n> But I was totally wrong ;-)  No matter what a unprivileged attacker\n> does with these knobs, the actual access will be done by a process\n> run by the attacker, and the actual security at the filesystem level\n> still kicks in to prevent the attacker from doing anything that the\n> attacker cannot normally do.\n\nWhile I agree with you in principle, wouldn't this approach (while far\nmore flexible) also be more risky?\n\nLet's imagine a scenario where we enhance SUDO_UID (because it\nactually makes sense to do so now since it's probably better to run\nhooks as a non privileged user by default instead of root). At that\npoint all an attacker needs to do to escalate to root is to set its\nown SUDO_UID=0 and whatever else we put in the production binary for\nhim to use.  At least by restricting this overriding functionality to\na real root user (as done in the proposal) we could make that attack\nvector less likely.\n\nAfter all, I am sure that when (I know it is not fair, because it is\nnot the only way to do so) core.fsmonitor was invented as a useful way\nto run things in a repository, nobody expected it could be weaponized\nlater into a privilege escalation, and feels like doing the same here\nmight show we have not learned that lesson.\n\nEitherway RFC v4 is out and waiting for feedback, and I even have an\nenhanced (with even more comments and hopefully even better commit\nmessages) in which every single message has gone through a free\ngrammar checker[1] which I am planning to publish as v4 proper\nsometime this week.\n\nCarlo\n\n[1] https://www.gingersoftware.com/grammarcheck\n"},{"id":"455024","messageId":"xmqq1qx2ejdv.fsf@gitster.g","threadId":"57799","inReplyTo":"20220507185624.k5n6xihvzcuuj3vt@carlos-mbp.lan","subject":"Re: [RFC PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-09T16:54:52Z","receivedAt":"2022-05-09T16:55:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón <carenas@gmail.com> writes:\n\n>> In exchange, the only attack scenario the code prevents is this,\n>> IIUC.\n>> \n>>  * You, the aspiring cracker, are a user not allowed to run \"sudo\" on\n>>    the box, and you know your uid is 1000\n>> \n>>  * You look for another user, a potential victim, whose uid is 1000\n>>    modulo 65536 (if your uid_t is 16-bit) and who can run \"sudo\" on\n>>    the box.\n>> \n>>  * You prepare a malicious repository, invite that user there and\n>>    ask them to run \"sudo something\" there.\n>> \n>> I'd say such an attack vector is not likely,...\n\nSorry, I was totally wrong here.\n\nIt is not just \"not likely\", but such an attack, with a potential\nvictim not futzing with SUDO_UID environment themselves, would not\nwork at all.  The value of SUDO_UID and the original uid of the\npotential victim by definition should fit in the uid_t type.  So if\nyou, the aspiring cracker, have UID 1000, nobody else on the system\nhas UID that is congruent modulo uid_t and wrap-around attack does\nnot exist.  As long as the type we use to read SUDO_UID string into\na variable is not narrower than uid_t, there.\n\nOf course you can tell any user who runs \"sudo\" to set SUDO_UID to\n1000 + 64k and cause wrap-around, but then you can tell them to set\nSUDO_UID to 1000 without relying on wrap-around and have the same\neffect.  So, let's stop worrying about this bogus scenario.\n\nAs to the \"we can break compilation with -Wsign-compare on a system\nwith signed uid_t\", I agree that is true if we have\n\n\tenv_id <= (uid_t) -1\n\nthere.  But I am not sure if that is the most effective way to smoke\nout platforms where this code has trouble working correctly.  Also,\nI would think that a system with signed uid_t is a possibility, but\na user with a negative UID?\n\nI do not think even nobody4 was negative ;-)\n"},{"id":"455028","messageId":"036501d863cb$51776640$f46632c0$@nexbridge.com","threadId":"57799","inReplyTo":"xmqq1qx2ejdv.fsf@gitster.g","subject":"RE: [RFC PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-05-09T17:36:24Z","receivedAt":"2022-05-09T17:36:34Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On May 9, 2022 12:55 PM, Junio C Hamano wrote:\n>Carlo Marcelo Arenas Belón <carenas@gmail.com> writes:\n>\n>>> In exchange, the only attack scenario the code prevents is this,\n>>> IIUC.\n>>>\n>>>  * You, the aspiring cracker, are a user not allowed to run \"sudo\" on\n>>>    the box, and you know your uid is 1000\n>>>\n>>>  * You look for another user, a potential victim, whose uid is 1000\n>>>    modulo 65536 (if your uid_t is 16-bit) and who can run \"sudo\" on\n>>>    the box.\n>>>\n>>>  * You prepare a malicious repository, invite that user there and\n>>>    ask them to run \"sudo something\" there.\n>>>\n>>> I'd say such an attack vector is not likely,...\n>\n>Sorry, I was totally wrong here.\n>\n>It is not just \"not likely\", but such an attack, with a potential victim not futzing with\n>SUDO_UID environment themselves, would not work at all.  The value of\n>SUDO_UID and the original uid of the potential victim by definition should fit in the\n>uid_t type.  So if you, the aspiring cracker, have UID 1000, nobody else on the\n>system has UID that is congruent modulo uid_t and wrap-around attack does not\n>exist.  As long as the type we use to read SUDO_UID string into a variable is not\n>narrower than uid_t, there.\n>\n>Of course you can tell any user who runs \"sudo\" to set SUDO_UID to\n>1000 + 64k and cause wrap-around, but then you can tell them to set SUDO_UID to\n>1000 without relying on wrap-around and have the same effect.  So, let's stop\n>worrying about this bogus scenario.\n>\n>As to the \"we can break compilation with -Wsign-compare on a system with signed\n>uid_t\", I agree that is true if we have\n>\n>\tenv_id <= (uid_t) -1\n>\n>there.  But I am not sure if that is the most effective way to smoke out platforms\n>where this code has trouble working correctly.  Also, I would think that a system\n>with signed uid_t is a possibility, but a user with a negative UID?\n>\n>I do not think even nobody4 was negative ;-)\n\nI can test the code when it's ready.\n\n"},{"id":"455048","messageId":"CAPUEspidmqiUYd3xB4QaR72YU=H8pA-3yNXxOF_MWyA_0wrKcA@mail.gmail.com","threadId":"57799","inReplyTo":"xmqq1qx2ejdv.fsf@gitster.g","subject":"Re: [RFC PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-09T18:48:31Z","receivedAt":"2022-05-09T18:48:49Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Mon, May 9, 2022 at 9:54 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> It is not just \"not likely\", but such an attack, with a potential\n> victim not futzing with SUDO_UID environment themselves, would not\n> work at all.  The value of SUDO_UID and the original uid of the\n> potential victim by definition should fit in the uid_t type.  So if\n> you, the aspiring cracker, have UID 1000, nobody else on the system\n> has UID that is congruent modulo uid_t and wrap-around attack does\n> not exist.  As long as the type we use to read SUDO_UID string into\n> a variable is not narrower than uid_t, there.\n\ncorrect; would adding a less elegant \"static_assert\" (obviously not\navailable in C99) in the code an alternative?, or you are suggesting\nthat documenting that constrain should be done in a comment and hope\nit doesn't get ignored in the future, or maybe gets instead made less\nlikely to fail by some additional work, like the one I suggested to do\nlater by moving this code around and using intmax_t instead?\n\nnot that there are 2 different scenarios which we might seem to be\nflip flopping about :\n\n1) victim gets attacked by tricking them into using the wrong SUDO_UID\n\nunlikely to be useful as you pointed out, and totally useless if we\nstill restrict this code to run only as root\n\n2) attacker using this code to elevate privileges themselves\n\nonly useful if this code is not run as root.\n\nMy concern again, is not with this code AS-IS but how it might be used\nin the future.\n\n> Of course you can tell any user who runs \"sudo\" to set SUDO_UID to\n> 1000 + 64k and cause wrap-around, but then you can tell them to set\n> SUDO_UID to 1000 without relying on wrap-around and have the same\n> effect.  So, let's stop worrying about this bogus scenario.\n\nbogus only if we are still only running this code as root, of course.\n\n> As to the \"we can break compilation with -Wsign-compare on a system\n> with signed uid_t\", I agree that is true if we have\n\nApologies for not documenting it until now, but I had\n-Wtautological-constant-out-of-range-compare in mind instead, but your\nare correct either one would work and the point was that (without\nhaving to add even an \"static assert\") we were able to find them and\nwarn them that they need to patch.\n\n>         env_id <= (uid_t) -1\n\nIf that was not enough, that simple code ALSO disabled the code in\nthat case to make sure they MUST patch locally if they need to make it\nwork, or come back to us to figure out a portable way to accommodate\nthem in the future, with all the information about their system we\ncurrently lack.\n\n> there.  But I am not sure if that is the most effective way to smoke\n> out platforms where this code has trouble working correctly.  Also,\n> I would think that a system with signed uid_t is a possibility, but\n> a user with a negative UID?\n\nIt doesn't need to be a real user (specially if someone independently\ndecides to remove the restriction that keeps this code available only\nto root).\n\nThe fact that it was negative but was treated as a positive number on\nour code just makes the wraparound we decided to ignore before more\nlikely to work without triggering alarms somewhere else and because we\ndecided to ignore an unlikely to be useful positive wraparound, we\nalso would fall from the negative wraparound here that would had\nprotected this code from both if that humble line of code wouldn't had\nbeen removed.\n\nIn your hypothetical system where uid_t is 16-bit (hence 15-bit for\nvalid non-negative ids if uid_t is signed, since no sane system would\nhave negative ones), either 65536 or -65536 would become 0, as well as\nat least the other 2^16 possibilities that a larger long would\nprovide.\n\nIf the size difference is even smaller (ex: uid_t is signed int), so\nthe type we are using to parse those values is only 1 bit wider it\nwill still be a concern IMHO.\n\nI know people that wrote code to check if \"/\" was writable as means to\nmake sure they were \"root\", because that is what any sane system would\ndo, and then came Windows and even in 2022 anyone can write to \"/\"\nthere and create subdirectories.\n\nCarlo\n"},{"id":"455049","messageId":"036901d863d9$3fb32df0$bf1989d0$@nexbridge.com","threadId":"57799","inReplyTo":"CAPUEspidmqiUYd3xB4QaR72YU=H8pA-3yNXxOF_MWyA_0wrKcA@mail.gmail.com","subject":"RE: [RFC PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2022-05-09T19:16:06Z","receivedAt":"2022-05-09T19:16:24Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On May 9, 2022 2:49 PM, Carlo Arenas wrote:\n>On Mon, May 9, 2022 at 9:54 AM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> It is not just \"not likely\", but such an attack, with a potential\n>> victim not futzing with SUDO_UID environment themselves, would not\n>> work at all.  The value of SUDO_UID and the original uid of the\n>> potential victim by definition should fit in the uid_t type.  So if\n>> you, the aspiring cracker, have UID 1000, nobody else on the system\n>> has UID that is congruent modulo uid_t and wrap-around attack does not\n>> exist.  As long as the type we use to read SUDO_UID string into a\n>> variable is not narrower than uid_t, there.\n>\n>correct; would adding a less elegant \"static_assert\" (obviously not available in C99)\n>in the code an alternative?, or you are suggesting that documenting that constrain\n>should be done in a comment and hope it doesn't get ignored in the future, or\n>maybe gets instead made less likely to fail by some additional work, like the one I\n>suggested to do later by moving this code around and using intmax_t instead?\n>\n>not that there are 2 different scenarios which we might seem to be flip flopping\n>about :\n>\n>1) victim gets attacked by tricking them into using the wrong SUDO_UID\n>\n>unlikely to be useful as you pointed out, and totally useless if we still restrict this\n>code to run only as root\n>\n>2) attacker using this code to elevate privileges themselves\n>\n>only useful if this code is not run as root.\n>\n>My concern again, is not with this code AS-IS but how it might be used in the\n>future.\n>\n>> Of course you can tell any user who runs \"sudo\" to set SUDO_UID to\n>> 1000 + 64k and cause wrap-around, but then you can tell them to set\n>> SUDO_UID to 1000 without relying on wrap-around and have the same\n>> effect.  So, let's stop worrying about this bogus scenario.\n>\n>bogus only if we are still only running this code as root, of course.\n>\n>> As to the \"we can break compilation with -Wsign-compare on a system\n>> with signed uid_t\", I agree that is true if we have\n>\n>Apologies for not documenting it until now, but I had -Wtautological-constant-out-\n>of-range-compare in mind instead, but your are correct either one would work\n>and the point was that (without having to add even an \"static assert\") we were\n>able to find them and warn them that they need to patch.\n>\n>>         env_id <= (uid_t) -1\n>\n>If that was not enough, that simple code ALSO disabled the code in that case to\n>make sure they MUST patch locally if they need to make it work, or come back to\n>us to figure out a portable way to accommodate them in the future, with all the\n>information about their system we currently lack.\n>\n>> there.  But I am not sure if that is the most effective way to smoke\n>> out platforms where this code has trouble working correctly.  Also, I\n>> would think that a system with signed uid_t is a possibility, but a\n>> user with a negative UID?\n>\n>It doesn't need to be a real user (specially if someone independently decides to\n>remove the restriction that keeps this code available only to root).\n>\n>The fact that it was negative but was treated as a positive number on our code just\n>makes the wraparound we decided to ignore before more likely to work without\n>triggering alarms somewhere else and because we decided to ignore an unlikely to\n>be useful positive wraparound, we also would fall from the negative wraparound\n>here that would had protected this code from both if that humble line of code\n>wouldn't had been removed.\n>\n>In your hypothetical system where uid_t is 16-bit (hence 15-bit for valid non-\n>negative ids if uid_t is signed, since no sane system would have negative ones),\n>either 65536 or -65536 would become 0, as well as at least the other 2^16\n>possibilities that a larger long would provide.\n>\n>If the size difference is even smaller (ex: uid_t is signed int), so the type we are\n>using to parse those values is only 1 bit wider it will still be a concern IMHO.\n\nJust to be pedantic uid_t is signed int is not always smaller. It is 32-bit on NonStop. uid_t signed short or signed char would be smaller. I have wondered why uid_t was not defined as unsigned int or unsigned long (although unsigned long is 64 bits on the x86 wide model NonStop) because they cannot be negative. Making assumptions about size or sign when doing this check is not correct IMHO. It should be a direct comparison of env_id != ROOT_UID, where you know what ROOT_UID is on the specific platform. I do not like the <= concept for user id comparison because it is making assumptions. Structurally, on NonStop, (uid & 0x0000FF00) == 0x0000FF00 can be used to check whether the user is in the root group but that is coincidental and subject to change without notice. No one worth their salt does that comparison on platform, rather they compare getgid() == 255 to do that test.\n\n>\n>I know people that wrote code to check if \"/\" was writable as means to make sure\n>they were \"root\", because that is what any sane system would do, and then came\n>Windows and even in 2022 anyone can write to \"/\"\n>there and create subdirectories.\n\nOn NonStop: / is often writable by non-root users in the root group. Non-root users in the root group sometimes have repositories. In cygwin, / is owned by the user who installed cygwin or the OS rather than root. It is a relatively random number, and definitely not 0. It is also possible that a dedicated VM in Linux can be spun up for sandbox testing allowing anyone to write anywhere. Even if you run git as Administrator on Windows 10+, it will not have the userId of 0 in cygwin git. I do not think the / writable assumption is portable.\n\n"},{"id":"455051","messageId":"xmqq7d6ucx4c.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspidmqiUYd3xB4QaR72YU=H8pA-3yNXxOF_MWyA_0wrKcA@mail.gmail.com","subject":"Re: [RFC PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-09T19:41:07Z","receivedAt":"2022-05-09T19:41:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> not that there are 2 different scenarios which we might seem to be\n> flip flopping about :\n>\n> 1) victim gets attacked by tricking them into using the wrong SUDO_UID\n>\n> unlikely to be useful as you pointed out, and totally useless if we\n> still restrict this code to run only as root\n\nI think we established that we are not interested in this long ago.\n\n> 2) attacker using this code to elevate privileges themselves\n>\n> only useful if this code is not run as root.\n\nAn attacker who is not root would not make the \"what does SUDO_UID\nsay about the user we came from?\", and \"git\" will not be setuid\nbinary, so I agree the code is not useful for such an attack,\neither.\n\n> My concern again, is not with this code AS-IS but how it might be used\n> in the future.\n\n\nI'd rather not such a \"concern\" to block us for too long.\n\n\n>> Of course you can tell any user who runs \"sudo\" to set SUDO_UID to\n>> 1000 + 64k and cause wrap-around, but then you can tell them to set\n>> SUDO_UID to 1000 without relying on wrap-around and have the same\n>> effect.  So, let's stop worrying about this bogus scenario.\n>\n> bogus only if we are still only running this code as root, of course.\n\nAnd this code is only run to learn what SUDO_UID says, which is what\nwe check when we notice geteuid() says we are root.\n\n>> As to the \"we can break compilation with -Wsign-compare on a system\n>> with signed uid_t\", I agree that is true if we have\n>\n> Apologies for not documenting it until now, but I had\n> -Wtautological-constant-out-of-range-compare in mind instead, but your\n> are correct either one would work and the point was that (without\n> having to add even an \"static assert\") we were able to find them and\n> warn them that they need to patch.\n>\n>>         env_id <= (uid_t) -1\n>\n> If that was not enough, that simple code ALSO disabled the code in\n> that case to make sure they MUST patch locally if they need to make it\n> work, or come back to us to figure out a portable way to accommodate\n> them in the future, with all the information about their system we\n> currently lack.\n\nWithout a comment to say that, nobody would be able to figure out\nthat we are waiting for them to speak up.\n\n\t/* the code does not work on a system with signed uid */\n\tintmax_t tmp = (uid_t) -1;\n\tif (tmp < 0)\n\t\tBUG(\"report to git@vger that you have a signed uid_t\");\n\nor better yet, a compile-time equivalent, perhaps.\n\n>> there.  But I am not sure if that is the most effective way to smoke\n>> out platforms where this code has trouble working correctly.  Also,\n>> I would think that a system with signed uid_t is a possibility, but\n>> a user with a negative UID?\n>\n> It doesn't need to be a real user (specially if someone independently\n> decides to remove the restriction that keeps this code available only\n> to root).\n\nWhen they break, they can keep both halves.  Is it our concern?\n"},{"id":"455082","messageId":"a6094881-7e63-7dc6-2fc1-7e5573cfe55b@gmail.com","threadId":"57799","inReplyTo":"20220507163508.78459-1-carenas@gmail.com","subject":"Re: [RFC PATCH v4 0/3] fix `sudo make install` regression in maint","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-05-10T14:17:15Z","receivedAt":"2022-05-10T14:53:28Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Carlo\n\nOn 07/05/2022 17:35, Carlo Marcelo Arenas Belón wrote:\n> A reroll for cb/path-owner-check-with-sudo with most of the suggestions\n> included but planned originally as an RFC, because I am frankly not sure\n> that I read and addressed all of it, but also because after seeing how\n> my only chance to get an official Reviewed-by: Junio vanished I also\n> realized that I wasn't been clear enough and careful enough from the\n> beginning to explain the code correctly and therefore had maybe wasted\n> more of the review quota this change should require.\n> \n> Important changes (eventhough most are not affecting the logic)\n> * Document hopefully better which environments are supported and what\n>    to do if you want to test it in one that is not (thanks to dscho)\n> * Removed the arguably premature optimization to try to keep the sudo\n>    cache warm which was actually buggy, as it was also not needed.\n>    The CI does passwordless sudo unconditionally and even when running\n>    it locally it will go so fast that is shouldn't be an issue (thanks\n>    to Philip)\n> * No longer using the ugly and controversial variable name so now it\n>    will need GIT_TEST_ENABLE_SUDO to be used to enable it on CI (which\n>    is not done in this series, but a run with it enabled on top of\n>    seen is available[1])\n> * Stop the arguing about what is or not a regression worth fixing and\n>    instead document it as one through a test, which would be easy to\n>    fix in a follow up since the code was already provided by Junio\n\nI've had a read of the patches and I agree with Junio's comments on the \nsecond patch. I'd really like us to avoid sudo in the tests if we can as \nit causes a lot of problems. Just to let you know I'm going to be off \nthe list for the next couple of weeks, so I wont be looking at these \npatches in that time.\n\nBest Wishes\n\nPhillip\n\n> Lastly I am little concerned by the fact this is going to maint but\n> has a \"weather balloon\" of sorts, which might not be wise, since it\n> might prevent people that might be affected from upgrading if they\n> have a -Werror policy.\n> \n> The effect is minor though, as worst case, if someone has a system\n> with a signed uid_t then this \"feature\" wouldn't work for them and\n> nothing has changed but I think it is worth to consider the alternatives\n> which are (in my own order of preference)\n> \n> * Revert the change to use unsigned long and strtoul()\n> \n>    This will mean that people running in a 32bit system with an uid bigger\n>    than INT_MAX wouldn't be able to use the feature\n> \n> * Move the code out (which is indeed an artificial restriction) so that\n>    we can use intmax_t and strtoimax() instead and a cast to compare the\n>    uid_t.\n> \n>    This avoids all issues and restrictions but means more code changes\n> \n> * Throw away the custom function and expand the API ones to be used\n>    instead as dscho suggested.\n> \n>    Even more code changes, but maybe less risk as we will be building\n>    on top of battle tested code.\n> \n> [1] https://github.com/carenas/git/actions/runs/2286452160\n> \n> Carlo Marcelo Arenas Belón (3):\n>    t: regression git needs safe.directory when using sudo\n>    git-compat-util: avoid failing dir ownership checks if running\n>      privileged\n>    t0034: add negative tests and allow git init to mostly work under sudo\n> \n>   Documentation/config/safe.txt  |  10 ++++\n>   git-compat-util.h              |  49 +++++++++++++++-\n>   t/lib-sudo.sh                  |  12 ++++\n>   t/t0034-root-safe-directory.sh | 103 +++++++++++++++++++++++++++++++++\n>   4 files changed, 173 insertions(+), 1 deletion(-)\n>   create mode 100644 t/lib-sudo.sh\n>   create mode 100755 t/t0034-root-safe-directory.sh\n> \n"},{"id":"455083","messageId":"CAPUEspitjykLSvSwDU7VAQm15Q+J1jPH9xonkmsn2f+mRGxOqg@mail.gmail.com","threadId":"57799","inReplyTo":"a6094881-7e63-7dc6-2fc1-7e5573cfe55b@gmail.com","subject":"Re: [RFC PATCH v4 0/3] fix `sudo make install` regression in maint","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-10T15:47:55Z","receivedAt":"2022-05-10T15:48:59Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, May 10, 2022 at 7:17 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> On 07/05/2022 17:35, Carlo Marcelo Arenas Belón wrote:\n> > A reroll for cb/path-owner-check-with-sudo with most of the suggestions\n> > included but planned originally as an RFC, because I am frankly not sure\n> > that I read and addressed all of it, but also because after seeing how\n> > my only chance to get an official Reviewed-by: Junio vanished I also\n> > realized that I wasn't clear enough and careful enough from the\n> > beginning to explain the code correctly and therefore had maybe wasted\n> > more of the review quota this change should require.\n> >\n> > Important changes (eventhough most are not affecting the logic)\n> > * Document hopefully better which environments are supported and what\n> >    to do if you want to test it in one that is not (thanks to dscho)\n> > * Removed the arguably premature optimization to try to keep the sudo\n> >    cache warm which was actually buggy, as it was also not needed.\n> >    The CI does passwordless sudo unconditionally and even when running\n> >    it locally it will go so fast that is shouldn't be an issue (thanks\n> >    to Phillip)\n> > * No longer using the ugly and controversial variable name so now it\n> >    will need GIT_TEST_ENABLE_SUDO to be used to enable it on CI (which\n> >    is not done in this series, but a run with it enabled on top of\n> >    seen is available[1])\n> > * Stop the arguing about what is or not a regression worth fixing and\n> >    instead document it as one through a test, which would be easy to\n> >    fix in a follow up since the code was already provided by Junio\n>\n> I've had a read of the patches and I agree with Junio's comments on the\n> second patch.\n\nNot sure which comments you are referring to, but\nI'd implemented Junio's suggestion and removed the \"too clever\" (uid_t)-1 in v4.\n\n> I'd really like us to avoid sudo in the tests if we can as\n> it causes a lot of problems.\n\nEven if it might not seem like it, I agree with you both (and dscho)\ntoo, and if I could come out with a way to do so that would be still\nsecure, I would do it in a pinch, but I can't (at least until now) and\nI don't want for that to hold up this fix so will be publishing soon a\nv4 that still uses sudo in the tests, I am afraid.\n\n> Just to let you know I'm going to be off\n> the list for the next couple of weeks, so I wont be looking at these\n> patches in that time.\n\nThanks for all your help reviewing them and more importantly improving\nthem, enjoy your time off.\n\nCarlo\n"},{"id":"455093","messageId":"20220510174616.18629-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220507163508.78459-1-carenas@gmail.com","subject":"[PATCH v4 0/3] fix `sudo make install` regression in maint","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-10T17:46:13Z","receivedAt":"2022-05-10T17:46:38Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"A reroll for cb/path-owner-check-with-sudo with all the suggestions by\nJunio since RFC v4 and that only include a small code change in patch 2\nto get rid of the maligned and probably buggy `(uid_t)-1` which is not\nneeded and making sure the code would most likely work (ad discussed)\neven when uid_t is signed, sudo behaves and git is running as root.\n\nRange-diff provided below to make easier to spot all the other changes\nin documentation and commit messages as well.\n\nCarlo Marcelo Arenas Belón (3):\n  t: regression git needs safe.directory when using sudo\n  git-compat-util: avoid failing dir ownership checks if running\n    privileged\n  t0034: add negative tests and allow git init to mostly work under sudo\n\n Documentation/config/safe.txt  |  10 ++++\n git-compat-util.h              |  54 ++++++++++++++++-\n t/lib-sudo.sh                  |  12 ++++\n t/t0034-root-safe-directory.sh | 103 +++++++++++++++++++++++++++++++++\n 4 files changed, 178 insertions(+), 1 deletion(-)\n create mode 100644 t/lib-sudo.sh\n create mode 100755 t/t0034-root-safe-directory.sh\n\n--\n1:  4d078785cb ! 1:  8296d93ec0 t: regression git needs safe.directory when using sudo\n    @@ Commit message\n     \n         The test file also uses at least one initial \"setup\" test that creates\n         a parallel execution directory, while ignoring the repository created\n    -    by the test framework, and special care should be taken when invoking\n    -    commands through sudo, since the environment is otherwise independent\n    -    from what the test framework expects.  Indeed `git status` was used\n    -    as a proxy because it doesn't even require commits in the repository\n    -    to work.\n    +    by the test framework.\n    +\n    +    Special care should be taken when invoking commands through sudo, since\n    +    the environment is otherwise independent from what the test framework\n    +    setup and might have changed the values for HOME, SHELL and dropped\n    +    several relevant environment variables for your test.  Indeed `git status`\n    +    was used as a proxy because it doesn't even require commits in the\n    +    repository to work and usually doesn't require much from the environment\n    +    to run, but a future patch will add calls to `git init` and that will\n    +    fail to honor the default branch name, unless that setting is NOT\n    +    provided through an environment variable (which means even a CI run\n    +    could fail that test if enabled incorrectly).\n     \n         A new SUDO prerequisite is provided that does some sanity checking\n         to make sure the sudo command that will be used allows for passwordless\n    @@ Commit message\n         execution path.  This matches what is provided by the macOS agents that\n         are used as part of GitHub actions and probably nowhere else.\n     \n    -    Most of those characteristics make this test mostly suitable only for\n    +    Most of those characteristics make this test mostly only suitable for\n         CI, but it might be executed locally if special care is taken to provide\n    -    for some of them in the local configuration and maybe making use of the\n    +    for all of them in the local configuration and maybe making use of the\n         sudo credential cache by first invoking sudo, entering your password if\n         needed, and then invoking the test with:\n     \n           $ GIT_TEST_ALLOW_SUDO=YES ./t0034-root-safe-directory.sh\n     \n         If it fails to run, then it means your local setup wouldn't work for the\n    -    test and things that might help is to comment out sudo's secure_path config\n    -    and make sure your account has similar privileges than what the CI\n    -    provides (for example an entry in /etc/sudoers for the user marta like)\n    +    test because of the configuration sudo has or other system settings, and\n    +    things that might help are to comment out sudo's secure_path config, and\n    +    make sure that the account you are using has no restrictions on the\n    +    commands it can run through sudo, just like is provided for the user in\n    +    the CI.\n    +\n    +    For example (assuming a username of marta for you) something probably\n    +    similar to the following entry in your /etc/sudoers (or equivalent) file:\n     \n           marta ALL=(ALL:ALL) NOPASSWD: ALL\n     \n         Reported-by: SZEDER Gábor <szeder.dev@gmail.com>\n         Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n         Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n     \n      ## t/t0034-root-safe-directory.sh (new) ##\n     @@\n2:  073b73eb26 ! 2:  e3efd6a178 git-compat-util: avoid failing dir ownership checks if running privileged\n    @@ Commit message\n         privileges didn't track the original id in a sudo compatible way.\n     \n         Because of compatibility with sudo, the code assumes that uid_t is an\n    -    unsigned integer type, but adds additional logic to protect itself\n    -    against possibly malicious ids outside the expected range and ignore\n    -    them.\n    -\n    -    A warning should be generated if uid_t is signed and the code would\n    -    need to be locally patched to work correctly, but this is also a\n    -    weather balloon of sorts so we will then now which systems those are\n    -    and whether we should accommodate for their portability in our codebase.\n    +    unsigned integer type (which is not required by the standard) but is used\n    +    that way in their codebase to generate SUDO_UID.  In systems where uid_t\n    +    is signed, sudo might be also patched to NOT be unsigned and that might\n    +    be able to trigger an edge case and a bug (as described in the code), but\n    +    it is considered unlikely to be triggered, and even when it does the code\n    +    would just safely fail, so there is no attempt either to detect it or\n    +    prevent it in the code, which might need to be changed in the future.\n     \n         Reported-by: Guy Maurel <guy.j@maurel.de>\n         Helped-by: SZEDER Gábor <szeder.dev@gmail.com>\n    @@ Commit message\n         Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n         Suggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n         Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n     \n      ## Documentation/config/safe.txt ##\n     @@ Documentation/config/safe.txt: directory was listed in the `safe.directory` list. If `safe.directory=*`\n    @@ Documentation/config/safe.txt: directory was listed in the `safe.directory` list\n     +obviously do so with the uid of the user that is running git itself,\n     +but if git is running as root, in a platform that provides sudo and is\n     +not Windows, it will check first if it might have been started through\n    -+it, and if that is the case, will instead use the uid of the user that\n    -+did invoke that instead.\n    ++it, and if that is the case, will use the uid of the user that invoked\n    ++sudo instead.\n     +If that is not what you would prefer and want git to only trust\n     +repositories that are owned by root instead, then you should remove\n     +the `SUDO_UID` variable from root's environment.\n    @@ git-compat-util.h: static inline int git_offset_1st_component(const char *path)\n     +#endif\n     +\n     +/*\n    -+ * this helper function overrides a ROOT_UID with the one provided by\n    ++ * This helper function overrides a ROOT_UID with the one provided by\n     + * an environment variable, do not use unless the original user is\n    -+ * root\n    -+ * WARNING: this function assumes uid_t is unsigned, if you got here\n    -+ *          because of a warning or a bug will need a patch and would\n    -+ *          be nice if you let us know\n    ++ * root or could be used as means to escalate to root privileges.\n    ++ *\n    ++ * PORTABILITY WARNING:\n    ++ * This code assumes uid_t is unsigned because that is what sudo does.\n    ++ * If your uid_t type is signed and all your ids are positive then it\n    ++ * should all work fine, but need to make sure sudo never generates a\n    ++ * value higher than what can be represented by your uid_t type or a\n    ++ * negative value or it will trigger wraparound bugs.\n    ++ *\n    ++ * If that happens the uid used might be incorrect and then trigger\n    ++ * an access error from the filesystem itself.\n    ++ *\n    ++ * In the unlikely scenario this happened to you, and that is how you\n    ++ * got to this message, we would like to know about it by letting us\n    ++ * now with an email to git@vger.kernel.org indicating which platform,\n    ++ * you are running on and which version of sudo you used to see if we\n    ++ * can provide you a patch that would prevent this issue in the future.\n     + */\n     +static inline void extract_id_from_env(const char *env, uid_t *id)\n     +{\n     +\tconst char *real_uid = getenv(env);\n     +\n    -+\t/* discard any empty values */\n    ++\t/* discard anything empty to avoid a more complex check below */\n     +\tif (real_uid && *real_uid) {\n     +\t\tchar *endptr = NULL;\n     +\t\tunsigned long env_id;\n     +\n     +\t\terrno = 0;\n    ++\t\t/* silent overflow errors could trigger a bug below */\n     +\t\tenv_id = strtoul(real_uid, &endptr, 10);\n    -+\t\t/*\n    -+\t\t * env_id could underflow/overflow in the previous call\n    -+\t\t * and if it will still fit in a long it will not report\n    -+\t\t * it as error with ERANGE, instead silently using an\n    -+\t\t * equivalent positive number that might be bogus.\n    -+\t\t * if uid_t is narrower than long, it might not fit,\n    -+\t\t * hence why we  need to check it against the maximum\n    -+\t\t * possible uid_t value before accepting it.\n    -+\t\t */\n    -+\t\tif (!*endptr && !errno && env_id <= (uid_t)-1)\n    ++\t\tif (!*endptr && !errno)\n     +\t\t\t*id = env_id;\n     +\t}\n     +}\n3:  e772e4d128 ! 3:  1b8003c599 t0034: add negative tests and allow git init to mostly work under sudo\n    @@ Commit message\n     \n         Note that the specific test that documents that after the previous\n         changes, it is no longer possible for root (if obtained through sudo)\n    -    to NOT add an exception or need a \"workaround\" to be able to run git\n    +    to NOT add an exception or NOT need a \"workaround\" to be able to run git\n         commands in a repository owned by thyself, is marked as a regression\n         and is expected to be fixed with a future change, which hasn't been\n         provided yet and that is not part of this series.\n     \n    +    As described in the comments from the test itself, at least one of the\n    +    documented workarounds could fail if sudo doesn't allow root to call sudo\n    +    or if root is not in sudoers, but that is very unlikely, and more\n    +    importantly actually not what is provided by the currently supported sudo\n    +    configuration this test already relies on and therefore adding a way to\n    +    validate it works in the prerequisite has been punted for now.\n    +\n         Helped-by: Junio C Hamano <gitster@pobox.com>\n         Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n         Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n    -    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n     \n      ## t/lib-sudo.sh (new) ##\n     @@\n    @@ t/t0034-root-safe-directory.sh: test_expect_success SUDO 'sudo git status as ori\n     +'\n     +\n     +test_expect_success SUDO 'can access with sudo using a workaround' '\n    -+\t# run sudo twice; would fail is root is not in the sudoers\n    ++\t# run sudo twice; would fail if root is not in sudoers\n     +\t(\n     +\t\tcd root/p &&\n     +\t\tsudo sudo git status\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455094","messageId":"20220510174616.18629-2-carenas@gmail.com","threadId":"57799","inReplyTo":"20220510174616.18629-1-carenas@gmail.com","subject":"[PATCH v4 1/3] t: regression git needs safe.directory when using sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-10T17:46:14Z","receivedAt":"2022-05-10T17:46:42Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Originally reported after release of v2.35.2 (and other maint branches)\nfor CVE-2022-24765 and blocking otherwise harmless commands that were\ndone using sudo in a repository that was owned by the user.\n\nAdd a new test script with very basic support to allow running git\ncommands through sudo, so a reproduction could be implemented and that\nuses only `git status` as a proxy of the issue reported.\n\nNote that because of the way sudo interacts with the system, a much\nmore complete integration with the test framework will require a lot\nmore work and that was therefore intentionally punted for now.\n\nThe current implementation requires the execution of a special cleanup\nfunction which should always be kept as the last \"test\" or otherwise\nthe standard cleanup functions will fail because they can't remove\nthe root owned directories that are used.  This also means that if\nfailures are found while running, the specifics of the failure might\nnot be kept for further debugging and if the test was interrupted, it\nwill be necessary to clean the working directory manually before\nrestarting by running:\n\n  $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n\nThe test file also uses at least one initial \"setup\" test that creates\na parallel execution directory, while ignoring the repository created\nby the test framework.\n\nSpecial care should be taken when invoking commands through sudo, since\nthe environment is otherwise independent from what the test framework\nsetup and might have changed the values for HOME, SHELL and dropped\nseveral relevant environment variables for your test.  Indeed `git status`\nwas used as a proxy because it doesn't even require commits in the\nrepository to work and usually doesn't require much from the environment\nto run, but a future patch will add calls to `git init` and that will\nfail to honor the default branch name, unless that setting is NOT\nprovided through an environment variable (which means even a CI run\ncould fail that test if enabled incorrectly).\n\nA new SUDO prerequisite is provided that does some sanity checking\nto make sure the sudo command that will be used allows for passwordless\nexecution as root without restrictions and doesn't mess with git's\nexecution path.  This matches what is provided by the macOS agents that\nare used as part of GitHub actions and probably nowhere else.\n\nMost of those characteristics make this test mostly only suitable for\nCI, but it might be executed locally if special care is taken to provide\nfor all of them in the local configuration and maybe making use of the\nsudo credential cache by first invoking sudo, entering your password if\nneeded, and then invoking the test with:\n\n  $ GIT_TEST_ALLOW_SUDO=YES ./t0034-root-safe-directory.sh\n\nIf it fails to run, then it means your local setup wouldn't work for the\ntest because of the configuration sudo has or other system settings, and\nthings that might help are to comment out sudo's secure_path config, and\nmake sure that the account you are using has no restrictions on the\ncommands it can run through sudo, just like is provided for the user in\nthe CI.\n\nFor example (assuming a username of marta for you) something probably\nsimilar to the following entry in your /etc/sudoers (or equivalent) file:\n\n  marta\tALL=(ALL:ALL) NOPASSWD: ALL\n\nReported-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/t0034-root-safe-directory.sh | 45 ++++++++++++++++++++++++++++++++++\n 1 file changed, 45 insertions(+)\n create mode 100755 t/t0034-root-safe-directory.sh\n\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nnew file mode 100755\nindex 0000000000..2e4492a66d\n--- /dev/null\n+++ b/t/t0034-root-safe-directory.sh\n@@ -0,0 +1,45 @@\n+#!/bin/sh\n+\n+test_description='verify safe.directory checks while running as root'\n+\n+. ./test-lib.sh\n+\n+if [ \"$GIT_TEST_ALLOW_SUDO\" != \"YES\" ]\n+then\n+\tskip_all=\"You must set env var GIT_TEST_ALLOW_SUDO=YES in order to run this test\"\n+\ttest_done\n+fi\n+\n+test_lazy_prereq SUDO '\n+\tsudo -n id -u >u &&\n+\tid -u root >r &&\n+\ttest_cmp u r &&\n+\tcommand -v git >u &&\n+\tsudo command -v git >r &&\n+\ttest_cmp u r\n+'\n+\n+test_expect_success SUDO 'setup' '\n+\tsudo rm -rf root &&\n+\tmkdir -p root/r &&\n+\tsudo chown root root &&\n+\t(\n+\t\tcd root/r &&\n+\t\tgit init\n+\t)\n+'\n+\n+test_expect_failure SUDO 'sudo git status as original owner' '\n+\t(\n+\t\tcd root/r &&\n+\t\tgit status &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+# this MUST be always the last test\n+test_expect_success SUDO 'cleanup' '\n+\tsudo rm -rf root\n+'\n+\n+test_done\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455095","messageId":"20220510174616.18629-3-carenas@gmail.com","threadId":"57799","inReplyTo":"20220510174616.18629-1-carenas@gmail.com","subject":"[PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-10T17:46:15Z","receivedAt":"2022-05-10T17:46:44Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that user was\nroot (because git was invoked through sudo or a compatible tool) and the\noriginal uid that repository trusted for its config was no longer known,\ntherefore failing the following otherwise safe call:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nthose tools create to keep track of the original user id, and do the\nownership check using that instead.\n\nThis assumes the environment the user is running on after going\nprivileged can't be tampered with, and also adds code to restrict that\nthe new behavior only applies if running as root, therefore keeping the\nmost common case, which runs unprivileged, from changing, but because of\nthat, it will miss cases where sudo (or an equivalent) was used to change\nto another unprivileged user or where the equivalent tool used to raise\nprivileges didn't track the original id in a sudo compatible way.\n\nBecause of compatibility with sudo, the code assumes that uid_t is an\nunsigned integer type (which is not required by the standard) but is used\nthat way in their codebase to generate SUDO_UID.  In systems where uid_t\nis signed, sudo might be also patched to NOT be unsigned and that might\nbe able to trigger an edge case and a bug (as described in the code), but\nit is considered unlikely to be triggered, and even when it does the code\nwould just safely fail, so there is no attempt either to detect it or\nprevent it in the code, which might need to be changed in the future.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n Documentation/config/safe.txt  | 10 +++++++\n git-compat-util.h              | 54 +++++++++++++++++++++++++++++++++-\n t/t0034-root-safe-directory.sh |  2 +-\n 3 files changed, 64 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex 6d764fe0cc..dba9d5b2d1 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -26,3 +26,13 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n is set in system config and you want to re-enable this protection, then\n initialize your list with an empty value before listing the repositories\n that you deem safe.\n++\n+When git tries to check for ownership of git repositories, it will\n+obviously do so with the uid of the user that is running git itself,\n+but if git is running as root, in a platform that provides sudo and is\n+not Windows, it will check first if it might have been started through\n+it, and if that is the case, will use the uid of the user that invoked\n+sudo instead.\n+If that is not what you would prefer and want git to only trust\n+repositories that are owned by root instead, then you should remove\n+the `SUDO_UID` variable from root's environment.\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 63ba89dd31..754cd90d43 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -393,12 +393,64 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n+/*\n+ * This helper function overrides a ROOT_UID with the one provided by\n+ * an environment variable, do not use unless the original user is\n+ * root or could be used as means to escalate to root privileges.\n+ *\n+ * PORTABILITY WARNING:\n+ * This code assumes uid_t is unsigned because that is what sudo does.\n+ * If your uid_t type is signed and all your ids are positive then it\n+ * should all work fine, but need to make sure sudo never generates a\n+ * value higher than what can be represented by your uid_t type or a\n+ * negative value or it will trigger wraparound bugs.\n+ *\n+ * If that happens the uid used might be incorrect and then trigger\n+ * an access error from the filesystem itself.\n+ *\n+ * In the unlikely scenario this happened to you, and that is how you\n+ * got to this message, we would like to know about it by letting us\n+ * now with an email to git@vger.kernel.org indicating which platform,\n+ * you are running on and which version of sudo you used to see if we\n+ * can provide you a patch that would prevent this issue in the future.\n+ */\n+static inline void extract_id_from_env(const char *env, uid_t *id)\n+{\n+\tconst char *real_uid = getenv(env);\n+\n+\t/* discard anything empty to avoid a more complex check below */\n+\tif (real_uid && *real_uid) {\n+\t\tchar *endptr = NULL;\n+\t\tunsigned long env_id;\n+\n+\t\terrno = 0;\n+\t\t/* silent overflow errors could trigger a bug below */\n+\t\tenv_id = strtoul(real_uid, &endptr, 10);\n+\t\tif (!*endptr && !errno)\n+\t\t\t*id = env_id;\n+\t}\n+}\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID)\n+\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex 2e4492a66d..ecd9dca6b3 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -29,7 +29,7 @@ test_expect_success SUDO 'setup' '\n \t)\n '\n \n-test_expect_failure SUDO 'sudo git status as original owner' '\n+test_expect_success SUDO 'sudo git status as original owner' '\n \t(\n \t\tcd root/r &&\n \t\tgit status &&\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455096","messageId":"20220510174616.18629-4-carenas@gmail.com","threadId":"57799","inReplyTo":"20220510174616.18629-1-carenas@gmail.com","subject":"[PATCH v4 3/3] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-10T17:46:16Z","receivedAt":"2022-05-10T17:46:46Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Add a support library that provides one function that can be used\nto run a \"scriplet\" of commands through sudo and that helps invoking\nsudo in the slightly awkward way that is required to ensure it doesn't\nblock the call (if shell was allowed as tested in the prerequisite)\nand it doesn't run the command through a different shell than the one\nwe intended.\n\nAdd additional negative tests as suggested by Junio and that use a\nnew workspace that is owned by root.\n\nNote that the specific test that documents that after the previous\nchanges, it is no longer possible for root (if obtained through sudo)\nto NOT add an exception or NOT need a \"workaround\" to be able to run git\ncommands in a repository owned by thyself, is marked as a regression\nand is expected to be fixed with a future change, which hasn't been\nprovided yet and that is not part of this series.\n\nAs described in the comments from the test itself, at least one of the\ndocumented workarounds could fail if sudo doesn't allow root to call sudo\nor if root is not in sudoers, but that is very unlikely, and more\nimportantly actually not what is provided by the currently supported sudo\nconfiguration this test already relies on and therefore adding a way to\nvalidate it works in the prerequisite has been punted for now.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/lib-sudo.sh                  | 12 +++++++\n t/t0034-root-safe-directory.sh | 58 ++++++++++++++++++++++++++++++++++\n 2 files changed, 70 insertions(+)\n create mode 100644 t/lib-sudo.sh\n\ndiff --git a/t/lib-sudo.sh b/t/lib-sudo.sh\nnew file mode 100644\nindex 0000000000..d8a88fb9db\n--- /dev/null\n+++ b/t/lib-sudo.sh\n@@ -0,0 +1,12 @@\n+# Helpers for running git commands under sudo.\n+\n+# Runs a scriplet passed through stdin under sudo.\n+run_with_sudo () {\n+\tlocal ret\n+\tlocal RUN=\"$TEST_DIRECTORY/$$.sh\"\n+\twrite_script \"$RUN\" \"$TEST_SHELL_PATH\"\n+\tsudo \"$TEST_SHELL_PATH\" -c \"\\\"$RUN\\\"\"\n+\tret=$?\n+\trm -f \"$RUN\"\n+\treturn $ret\n+}\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex ecd9dca6b3..54f687d787 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -3,6 +3,7 @@\n test_description='verify safe.directory checks while running as root'\n \n . ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-sudo.sh\n \n if [ \"$GIT_TEST_ALLOW_SUDO\" != \"YES\" ]\n then\n@@ -10,6 +11,12 @@ then\n \ttest_done\n fi\n \n+if ! test_have_prereq NOT_ROOT\n+then\n+\tskip_all=\"These tests do not support running as root\"\n+\ttest_done\n+fi\n+\n test_lazy_prereq SUDO '\n \tsudo -n id -u >u &&\n \tid -u root >r &&\n@@ -19,6 +26,12 @@ test_lazy_prereq SUDO '\n \ttest_cmp u r\n '\n \n+if ! test_have_prereq SUDO\n+then\n+\tskip_all=\"Your sudo/system configuration is either too strict or unsupported\"\n+\ttest_done\n+fi\n+\n test_expect_success SUDO 'setup' '\n \tsudo rm -rf root &&\n \tmkdir -p root/r &&\n@@ -37,6 +50,51 @@ test_expect_success SUDO 'sudo git status as original owner' '\n \t)\n '\n \n+test_expect_success SUDO 'setup root owned repository' '\n+\tsudo mkdir -p root/p &&\n+\tsudo git init root/p\n+'\n+\n+test_expect_success 'cannot access if owned by root' '\n+\t(\n+\t\tcd root/p &&\n+\t\ttest_must_fail git status\n+\t)\n+'\n+\n+test_expect_failure SUDO 'can access with sudo if root' '\n+\t(\n+\t\tcd root/p &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'can access with sudo using a workaround' '\n+\t# run sudo twice; would fail if root is not in sudoers\n+\t(\n+\t\tcd root/p &&\n+\t\tsudo sudo git status\n+\t) &&\n+\t# provide explicit GIT_DIR\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tGIT_DIR=.git &&\n+\t\t\tGIT_WORK_TREE=. &&\n+\t\t\texport GIT_DIR GIT_WORK_TREE &&\n+\t\t\tgit status\n+\t\tEND\n+\t) &&\n+\t# discard SUDO_UID\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tunset SUDO_UID &&\n+\t\t\tgit status\n+\t\tEND\n+\t)\n+'\n+\n # this MUST be always the last test\n test_expect_success SUDO 'cleanup' '\n \tsudo rm -rf root\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455124","messageId":"xmqqczgl6nua.fsf@gitster.g","threadId":"57799","inReplyTo":"20220510174616.18629-2-carenas@gmail.com","subject":"Re: [PATCH v4 1/3] t: regression git needs safe.directory when using sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-10T22:10:21Z","receivedAt":"2022-05-10T22:10:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> Note that because of the way sudo interacts with the system, a much\n> more complete integration with the test framework will require a lot\n> more work and that was therefore intentionally punted for now.\n>\n> The current implementation requires ...\n> ...\n> If it fails to run, then it means your local setup wouldn't work for the\n> test because of the configuration sudo has or other system settings, and\n> things that might help are to comment out sudo's secure_path config, and\n> make sure that the account you are using has no restrictions on the\n> commands it can run through sudo, just like is provided for the user in\n> the CI.\n>\n> For example (assuming a username of marta for you) something probably\n> similar to the following entry in your /etc/sudoers (or equivalent) file:\n>\n>   marta\tALL=(ALL:ALL) NOPASSWD: ALL\n>\n> Reported-by: SZEDER Gábor <szeder.dev@gmail.com>\n> Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n\nVery well written.\n\n> +test_lazy_prereq SUDO '\n> +\tsudo -n id -u >u &&\n> +\tid -u root >r &&\n> +\ttest_cmp u r &&\n> +\tcommand -v git >u &&\n> +\tsudo command -v git >r &&\n> +\ttest_cmp u r\n> +'\n\nI vaguely recall mentions of older dash that lack \"command -v\" made\nearlier, but implementations of dash I have handy seem to know it.\nI am personally fine with this as this script has a very narrow and\nlimited audience in mind.\n\n> +test_expect_success SUDO 'setup' '\n> +\tsudo rm -rf root &&\n> +\tmkdir -p root/r &&\n> +\tsudo chown root root &&\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit init\n> +\t)\n> +'\n\nSo, \"root/\" is owned by root, \"root/r\" is owned by the tester.\n\n> +test_expect_failure SUDO 'sudo git status as original owner' '\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit status &&\n\nThe tester runs \"git status\" in \"root/r\" owned by the tester and it\nshould succeed.\n\n> +\t\tsudo git status\n\nWe want the tester to be able to do the same while temporarily\nbecoming 'root' with \"sudo\", but we know it fails right now.\n\n> +\t)\n> +'\n\nMental note.  We do not need root to be owned by 'root' with the\ntests we see here.  Perhaps we would add some that requires it in\nlater patches.  We'll see.\n\n> +# this MUST be always the last test\n> +test_expect_success SUDO 'cleanup' '\n> +\tsudo rm -rf root\n> +'\n> +\n> +test_done\n\nSo far, looking good.\n\nThanks.\n"},{"id":"455127","messageId":"xmqqv8ud5741.fsf@gitster.g","threadId":"57799","inReplyTo":"20220510174616.18629-3-carenas@gmail.com","subject":"Re: [PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-10T22:57:02Z","receivedAt":"2022-05-10T22:57:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> This assumes the environment the user is running on after going\n> privileged can't be tampered with, and also adds code to restrict that\n> the new behavior only applies if running as root, therefore keeping the\n> most common case, which runs unprivileged, from changing, but because of\n> that, it will miss cases where sudo (or an equivalent) was used to change\n> to another unprivileged user or where the equivalent tool used to raise\n> privileges didn't track the original id in a sudo compatible way.\n\nWell written.\n\n> Because of compatibility with sudo, the code assumes that uid_t is an\n> unsigned integer type (which is not required by the standard) but is used\n> that way in their codebase to generate SUDO_UID.\n\nHeh, that is a good point.\n\n> ++\n> +When git tries to check for ownership of git repositories, it will\n> +obviously do so with the uid of the user that is running git itself,\n\nWe do not need \"obviously\" here, but this has overlap with the\nbeginning part of the safe.directory explanation, so I would\nprobably suggest rewriting it altogether.\n\n> +but if git is running as root, in a platform that provides sudo and is\n> +not Windows, it will check first if it might have been started through\n\nDoes Windows provide sudo that leaves the original user in SUDO_UID\n(I doubt it)?  If not, then \"on a platform that provides sudo, it will\"\nwould be sufficient.\n\n> +it, and if that is the case, will use the uid of the user that invoked\n> +sudo instead.\n\n  \n  As explained, Git only allows you to access repositories owned by\n  yourself, i.e. the user who is running Git, by default.  When Git\n  is running as 'root', however, instead of allowing accesses to\n  repositories owned by 'root', it checks the SUDO_UID environment\n  variable and if it is set, allows access to repositories owned by\n  the uid recorded as its value.  This is to make it easy to perform\n  a common sequence \"make && sudo make install\".  A process running\n  under 'sudo' runs as 'root' but the 'sudo' command exports the\n  environment variable to record who the original user was.\n\n> +If that is not what you would prefer and want git to only trust\n> +repositories that are owned by root instead, then you should remove\n> +the `SUDO_UID` variable from root's environment.\n\ns/should/can/.  But otherwise this is excellent.\n\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 63ba89dd31..754cd90d43 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -393,12 +393,64 @@ static inline int git_offset_1st_component(const char *path)\n>  #endif\n>  \n>  #ifndef is_path_owned_by_current_user\n> +\n> +#ifdef __TANDEM\n> +#define ROOT_UID 65535\n> +#else\n> +#define ROOT_UID 0\n> +#endif\n> +\n> +/*\n> + * This helper function overrides a ROOT_UID with the one provided by\n> + * an environment variable, do not use unless the original user is\n> + * root or could be used as means to escalate to root privileges.\n\nI do not understand the \"or could be used ...\" at all.  If the\noriginal user obtained from geteuid() is not root, then no matter\nwhat we do to *id here in this function, we won't let you gain the\nroot privilege.  The system won't let us give you the root privilege\nbecause we (Git) are running as a normal user.\n\nOr do you mean\n\n\tDo not use this function when\n\n\t (1) geteuid() did not say we are running as 'root', or \n\t (2) using this function will compromise the system. \n\nThen I can sort-of understand it, but (2) is a too obvious thing to\nsay.\n\n> + * PORTABILITY WARNING:\n> + * This code assumes uid_t is unsigned because that is what sudo does.\n> + * If your uid_t type is signed and all your ids are positive then it\n> + * should all work fine, but need to make sure sudo never generates a\n> + * value higher than what can be represented by your uid_t type or a\n> + * negative value or it will trigger wraparound bugs.\n\n\"sudo\" generating a value higher than what uid_t can represent in\nSUDO_UID *is* a bug that we shouldn't have to worry about.\nOtherwise \"sudo\" as a tool would be unusable by folks with higher\nUID on their system.\n\nIn their implementation of \"sudo\", they must have done getuid(),\nstored the value in uid_t and formatted it into a string.  If they\nlost precision there by wrapping around or truncating, we can do\nnothing about it, but the thing is, we cannot even tell.\n\n> + * If that happens the uid used might be incorrect and then trigger\n> + * an access error from the filesystem itself.\n\nIf uid we are extracting is incorrect, Git will fail to refuse\naccess, the access is done as 'root', and filesystem level safety\nwill not trigger.  The end result is that I run \"sudo git describe\"\nin your repository and instead of getting refused, because our \"sudo\"\nwas broken and SUDO_UID had your numeric uid, I execute \"git\" as root\nin your repository.\n\nIOW, this change is meant to make it slightly convenient to allow\naccess to one's own stuff, but it got a bit more convenient by\nallowing me access to my own stuff plus yours ;-)\n\n> + * In the unlikely scenario this happened to you, and that is how you\n> + * got to this message, we would like to know about it by letting us\n> + * now with an email to git@vger.kernel.org indicating which platform,\n> + * you are running on and which version of sudo you used to see if we\n> + * can provide you a patch that would prevent this issue in the future.\n\nNice.  What message does the reporter see?\n\n> + */\n> +static inline void extract_id_from_env(const char *env, uid_t *id)\n> +{\n> +\tconst char *real_uid = getenv(env);\n> +\n> +\t/* discard anything empty to avoid a more complex check below */\n> +\tif (real_uid && *real_uid) {\n> +\t\tchar *endptr = NULL;\n> +\t\tunsigned long env_id;\n> +\n> +\t\terrno = 0;\n> +\t\t/* silent overflow errors could trigger a bug below */\n\nWhat \"bug\" are we referring to?\n\n> +\t\tenv_id = strtoul(real_uid, &endptr, 10);\n> +\t\tif (!*endptr && !errno)\n> +\t\t\t*id = env_id;\n> +\t}\n> +}\n> +\n>  static inline int is_path_owned_by_current_uid(const char *path)\n>  {\n>  \tstruct stat st;\n> +\tuid_t euid;\n> +\n>  \tif (lstat(path, &st))\n>  \t\treturn 0;\n> -\treturn st.st_uid == geteuid();\n> +\n> +\teuid = geteuid();\n> +\tif (euid == ROOT_UID)\n> +\t\textract_id_from_env(\"SUDO_UID\", &euid);\n> +\n> +\treturn st.st_uid == euid;\n>  }\n>  \n>  #define is_path_owned_by_current_user is_path_owned_by_current_uid\n> diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\n> index 2e4492a66d..ecd9dca6b3 100755\n> --- a/t/t0034-root-safe-directory.sh\n> +++ b/t/t0034-root-safe-directory.sh\n> @@ -29,7 +29,7 @@ test_expect_success SUDO 'setup' '\n>  \t)\n>  '\n>  \n> -test_expect_failure SUDO 'sudo git status as original owner' '\n> +test_expect_success SUDO 'sudo git status as original owner' '\n>  \t(\n>  \t\tcd root/r &&\n>  \t\tgit status &&\n\nOK.\n\nThanks.\n"},{"id":"455128","messageId":"xmqqczgl56fi.fsf@gitster.g","threadId":"57799","inReplyTo":"20220510174616.18629-4-carenas@gmail.com","subject":"Re: [PATCH v4 3/3] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-10T23:11:45Z","receivedAt":"2022-05-10T23:11:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> Note that the specific test that documents that after the previous\n> changes, it is no longer possible for root (if obtained through sudo)\n> to NOT add an exception or NOT need a \"workaround\" to be able to run git\n> commands in a repository owned by thyself, is marked as a regression\n> and is expected to be fixed with a future change, which hasn't been\n> provided yet and that is not part of this series.\n\nDo you mean \"you can easily unset SUDO_UID to access root-owned\nrepositories as root\"?  Ahh, no, \"after tentatively becoming root,\nyou can access your own (via SUDO_UID) and root-owned repositories\"\nis what you meant, I think.  I think that is reasonable to stop the\ncurrent round before adding the support for it.\n\n> As described in the comments from the test itself, at least one of the\n> documented workarounds could fail if sudo doesn't allow root to call sudo\n> or if root is not in sudoers, but that is very unlikely, and more\n> importantly actually not what is provided by the currently supported sudo\n> configuration this test already relies on and therefore adding a way to\n> validate it works in the prerequisite has been punted for now.\n\nOK.\n\n> diff --git a/t/lib-sudo.sh b/t/lib-sudo.sh\n> new file mode 100644\n> index 0000000000..d8a88fb9db\n> --- /dev/null\n> +++ b/t/lib-sudo.sh\n> @@ -0,0 +1,12 @@\n> +# Helpers for running git commands under sudo.\n> +\n> +# Runs a scriplet passed through stdin under sudo.\n> +run_with_sudo () {\n> +\tlocal ret\n> +\tlocal RUN=\"$TEST_DIRECTORY/$$.sh\"\n> +\twrite_script \"$RUN\" \"$TEST_SHELL_PATH\"\n> +\tsudo \"$TEST_SHELL_PATH\" -c \"\\\"$RUN\\\"\"\n\nThis is not wrong per-se, but I think\n\n\tsudo \"$RUN\"\n\nwould be sufficient, wouldn't it? \n\n> @@ -19,6 +26,12 @@ test_lazy_prereq SUDO '\n>  \ttest_cmp u r\n>  '\n>  \n> +if ! test_have_prereq SUDO\n> +then\n> +\tskip_all=\"Your sudo/system configuration is either too strict or unsupported\"\n> +\ttest_done\n> +fi\n\nQuite sensible and understandable.\n\n> @@ -37,6 +50,51 @@ test_expect_success SUDO 'sudo git status as original owner' '\n>  \t)\n>  '\n>  \n> +test_expect_success SUDO 'setup root owned repository' '\n> +\tsudo mkdir -p root/p &&\n> +\tsudo git init root/p\n> +'\n\nOK, so \n\n\troot/ is owned by 'root',\n\troot/r is owned by the tester, and\n\troot/p is owned by 'root'.\n\n> +test_expect_success 'cannot access if owned by root' '\n> +\t(\n> +\t\tcd root/p &&\n> +\t\ttest_must_fail git status\n> +\t)\n> +'\n\nOK.\n\nMark this point as [A] for future reference.\n\n> +test_expect_failure SUDO 'can access with sudo if root' '\n> +\t(\n> +\t\tcd root/p &&\n> +\t\tsudo git status\n> +\t)\n> +'\n\nOK.\n\n\n> +test_expect_success SUDO 'can access with sudo using a workaround' '\n> +\t# run sudo twice; would fail if root is not in sudoers\n\nIt probably is a good idea to check \"you can run nested sudo\" before\nsetting SUDO prerequisite.  Then we do not have to say \"would fail\"\nhere.\n\n> +\t(\n> +\t\tcd root/p &&\n> +\t\tsudo sudo git status\n> +\t) &&\n> +\t# provide explicit GIT_DIR\n> +\t(\n> +\t\tcd root/p &&\n> +\t\trun_with_sudo <<-END\n> +\t\t\tGIT_DIR=.git &&\n> +\t\t\tGIT_WORK_TREE=. &&\n> +\t\t\texport GIT_DIR GIT_WORK_TREE &&\n> +\t\t\tgit status\n> +\t\tEND\n> +\t) &&\n\nOK.  We probably want to highlight that this \"by default you can\nonly access your own repository\" is *not* a security measure that\nprotects the repositories---it is a security measure to protect\nyou from potentially malicious repositories by unknowingly stepping\ninto them.  To do so, let's go back to point [A] and add a similar\n\"I as a tester can still access repository owned by root, as long as\nI express that I want to access it explicitly\" test after it. i.e.\n\n\t(\n\t\tcd root/p &&\n\t\tGIT_DIR=.git GIT_WORK_TREE=. git status\n\t)\n\n> +\t# discard SUDO_UID\n> +\t(\n> +\t\tcd root/p &&\n> +\t\trun_with_sudo <<-END\n> +\t\t\tunset SUDO_UID &&\n> +\t\t\tgit status\n> +\t\tEND\n> +\t)\n> +'\n\nOK.\n\nThanks.\n"},{"id":"455129","messageId":"CAPUEspgGZeF8LA5PZNF87=+zZLKvWLqWtpD5YUBUON4gq_TaDg@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqczgl6nua.fsf@gitster.g","subject":"Re: [PATCH v4 1/3] t: regression git needs safe.directory when using sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-10T23:11:55Z","receivedAt":"2022-05-10T23:12:13Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, May 10, 2022 at 3:10 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n>\n> > +test_lazy_prereq SUDO '\n> > +     sudo -n id -u >u &&\n> > +     id -u root >r &&\n> > +     test_cmp u r &&\n> > +     command -v git >u &&\n> > +     sudo command -v git >r &&\n> > +     test_cmp u r\n> > +'\n>\n> I vaguely recall mentions of older dash that lack \"command -v\" made\n> earlier, but implementations of dash I have handy seem to know it.\n> I am personally fine with this as this script has a very narrow and\n> limited audience in mind.\n\nI did check that, but think the report was mistaken.\nDebian, Ubuntu, NetBSD and OpenBSD would fail the same way here, but\nit is not because of the use of dash, as much as sudo NOT being\nconfigured to default to `-s` mode.\n\ndscho was right to point out that I should had usen type instead, but\nthat wouldn't work because of the mismatch of shells and therefore the\nmismatch of outputs, so I went with command instead as an extra clever\nway to make sure both the shell inside and outside were most likely\nthe same, even if some sudo somewhere decides in the name of security\nnot to respect its own \"-s mode\" and force a \"safer\" shell.\n\nI have a real fix for this which will be released later as part of\nthat \"better integration with the framework\", which basically makes\nsure all invocations through sudo are done through the test shell\n(just like that ugly function that gets added in patch 3), but it\nrequires changing write_shell and therefore not something that is\nworth doing now.\n\n> +test_expect_success SUDO 'setup' '\n> > +     sudo rm -rf root &&\n> > +     mkdir -p root/r &&\n> > +     sudo chown root root &&\n> > +     (\n> > +             cd root/r &&\n> > +             git init\n> > +     )\n> > +'\n>\n> So, \"root/\" is owned by root, \"root/r\" is owned by the tester.\n\nIt doesn't need to be root, but needs to be different than \"tester\",\nand since I know root is different and I validated in the prerequisite\nthat I can sudo to it, that is what is used here.\n\n> > +test_expect_failure SUDO 'sudo git status as original owner' '\n> > +     (\n> > +             cd root/r &&\n> > +             git status &&\n>\n> The tester runs \"git status\" in \"root/r\" owned by the tester and it\n> should succeed.\n>\n> > +             sudo git status\n>\n> We want the tester to be able to do the same while temporarily\n> becoming 'root' with \"sudo\", but we know it fails right now.\n>\n> > +     )\n> > +'\n>\n> Mental note.  We do not need root to be owned by 'root' with the\n> tests we see here.  Perhaps we would add some that requires it in\n> later patches.  We'll see.\n\nI am not good with subtle messages in a foreign language, but is this\na way to imply that I shouldn't need to chown and instead use the\nGIT_TEST_PRETEND feature more?\n\nfrankly I might had overused sudo, but it is because every extra\ninvocation refreshes the cache, and all tests depend on SUDO anyway,\nso I wanted to make sure they were also more easily reconizable for\nthe real thing.\n\nCarlo\n"},{"id":"455131","messageId":"xmqq4k1x55ru.fsf@gitster.g","threadId":"57799","inReplyTo":"xmqqczgl56fi.fsf@gitster.g","subject":"Re: [PATCH v4 3/3] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-10T23:25:57Z","receivedAt":"2022-05-10T23:26:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> OK, so \n>\n> \troot/ is owned by 'root',\n> \troot/r is owned by the tester, and\n> \troot/p is owned by 'root'.\n\nOne thing I forgot.  In these three patches, I didn't see anything\nthat required root/ to be owned by 'root'.  So perhaps we can lose\nthe \"chown root root\" in the earlier test.\n"},{"id":"455139","messageId":"xmqqwnet3qcv.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspgGZeF8LA5PZNF87=+zZLKvWLqWtpD5YUBUON4gq_TaDg@mail.gmail.com","subject":"Re: [PATCH v4 1/3] t: regression git needs safe.directory when using sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-10T23:44:16Z","receivedAt":"2022-05-10T23:44:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n>> > +test_lazy_prereq SUDO '\n>> > +     sudo -n id -u >u &&\n>> > +     id -u root >r &&\n>> > +     test_cmp u r &&\n>> > +     command -v git >u &&\n>> > +     sudo command -v git >r &&\n>> > +     test_cmp u r\n>> > +'\n>>\n>> I vaguely recall mentions of older dash that lack \"command -v\" made\n>> earlier, but implementations of dash I have handy seem to know it.\n>> I am personally fine with this as this script has a very narrow and\n>> limited audience in mind.\n>\n> I did check that, but think the report was mistaken.\n> Debian, Ubuntu, NetBSD and OpenBSD would fail the same way here, but\n> it is not because of the use of dash, as much as sudo NOT being\n> configured to default to `-s` mode.\n\nOK.\n\n> dscho was right to point out that I should had usen type instead, but\n> that wouldn't work because of the mismatch of shells and therefore the\n> mismatch of outputs, so I went with command instead as an extra clever\n> way to make sure both the shell inside and outside were most likely\n> the same, even if some sudo somewhere decides in the name of security\n> not to respect its own \"-s mode\" and force a \"safer\" shell.\n\nIn this particular case, \"command -v\" is the right thing to use, as\nyou care where the command is found on the $PATH and \"type --path\"\nis *NOT* portable.\n\n>> > +     sudo chown root root &&\n>> > +     (\n>> > +             cd root/r &&\n>> > +             git init\n>> > +     )\n>> > +'\n>>\n>> So, \"root/\" is owned by root, \"root/r\" is owned by the tester.\n>\n> It doesn't need to be root, but needs to be different than \"tester\",\n\nTo make sure you do not misunderstand, I know the ownership of\nroot/r and root/p matter---tester and root must be different.  And\nwe use these two as sample repositories owned by two different\nusers.\n\nWhat I am pointing out here is the root/ directory itself.  I do not\nthink its ownership does not matter anywhere in these new tests (not\njust this patch, but after applying all three patches).\n\n>> > +test_expect_failure SUDO 'sudo git status as original owner' '\n>> > +     (\n>> > +             cd root/r &&\n>> > +             git status &&\n>>\n>> The tester runs \"git status\" in \"root/r\" owned by the tester and it\n>> should succeed.\n>>\n>> > +             sudo git status\n>>\n>> We want the tester to be able to do the same while temporarily\n>> becoming 'root' with \"sudo\", but we know it fails right now.\n>>\n>> > +     )\n>> > +'\n>>\n>> Mental note.  We do not need root to be owned by 'root' with the\n>> tests we see here.  Perhaps we would add some that requires it in\n>> later patches.  We'll see.\n>\n> I am not good with subtle messages in a foreign language, but is this\n> a way to imply that I shouldn't need to chown and instead use the\n> GIT_TEST_PRETEND feature more?\n\nNo.  I just said I made a mental note of the fact that the ownership\nof root/ directory (not root/r which is the other directory this\ntest script creates in this step) does not matter at least in patch\n1/3, but I cannot say, by that observation alone, that chown we saw\nearlier should be removed, because patches 2/3 and 3/3 might start\nrequiring root/ to be owned by 'root'.  Hence \"I made a mental note\nhere.  We do not have anything that requires the above chown in this\npatch, but we might see something that makes it a good idea to keep\nthe chown in later patches\".\n\nI do not think GIT_TEST_PRETEND needs to be involved at all.  It's\njust root/ can be left owned by the tester, because we only care\nabout the owners of root/p and root/r in these three patches.\n\nThanks.\n\n"},{"id":"455142","messageId":"CAPUEspjppJh3+obLoNpP8ckHz=-0G=MEUUBHnrab6=Znv+RiUg@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqwnet3qcv.fsf@gitster.g","subject":"Re: [PATCH v4 1/3] t: regression git needs safe.directory when using sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-11T00:56:37Z","receivedAt":"2022-05-11T00:56:54Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, May 10, 2022 at 4:44 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Arenas <carenas@gmail.com> writes:\n> >>\n> >> Mental note.  We do not need root to be owned by 'root' with the\n> >> tests we see here.  Perhaps we would add some that requires it in\n> >> later patches.  We'll see.\n> >\n> > I am not good with subtle messages in a foreign language, but is this\n> > a way to imply that I shouldn't need to chown and instead use the\n> > GIT_TEST_PRETEND feature more?\n>\n> No.  I just said I made a mental note of the fact that the ownership\n> of root/ directory (not root/r which is the other directory this\n> test script creates in this step) does not matter at least in patch\n> 1/3, but I cannot say, by that observation alone, that chown we saw\n> earlier should be removed, because patches 2/3 and 3/3 might start\n> requiring root/ to be owned by 'root'.  Hence \"I made a mental note\n> here.  We do not have anything that requires the above chown in this\n> patch, but we might see something that makes it a good idea to keep\n> the chown in later patches\".\n\ngot it; we actually DO (or at least I intended to, but didn't because\nof a bug and complicating the tests unnecessarily).but then as usual I\ndidn't document it well, apologize for that.\n\n`root` is called that way because it was meant to be a ceiling of\nsorts and used as a safetynet (like GIT_CEILING in the test suite) to\nblock the tests in this file for going up one more level and using the\ndefault git repository from the suite by mistake.  That is also why it\nis owned by root.\n\nof course later I find out that for it to really stop the walking it\nneeded a .git on its own and to create one I needed to do it as root\nwhich I didn't even attempt to do until patch 3 (at that time too, I\nwas thinking maybe I could get patch 1 and 2 ready first, so my name\nwouldn't be on every git update and one of the reasons why nobody can\nget anything merged into next)\n\none option would be to consolidate its use with the root repository\nthat gets created in patch 3, which I could have done originally\ninstead of just using the ones you provided almost AS-IS, or as you\npointed out we could remove the safety net since it is not needed and\nit is buggy anyway.\n\nwill remove the chown in v5 otherwise but I think the plan above\nshouldn't be that intrusive and might be better.\n\nCarlo\n"},{"id":"455143","messageId":"xmqqh75w50w3.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspjppJh3+obLoNpP8ckHz=-0G=MEUUBHnrab6=Znv+RiUg@mail.gmail.com","subject":"Re: [PATCH v4 1/3] t: regression git needs safe.directory when using sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-11T01:11:24Z","receivedAt":"2022-05-11T01:11:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> one option would be to consolidate its use with the root repository\n> that gets created in patch 3, which I could have done originally\n> instead of just using the ones you provided almost AS-IS, or as you\n> pointed out we could remove the safety net since it is not needed and\n> it is buggy anyway.\n\nI agree that there is no point to chown the directory, especially if\nit does not offer any additional safety of any sort.  And quite\nhonstly, a test that is designed to be run ONLY in a very controlled\nCI environment, it does not need one that complicates the tests.\n\nThanks.\n"},{"id":"455153","messageId":"CAPUEspiDeDm1p==H+yNq-s1cNyCyo8qOdqE20d7F4MVBi0thHw@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqv8ud5741.fsf@gitster.g","subject":"Re: [PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-11T07:34:02Z","receivedAt":"2022-05-11T07:34:23Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, May 10, 2022 at 3:57 PM Junio C Hamano <gitster@pobox.com> wrote:\n> > Because of compatibility with sudo, the code assumes that uid_t is an\n> > unsigned integer type (which is not required by the standard) but is used\n> > that way in their codebase to generate SUDO_UID.\n>\n> Heh, that is a good point.\n\nexcept it is an implementation detail we can't control, and that we\nhave no way to test for (at least yet and definitely in these series)\n\njust because sudo upstream does this, doesn't mean the sudo that was\nbuilt in that specific system does as well, and because strto*l will\nsilently convert a value from one sign to another it might even \"do\nthe right thing\" (tm) even when a signed uid_t exist and a negative\none is valid.\n\nbut since we are using a larger integer type to hold those values we\nare especially at risk of misbehaving when uid_t is signed because we\ndidn't want to use atoi (and really couldn't safely).\n\nsome systems provide UID_T_MAX as means to figure out (both if it is\nsigned or not and to truncate safely), and I presume there are others\nwhere you can get that value at runtime with something like getconf(),\nbut as you pointed out all that is moot if we still run as root so has\nbeen punted from this series and all that is left are these documented\nissues, which I meant to get to and fix ASAP (but with changes that\nwill be more intrusive and wouldn't be safe for maint), but that I\nalso want to leave clearly visible as bus factor protection.\n\n> > +When git tries to check for ownership of git repositories, it will\n> > +obviously do so with the uid of the user that is running git itself,\n>\n> We do not need \"obviously\" here, but this has overlap with the\n> beginning part of the safe.directory explanation, so I would\n> probably suggest rewriting it altogether.\n\nobviously\n\n> > +but if git is running as root, in a platform that provides sudo and is\n> > +not Windows, it will check first if it might have been started through\n>\n> Does Windows provide sudo that leaves the original user in SUDO_UID\n> (I doubt it)?  If not, then \"on a platform that provides sudo, it will\"\n> would be sufficient.\n\nAt least my windows box does not, but dscho's somehow had and so that\nline was added at his request[1] after he wasted so much time trying\nto get this to work and realized the function where SUDO_UID logic\nresides doesn't even exist in a Windows build.\n\nWhile I think it is probably ok to go, something that would save\nsomeone else that trouble is probably worth having one way or another,\nespecially since he wasn't the only one while reviewing[2] this code,\nthat got it wrong, either.\n\n> > +If that is not what you would prefer and want git to only trust\n> > +repositories that are owned by root instead, then you should remove\n> > +the `SUDO_UID` variable from root's environment.\n>\n> s/should/can/.  But otherwise this is excellent.\n\nIt weakens the message I wanted to apply to this as being a way to\nsignal intention, and also being kind of the \"official\" way to do so\nfor the future, but I agree it might be premature and it is obviously\nnot that relevant once the next thing we might add is your code that\nfixes the \"regression\" and allows both root and SUDO_UID to work for\nthis code.\n\n> > diff --git a/git-compat-util.h b/git-compat-util.h\n> > index 63ba89dd31..754cd90d43 100644\n> > --- a/git-compat-util.h\n> > +++ b/git-compat-util.h\n> > @@ -393,12 +393,64 @@ static inline int git_offset_1st_component(const char *path)\n> >  #endif\n> >\n> >  #ifndef is_path_owned_by_current_user\n> > +\n> > +#ifdef __TANDEM\n> > +#define ROOT_UID 65535\n> > +#else\n> > +#define ROOT_UID 0\n> > +#endif\n> > +\n> > +/*\n> > + * This helper function overrides a ROOT_UID with the one provided by\n> > + * an environment variable, do not use unless the original user is\n> > + * root or could be used as means to escalate to root privileges.\n>\n> I do not understand the \"or could be used ...\" at all.  If the\n> original user obtained from geteuid() is not root, then no matter\n> what we do to *id here in this function, we won't let you gain the\n> root privilege.  The system won't let us give you the root privilege\n> because we (Git) are running as a normal user.\n\nIt is just there to explain the risks of using this function (which is\nvery visible) somewhere else, as well as to explain why it is only\nmeant to be used in a process running as root.\n\n> Or do you mean\n>\n>         Do not use this function when\n>\n>          (1) geteuid() did not say we are running as 'root', or\n>          (2) using this function will compromise the system.\n>\n> Then I can sort-of understand it, but (2) is a too obvious thing to\n> say.\n\nAs usual I like your wording of it better, and yes I agree it is\nobvious but since this function is very visible (which is not\nnecessary) and it is going to sit there in several maint releases, it\nmight not be that all unwarranted IMHO.\n\n> > + * PORTABILITY WARNING:\n> > + * This code assumes uid_t is unsigned because that is what sudo does.\n> > + * If your uid_t type is signed and all your ids are positive then it\n> > + * should all work fine, but need to make sure sudo never generates a\n> > + * value higher than what can be represented by your uid_t type or a\n> > + * negative value or it will trigger wraparound bugs.\n>\n> \"sudo\" generating a value higher than what uid_t can represent in\n> SUDO_UID *is* a bug that we shouldn't have to worry about.\n> Otherwise \"sudo\" as a tool would be unusable by folks with higher\n> UID on their system.\n\nnot necessarily; that system might had decided to use negative uids\ninstead of changing to unsigned and everything will still work, but\nyou are correct that in that case sudo printing the uid_t with \"%u\" is\na bug in that sudo and should be fixed there, but the irony is that if\nfixed, would then cause a bug on our side since we assume uid was\nalways positive and was printed with \"%u\".\n\nthis whole message is there just to try to explain the portability\nissue that having signed uid_t might trigger and that would be\nunlikely to happen in real life as an alternative to try to do\nsomething about it (like I did in previous versions), or plainly\nrefusing to run like you proposed (at least NONSTOP seems to have\nsigned uid_t), specially considering this is in a maint track,\n\nI was thinking it might be something better done (in the future) and\nwith all the portability bits hidden away in a proper compat file\ninstead of here.\n\n> In their implementation of \"sudo\", they must have done getuid(),\n> stored the value in uid_t and formatted it into a string.  If they\n> lost precision there by wrapping around or truncating, we can do\n> nothing about it, but the thing is, we cannot even tell.\n\nexactly, but we can warn the users that the problems they might have\nwith this feature might be because of that, and the information they\nwill provide could guide us into implementing a more portable version\nof this code in the future.\n\nand meanwhile, they might be able to keep a local patch which would be\nreally simple to write on their side.\n\n> > + * If that happens the uid used might be incorrect and then trigger\n> > + * an access error from the filesystem itself.\n>\n> If uid we are extracting is incorrect, Git will fail to refuse\n> access, the access is done as 'root', and filesystem level safety\n> will not trigger.\n\nMy bad, I didn't mean that the filesystem will trigger the error, but\nthat we might fail to match the uid_t we got from the filesystem with\nthe one we parsed from uid_t and therefore fail to allow access.\n\nHopefully that mismatch would be easy to spot as well because of a\ncompiler warning (like -Wsign-compare), or we might get lucky and\nmight even work (ex: sizeof(long) == sizeof(uid_t))\n\n> The end result is that I run \"sudo git describe\"\n> in your repository and instead of getting refused, because our \"sudo\"\n> was broken and SUDO_UID had your numeric uid, I execute \"git\" as root\n> in your repository.\n\nThat shouldn't happen unless the overflow was big enough to trigger an\nERANGE though, which also means uid_t would be much larger than the\nexpected uint32_t it seems to have almost everywhere I looked.\n\n> IOW, this change is meant to make it slightly convenient to allow\n> access to one's own stuff, but it got a bit more convenient by\n> allowing me access to my own stuff plus yours ;-)\n\nWell, you said before that since we are running as root you can\nalready have access to mine so it shouldn't matter ;)\n\n> > + * In the unlikely scenario this happened to you, and that is how you\n> > + * got to this message, we would like to know about it by letting us\n> > + * now with an email to git@vger.kernel.org indicating which platform,\n> > + * you are running on and which version of sudo you used to see if we\n> > + * can provide you a patch that would prevent this issue in the future.\n>\n> Nice.  What message does the reporter see?\n\nwhen using `sudo git status` a rejection of access to the directory they own\n\n> > + */\n> > +static inline void extract_id_from_env(const char *env, uid_t *id)\n> > +{\n> > +     const char *real_uid = getenv(env);\n> > +\n> > +     /* discard anything empty to avoid a more complex check below */\n> > +     if (real_uid && *real_uid) {\n> > +             char *endptr = NULL;\n> > +             unsigned long env_id;\n> > +\n> > +             errno = 0;\n> > +             /* silent overflow errors could trigger a bug below */\n>\n> What \"bug\" are we referring to?\n\nAll of them, the ones we decided to ignore because they are irrelevant\nwhen running as root, and the ones that are documented in the long\nparagraph above.\n\nCarlo\n\n[1] https://lore.kernel.org/git/nycvar.QRO.7.76.6.2205051545370.355@tvgsbejvaqbjf.bet/\n[2] https://lore.kernel.org/git/CAPUEspitAQrEjMpUyw8e2pyT1MT+h_dO5wSU0wWDWTqSye5TwA@mail.gmail.com/\n"},{"id":"455160","messageId":"CAPUEspiJSn5onUDpGQOtP7-51F87SfKRkcW+RC693EOboymnPQ@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqczgl56fi.fsf@gitster.g","subject":"Re: [PATCH v4 3/3] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-11T14:04:00Z","receivedAt":"2022-05-11T14:04:21Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Tue, May 10, 2022 at 4:11 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n>\n> > Note that the specific test that documents that after the previous\n> > changes, it is no longer possible for root (if obtained through sudo)\n> > to NOT add an exception or NOT need a \"workaround\" to be able to run git\n> > commands in a repository owned by thyself, is marked as a regression\n> > and is expected to be fixed with a future change, which hasn't been\n> > provided yet and that is not part of this series.\n>\n> Do you mean \"you can easily unset SUDO_UID to access root-owned\n> repositories as root\"?  Ahh, no, \"after tentatively becoming root,\n> you can access your own (via SUDO_UID) and root-owned repositories\"\n> is what you meant, I think.  I think that is reasonable to stop the\n> current round before adding the support for it.\n\nI thought so too, but now I am not sure anymore; it would seem this is\na \"regression\" worth fixing by some (especially since there is little\nappetite for behaviour changes since the last CVE that had a \"fixup\"\non top) and the code is available to do so, so will add it as an\n\"optional\" patch on top and then we can decide.\n\n> > --- /dev/null\n> > +++ b/t/lib-sudo.sh\n> > @@ -0,0 +1,12 @@\n> > +# Helpers for running git commands under sudo.\n> > +\n> > +# Runs a scriplet passed through stdin under sudo.\n> > +run_with_sudo () {\n> > +     local ret\n> > +     local RUN=\"$TEST_DIRECTORY/$$.sh\"\n> > +     write_script \"$RUN\" \"$TEST_SHELL_PATH\"\n> > +     sudo \"$TEST_SHELL_PATH\" -c \"\\\"$RUN\\\"\"\n>\n> This is not wrong per-se, but I think\n>\n>         sudo \"$RUN\"\n>\n> would be sufficient, wouldn't it?\n\nonly because currently we rely in a sudo that defaults to \"-s\" and\nSHELL should be TEST_SHELL_PATH, but that wasn't explicitly tested by\nthe prerequisite, and so this just makes sure we ALWAYS use the right\nshell, even if sudo might not want to normally.\n\nBTW, sudo IS very opinionated, and just like it can ignore PATH when\nit thinks that is the most secure option, can also ignore the #! line\nin a shell script and use a more secure SHELL for the same reason, or\neven not run ANY shell script, so by doing it this convoluted and\nackward way (as explained in the commit message) we ensure it works,\nand works the right way, and is indeed how I was planning to \"fix\" the\n'can we use it also when sudo doesn't default to \"-s\"', which is\nobviously not part of this series, but a future one that should also\nimprove coverage for this test both in CI and for people brave enough\nto try to run it locally.\n\nI guess I will remove it in v5 and which seems better again as an RFC\nto make sure we can iron out all remaining controversial things, but\nthanks again for your thorough review.\n\nCarlo\n"},{"id":"455161","messageId":"xmqqtu9wm7zj.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspiDeDm1p==H+yNq-s1cNyCyo8qOdqE20d7F4MVBi0thHw@mail.gmail.com","subject":"Re: [PATCH v4 2/3] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-11T14:58:24Z","receivedAt":"2022-05-11T14:59:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n>> Does Windows provide sudo that leaves the original user in SUDO_UID\n>> (I doubt it)?  If not, then \"on a platform that provides sudo, it will\"\n>> would be sufficient.\n>\n> At least my windows box does not, but dscho's somehow had and so that\n> line was added at his request[1] after he wasted so much time trying\n> to get this to work and realized the function where SUDO_UID logic\n> resides doesn't even exist in a Windows build.\n\nAhh, of course.  \n\nI forgot that this patch sent into is_path_owned_by_current_uid(),\nas a UID as a value of some integer type is not a thing on Windows.\nOK, so it does need to be as you wrote to mean \"not on Windows, and\nwith 'sudo' that uses 'SUDO_UID' to record from whom 'root' came\".\n\nOK.\n\n>> > + * In the unlikely scenario this happened to you, and that is how you\n>> > + * got to this message, we would like to know about it by letting us\n>> > + * now with an email to git@vger.kernel.org indicating which platform,\n>> > + * you are running on and which version of sudo you used to see if we\n>> > + * can provide you a patch that would prevent this issue in the future.\n>>\n>> Nice.  What message does the reporter see?\n>\n> when using `sudo git status` a rejection of access to the directory they own\n\nIt may have been obvious to who wrote the above comment, but it was\nnot, at least to me.\n\n>> > + */\n>> > +static inline void extract_id_from_env(const char *env, uid_t *id)\n>> > +{\n>> > +     const char *real_uid = getenv(env);\n>> > +\n>> > +     /* discard anything empty to avoid a more complex check below */\n>> > +     if (real_uid && *real_uid) {\n>> > +             char *endptr = NULL;\n>> > +             unsigned long env_id;\n>> > +\n>> > +             errno = 0;\n>> > +             /* silent overflow errors could trigger a bug below */\n>>\n>> What \"bug\" are we referring to?\n>\n> All of them, the ones we decided to ignore because they are irrelevant\n> when running as root, and the ones that are documented in the long\n> paragraph above.\n\nLikewise.  It did not click \"a bug below\" referred to \"your sudo is\nbehaving in a way different from what we expected\".\n\nThanks.\n"},{"id":"455164","messageId":"xmqqh75wm6jl.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspiJSn5onUDpGQOtP7-51F87SfKRkcW+RC693EOboymnPQ@mail.gmail.com","subject":"Re: [PATCH v4 3/3] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-11T15:29:34Z","receivedAt":"2022-05-11T15:29:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n>> > --- /dev/null\n>> > +++ b/t/lib-sudo.sh\n>> > @@ -0,0 +1,12 @@\n>> > +# Helpers for running git commands under sudo.\n>> > +\n>> > +# Runs a scriplet passed through stdin under sudo.\n>> > +run_with_sudo () {\n>> > +     local ret\n>> > +     local RUN=\"$TEST_DIRECTORY/$$.sh\"\n>> > +     write_script \"$RUN\" \"$TEST_SHELL_PATH\"\n>> > +     sudo \"$TEST_SHELL_PATH\" -c \"\\\"$RUN\\\"\"\n>>\n>> This is not wrong per-se, but I think\n>>\n>>         sudo \"$RUN\"\n>>\n>> would be sufficient, wouldn't it?\n>\n> only because currently we rely in a sudo that defaults to \"-s\" and\n> SHELL should be TEST_SHELL_PATH, but that wasn't explicitly tested by\n> the prerequisite, and so this just makes sure we ALWAYS use the right\n> shell, even if sudo might not want to normally.\n\nAh, OK.  So giving \"$TEST_SHELL_PATH\" to write_script and then\nrunning the resulting script explicitly with \"$TEST_SHELL_PATH\" is\nbelt-and-suspenders kind of defensiveness.  This was puzzling\nwithout explanation, but starts making sense when explained.\n\nThanks.\n\n"},{"id":"455246","messageId":"20220513010020.55361-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220510174616.18629-1-carenas@gmail.com","subject":"[PATCH v5 0/4] fix `sudo make install` regression in maint","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-13T01:00:16Z","receivedAt":"2022-05-13T01:00:43Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"A reroll for cb/path-owner-check-with-sudo which should hopefully cover\nfor all feedback plus an extra (optional) patch to implement a fix for\nthe \"regression\" that this introduces\n\nA range-diff against v4 provided below to easy review but the only code\nchanges come from the 4th patch which might be ironically the less\ncontroversial even if not strictly needed.\n\nThe tests are not enabled by default, but a run of this on top of seen\nthat had an extra patch to enable them shows no failures[1].  Either way\nthey are only expected to run in the macOS agents because of the sudo\nconfiguration that is needed, and which will require additional changes\nto improve coverage.\n\nCarlo Marcelo Arenas Belón (4):\n  t: regression git needs safe.directory when using sudo\n  git-compat-util: avoid failing dir ownership checks if running\n    privileged\n  t0034: add negative tests and allow git init to mostly work under sudo\n  git-compat-util: allow root to access both SUDO_UID and root owned\n\n Documentation/config/safe.txt  | 14 +++++\n git-compat-util.h              | 58 ++++++++++++++++++++-\n t/lib-sudo.sh                  | 15 ++++++\n t/t0034-root-safe-directory.sh | 93 ++++++++++++++++++++++++++++++++++\n 4 files changed, 179 insertions(+), 1 deletion(-)\n create mode 100644 t/lib-sudo.sh\n create mode 100755 t/t0034-root-safe-directory.sh\n\n[1] https://github.com/carenas/git/actions/runs/2316684806\n-- \n1:  0096bb0968f ! 1:  2f17307e1a9 t: regression git needs safe.directory when using sudo\n    @@ Commit message\n           $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n     \n         The test file also uses at least one initial \"setup\" test that creates\n    -    a parallel execution directory, while ignoring the repository created\n    -    by the test framework.\n    +    a parallel execution directory under the \"root\" sub directory, which\n    +    should be used as top level directory for all repositories that are\n    +    used in this test file.  Unlike all other tests the repository provided\n    +    by the test framework should go unused.\n     \n         Special care should be taken when invoking commands through sudo, since\n         the environment is otherwise independent from what the test framework\n    @@ t/t0034-root-safe-directory.sh (new)\n     +test_expect_success SUDO 'setup' '\n     +\tsudo rm -rf root &&\n     +\tmkdir -p root/r &&\n    -+\tsudo chown root root &&\n     +\t(\n     +\t\tcd root/r &&\n     +\t\tgit init\n2:  7ba248dace4 ! 2:  ccaa3f3c71d git-compat-util: avoid failing dir ownership checks if running privileged\n    @@ Commit message\n         that way in their codebase to generate SUDO_UID.  In systems where uid_t\n         is signed, sudo might be also patched to NOT be unsigned and that might\n         be able to trigger an edge case and a bug (as described in the code), but\n    -    it is considered unlikely to be triggered, and even when it does the code\n    -    would just safely fail, so there is no attempt either to detect it or\n    -    prevent it in the code, which might need to be changed in the future.\n    +    it is considered unlikely to happen and even if it does, the code would\n    +    just mostly fail safely, so there was no attempt either to detect it or\n    +    prevent it by the code, which is something that might change in the future,\n    +    based on expected user feedback.\n     \n         Reported-by: Guy Maurel <guy.j@maurel.de>\n         Helped-by: SZEDER Gábor <szeder.dev@gmail.com>\n    @@ Documentation/config/safe.txt: directory was listed in the `safe.directory` list\n      initialize your list with an empty value before listing the repositories\n      that you deem safe.\n     ++\n    -+When git tries to check for ownership of git repositories, it will\n    -+obviously do so with the uid of the user that is running git itself,\n    -+but if git is running as root, in a platform that provides sudo and is\n    -+not Windows, it will check first if it might have been started through\n    -+it, and if that is the case, will use the uid of the user that invoked\n    -+sudo instead.\n    ++As explained, Git only allows you to access repositories owned by\n    ++yourself, i.e. the user who is running Git, by default.  When Git\n    ++is running as 'root' in a non Windows platform that provides sudo,\n    ++ however, git checks the SUDO_UID environment variable that sudo creates\n    ++and will allow access to the uid recorded as its value instead.\n    ++This is to make it easy to perform a common sequence during installation\n    ++\"make && sudo make install\".  A git process running under 'sudo' runs as\n    ++'root' but the 'sudo' command exports the environment variable to record\n    ++which id the original user has.\n     +If that is not what you would prefer and want git to only trust\n    -+repositories that are owned by root instead, then you should remove\n    -+the `SUDO_UID` variable from root's environment.\n    ++repositories that are owned by root instead, then you must remove\n    ++the `SUDO_UID` variable from root's environment before invoking git.\n     \n      ## git-compat-util.h ##\n     @@ git-compat-util.h: static inline int git_offset_1st_component(const char *path)\n    @@ git-compat-util.h: static inline int git_offset_1st_component(const char *path)\n     +#endif\n     +\n     +/*\n    -+ * This helper function overrides a ROOT_UID with the one provided by\n    -+ * an environment variable, do not use unless the original user is\n    -+ * root or could be used as means to escalate to root privileges.\n    ++ * Do not use this function when\n    ++ * (1) geteuid() did not say we are running as 'root', or\n    ++ * (2) using this function will compromise the system.\n     + *\n     + * PORTABILITY WARNING:\n     + * This code assumes uid_t is unsigned because that is what sudo does.\n     + * If your uid_t type is signed and all your ids are positive then it\n    -+ * should all work fine, but need to make sure sudo never generates a\n    -+ * value higher than what can be represented by your uid_t type or a\n    -+ * negative value or it will trigger wraparound bugs.\n    -+ *\n    -+ * If that happens the uid used might be incorrect and then trigger\n    -+ * an access error from the filesystem itself.\n    -+ *\n    ++ * should all work fine.\n    ++ * If your version of sudo uses negative values for uid_t or it is\n    ++ * buggy and return an overflowed value in SUDO_UID, then git might\n    ++ * fail to grant access to your repository properly or even mistakenly\n    ++ * grant access to someone else.\n     + * In the unlikely scenario this happened to you, and that is how you\n    -+ * got to this message, we would like to know about it by letting us\n    -+ * now with an email to git@vger.kernel.org indicating which platform,\n    -+ * you are running on and which version of sudo you used to see if we\n    -+ * can provide you a patch that would prevent this issue in the future.\n    ++ * got to this message, we would like to know about it; so sent us an\n    ++ * email to git@vger.kernel.org indicating which platform you are\n    ++ * using and which version of sudo, so we can improve this logic and\n    ++ * maybe provide you with a patch that would prevent this issue again\n    ++ * in the future.\n     + */\n     +static inline void extract_id_from_env(const char *env, uid_t *id)\n     +{\n    @@ git-compat-util.h: static inline int git_offset_1st_component(const char *path)\n     +\t\tunsigned long env_id;\n     +\n     +\t\terrno = 0;\n    -+\t\t/* silent overflow errors could trigger a bug below */\n    ++\t\t/* silent overflow errors could trigger a bug here */\n     +\t\tenv_id = strtoul(real_uid, &endptr, 10);\n     +\t\tif (!*endptr && !errno)\n     +\t\t\t*id = env_id;\n3:  1ed06acc93c ! 3:  2a9c0c20e08 t0034: add negative tests and allow git init to mostly work under sudo\n    @@ Commit message\n         Add additional negative tests as suggested by Junio and that use a\n         new workspace that is owned by root.\n     \n    -    Note that the specific test that documents that after the previous\n    -    changes, it is no longer possible for root (if obtained through sudo)\n    -    to NOT add an exception or NOT need a \"workaround\" to be able to run git\n    -    commands in a repository owned by thyself, is marked as a regression\n    -    and is expected to be fixed with a future change, which hasn't been\n    -    provided yet and that is not part of this series.\n    +    Document a regression that was introduced by previous commits where\n    +    root won't be able anymore to access directories they own unless\n    +    SUDO_UID is removed from their environment.\n     \n    -    As described in the comments from the test itself, at least one of the\n    -    documented workarounds could fail if sudo doesn't allow root to call sudo\n    -    or if root is not in sudoers, but that is very unlikely, and more\n    -    importantly actually not what is provided by the currently supported sudo\n    -    configuration this test already relies on and therefore adding a way to\n    -    validate it works in the prerequisite has been punted for now.\n    +    The tests document additional ways that this new restriction could\n    +    be worked around and the documentation explains why it might be instead\n    +    considered a feature, but a \"fix\" is planned for a future change.\n     \n         Helped-by: Junio C Hamano <gitster@pobox.com>\n         Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n    @@ t/lib-sudo.sh (new)\n     +\tlocal ret\n     +\tlocal RUN=\"$TEST_DIRECTORY/$$.sh\"\n     +\twrite_script \"$RUN\" \"$TEST_SHELL_PATH\"\n    ++\t# avoid calling \"$RUN\" directly so sudo doesn't get a chance to\n    ++\t# override the shell, add aditional restrictions or even reject\n    ++\t# running the script because its security policy deem it unsafe\n     +\tsudo \"$TEST_SHELL_PATH\" -c \"\\\"$RUN\\\"\"\n     +\tret=$?\n     +\trm -f \"$RUN\"\n    @@ t/t0034-root-safe-directory.sh: test_expect_success SUDO 'sudo git status as ori\n     +\t)\n     +'\n     +\n    -+test_expect_failure SUDO 'can access with sudo if root' '\n    ++test_expect_success 'can access if addressed explicitly' '\n     +\t(\n     +\t\tcd root/p &&\n    -+\t\tsudo git status\n    ++\t\tGIT_DIR=.git GIT_WORK_TREE=. git status\n     +\t)\n     +'\n     +\n    -+test_expect_success SUDO 'can access with sudo using a workaround' '\n    -+\t# run sudo twice; would fail if root is not in sudoers\n    ++test_expect_failure SUDO 'can access with sudo if root' '\n     +\t(\n     +\t\tcd root/p &&\n    -+\t\tsudo sudo git status\n    -+\t) &&\n    -+\t# provide explicit GIT_DIR\n    ++\t\tsudo git status\n    ++\t)\n    ++'\n    ++\n    ++test_expect_success SUDO 'can access with sudo if root by removing SUDO_UID' '\n     +\t(\n     +\t\tcd root/p &&\n     +\t\trun_with_sudo <<-END\n    -+\t\t\tGIT_DIR=.git &&\n    -+\t\t\tGIT_WORK_TREE=. &&\n    -+\t\t\texport GIT_DIR GIT_WORK_TREE &&\n    ++\t\t\tunset SUDO_UID &&\n     +\t\t\tgit status\n     +\t\tEND\n    -+\t) &&\n    -+\t# discard SUDO_UID\n    ++\t)\n    ++'\n    ++\n    ++test_lazy_prereq SUDO_SUDO '\n    ++\tsudo sudo id -u >u &&\n    ++\tid -u root >r &&\n    ++\ttest_cmp u r\n    ++'\n    ++\n    ++test_expect_success SUDO_SUDO 'can access with sudo abusing SUDO_UID' '\n     +\t(\n     +\t\tcd root/p &&\n    -+\t\trun_with_sudo <<-END\n    -+\t\t\tunset SUDO_UID &&\n    -+\t\t\tgit status\n    -+\t\tEND\n    ++\t\tsudo sudo git status\n     +\t)\n     +'\n     +\n-:  ----------- > 4:  8486777a417 git-compat-util: allow root to access both SUDO_UID and root owned\n--\n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455247","messageId":"20220513010020.55361-2-carenas@gmail.com","threadId":"57799","inReplyTo":"20220513010020.55361-1-carenas@gmail.com","subject":"[PATCH v5 1/4] t: regression git needs safe.directory when using sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-13T01:00:17Z","receivedAt":"2022-05-13T01:00:45Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Originally reported after release of v2.35.2 (and other maint branches)\nfor CVE-2022-24765 and blocking otherwise harmless commands that were\ndone using sudo in a repository that was owned by the user.\n\nAdd a new test script with very basic support to allow running git\ncommands through sudo, so a reproduction could be implemented and that\nuses only `git status` as a proxy of the issue reported.\n\nNote that because of the way sudo interacts with the system, a much\nmore complete integration with the test framework will require a lot\nmore work and that was therefore intentionally punted for now.\n\nThe current implementation requires the execution of a special cleanup\nfunction which should always be kept as the last \"test\" or otherwise\nthe standard cleanup functions will fail because they can't remove\nthe root owned directories that are used.  This also means that if\nfailures are found while running, the specifics of the failure might\nnot be kept for further debugging and if the test was interrupted, it\nwill be necessary to clean the working directory manually before\nrestarting by running:\n\n  $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n\nThe test file also uses at least one initial \"setup\" test that creates\na parallel execution directory under the \"root\" sub directory, which\nshould be used as top level directory for all repositories that are\nused in this test file.  Unlike all other tests the repository provided\nby the test framework should go unused.\n\nSpecial care should be taken when invoking commands through sudo, since\nthe environment is otherwise independent from what the test framework\nsetup and might have changed the values for HOME, SHELL and dropped\nseveral relevant environment variables for your test.  Indeed `git status`\nwas used as a proxy because it doesn't even require commits in the\nrepository to work and usually doesn't require much from the environment\nto run, but a future patch will add calls to `git init` and that will\nfail to honor the default branch name, unless that setting is NOT\nprovided through an environment variable (which means even a CI run\ncould fail that test if enabled incorrectly).\n\nA new SUDO prerequisite is provided that does some sanity checking\nto make sure the sudo command that will be used allows for passwordless\nexecution as root without restrictions and doesn't mess with git's\nexecution path.  This matches what is provided by the macOS agents that\nare used as part of GitHub actions and probably nowhere else.\n\nMost of those characteristics make this test mostly only suitable for\nCI, but it might be executed locally if special care is taken to provide\nfor all of them in the local configuration and maybe making use of the\nsudo credential cache by first invoking sudo, entering your password if\nneeded, and then invoking the test with:\n\n  $ GIT_TEST_ALLOW_SUDO=YES ./t0034-root-safe-directory.sh\n\nIf it fails to run, then it means your local setup wouldn't work for the\ntest because of the configuration sudo has or other system settings, and\nthings that might help are to comment out sudo's secure_path config, and\nmake sure that the account you are using has no restrictions on the\ncommands it can run through sudo, just like is provided for the user in\nthe CI.\n\nFor example (assuming a username of marta for you) something probably\nsimilar to the following entry in your /etc/sudoers (or equivalent) file:\n\n  marta\tALL=(ALL:ALL) NOPASSWD: ALL\n\nReported-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t0034-root-safe-directory.sh | 44 ++++++++++++++++++++++++++++++++++\n 1 file changed, 44 insertions(+)\n create mode 100755 t/t0034-root-safe-directory.sh\n\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nnew file mode 100755\nindex 00000000000..f6a5d63ff41\n--- /dev/null\n+++ b/t/t0034-root-safe-directory.sh\n@@ -0,0 +1,44 @@\n+#!/bin/sh\n+\n+test_description='verify safe.directory checks while running as root'\n+\n+. ./test-lib.sh\n+\n+if [ \"$GIT_TEST_ALLOW_SUDO\" != \"YES\" ]\n+then\n+\tskip_all=\"You must set env var GIT_TEST_ALLOW_SUDO=YES in order to run this test\"\n+\ttest_done\n+fi\n+\n+test_lazy_prereq SUDO '\n+\tsudo -n id -u >u &&\n+\tid -u root >r &&\n+\ttest_cmp u r &&\n+\tcommand -v git >u &&\n+\tsudo command -v git >r &&\n+\ttest_cmp u r\n+'\n+\n+test_expect_success SUDO 'setup' '\n+\tsudo rm -rf root &&\n+\tmkdir -p root/r &&\n+\t(\n+\t\tcd root/r &&\n+\t\tgit init\n+\t)\n+'\n+\n+test_expect_failure SUDO 'sudo git status as original owner' '\n+\t(\n+\t\tcd root/r &&\n+\t\tgit status &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+# this MUST be always the last test\n+test_expect_success SUDO 'cleanup' '\n+\tsudo rm -rf root\n+'\n+\n+test_done\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455248","messageId":"20220513010020.55361-3-carenas@gmail.com","threadId":"57799","inReplyTo":"20220513010020.55361-1-carenas@gmail.com","subject":"[PATCH v5 2/4] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-13T01:00:18Z","receivedAt":"2022-05-13T01:00:48Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"bdc77d1d685 (Add a function to determine whether a path is owned by the\ncurrent user, 2022-03-02) checks for the effective uid of the running\nprocess using geteuid() but didn't account for cases where that user was\nroot (because git was invoked through sudo or a compatible tool) and the\noriginal uid that repository trusted for its config was no longer known,\ntherefore failing the following otherwise safe call:\n\n  guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n  [sudo] password for guy:\n  fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n\nAttempt to detect those cases by using the environment variables that\nthose tools create to keep track of the original user id, and do the\nownership check using that instead.\n\nThis assumes the environment the user is running on after going\nprivileged can't be tampered with, and also adds code to restrict that\nthe new behavior only applies if running as root, therefore keeping the\nmost common case, which runs unprivileged, from changing, but because of\nthat, it will miss cases where sudo (or an equivalent) was used to change\nto another unprivileged user or where the equivalent tool used to raise\nprivileges didn't track the original id in a sudo compatible way.\n\nBecause of compatibility with sudo, the code assumes that uid_t is an\nunsigned integer type (which is not required by the standard) but is used\nthat way in their codebase to generate SUDO_UID.  In systems where uid_t\nis signed, sudo might be also patched to NOT be unsigned and that might\nbe able to trigger an edge case and a bug (as described in the code), but\nit is considered unlikely to happen and even if it does, the code would\njust mostly fail safely, so there was no attempt either to detect it or\nprevent it by the code, which is something that might change in the future,\nbased on expected user feedback.\n\nReported-by: Guy Maurel <guy.j@maurel.de>\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nHelped-by: Randall Becker <rsbecker@nexbridge.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSuggested-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/config/safe.txt  | 13 +++++++++\n git-compat-util.h              | 53 +++++++++++++++++++++++++++++++++-\n t/t0034-root-safe-directory.sh |  2 +-\n 3 files changed, 66 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex 6d764fe0ccf..c6ebd1674dd 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -26,3 +26,16 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`\n is set in system config and you want to re-enable this protection, then\n initialize your list with an empty value before listing the repositories\n that you deem safe.\n++\n+As explained, Git only allows you to access repositories owned by\n+yourself, i.e. the user who is running Git, by default.  When Git\n+is running as 'root' in a non Windows platform that provides sudo,\n+ however, git checks the SUDO_UID environment variable that sudo creates\n+and will allow access to the uid recorded as its value instead.\n+This is to make it easy to perform a common sequence during installation\n+\"make && sudo make install\".  A git process running under 'sudo' runs as\n+'root' but the 'sudo' command exports the environment variable to record\n+which id the original user has.\n+If that is not what you would prefer and want git to only trust\n+repositories that are owned by root instead, then you must remove\n+the `SUDO_UID` variable from root's environment before invoking git.\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 63ba89dd31d..e7cbfa65c9a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -393,12 +393,63 @@ static inline int git_offset_1st_component(const char *path)\n #endif\n \n #ifndef is_path_owned_by_current_user\n+\n+#ifdef __TANDEM\n+#define ROOT_UID 65535\n+#else\n+#define ROOT_UID 0\n+#endif\n+\n+/*\n+ * Do not use this function when\n+ * (1) geteuid() did not say we are running as 'root', or\n+ * (2) using this function will compromise the system.\n+ *\n+ * PORTABILITY WARNING:\n+ * This code assumes uid_t is unsigned because that is what sudo does.\n+ * If your uid_t type is signed and all your ids are positive then it\n+ * should all work fine.\n+ * If your version of sudo uses negative values for uid_t or it is\n+ * buggy and return an overflowed value in SUDO_UID, then git might\n+ * fail to grant access to your repository properly or even mistakenly\n+ * grant access to someone else.\n+ * In the unlikely scenario this happened to you, and that is how you\n+ * got to this message, we would like to know about it; so sent us an\n+ * email to git@vger.kernel.org indicating which platform you are\n+ * using and which version of sudo, so we can improve this logic and\n+ * maybe provide you with a patch that would prevent this issue again\n+ * in the future.\n+ */\n+static inline void extract_id_from_env(const char *env, uid_t *id)\n+{\n+\tconst char *real_uid = getenv(env);\n+\n+\t/* discard anything empty to avoid a more complex check below */\n+\tif (real_uid && *real_uid) {\n+\t\tchar *endptr = NULL;\n+\t\tunsigned long env_id;\n+\n+\t\terrno = 0;\n+\t\t/* silent overflow errors could trigger a bug here */\n+\t\tenv_id = strtoul(real_uid, &endptr, 10);\n+\t\tif (!*endptr && !errno)\n+\t\t\t*id = env_id;\n+\t}\n+}\n+\n static inline int is_path_owned_by_current_uid(const char *path)\n {\n \tstruct stat st;\n+\tuid_t euid;\n+\n \tif (lstat(path, &st))\n \t\treturn 0;\n-\treturn st.st_uid == geteuid();\n+\n+\teuid = geteuid();\n+\tif (euid == ROOT_UID)\n+\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\n+\treturn st.st_uid == euid;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex f6a5d63ff41..6b8ea5357f6 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -28,7 +28,7 @@ test_expect_success SUDO 'setup' '\n \t)\n '\n \n-test_expect_failure SUDO 'sudo git status as original owner' '\n+test_expect_success SUDO 'sudo git status as original owner' '\n \t(\n \t\tcd root/r &&\n \t\tgit status &&\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455249","messageId":"20220513010020.55361-4-carenas@gmail.com","threadId":"57799","inReplyTo":"20220513010020.55361-1-carenas@gmail.com","subject":"[PATCH v5 3/4] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-13T01:00:19Z","receivedAt":"2022-05-13T01:00:52Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Add a support library that provides one function that can be used\nto run a \"scriplet\" of commands through sudo and that helps invoking\nsudo in the slightly awkward way that is required to ensure it doesn't\nblock the call (if shell was allowed as tested in the prerequisite)\nand it doesn't run the command through a different shell than the one\nwe intended.\n\nAdd additional negative tests as suggested by Junio and that use a\nnew workspace that is owned by root.\n\nDocument a regression that was introduced by previous commits where\nroot won't be able anymore to access directories they own unless\nSUDO_UID is removed from their environment.\n\nThe tests document additional ways that this new restriction could\nbe worked around and the documentation explains why it might be instead\nconsidered a feature, but a \"fix\" is planned for a future change.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nHelped-by: Phillip Wood <phillip.wood123@gmail.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/lib-sudo.sh                  | 15 ++++++++\n t/t0034-root-safe-directory.sh | 62 ++++++++++++++++++++++++++++++++++\n 2 files changed, 77 insertions(+)\n create mode 100644 t/lib-sudo.sh\n\ndiff --git a/t/lib-sudo.sh b/t/lib-sudo.sh\nnew file mode 100644\nindex 00000000000..b4d7788f4e5\n--- /dev/null\n+++ b/t/lib-sudo.sh\n@@ -0,0 +1,15 @@\n+# Helpers for running git commands under sudo.\n+\n+# Runs a scriplet passed through stdin under sudo.\n+run_with_sudo () {\n+\tlocal ret\n+\tlocal RUN=\"$TEST_DIRECTORY/$$.sh\"\n+\twrite_script \"$RUN\" \"$TEST_SHELL_PATH\"\n+\t# avoid calling \"$RUN\" directly so sudo doesn't get a chance to\n+\t# override the shell, add aditional restrictions or even reject\n+\t# running the script because its security policy deem it unsafe\n+\tsudo \"$TEST_SHELL_PATH\" -c \"\\\"$RUN\\\"\"\n+\tret=$?\n+\trm -f \"$RUN\"\n+\treturn $ret\n+}\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex 6b8ea5357f6..a621f1ea5eb 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -3,6 +3,7 @@\n test_description='verify safe.directory checks while running as root'\n \n . ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-sudo.sh\n \n if [ \"$GIT_TEST_ALLOW_SUDO\" != \"YES\" ]\n then\n@@ -10,6 +11,12 @@ then\n \ttest_done\n fi\n \n+if ! test_have_prereq NOT_ROOT\n+then\n+\tskip_all=\"These tests do not support running as root\"\n+\ttest_done\n+fi\n+\n test_lazy_prereq SUDO '\n \tsudo -n id -u >u &&\n \tid -u root >r &&\n@@ -19,6 +26,12 @@ test_lazy_prereq SUDO '\n \ttest_cmp u r\n '\n \n+if ! test_have_prereq SUDO\n+then\n+\tskip_all=\"Your sudo/system configuration is either too strict or unsupported\"\n+\ttest_done\n+fi\n+\n test_expect_success SUDO 'setup' '\n \tsudo rm -rf root &&\n \tmkdir -p root/r &&\n@@ -36,6 +49,55 @@ test_expect_success SUDO 'sudo git status as original owner' '\n \t)\n '\n \n+test_expect_success SUDO 'setup root owned repository' '\n+\tsudo mkdir -p root/p &&\n+\tsudo git init root/p\n+'\n+\n+test_expect_success 'cannot access if owned by root' '\n+\t(\n+\t\tcd root/p &&\n+\t\ttest_must_fail git status\n+\t)\n+'\n+\n+test_expect_success 'can access if addressed explicitly' '\n+\t(\n+\t\tcd root/p &&\n+\t\tGIT_DIR=.git GIT_WORK_TREE=. git status\n+\t)\n+'\n+\n+test_expect_failure SUDO 'can access with sudo if root' '\n+\t(\n+\t\tcd root/p &&\n+\t\tsudo git status\n+\t)\n+'\n+\n+test_expect_success SUDO 'can access with sudo if root by removing SUDO_UID' '\n+\t(\n+\t\tcd root/p &&\n+\t\trun_with_sudo <<-END\n+\t\t\tunset SUDO_UID &&\n+\t\t\tgit status\n+\t\tEND\n+\t)\n+'\n+\n+test_lazy_prereq SUDO_SUDO '\n+\tsudo sudo id -u >u &&\n+\tid -u root >r &&\n+\ttest_cmp u r\n+'\n+\n+test_expect_success SUDO_SUDO 'can access with sudo abusing SUDO_UID' '\n+\t(\n+\t\tcd root/p &&\n+\t\tsudo sudo git status\n+\t)\n+'\n+\n # this MUST be always the last test\n test_expect_success SUDO 'cleanup' '\n \tsudo rm -rf root\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455250","messageId":"20220513010020.55361-5-carenas@gmail.com","threadId":"57799","inReplyTo":"20220513010020.55361-1-carenas@gmail.com","subject":"[PATCH v5 4/4] git-compat-util: allow root to access both SUDO_UID and root owned","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-13T01:00:20Z","receivedAt":"2022-05-13T01:01:04Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Previous changes introduced a regression which will prevent root for\naccessing repositories owned by thyself if using sudo because SUDO_UID\ntakes precedence.\n\nLoosen that restriction by allowing root to access repositories owned\nby both uid by default and without having to add a safe.directory\nexception.\n\nA previous workaround that was documented in the tests is no longer\nneeded so it has been removed together with its specially crafted\nprerequisite.\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n Documentation/config/safe.txt  |  5 +++--\n git-compat-util.h              | 15 ++++++++++-----\n t/t0034-root-safe-directory.sh | 15 +--------------\n 3 files changed, 14 insertions(+), 21 deletions(-)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex c6ebd1674dd..3128b132713 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -31,11 +31,12 @@ As explained, Git only allows you to access repositories owned by\n yourself, i.e. the user who is running Git, by default.  When Git\n is running as 'root' in a non Windows platform that provides sudo,\n  however, git checks the SUDO_UID environment variable that sudo creates\n-and will allow access to the uid recorded as its value instead.\n+and will allow access to the uid recorded as its value in addition to\n+the id from 'root'.\n This is to make it easy to perform a common sequence during installation\n \"make && sudo make install\".  A git process running under 'sudo' runs as\n 'root' but the 'sudo' command exports the environment variable to record\n which id the original user has.\n If that is not what you would prefer and want git to only trust\n-repositories that are owned by root instead, then you must remove\n+repositories that are owned by root instead, then you can remove\n the `SUDO_UID` variable from root's environment before invoking git.\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex e7cbfa65c9a..0a5a4ee7a9a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -420,9 +420,10 @@ static inline int git_offset_1st_component(const char *path)\n  * maybe provide you with a patch that would prevent this issue again\n  * in the future.\n  */\n-static inline void extract_id_from_env(const char *env, uid_t *id)\n+static inline int id_from_env_matches(const char *env, uid_t id)\n {\n \tconst char *real_uid = getenv(env);\n+\tint matches = 0;\n \n \t/* discard anything empty to avoid a more complex check below */\n \tif (real_uid && *real_uid) {\n@@ -432,9 +433,10 @@ static inline void extract_id_from_env(const char *env, uid_t *id)\n \t\terrno = 0;\n \t\t/* silent overflow errors could trigger a bug here */\n \t\tenv_id = strtoul(real_uid, &endptr, 10);\n-\t\tif (!*endptr && !errno)\n-\t\t\t*id = env_id;\n+\t\tif (!*endptr && !errno && (uid_t)env_id == id)\n+\t\t\tmatches = 1;\n \t}\n+\treturn matches;\n }\n \n static inline int is_path_owned_by_current_uid(const char *path)\n@@ -446,10 +448,13 @@ static inline int is_path_owned_by_current_uid(const char *path)\n \t\treturn 0;\n \n \teuid = geteuid();\n+\tif (st.st_uid == euid)\n+\t\treturn 1;\n+\n \tif (euid == ROOT_UID)\n-\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\t\treturn id_from_env_matches(\"SUDO_UID\", st.st_uid);\n \n-\treturn st.st_uid == euid;\n+\treturn 0;\n }\n \n #define is_path_owned_by_current_user is_path_owned_by_current_uid\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex a621f1ea5eb..ff311761289 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -68,7 +68,7 @@ test_expect_success 'can access if addressed explicitly' '\n \t)\n '\n \n-test_expect_failure SUDO 'can access with sudo if root' '\n+test_expect_success SUDO 'can access with sudo if root' '\n \t(\n \t\tcd root/p &&\n \t\tsudo git status\n@@ -85,19 +85,6 @@ test_expect_success SUDO 'can access with sudo if root by removing SUDO_UID' '\n \t)\n '\n \n-test_lazy_prereq SUDO_SUDO '\n-\tsudo sudo id -u >u &&\n-\tid -u root >r &&\n-\ttest_cmp u r\n-'\n-\n-test_expect_success SUDO_SUDO 'can access with sudo abusing SUDO_UID' '\n-\t(\n-\t\tcd root/p &&\n-\t\tsudo sudo git status\n-\t)\n-'\n-\n # this MUST be always the last test\n test_expect_success SUDO 'cleanup' '\n \tsudo rm -rf root\n-- \n2.36.1.371.g0fb0ef0c8d\n\n"},{"id":"455251","messageId":"xmqqee0ycjos.fsf@gitster.g","threadId":"57799","inReplyTo":"20220513010020.55361-4-carenas@gmail.com","subject":"Re: [PATCH v5 3/4] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-13T01:20:19Z","receivedAt":"2022-05-13T01:20:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> Add a support library that provides one function that can be used\n> to run a \"scriplet\" of commands through sudo and that helps invoking\n> sudo in the slightly awkward way that is required to ensure it doesn't\n> block the call (if shell was allowed as tested in the prerequisite)\n> and it doesn't run the command through a different shell than the one\n> we intended.\n>\n> Add additional negative tests as suggested by Junio and that use a\n> new workspace that is owned by root.\n>\n> Document a regression that was introduced by previous commits where\n> root won't be able anymore to access directories they own unless\n> SUDO_UID is removed from their environment.\n>\n> The tests document additional ways that this new restriction could\n> be worked around and the documentation explains why it might be instead\n> considered a feature, but a \"fix\" is planned for a future change.\n>\n> Helped-by: Junio C Hamano <gitster@pobox.com>\n> Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  t/lib-sudo.sh                  | 15 ++++++++\n>  t/t0034-root-safe-directory.sh | 62 ++++++++++++++++++++++++++++++++++\n>  2 files changed, 77 insertions(+)\n>  create mode 100644 t/lib-sudo.sh\n\nHeh.  I am a bit surprised that double sudo would become a separate\nprerequisite, instead of a new part of SUDO prerequisite.  After all\nwe expect from SUDO prerequisite quite a lot (e.g. most sane\ninstallatios facing end-users will futz with $PATH, but we require\nnot to do so to satisfy the SUDO prereq) and it is already very\nnarrowly targetted to a throw-away CI environment whose sudo\nbasically lets us do anything.\n\nBut that is not a serious enough \"thing\" to trigger a reroll.\n\nThis step looks good to me (others I'll comment later).\n\nThanks.\n"},{"id":"455289","messageId":"CAPUEspj1JTG2Ujuk4O6ogo6qEQEwe-2aHF8J95xjX+OpY4cenQ@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqee0ycjos.fsf@gitster.g","subject":"Re: [PATCH v5 3/4] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-14T14:36:16Z","receivedAt":"2022-05-14T14:36:39Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Thu, May 12, 2022 at 6:20 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Heh.  I am a bit surprised that double sudo would become a separate\n> prerequisite,\n\nIt is because it goes away in the optional patch 4, since it won't be\nneeded anymore after that.\nAlso, it shared the same test with the other 2 workarounds which moved\ninto their own (one as you suggested is more of a statement of policy\nthat says, git trusts the developer and doesn't check if --git-dir or\n--worktree (or equivalent means to explicitly identify those parts of\nyour repository) are used.\n\nand the other, was always \"special\" since it was documented as an\nindicator of what to do which could be considered a least privilege\nmarker as well.\n\nwithout the optional patch that brings it back, root MUST indicate\nthrough its use of that (or other \"workarounds\") that he really meant\nto access a directory owned by root, and will instead defalt (when\nappropriate) to use the id of the user that invoked sudo, which has\n(normally) less privilege.\n\n> of a new part of SUDO prerequisite.  After all\n> we expect from SUDO prerequisite quite a lot (e.g. most sane\n> installatios facing end-users will futz with $PATH, but we require\n> not to do so to satisfy the SUDO prereq) and it is already very\n> narrowly targetted to a throw-away CI environment whose sudo\n> basically lets us do anything.\n\njust because I didn't want this to become a bigger change that it was already\nindeed I'd been \"cutting\" it since the very beginning, by first\ndropping DOAS support and then avoiding moving things around so it\ncould be easy to backport.\n\nI think I can provide a version of it that might be able to work with\nless restrictions that it currently has, but that would get us into\nthe \"test framework integration\" that was specifically punted as well.\n\nCarlo\n"},{"id":"455301","messageId":"xmqqr14u7n4l.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspj1JTG2Ujuk4O6ogo6qEQEwe-2aHF8J95xjX+OpY4cenQ@mail.gmail.com","subject":"Re: [PATCH v5 3/4] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-15T16:54:02Z","receivedAt":"2022-05-15T16:54:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n> On Thu, May 12, 2022 at 6:20 PM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> Heh.  I am a bit surprised that double sudo would become a separate\n>> prerequisite,\n>\n> It is because it goes away in the optional patch 4, since it won't be\n> needed anymore after that.\n\nHmph, it may not be needed, but it should still work, in which case\nit probably is still worth testing, even with the optional patch #4.\n\nNo?\n"},{"id":"455302","messageId":"CAPUEsphNOf37WB_xUuRNdfcz1TRRsSocbUoCbrmA3OjS_BTpdw@mail.gmail.com","threadId":"57799","inReplyTo":"xmqqr14u7n4l.fsf@gitster.g","subject":"Re: [PATCH v5 3/4] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-05-15T19:21:55Z","receivedAt":"2022-05-15T19:22:13Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Sun, May 15, 2022 at 9:54 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Carlo Arenas <carenas@gmail.com> writes:\n>\n> > On Thu, May 12, 2022 at 6:20 PM Junio C Hamano <gitster@pobox.com> wrote:\n> >>\n> >> Heh.  I am a bit surprised that double sudo would become a separate\n> >> prerequisite,\n> >\n> > It is because it goes away in the optional patch 4, since it won't be\n> > needed anymore after that.\n>\n> Hmph, it may not be needed, but it should still work, in which case\n> it probably is still worth testing, even with the optional patch #4.\n\nJust because it works, it doesn't mean we have to test it.\n\nIMHO tests are better reserved for things that might not work or that\nshould work, so this gets in the same bucket than \"triple sudo\" would\ngo, and interestingly enough we could add that test without having to\nadd a new prerequisite too!\n\n> No?\n\nYour call, my assumption was (since this patch is part of this series,\nalbeit optional), that the \"double sudo\" need will be short lived and\ntherefore better not to have this test to begin with, or remove it as\nsoon as the need is gone, which in practice would be the time between\nwhen this series (without the optional patch) is released, and the\ntime that optional path gets released (maybe as part of another\nseries, since it might be dropped from this one).\n\nalternatively we can make it not optional, and then the test will\nNEVER be needed.\n\nCarlo\n"},{"id":"455305","messageId":"xmqqo7zy59p3.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEsphNOf37WB_xUuRNdfcz1TRRsSocbUoCbrmA3OjS_BTpdw@mail.gmail.com","subject":"Re: [PATCH v5 3/4] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-16T05:27:04Z","receivedAt":"2022-05-16T05:27:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n>> Hmph, it may not be needed, but it should still work, in which case\n>> it probably is still worth testing, even with the optional patch #4.\n>\n> Just because it works, it doesn't mean we have to test it.\n\nYes.  It all depends on the answer to this question: Is it\nreasonably expected that any half-way intelligent Git user would not\nbe surprised to learn that \"sudo sudo git status\" would be a way to\nwork on a repository that is owned by root as root?  Given that\n\"sudo git status\" is a good way to work on a repository that is\nowned by you as root, perhaps the answer is yes, but I am not\na representative sample ;-)\n\nIf the answer is yes, then we would want to make sure it will\ncontinue to work by having a test to protect it from future\nbreakage.  If not, and \"sudo sudo git\" (or worse \"sudo sudo sudo\ngit\") is something that would be imagined by the most wicked mind\nand no sane person would imagine it would be a way to achieve\nsomething useful, no, it does not have to be protected from any\nfuture breakage.\n\nSo...\n"},{"id":"455317","messageId":"20220516130753.kgelgbfovs5kze7h@Carlos-MacBook-Pro-2.local","threadId":"57799","inReplyTo":"xmqqo7zy59p3.fsf@gitster.g","subject":"Re: [PATCH v5 3/4] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-05-16T13:07:53Z","receivedAt":"2022-05-16T13:08:14Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Sun, May 15, 2022 at 10:27:04PM -0700, Junio C Hamano wrote:\n> Carlo Arenas <carenas@gmail.com> writes:\n> \n> >> Hmph, it may not be needed, but it should still work, in which case\n> >> it probably is still worth testing, even with the optional patch #4.\n> >\n> > Just because it works, it doesn't mean we have to test it.\n> \n> Yes.  It all depends on the answer to this question\n\nNot quite, after all this is part of the \"git\" testsuite and therefore will\nonly apply if it would be testing git's functionality, and in this case it\ndoes not.\n\nMore details below.\n\n> Is it\n> reasonably expected that any half-way intelligent Git user would not\n> be surprised to learn that \"sudo sudo git status\" would be a way to\n> work on a repository that is owned by root as root?  Given that\n> \"sudo git status\" is a good way to work on a repository that is\n> owned by you as root, perhaps the answer is yes, but I am not\n> a representative sample ;-)\n> \n> If the answer is yes, then we would want to make sure it will\n> continue to work by having a test to protect it from future\n> breakage.  If not, and \"sudo sudo git\" (or worse \"sudo sudo sudo\n> git\") is something that would be imagined by the most wicked mind\n> and no sane person would imagine it would be a way to achieve\n> something useful, no, it does not have to be protected from any\n> future breakage.\n\nThe answer is \"yes\", but it is because of a misunderstanding (which has\nnothing to do with intelligence, but just experience with sudo and the type\nof environment where it runs).\n\n* sudo does NOT respect SUDO_UID, indeed is one of those few *NIX tools\n  that doesn't even respect EUID but insist on only trusting the real id.\n* once you run something through sudo, it creates an environment for you\n  that is based on its security policy and not even the invoking user can\n  change some of the parametersr it uses to do that, only \"root\" can.\n* that means that once you invoke the first sudo, then the second runs as\n  root and ignores the SUDO_UID the first sudo creates, so by the time git\n  gets to run, it will only see the SUDO_UID that the one that invoked it\n  creates, and since that sudo was running as root it MUST be the same than\n  a root owned file/directory would use, hence why it works for that root\n  owned repository and would fail in one that is owned by the original user.\n\nthere is no new functionality or code path difference inside git between the\nfirst and second invocation of sudo, the only relevant difference is that\nthe starting environment from the two last processes in that triple chain\nhave different values for the SUDO_UID environment variable.\n\nCarlo\n"},{"id":"455327","messageId":"xmqqee0t4f7h.fsf@gitster.g","threadId":"57799","inReplyTo":"20220516130753.kgelgbfovs5kze7h@Carlos-MacBook-Pro-2.local","subject":"Re: [PATCH v5 3/4] t0034: add negative tests and allow git init to mostly work under sudo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-16T16:25:38Z","receivedAt":"2022-05-16T16:25:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón <carenas@gmail.com> writes:\n\n> On Sun, May 15, 2022 at 10:27:04PM -0700, Junio C Hamano wrote:\n>> Carlo Arenas <carenas@gmail.com> writes:\n>> \n>> >> Hmph, it may not be needed, but it should still work, in which case\n>> >> it probably is still worth testing, even with the optional patch #4.\n>> >\n>> > Just because it works, it doesn't mean we have to test it.\n>> \n>> Yes.  It all depends on the answer to this question\n>\n> Not quite, after all this is part of the \"git\" testsuite and therefore will\n> only apply if it would be testing git's functionality, and in this case it\n> does not.\n\nIt is immaterial if the way how \"sudo sudo git\" behaves is \"git's\nfunctionality\" or not, because what we care about is what the end\nuser sees as a whole and it does not matter all that much to them\nwhere the observed behaviour comes from.\n\nThe rule is simple.  If we care about the behaviour to stay with us\nover time, we ensure it with a test.  If we are certain that no\nusers will depend on such a behaviour and are willing to break them\n(i.e. users who depend on how \"sudo sudo git\" behaves, which is an\nempty set) when we need to update the code, then we don't.\n\nAnd if that changes with and without the optional patch #4, it makes\nit more important to have test (if we care, that is).  Later we may\nfind what patch #4 does is detrimental to user experience and decide\nto tweak it out (not necessarily with a revert of #4, but doing an\nequivalent of reverting of it only in the code part and not tests).\n\nIn any case, as I said in the beginning, this was merely \"a bit\nsurprised\" and \"not a serious enough thing to trigger a reroll\", so\nI will stop wasting our time on this thread.\n\nThanks.\n"},{"id":"456561","messageId":"20220603110507.GA1749@szeder.dev","threadId":"57799","inReplyTo":"20220513010020.55361-3-carenas@gmail.com","subject":"Re: [PATCH v5 2/4] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2022-06-03T11:05:07Z","receivedAt":"2022-06-03T11:05:15Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, May 12, 2022 at 06:00:18PM -0700, Carlo Marcelo Arenas Belón wrote:\n> bdc77d1d685 (Add a function to determine whether a path is owned by the\n> current user, 2022-03-02) checks for the effective uid of the running\n> process using geteuid() but didn't account for cases where that user was\n> root (because git was invoked through sudo or a compatible tool) and the\n> original uid that repository trusted for its config was no longer known,\n> therefore failing the following otherwise safe call:\n> \n>   guy@renard ~/Software/uncrustify $ sudo git describe --always --dirty\n>   [sudo] password for guy:\n>   fatal: unsafe repository ('/home/guy/Software/uncrustify' is owned by someone else)\n> \n> Attempt to detect those cases by using the environment variables that\n> those tools create to keep track of the original user id, and do the\n> ownership check using that instead.\n\nThanks for working on this!\n\nUnfortunately, I haven't been able to follow the discussion on this\npatch series at all, but by a cursory look now I didn't notice any\ndiscussion about what should happen if someone were to use 'sudo' to\naccess a repository owned by root.  I think it should work, and it did\nin fact work in the past, even after bdc77d1d685, but this patch\nbroke it.\n\nCase in point are tools like 'etckeeper', which keeps track of '/etc'\nin a root-owned Git repository, and hooks into package managers to\nautomatically create a commit when a package installation/update\nchanges something in '/etc'.  After this patch when 'sudo apt install\n<pkg>' invokes 'etckeeper', it complains about the unsafe repository\nin '/etc', and doesn't make that commit.\n\n\n>  static inline int is_path_owned_by_current_uid(const char *path)\n>  {\n>  \tstruct stat st;\n> +\tuid_t euid;\n> +\n>  \tif (lstat(path, &st))\n>  \t\treturn 0;\n> -\treturn st.st_uid == geteuid();\n> +\n> +\teuid = geteuid();\n\nPerhaps all we'd need is just a simple condition here:\n\n        if (st.st_uid == euid)\n                return 1;\n\nwhich does make it work again in my manual tests, e.g.:\n\n  $ id -u\n  1000\n  $ sudo ./git -C /etc/ rev-parse --absolute-git-dir\n  /etc/.git\n\nAlas, I couldn't get 't0034-root-safe-directory.sh' work for me at\nall, so I'm not sure it doesn't break something else.\n\nAnd it would also allow 'sudo -u somebody git ...' to access a\nrepository owned by that somebody, which, I think, should work as\nwell.\n\n> +\tif (euid == ROOT_UID)\n> +\t\textract_id_from_env(\"SUDO_UID\", &euid);\n> +\n> +\treturn st.st_uid == euid;\n>  }\n>  \n>  #define is_path_owned_by_current_user is_path_owned_by_current_uid\n"},{"id":"456570","messageId":"20220603121223.GB1749@szeder.dev","threadId":"57799","inReplyTo":"20220513010020.55361-2-carenas@gmail.com","subject":"Re: [PATCH v5 1/4] t: regression git needs safe.directory when using sudo","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2022-06-03T12:12:23Z","receivedAt":"2022-06-03T12:12:31Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, May 12, 2022 at 06:00:17PM -0700, Carlo Marcelo Arenas Belón wrote:\n> Originally reported after release of v2.35.2 (and other maint branches)\n> for CVE-2022-24765 and blocking otherwise harmless commands that were\n> done using sudo in a repository that was owned by the user.\n> \n> Add a new test script with very basic support to allow running git\n> commands through sudo, so a reproduction could be implemented and that\n> uses only `git status` as a proxy of the issue reported.\n> \n> Note that because of the way sudo interacts with the system, a much\n> more complete integration with the test framework will require a lot\n> more work and that was therefore intentionally punted for now.\n> \n> The current implementation requires the execution of a special cleanup\n> function which should always be kept as the last \"test\" or otherwise\n> the standard cleanup functions will fail because they can't remove\n> the root owned directories that are used.  This also means that if\n> failures are found while running, the specifics of the failure might\n> not be kept for further debugging and if the test was interrupted, it\n> will be necessary to clean the working directory manually before\n> restarting by running:\n> \n>   $ sudo rm -rf trash\\ directory.t0034-root-safe-directory/\n> \n> The test file also uses at least one initial \"setup\" test that creates\n> a parallel execution directory under the \"root\" sub directory, which\n> should be used as top level directory for all repositories that are\n> used in this test file.  Unlike all other tests the repository provided\n> by the test framework should go unused.\n> \n> Special care should be taken when invoking commands through sudo, since\n> the environment is otherwise independent from what the test framework\n> setup and might have changed the values for HOME, SHELL and dropped\n> several relevant environment variables for your test.  Indeed `git status`\n> was used as a proxy because it doesn't even require commits in the\n> repository to work and usually doesn't require much from the environment\n> to run, but a future patch will add calls to `git init` and that will\n> fail to honor the default branch name, unless that setting is NOT\n> provided through an environment variable (which means even a CI run\n> could fail that test if enabled incorrectly).\n> \n> A new SUDO prerequisite is provided that does some sanity checking\n> to make sure the sudo command that will be used allows for passwordless\n> execution as root without restrictions and doesn't mess with git's\n> execution path.  This matches what is provided by the macOS agents that\n> are used as part of GitHub actions and probably nowhere else.\n> \n> Most of those characteristics make this test mostly only suitable for\n> CI, but it might be executed locally if special care is taken to provide\n> for all of them in the local configuration and maybe making use of the\n> sudo credential cache by first invoking sudo, entering your password if\n> needed, and then invoking the test with:\n> \n>   $ GIT_TEST_ALLOW_SUDO=YES ./t0034-root-safe-directory.sh\n> \n> If it fails to run, then it means your local setup wouldn't work for the\n> test because of the configuration sudo has or other system settings, and\n> things that might help are to comment out sudo's secure_path config, and\n> make sure that the account you are using has no restrictions on the\n> commands it can run through sudo, just like is provided for the user in\n> the CI.\n> \n> For example (assuming a username of marta for you) something probably\n> similar to the following entry in your /etc/sudoers (or equivalent) file:\n> \n>   marta\tALL=(ALL:ALL) NOPASSWD: ALL\n> \n> Reported-by: SZEDER Gábor <szeder.dev@gmail.com>\n> Helped-by: Phillip Wood <phillip.wood123@gmail.com>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  t/t0034-root-safe-directory.sh | 44 ++++++++++++++++++++++++++++++++++\n>  1 file changed, 44 insertions(+)\n>  create mode 100755 t/t0034-root-safe-directory.sh\n> \n> diff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\n> new file mode 100755\n> index 00000000000..f6a5d63ff41\n> --- /dev/null\n> +++ b/t/t0034-root-safe-directory.sh\n> @@ -0,0 +1,44 @@\n> +#!/bin/sh\n> +\n> +test_description='verify safe.directory checks while running as root'\n> +\n> +. ./test-lib.sh\n> +\n> +if [ \"$GIT_TEST_ALLOW_SUDO\" != \"YES\" ]\n> +then\n> +\tskip_all=\"You must set env var GIT_TEST_ALLOW_SUDO=YES in order to run this test\"\n> +\ttest_done\n> +fi\n> +\n> +test_lazy_prereq SUDO '\n> +\tsudo -n id -u >u &&\n> +\tid -u root >r &&\n> +\ttest_cmp u r &&\n> +\tcommand -v git >u &&\n> +\tsudo command -v git >r &&\n\n'command' is a shell builtin, thus it's not something 'sudo' can\nexecute, so this prereq fails with:\n\n  [...]\n  + command -v git\n  + sudo command -v git\n  sudo: command: command not found\n  error: last command exited with $?=1\n  prerequisite SUDO not satisfied\n  ok 1 # skip setup (missing SUDO)\n\nChanging it to:\n\n  sudo sh -c \"command -v git\" >r &&\n\nmakes it work, but then it lists the path of the system git binary\ninstead of the one that's supposed to be tested, so the prereq is\nstill not satisfied (this is why the commit message suggested\nadjusting that secure_path config, right?  I haven't got that far\nyet.)\n\n> +\ttest_cmp u r\n> +'\n> +\n> +test_expect_success SUDO 'setup' '\n> +\tsudo rm -rf root &&\n> +\tmkdir -p root/r &&\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit init\n> +\t)\n> +'\n> +\n> +test_expect_failure SUDO 'sudo git status as original owner' '\n> +\t(\n> +\t\tcd root/r &&\n> +\t\tgit status &&\n> +\t\tsudo git status\n> +\t)\n> +'\n> +\n> +# this MUST be always the last test\n> +test_expect_success SUDO 'cleanup' '\n> +\tsudo rm -rf root\n> +'\n> +\n> +test_done\n> -- \n> 2.36.1.371.g0fb0ef0c8d\n> \n"},{"id":"456593","messageId":"xmqqtu91helx.fsf@gitster.g","threadId":"57799","inReplyTo":"20220603110507.GA1749@szeder.dev","subject":"Re: [PATCH v5 2/4] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-03T16:54:34Z","receivedAt":"2022-06-03T16:54:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder.dev@gmail.com> writes:\n\n> Unfortunately, I haven't been able to follow the discussion on this\n> patch series at all, but by a cursory look now I didn't notice any\n> discussion about what should happen if someone were to use 'sudo' to\n> access a repository owned by root.  I think it should work, and it did\n> in fact work in the past, even after bdc77d1d685, but this patch\n> broke it.\n\nI thought 4/4 of the series was meant to discuss that?  Right now it\nis split out as Carlo was hesitant to push the step forward?\n\nhttps://lore.kernel.org/git/20220519152344.ktrifm3pc42bjruh@Carlos-MacBook-Pro-2.local/\n\n"},{"id":"456597","messageId":"20220603173427.GC1749@szeder.dev","threadId":"57799","inReplyTo":"xmqqtu91helx.fsf@gitster.g","subject":"Re: [PATCH v5 2/4] git-compat-util: avoid failing dir ownership checks if running privileged","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2022-06-03T17:34:27Z","receivedAt":"2022-06-03T17:34:35Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Fri, Jun 03, 2022 at 09:54:34AM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder.dev@gmail.com> writes:\n> \n> > Unfortunately, I haven't been able to follow the discussion on this\n> > patch series at all, but by a cursory look now I didn't notice any\n> > discussion about what should happen if someone were to use 'sudo' to\n> > access a repository owned by root.  I think it should work, and it did\n> > in fact work in the past, even after bdc77d1d685, but this patch\n> > broke it.\n> \n> I thought 4/4 of the series was meant to discuss that?  Right now it\n> is split out as Carlo was hesitant to push the step forward?\n> \n> https://lore.kernel.org/git/20220519152344.ktrifm3pc42bjruh@Carlos-MacBook-Pro-2.local/\n> \n\nOh, indeed.  I only looked through my mailbox, not the ML archives,\nand I wasn't on Cc for the last two patches of the series.  Thanks for\npointing it out.\n\nI think we do need that additional fix as well, because we now break\nat least one tool built around Git.\n\nThough looking at patch 4/4, I'm not so keen about restructuring the\nextract_id_from_env() helper function into id_from_env_matches(),\nbecause I'd prefer to have a helper function for ID extraction and\nnothing else, and to have all the uid matching inside one function.\n\n"},{"id":"457284","messageId":"nycvar.QRO.7.76.6.2206151557510.349@tvgsbejvaqbjf.bet","threadId":"57799","inReplyTo":"20220513010020.55361-5-carenas@gmail.com","subject":"Re: [PATCH v5 4/4] git-compat-util: allow root to access both SUDO_UID and root owned","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-06-15T14:02:51Z","receivedAt":"2022-06-15T14:05:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Carlo,\n\nOn Thu, 12 May 2022, Carlo Marcelo Arenas Belón wrote:\n\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index e7cbfa65c9a..0a5a4ee7a9a 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -420,9 +420,10 @@ static inline int git_offset_1st_component(const char *path)\n>   * maybe provide you with a patch that would prevent this issue again\n>   * in the future.\n>   */\n> -static inline void extract_id_from_env(const char *env, uid_t *id)\n> +static inline int id_from_env_matches(const char *env, uid_t id)\n\nI agree somewhat with Gabór's concern that this patch tries to do too many\nthings at once, including this rename.\n\nWe have a recent history of introducing so many regressions that `.1`\nreleases have become the norm rather than the exception, and from where I\nsit, the reason is squarely with the uptick in refactoring (including\nrenames like this one).\n\nSo unless the refactoring is done to any other end than for refactoring's\nown sake (which is really not a good reason), I see it as problematic.\n\n>  {\n>  \tconst char *real_uid = getenv(env);\n> +\tint matches = 0;\n>\n>  \t/* discard anything empty to avoid a more complex check below */\n>  \tif (real_uid && *real_uid) {\n> @@ -432,9 +433,10 @@ static inline void extract_id_from_env(const char *env, uid_t *id)\n>  \t\terrno = 0;\n>  \t\t/* silent overflow errors could trigger a bug here */\n>  \t\tenv_id = strtoul(real_uid, &endptr, 10);\n> -\t\tif (!*endptr && !errno)\n> -\t\t\t*id = env_id;\n> +\t\tif (!*endptr && !errno && (uid_t)env_id == id)\n> +\t\t\tmatches = 1;\n>  \t}\n> +\treturn matches;\n>  }\n>\n>  static inline int is_path_owned_by_current_uid(const char *path)\n> @@ -446,10 +448,13 @@ static inline int is_path_owned_by_current_uid(const char *path)\n>  \t\treturn 0;\n>\n>  \teuid = geteuid();\n> +\tif (st.st_uid == euid)\n> +\t\treturn 1;\n> +\n>  \tif (euid == ROOT_UID)\n> -\t\textract_id_from_env(\"SUDO_UID\", &euid);\n> +\t\treturn id_from_env_matches(\"SUDO_UID\", st.st_uid);\n\nA much shorter, much more obvious patch would look like this:\n\n-\tif (euid == ROOT_UID)\n+\tif (st.st_uid != euid && euid == ROOT_UID && )\n \t\textract_id_from_env(\"SUDO_UID\", &euid);\n\nIt accomplishes the same goal, but is eminently easier to review. For\nregression fixes, I much prefer the safety and confidence that comes with\nthat.\n\nCiao,\nDscho\n"},{"id":"457453","messageId":"CAPUEspgrkVywKOAQz1ffyntaAXaw6=WnNNBZRhNRBHRH8nYUHQ@mail.gmail.com","threadId":"57799","inReplyTo":"nycvar.QRO.7.76.6.2206151557510.349@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v5 4/4] git-compat-util: allow root to access both SUDO_UID and root owned","fromName":"Carlo Arenas","fromEmail":"carenas@gmail.com","sentAt":"2022-06-17T14:26:37Z","receivedAt":"2022-06-17T14:26:39Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"On Wed, Jun 15, 2022 at 7:03 AM Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n>\n> On Thu, 12 May 2022, Carlo Marcelo Arenas Belón wrote:\n>\n> > diff --git a/git-compat-util.h b/git-compat-util.h\n> > index e7cbfa65c9a..0a5a4ee7a9a 100644\n> > --- a/git-compat-util.h\n> > +++ b/git-compat-util.h\n> > @@ -420,9 +420,10 @@ static inline int git_offset_1st_component(const char *path)\n> >   * maybe provide you with a patch that would prevent this issue again\n> >   * in the future.\n> >   */\n> > -static inline void extract_id_from_env(const char *env, uid_t *id)\n> > +static inline int id_from_env_matches(const char *env, uid_t id)\n>\n> I agree somewhat with Gabór's concern that this patch tries to do too many\n> things at once, including this rename.\n>\n> We have a recent history of introducing so many regressions that `.1`\n> releases have become the norm rather than the exception, and from where I\n> sit, the reason is squarely with the uptick in refactoring (including\n> renames like this one).\n>\n> So unless the refactoring is done to any other end than for refactoring's\n> own sake (which is really not a good reason), I see it as problematic.\n\nI couldn't agree more with that sentiment, but in this case the\nrefactoring was done to clean up the recently introduced function\nwhich was indeed too ugly (some would say on purpose) and replacing it\nwith not only better looking code, but also a cleaner interface.\n\nI would think that in this specific case an exemption could be\ngranted, but it is also true that while this code is almost a month\nold, it hasn't got the review it will require to be merged so late in\nthe release cycle without raising the concerns you both fairly put\nforward.\n\n> >  {\n> >       const char *real_uid = getenv(env);\n> > +     int matches = 0;\n> >\n> >       /* discard anything empty to avoid a more complex check below */\n> >       if (real_uid && *real_uid) {\n> > @@ -432,9 +433,10 @@ static inline void extract_id_from_env(const char *env, uid_t *id)\n> >               errno = 0;\n> >               /* silent overflow errors could trigger a bug here */\n> >               env_id = strtoul(real_uid, &endptr, 10);\n> > -             if (!*endptr && !errno)\n> > -                     *id = env_id;\n> > +             if (!*endptr && !errno && (uid_t)env_id == id)\n> > +                     matches = 1;\n> >       }\n> > +     return matches;\n> >  }\n> >\n> >  static inline int is_path_owned_by_current_uid(const char *path)\n> > @@ -446,10 +448,13 @@ static inline int is_path_owned_by_current_uid(const char *path)\n> >               return 0;\n> >\n> >       euid = geteuid();\n> > +     if (st.st_uid == euid)\n> > +             return 1;\n> > +\n> >       if (euid == ROOT_UID)\n> > -             extract_id_from_env(\"SUDO_UID\", &euid);\n> > +             return id_from_env_matches(\"SUDO_UID\", st.st_uid);\n>\n> A much shorter, much more obvious patch would look like this:\n>\n> -       if (euid == ROOT_UID)\n> +       if (st.st_uid != euid && euid == ROOT_UID && )\n>                 extract_id_from_env(\"SUDO_UID\", &euid);\n>\n> It accomplishes the same goal, but is eminently easier to review. For\n> regression fixes, I much prefer the safety and confidence that comes with\n> that.\n\nwill reroll with your suggestion, thanks again for your helpful\nreview, and apologies again to everyone for not cleaning it up earlier\nin the cycle.\n\nIMHO the alternative (which will be releasing with the regression)\nmight be worse than releasing with this version so we ought to do\nsomething before RC1.\n\nCarlo\n\nCarlo\n"},{"id":"457455","messageId":"xmqqmtebp9ee.fsf@gitster.g","threadId":"57799","inReplyTo":"CAPUEspgrkVywKOAQz1ffyntaAXaw6=WnNNBZRhNRBHRH8nYUHQ@mail.gmail.com","subject":"Re: [PATCH v5 4/4] git-compat-util: allow root to access both SUDO_UID and root owned","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-17T16:00:41Z","receivedAt":"2022-06-17T16:00:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Arenas <carenas@gmail.com> writes:\n\n>> So unless the refactoring is done to any other end than for refactoring's\n>> own sake (which is really not a good reason), I see it as problematic.\n>\n> I couldn't agree more with that sentiment, but in this case the\n> refactoring was done to clean up the recently introduced function\n> which was indeed too ugly (some would say on purpose) and replacing it\n> with not only better looking code, but also a cleaner interface.\n>\n> I would think that in this specific case an exemption could be\n> granted, but it is also true that while this code is almost a month\n> old, it hasn't got the review it will require to be merged so late in\n> the release cycle without raising the concerns you both fairly put\n> forward.\n>\n>> >       if (euid == ROOT_UID)\n>> > -             extract_id_from_env(\"SUDO_UID\", &euid);\n>> > +             return id_from_env_matches(\"SUDO_UID\", st.st_uid);\n>>\n>> A much shorter, much more obvious patch would look like this:\n>>\n>> -       if (euid == ROOT_UID)\n>> +       if (st.st_uid != euid && euid == ROOT_UID && )\n>>                 extract_id_from_env(\"SUDO_UID\", &euid);\n>>\n>> It accomplishes the same goal, but is eminently easier to review. For\n>> regression fixes, I much prefer the safety and confidence that comes with\n>> that.\n>\n> will reroll with your suggestion, thanks again for your helpful\n> review, and apologies again to everyone for not cleaning it up earlier\n> in the cycle.\n\nAs long as the syntax error with the \"like this\" suggestion gets\nfixed, I do not mind if you took the above verbatim ;-)\n\nQuite honestly, at this low level of small \"the caller asks if it is\nsafe for the current user to step into the given path to run git\"\nfunction, it would be a waste of time to quibble about the\nseparation of concerns between the helper function that figures out\nwho the \"current user\" is, and checking it against the user who owns\nthe path.  It is not like we are talking about a brutal-to-reviewers\n250-line function that is called from multiple places after all.\nThe extract_id_from_env() helper could be inlined the caller and the\nissue would disappear (I am not making a suggestion to actually do\nso, but an illustration why it does not matter much in the larger\npicture for something miniscule like this).\n\nWhere the function name and the separation of concerns truly matters\nis between the is_path_owned_by*() helper and its callers, as in the\nlonger term I expect it won't be just \"ownership\" that we would care\nabout and once we start checking permission bits and other things for\nthe path, we'd regret the \"owned by\" part of the name.\n\nBut that is not our immediate concern, so let's take whatever that\nis not incorrect and can achieve \"concensus\" the easiest and move\non.\n\nThanks for sticking with the larger topic of making the end-user\nexperience better around here.  Very much appreciated.\n"},{"id":"457461","messageId":"20220617202338.27984-1-carenas@gmail.com","threadId":"57799","inReplyTo":"20220513010020.55361-5-carenas@gmail.com","subject":"[PATCH v6] git-compat-util: allow root to access both SUDO_UID and root owned","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2022-06-17T20:23:38Z","receivedAt":"2022-06-17T20:24:02Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Previous changes introduced a regression which will prevent root for\naccessing repositories owned by thyself if using sudo because SUDO_UID\ntakes precedence.\n\nLoosen that restriction by allowing root to access repositories owned\nby both uid by default and without having to add a safe.directory\nexception.\n\nA previous workaround that was documented in the tests is no longer\nneeded so it has been removed together with its specially crafted\nprerequisite.\n\nHelped-by: Johanness Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\nIt is a little more involved than the proposed change just to make\nsure that it doesn't introduce any change on behavior (the code is\nstill strictly only invoked after we confirm process is running as\nroot) and keeps the documentation and test changes that were in the\noriginal proposal.\n\nA CI run (which is the only way to reliably test this, since the\nprerequisite only works in macOS agents like the ones provided by\nGitHub) with this patch merged into master is available[1]\n\n[1] https://github.com/carenas/git/actions/runs/2516394052\n\nChanges since v5:\n* simplify logic change to avoid additional refactoring\n\n Documentation/config/safe.txt  |  5 +++--\n git-compat-util.h              |  7 ++++++-\n t/t0034-root-safe-directory.sh | 15 +--------------\n 3 files changed, 10 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\nindex c6ebd1674d..3128b13271 100644\n--- a/Documentation/config/safe.txt\n+++ b/Documentation/config/safe.txt\n@@ -31,11 +31,12 @@ As explained, Git only allows you to access repositories owned by\n yourself, i.e. the user who is running Git, by default.  When Git\n is running as 'root' in a non Windows platform that provides sudo,\n  however, git checks the SUDO_UID environment variable that sudo creates\n-and will allow access to the uid recorded as its value instead.\n+and will allow access to the uid recorded as its value in addition to\n+the id from 'root'.\n This is to make it easy to perform a common sequence during installation\n \"make && sudo make install\".  A git process running under 'sudo' runs as\n 'root' but the 'sudo' command exports the environment variable to record\n which id the original user has.\n If that is not what you would prefer and want git to only trust\n-repositories that are owned by root instead, then you must remove\n+repositories that are owned by root instead, then you can remove\n the `SUDO_UID` variable from root's environment before invoking git.\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex e7cbfa65c9..f505f817d5 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -447,7 +447,12 @@ static inline int is_path_owned_by_current_uid(const char *path)\n \n \teuid = geteuid();\n \tif (euid == ROOT_UID)\n-\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\t{\n+\t\tif (st.st_uid == ROOT_UID)\n+\t\t\treturn 1;\n+\t\telse\n+\t\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\t}\n \n \treturn st.st_uid == euid;\n }\ndiff --git a/t/t0034-root-safe-directory.sh b/t/t0034-root-safe-directory.sh\nindex a621f1ea5e..ff31176128 100755\n--- a/t/t0034-root-safe-directory.sh\n+++ b/t/t0034-root-safe-directory.sh\n@@ -68,7 +68,7 @@ test_expect_success 'can access if addressed explicitly' '\n \t)\n '\n \n-test_expect_failure SUDO 'can access with sudo if root' '\n+test_expect_success SUDO 'can access with sudo if root' '\n \t(\n \t\tcd root/p &&\n \t\tsudo git status\n@@ -85,19 +85,6 @@ test_expect_success SUDO 'can access with sudo if root by removing SUDO_UID' '\n \t)\n '\n \n-test_lazy_prereq SUDO_SUDO '\n-\tsudo sudo id -u >u &&\n-\tid -u root >r &&\n-\ttest_cmp u r\n-'\n-\n-test_expect_success SUDO_SUDO 'can access with sudo abusing SUDO_UID' '\n-\t(\n-\t\tcd root/p &&\n-\t\tsudo sudo git status\n-\t)\n-'\n-\n # this MUST be always the last test\n test_expect_success SUDO 'cleanup' '\n \tsudo rm -rf root\n\nbase-commit: b9063afda17a2aa6310423c9f7b776c41f753091\n-- \n2.30.2\n\n"},{"id":"457462","messageId":"xmqq8rpvngvl.fsf@gitster.g","threadId":"57799","inReplyTo":"20220617202338.27984-1-carenas@gmail.com","subject":"Re: [PATCH v6] git-compat-util: allow root to access both SUDO_UID and root owned","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-17T21:02:06Z","receivedAt":"2022-06-17T21:02:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> Previous changes introduced a regression which will prevent root for\n> accessing repositories owned by thyself if using sudo because SUDO_UID\n> takes precedence.\n>\n> Loosen that restriction by allowing root to access repositories owned\n> by both uid by default and without having to add a safe.directory\n> exception.\n>\n> A previous workaround that was documented in the tests is no longer\n> needed so it has been removed together with its specially crafted\n> prerequisite.\n>\n> Helped-by: Johanness Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> ---\n> It is a little more involved than the proposed change just to make\n> sure that it doesn't introduce any change on behavior (the code is\n> still strictly only invoked after we confirm process is running as\n> root) and keeps the documentation and test changes that were in the\n> original proposal.\n>\n> A CI run (which is the only way to reliably test this, since the\n> prerequisite only works in macOS agents like the ones provided by\n> GitHub) with this patch merged into master is available[1]\n>\n> [1] https://github.com/carenas/git/actions/runs/2516394052\n>\n> Changes since v5:\n> * simplify logic change to avoid additional refactoring\n>\n>  Documentation/config/safe.txt  |  5 +++--\n>  git-compat-util.h              |  7 ++++++-\n>  t/t0034-root-safe-directory.sh | 15 +--------------\n>  3 files changed, 10 insertions(+), 17 deletions(-)\n>\n> diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt\n> index c6ebd1674d..3128b13271 100644\n> --- a/Documentation/config/safe.txt\n> +++ b/Documentation/config/safe.txt\n> @@ -31,11 +31,12 @@ As explained, Git only allows you to access repositories owned by\n>  yourself, i.e. the user who is running Git, by default.  When Git\n>  is running as 'root' in a non Windows platform that provides sudo,\n>   however, git checks the SUDO_UID environment variable that sudo creates\n\nNot a problem with this patch, but one extra space at the beginning\nof this line looks funny.  I'd probably remove it while queueing if\nI do not forget.\n\n> -and will allow access to the uid recorded as its value instead.\n> +and will allow access to the uid recorded as its value in addition to\n> +the id from 'root'.\n\nOK.  So the original user who invoked \"sudo\", plus root.  Does \"the\nid from root\" refer to ROOT_UID?  I am just wondering if \"from\" is\nthe right preposition (what the sentence wants to say is perfectly\nclear, so the patch is OK as-is, but \"user id of 'root'\" is probably\nwhat I would have said).\n\n>  This is to make it easy to perform a common sequence during installation\n>  \"make && sudo make install\".  A git process running under 'sudo' runs as\n>  'root' but the 'sudo' command exports the environment variable to record\n>  which id the original user has.\n>  If that is not what you would prefer and want git to only trust\n> -repositories that are owned by root instead, then you must remove\n> +repositories that are owned by root instead, then you can remove\n>  the `SUDO_UID` variable from root's environment before invoking git.\n\nOK.  The same escape hatch works, and the code change does not\ncontribut to any behaviour change in this area, so there is no\nreason to change the phrasing here.  I guess they mean the same\nthing anyway, so let's take it.\n\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index e7cbfa65c9..f505f817d5 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -447,7 +447,12 @@ static inline int is_path_owned_by_current_uid(const char *path)\n>  \n>  \teuid = geteuid();\n>  \tif (euid == ROOT_UID)\n> -\t\textract_id_from_env(\"SUDO_UID\", &euid);\n> +\t{\n\nStyle?\n\n-\tif (euid == ROOT_UID)\n-\t\textract_id_from_env(\"SUDO_UID\", &euid);\n+\tif (euid == ROOT_UID) {\n\n> +\t\tif (st.st_uid == ROOT_UID)\n> +\t\t\treturn 1;\n> +\t\telse\n> +\t\t\textract_id_from_env(\"SUDO_UID\", &euid);\n> +\t}\n>  \n>  \treturn st.st_uid == euid;\n>  }\n\nI would not call it clearer than what Dscho called \"something like\nthis\", and\n\n\tif (euid == ROOT_UID && st.st_uid != ROOT_UID)\n\t\textract(...);\n\treturn st.st_uid == euid;\n\nwould be what I would have written, but they mean the same thing, so\nlet's take it as-is.\n\nThanks.\n"}]}