git-compat-util: work around for access(X_OK) under root

On AIX, access(X_OK) may succeed when run as root even if the execution isn't possible. This behavior is allowed by POSIX which says: ... for a process with appropriate privileges, an implementation may indicate success for X_OK even if execute permission is not granted to any user. It can lead hook programs to have their execution refused: git commit -m content fatal: cannot exec '.git/hooks/pre-commit': Permission denied Add NEED_ACCESS_ROOT_HANDLER in order to use an access helper function. It checks with stat if any executable flags is set when the current user is root. Signed-off-by: Clément Chigot <clement.chigot@atos.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Clément Chigot committed Apr 25, 2019 at 07:01 UTC 400caafb2bb63712bb23cfa4d800261aab8e5cae
5 files changed +52 -2
Makefile
+8
@@ -439,6 +439,9 @@ all::
439 #
440 # Define FILENO_IS_A_MACRO if fileno() is a macro, not a real function.
441 #
442 +# Define NEED_ACCESS_ROOT_HANDLER if access() under root may success for X_OK
443 +# even if execution permission isn't granted for any user.
444 +#
445 # Define PAGER_ENV to a SP separated VAR=VAL pairs to define
446 # default environment variables to be passed when a pager is spawned, e.g.
447 #
@@ -1815,6 +1818,11 @@ ifdef FILENO_IS_A_MACRO
1818 COMPAT_OBJS += compat/fileno.o
1819 endif
1820
1821 +ifdef NEED_ACCESS_ROOT_HANDLER
1822 + COMPAT_CFLAGS += -DNEED_ACCESS_ROOT_HANDLER
1823 + COMPAT_OBJS += compat/access.o
1824 +endif
1825 +
1826 ifeq ($(TCLTK_PATH),)
1827 NO_TCLTK = NoThanks
1828 endif
compat/access.c new
+31
@@ -0,0 +1,31 @@
1 +#define COMPAT_CODE_ACCESS
2 +#include "../git-compat-util.h"
3 +
4 +/* Do the same thing access(2) does, but use the effective uid,
5 + * and don't make the mistake of telling root that any file is
6 + * executable. This version uses stat(2).
7 + */
8 +int git_access(const char *path, int mode)
9 +{
10 + struct stat st;
11 +
12 + /* do not interfere a normal user */
13 + if (geteuid())
14 + return access(path, mode);
15 +
16 + if (stat(path, &st) < 0)
17 + return -1;
18 +
19 + /* Root can read or write any file. */
20 + if (!(mode & X_OK))
21 + return 0;
22 +
23 + /* Root can execute any file that has any one of the execute
24 + * bits set.
25 + */
26 + if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
27 + return 0;
28 +
29 + errno = EACCES;
30 + return -1;
31 +}
compat/fileno.c
+1 -1
@@ -1,4 +1,4 @@
1 -#define COMPAT_CODE
1 +#define COMPAT_CODE_FILENO
2 #include "../git-compat-util.h"
3
4 int git_fileno(FILE *stream)
config.mak.uname
+1
@@ -270,6 +270,7 @@ ifeq ($(uname_S),AIX)
270 NEEDS_LIBICONV = YesPlease
271 BASIC_CFLAGS += -D_LARGE_FILES
272 FILENO_IS_A_MACRO = UnfortunatelyYes
273 + NEED_ACCESS_ROOT_HANDLER = UnfortunatelyYes
274 ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
275 NO_PTHREADS = YesPlease
276 else
git-compat-util.h
+11 -1
@@ -1236,12 +1236,22 @@ struct tm *git_gmtime_r(const time_t *, struct tm *);
1236
1237 #ifdef FILENO_IS_A_MACRO
1238 int git_fileno(FILE *stream);
1239 -# ifndef COMPAT_CODE
1239 +# ifndef COMPAT_CODE_FILENO
1240 # undef fileno
1241 # define fileno(p) git_fileno(p)
1242 # endif
1243 #endif
1244
1245 +#ifdef NEED_ACCESS_ROOT_HANDLER
1246 +int git_access(const char *path, int mode);
1247 +# ifndef COMPAT_CODE_ACCESS
1248 +# ifdef access
1249 +# undef access
1250 +# endif
1251 +# define access(path, mode) git_access(path, mode)
1252 +# endif
1253 +#endif
1254 +
1255 /*
1256 * Our code often opens a path to an optional file, to work on its
1257 * contents when we can successfully open it. We can ignore a failure