{"thread":{"id":"50987","subject":"[PATCH v3] git-compat-util: work around for access(X_OK) under root","startedAt":"2019-04-25T07:02:06Z","lastAt":"2019-04-25T07:02:06Z","messageCount":1,"participants":["CHIGOT, CLEMENT"],"isPatch":true,"patchVersion":3,"patchTotal":null},"messages":[{"id":"374458","messageId":"AM6PR02MB49501E0BCA8052FA7747B314EA3D0@AM6PR02MB4950.eurprd02.prod.outlook.com","threadId":"50987","inReplyTo":null,"subject":"[PATCH v3] git-compat-util: work around for access(X_OK) under root","fromName":"CHIGOT, CLEMENT","fromEmail":"clement.chigot@atos.net","sentAt":"2019-04-25T07:01:56Z","receivedAt":"2019-04-25T07:02:06Z","isPatch":true,"sender":{"key":"clement.chigot@atos.net","avatar":null},"body":"On AIX, access(X_OK) may succeed when run as root even if the\nexecution isn't possible. This behavior is allowed by POSIX\nwhich says:\n\n  ... for a process with appropriate privileges, an implementation\n  may indicate success for X_OK even if execute permission is not\n  granted to any user.\n\nIt can lead hook programs to have their execution refused:\n\n   git commit -m content\n   fatal: cannot exec '.git/hooks/pre-commit': Permission denied\n\nAdd NEED_ACCESS_ROOT_HANDLER in order to use an access helper function.\nIt checks with stat if any executable flags is set when the current user\nis root.\n\nSigned-off-by: Clément Chigot <clement.chigot@atos.net>\nMessage-ID: <AM6PR02MB4950ED66291B16F35BE61A26EA3C0@AM6PR02MB4950.eurprd02.prod.outlook.com>\n---\n Makefile          |  8 ++++++++\n compat/access.c   | 31 +++++++++++++++++++++++++++++++\n compat/fileno.c   |  2 +-\n config.mak.uname  |  1 +\n git-compat-util.h | 12 +++++++++++-\n 5 files changed, 52 insertions(+), 2 deletions(-)\n create mode 100644 compat/access.c\n\ndiff --git a/Makefile b/Makefile\nindex 9f1b6e8926..6ac7218106 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -439,6 +439,9 @@ all::\n #\n # Define FILENO_IS_A_MACRO if fileno() is a macro, not a real function.\n #\n+# Define NEED_ACCESS_ROOT_HANDLER if access() under root may success for X_OK\n+# even if execution permission isn't granted for any user.\n+#\n # Define PAGER_ENV to a SP separated VAR=VAL pairs to define\n # default environment variables to be passed when a pager is spawned, e.g.\n #\n@@ -1833,6 +1836,11 @@ ifdef FILENO_IS_A_MACRO\n \tCOMPAT_OBJS += compat/fileno.o\n endif\n \n+ifdef NEED_ACCESS_ROOT_HANDLER\n+\tCOMPAT_CFLAGS += -DNEED_ACCESS_ROOT_HANDLER\n+\tCOMPAT_OBJS += compat/access.o\n+endif\n+\n ifeq ($(TCLTK_PATH),)\n NO_TCLTK = NoThanks\n endif\ndiff --git a/compat/access.c b/compat/access.c\nnew file mode 100644\nindex 0000000000..19fda3e877\n--- /dev/null\n+++ b/compat/access.c\n@@ -0,0 +1,31 @@\n+#define COMPAT_CODE_ACCESS\n+#include \"../git-compat-util.h\"\n+\n+/* Do the same thing access(2) does, but use the effective uid,\n+ * and don't make the mistake of telling root that any file is\n+ * executable.  This version uses stat(2).\n+ */\n+int git_access(const char *path, int mode)\n+{\n+\tstruct stat st;\n+\n+\t/* do not interfere a normal user */\n+\tif (geteuid())\n+\t\treturn access(path, mode);\n+\n+\tif (stat(path, &st) < 0)\n+\t\treturn -1;\n+\n+\t/* Root can read or write any file. */\n+\tif (!(mode & X_OK))\n+\t\treturn 0;\n+\n+\t/* Root can execute any file that has any one of the execute\n+\t * bits set.\n+\t */\n+\tif (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))\n+\t\treturn 0;\n+\n+\terrno = EACCES;\n+\treturn -1;\n+}\ndiff --git a/compat/fileno.c b/compat/fileno.c\nindex 7b105f4cd7..8e80ef335d 100644\n--- a/compat/fileno.c\n+++ b/compat/fileno.c\n@@ -1,4 +1,4 @@\n-#define COMPAT_CODE\n+#define COMPAT_CODE_FILENO\n #include \"../git-compat-util.h\"\n \n int git_fileno(FILE *stream)\ndiff --git a/config.mak.uname b/config.mak.uname\nindex 86cbe47627..ce13ab8295 100644\n--- a/config.mak.uname\n+++ b/config.mak.uname\n@@ -270,6 +270,7 @@ ifeq ($(uname_S),AIX)\n \tNEEDS_LIBICONV = YesPlease\n \tBASIC_CFLAGS += -D_LARGE_FILES\n \tFILENO_IS_A_MACRO = UnfortunatelyYes\n+\tNEED_ACCESS_ROOT_HANDLER = UnfortunatelyYes\n \tifeq ($(shell expr \"$(uname_V)\" : '[1234]'),1)\n \t\tNO_PTHREADS = YesPlease\n \telse\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 31b47932bd..bdca50e64d 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -1236,12 +1236,22 @@ struct tm *git_gmtime_r(const time_t *, struct tm *);\n \n #ifdef FILENO_IS_A_MACRO\n int git_fileno(FILE *stream);\n-# ifndef COMPAT_CODE\n+# ifndef COMPAT_CODE_FILENO\n #  undef fileno\n #  define fileno(p) git_fileno(p)\n # endif\n #endif\n \n+#ifdef NEED_ACCESS_ROOT_HANDLER\n+int git_access(const char *path, int mode);\n+# ifndef COMPAT_CODE_ACCESS\n+#  ifdef access\n+#  undef access\n+#  endif\n+#  define access(path, mode) git_access(path, mode)\n+# endif\n+#endif\n+\n /*\n  * Our code often opens a path to an optional file, to work on its\n  * contents when we can successfully open it.  We can ignore a failure\n-- \n2.17.1\n\n\nClément Chigot\nATOS Bull SAS\n1 rue de Provence - 38432 Échirolles - France\n"}]}