]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Sync with 2.34.2
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Thu, 17 Mar 2022 09:57:59 +0000 (10:57 +0100)
committerJohannes Schindelin <johannes.schindelin@gmx.de>
Wed, 23 Mar 2022 23:31:42 +0000 (00:31 +0100)
* maint-2.34:
  Git 2.34.2
  Git 2.33.2
  Git 2.32.1
  Git 2.31.2
  GIT-VERSION-GEN: bump to v2.33.1
  Git 2.30.3
  setup_git_directory(): add an owner check for the top-level directory
  Add a function to determine whether a path is owned by the current user

1  2 
Documentation/config.txt
compat/mingw.c
git-compat-util.h
setup.c
t/t0060-path-utils.sh

diff --combined Documentation/config.txt
index b168f02dc3d92c77be4d37061403a2909e6235c8,cdff79b78df35628bd0f05591781626ceb1bc27b..8d3f5180831cf23de109bb012f035f3b4df54b33
@@@ -262,19 -262,11 +262,19 @@@ color:
         colors (at most two, one for foreground and one for background)
         and attributes (as many as you want), separated by spaces.
  +
 -The basic colors accepted are `normal`, `black`, `red`, `green`, `yellow`,
 -`blue`, `magenta`, `cyan` and `white`.  The first color given is the
 -foreground; the second is the background.  All the basic colors except
 -`normal` have a bright variant that can be specified by prefixing the
 -color with `bright`, like `brightred`.
 +The basic colors accepted are `normal`, `black`, `red`, `green`,
 +`yellow`, `blue`, `magenta`, `cyan`, `white` and `default`.  The first
 +color given is the foreground; the second is the background.  All the
 +basic colors except `normal` and `default` have a bright variant that can
 +be specified by prefixing the color with `bright`, like `brightred`.
 ++
 +The color `normal` makes no change to the color. It is the same as an
 +empty string, but can be used as the foreground color when specifying a
 +background color alone (for example, "normal red").
 ++
 +The color `default` explicitly resets the color to the terminal default,
 +for example to specify a cleared background. Although it varies between
 +terminals, this is usually not the same as setting to "white black".
  +
  Colors may also be given as numbers between 0 and 255; these use ANSI
  256-color mode (but note that not all terminals may support this).  If
@@@ -288,11 -280,6 +288,11 @@@ The position of any attributes with res
  be turned off by prefixing them with `no` or `no-` (e.g., `noreverse`,
  `no-ul`, etc).
  +
 +The pseudo-attribute `reset` resets all colors and attributes before
 +applying the specified coloring. For example, `reset green` will result
 +in a green foreground and default background without any active
 +attributes.
 ++
  An empty color string produces no color effect at all. This can be used
  to avoid coloring specific elements without disabling color entirely.
  +
@@@ -462,6 -449,8 +462,8 @@@ include::config/rerere.txt[
  
  include::config/reset.txt[]
  
+ include::config/safe.txt[]
  include::config/sendemail.txt[]
  
  include::config/sequencer.txt[]
diff --combined compat/mingw.c
index 03af369b2b972fdce2476b256ef3679ec88e025e,5e42191fa4acb4ec353df177488ec4d7d1555a05..41fc16310c8018057be238efdd348fdee94616bd
@@@ -1,5 -1,6 +1,6 @@@
  #include "../git-compat-util.h"
  #include "win32.h"
+ #include <aclapi.h>
  #include <conio.h>
  #include <wchar.h>
  #include "../strbuf.h"
@@@ -8,8 -9,6 +9,8 @@@
  #include "win32/lazyload.h"
  #include "../config.h"
  #include "dir.h"
 +#define SECURITY_WIN32
 +#include <sspi.h>
  
  #define HCAST(type, handle) ((type)(intptr_t)handle)
  
@@@ -1010,7 -1009,7 +1011,7 @@@ size_t mingw_strftime(char *s, size_t m
        /* a pointer to the original strftime in case we can't find the UCRT version */
        static size_t (*fallback)(char *, size_t, const char *, const struct tm *) = strftime;
        size_t ret;
 -      DECLARE_PROC_ADDR(ucrtbase.dll, size_t, strftime, char *, size_t,
 +      DECLARE_PROC_ADDR(ucrtbase.dll, size_t, __cdecl, strftime, char *, size_t,
                const char *, const struct tm *);
  
        if (INIT_PROC_ADDR(strftime))
@@@ -1127,10 -1126,6 +1128,10 @@@ char *mingw_getcwd(char *pointer, int l
        }
        if (!ret || ret >= ARRAY_SIZE(wpointer))
                return NULL;
 +      if (GetFileAttributesW(wpointer) == INVALID_FILE_ATTRIBUTES) {
 +              errno = ENOENT;
 +              return NULL;
 +      }
        if (xwcstoutf(pointer, wpointer, len) < 0)
                return NULL;
        convert_slashes(pointer);
@@@ -2191,7 -2186,7 +2192,7 @@@ enum EXTENDED_NAME_FORMAT 
  
  static char *get_extended_user_info(enum EXTENDED_NAME_FORMAT type)
  {
 -      DECLARE_PROC_ADDR(secur32.dll, BOOL, GetUserNameExW,
 +      DECLARE_PROC_ADDR(secur32.dll, BOOL, SEC_ENTRY, GetUserNameExW,
                enum EXTENDED_NAME_FORMAT, LPCWSTR, PULONG);
        static wchar_t wbuffer[1024];
        DWORD len;
@@@ -2630,6 -2625,92 +2631,92 @@@ static void setup_windows_environment(v
        }
  }
  
+ static PSID get_current_user_sid(void)
+ {
+       HANDLE token;
+       DWORD len = 0;
+       PSID result = NULL;
+       if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
+               return NULL;
+       if (!GetTokenInformation(token, TokenUser, NULL, 0, &len)) {
+               TOKEN_USER *info = xmalloc((size_t)len);
+               if (GetTokenInformation(token, TokenUser, info, len, &len)) {
+                       len = GetLengthSid(info->User.Sid);
+                       result = xmalloc(len);
+                       if (!CopySid(len, result, info->User.Sid)) {
+                               error(_("failed to copy SID (%ld)"),
+                                     GetLastError());
+                               FREE_AND_NULL(result);
+                       }
+               }
+               FREE_AND_NULL(info);
+       }
+       CloseHandle(token);
+       return result;
+ }
+ int is_path_owned_by_current_sid(const char *path)
+ {
+       WCHAR wpath[MAX_PATH];
+       PSID sid = NULL;
+       PSECURITY_DESCRIPTOR descriptor = NULL;
+       DWORD err;
+       static wchar_t home[MAX_PATH];
+       int result = 0;
+       if (xutftowcs_path(wpath, path) < 0)
+               return 0;
+       /*
+        * On Windows, the home directory is owned by the administrator, but for
+        * all practical purposes, it belongs to the user. Do pretend that it is
+        * owned by the user.
+        */
+       if (!*home) {
+               DWORD size = ARRAY_SIZE(home);
+               DWORD len = GetEnvironmentVariableW(L"HOME", home, size);
+               if (!len || len > size)
+                       wcscpy(home, L"::N/A::");
+       }
+       if (!wcsicmp(wpath, home))
+               return 1;
+       /* Get the owner SID */
+       err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT,
+                                   OWNER_SECURITY_INFORMATION |
+                                   DACL_SECURITY_INFORMATION,
+                                   &sid, NULL, NULL, NULL, &descriptor);
+       if (err != ERROR_SUCCESS)
+               error(_("failed to get owner for '%s' (%ld)"), path, err);
+       else if (sid && IsValidSid(sid)) {
+               /* Now, verify that the SID matches the current user's */
+               static PSID current_user_sid;
+               if (!current_user_sid)
+                       current_user_sid = get_current_user_sid();
+               if (current_user_sid &&
+                   IsValidSid(current_user_sid) &&
+                   EqualSid(sid, current_user_sid))
+                       result = 1;
+       }
+       /*
+        * We can release the security descriptor struct only now because `sid`
+        * actually points into this struct.
+        */
+       if (descriptor)
+               LocalFree(descriptor);
+       return result;
+ }
  int is_valid_win32_path(const char *path, int allow_literal_nul)
  {
        const char *p = path;
diff --combined git-compat-util.h
index 1229c8296b92547b89bc1cc29e6f2415fa1370af,4b57ae6f270e713d2e771c91a754e8aac39c4ff9..e30a374a84fa04440f48f42145d2591dd33a4c9f
@@@ -1,19 -1,6 +1,19 @@@
  #ifndef GIT_COMPAT_UTIL_H
  #define GIT_COMPAT_UTIL_H
  
 +#if __STDC_VERSION__ - 0 < 199901L
 +/*
 + * Git is in a testing period for mandatory C99 support in the compiler.  If
 + * your compiler is reasonably recent, you can try to enable C99 support (or,
 + * for MSVC, C11 support).  If you encounter a problem and can't enable C99
 + * support with your compiler (such as with "-std=gnu99") and don't have access
 + * to one with this support, such as GCC or Clang, you can remove this #if
 + * directive, but please report the details of your system to
 + * git@vger.kernel.org.
 + */
 +#error "Required C99 support is in a test phase.  Please see git-compat-util.h for more details."
 +#endif
 +
  #ifdef USE_MSVC_CRTDBG
  /*
   * For these to work they must appear very early in each
  /*
   * See if our compiler is known to support flexible array members.
   */
 -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && (!defined(__SUNPRO_C) || (__SUNPRO_C > 0x580))
 -# define FLEX_ARRAY /* empty */
 +
 +/*
 + * Check vendor specific quirks first, before checking the
 + * __STDC_VERSION__, as vendor compilers can lie and we need to be
 + * able to work them around.  Note that by not defining FLEX_ARRAY
 + * here, we can fall back to use the "safer but a bit wasteful" one
 + * later.
 + */
 +#if defined(__SUNPRO_C) && (__SUNPRO_C <= 0x580)
  #elif defined(__GNUC__)
  # if (__GNUC__ >= 3)
  #  define FLEX_ARRAY /* empty */
  # else
  #  define FLEX_ARRAY 0 /* older GNU extension */
  # endif
 +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
 +# define FLEX_ARRAY /* empty */
  #endif
  
  /*
  #define unsigned_mult_overflows(a, b) \
      ((a) && (b) > maximum_unsigned_value_of_type(a) / (a))
  
 +/*
 + * Returns true if the left shift of "a" by "shift" bits will
 + * overflow. The type of "a" must be unsigned.
 + */
 +#define unsigned_left_shift_overflows(a, shift) \
 +    ((shift) < bitsizeof(a) && \
 +     (a) > maximum_unsigned_value_of_type(a) >> (shift))
 +
  #ifdef __GNUC__
  #define TYPEOF(x) (__typeof__(x))
  #else
@@@ -430,6 -400,18 +430,18 @@@ static inline int git_offset_1st_compon
  #define is_valid_path(path) 1
  #endif
  
+ #ifndef is_path_owned_by_current_user
+ static inline int is_path_owned_by_current_uid(const char *path)
+ {
+       struct stat st;
+       if (lstat(path, &st))
+               return 0;
+       return st.st_uid == geteuid();
+ }
+ #define is_path_owned_by_current_user is_path_owned_by_current_uid
+ #endif
  #ifndef find_last_dir_sep
  static inline char *git_find_last_dir_sep(const char *path)
  {
@@@ -498,12 -480,11 +510,12 @@@ static inline int git_has_dir_sep(cons
  struct strbuf;
  
  /* General helper functions */
 -void vreportf(const char *prefix, const char *err, va_list params);
  NORETURN void usage(const char *err);
  NORETURN void usagef(const char *err, ...) __attribute__((format (printf, 1, 2)));
  NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2)));
  NORETURN void die_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
 +int die_message(const char *err, ...) __attribute__((format (printf, 1, 2)));
 +int die_message_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
  int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
  int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
  void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
@@@ -538,7 -519,6 +550,7 @@@ static inline int const_error(void
  typedef void (*report_fn)(const char *, va_list params);
  
  void set_die_routine(NORETURN_PTR report_fn routine);
 +report_fn get_die_message_routine(void);
  void set_error_routine(report_fn routine);
  report_fn get_error_routine(void);
  void set_warn_routine(report_fn routine);
@@@ -763,7 -743,7 +775,7 @@@ char *gitmkdtemp(char *)
  
  #ifdef NO_UNSETENV
  #define unsetenv gitunsetenv
 -void gitunsetenv(const char *);
 +int gitunsetenv(const char *);
  #endif
  
  #ifdef NO_STRCASESTR
@@@ -896,23 -876,6 +908,23 @@@ static inline size_t st_sub(size_t a, s
        return a - b;
  }
  
 +static inline size_t st_left_shift(size_t a, unsigned shift)
 +{
 +      if (unsigned_left_shift_overflows(a, shift))
 +              die("size_t overflow: %"PRIuMAX" << %u",
 +                  (uintmax_t)a, shift);
 +      return a << shift;
 +}
 +
 +static inline unsigned long cast_size_t_to_ulong(size_t a)
 +{
 +      if (a != (unsigned long)a)
 +              die("object too large to read on this platform: %"
 +                  PRIuMAX" is cut off to %lu",
 +                  (uintmax_t)a, (unsigned long)a);
 +      return (unsigned long)a;
 +}
 +
  #ifdef HAVE_ALLOCA_H
  # include <alloca.h>
  # define xalloca(size)      (alloca(size))
diff --combined setup.c
index af3b8c09abe398edd0f45828b81ecec72b3900b6,2ed94baac92091baf5bcb31fa3b7acbf712b26c9..b03c38297883651fc66343ac1cee1df764fdec01
+++ b/setup.c
@@@ -5,6 -5,7 +5,7 @@@
  #include "string-list.h"
  #include "chdir-notify.h"
  #include "promisor-remote.h"
+ #include "quote.h"
  
  static int inside_git_dir = -1;
  static int inside_work_tree = -1;
@@@ -12,7 -13,6 +13,7 @@@ static int work_tree_config_is_bogus
  
  static struct startup_info the_startup_info;
  struct startup_info *startup_info = &the_startup_info;
 +const char *tmp_original_cwd;
  
  /*
   * The input parameter must contain an absolute path, and it must already be
@@@ -433,69 -433,6 +434,69 @@@ void setup_work_tree(void
        initialized = 1;
  }
  
 +static void setup_original_cwd(void)
 +{
 +      struct strbuf tmp = STRBUF_INIT;
 +      const char *worktree = NULL;
 +      int offset = -1;
 +
 +      if (!tmp_original_cwd)
 +              return;
 +
 +      /*
 +       * startup_info->original_cwd points to the current working
 +       * directory we inherited from our parent process, which is a
 +       * directory we want to avoid removing.
 +       *
 +       * For convience, we would like to have the path relative to the
 +       * worktree instead of an absolute path.
 +       *
 +       * Yes, startup_info->original_cwd is usually the same as 'prefix',
 +       * but differs in two ways:
 +       *   - prefix has a trailing '/'
 +       *   - if the user passes '-C' to git, that modifies the prefix but
 +       *     not startup_info->original_cwd.
 +       */
 +
 +      /* Normalize the directory */
 +      strbuf_realpath(&tmp, tmp_original_cwd, 1);
 +      free((char*)tmp_original_cwd);
 +      tmp_original_cwd = NULL;
 +      startup_info->original_cwd = strbuf_detach(&tmp, NULL);
 +
 +      /*
 +       * Get our worktree; we only protect the current working directory
 +       * if it's in the worktree.
 +       */
 +      worktree = get_git_work_tree();
 +      if (!worktree)
 +              goto no_prevention_needed;
 +
 +      offset = dir_inside_of(startup_info->original_cwd, worktree);
 +      if (offset >= 0) {
 +              /*
 +               * If startup_info->original_cwd == worktree, that is already
 +               * protected and we don't need original_cwd as a secondary
 +               * protection measure.
 +               */
 +              if (!*(startup_info->original_cwd + offset))
 +                      goto no_prevention_needed;
 +
 +              /*
 +               * original_cwd was inside worktree; precompose it just as
 +               * we do prefix so that built up paths will match
 +               */
 +              startup_info->original_cwd = \
 +                      precompose_string_if_needed(startup_info->original_cwd
 +                                                  + offset);
 +              return;
 +      }
 +
 +no_prevention_needed:
 +      free((char*)startup_info->original_cwd);
 +      startup_info->original_cwd = NULL;
 +}
 +
  static int read_worktree_config(const char *var, const char *value, void *vdata)
  {
        struct repository_format *data = vdata;
@@@ -1089,6 -1026,42 +1090,42 @@@ static int canonicalize_ceiling_entry(s
        }
  }
  
+ struct safe_directory_data {
+       const char *path;
+       int is_safe;
+ };
+ static int safe_directory_cb(const char *key, const char *value, void *d)
+ {
+       struct safe_directory_data *data = d;
+       if (!value || !*value)
+               data->is_safe = 0;
+       else {
+               const char *interpolated = NULL;
+               if (!git_config_pathname(&interpolated, key, value) &&
+                   !fspathcmp(data->path, interpolated ? interpolated : value))
+                       data->is_safe = 1;
+               free((char *)interpolated);
+       }
+       return 0;
+ }
+ static int ensure_valid_ownership(const char *path)
+ {
+       struct safe_directory_data data = { .path = path };
+       if (is_path_owned_by_current_user(path))
+               return 1;
+       read_very_early_config(safe_directory_cb, &data);
+       return data.is_safe;
+ }
  enum discovery_result {
        GIT_DIR_NONE = 0,
        GIT_DIR_EXPLICIT,
        /* these are errors */
        GIT_DIR_HIT_CEILING = -1,
        GIT_DIR_HIT_MOUNT_POINT = -2,
-       GIT_DIR_INVALID_GITFILE = -3
+       GIT_DIR_INVALID_GITFILE = -3,
+       GIT_DIR_INVALID_OWNERSHIP = -4
  };
  
  /*
@@@ -1187,11 -1161,15 +1225,15 @@@ static enum discovery_result setup_git_
                }
                strbuf_setlen(dir, offset);
                if (gitdirenv) {
+                       if (!ensure_valid_ownership(dir->buf))
+                               return GIT_DIR_INVALID_OWNERSHIP;
                        strbuf_addstr(gitdir, gitdirenv);
                        return GIT_DIR_DISCOVERED;
                }
  
                if (is_git_directory(dir->buf)) {
+                       if (!ensure_valid_ownership(dir->buf))
+                               return GIT_DIR_INVALID_OWNERSHIP;
                        strbuf_addstr(gitdir, ".");
                        return GIT_DIR_BARE;
                }
@@@ -1323,6 -1301,19 +1365,19 @@@ const char *setup_git_directory_gently(
                            dir.buf);
                *nongit_ok = 1;
                break;
+       case GIT_DIR_INVALID_OWNERSHIP:
+               if (!nongit_ok) {
+                       struct strbuf quoted = STRBUF_INIT;
+                       sq_quote_buf_pretty(&quoted, dir.buf);
+                       die(_("unsafe repository ('%s' is owned by someone else)\n"
+                             "To add an exception for this directory, call:\n"
+                             "\n"
+                             "\tgit config --global --add safe.directory %s"),
+                           dir.buf, quoted.buf);
+               }
+               *nongit_ok = 1;
+               break;
        case GIT_DIR_NONE:
                /*
                 * As a safeguard against setup_git_directory_gently_1 returning
                setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
        }
  
 +      setup_original_cwd();
  
        strbuf_release(&dir);
        strbuf_release(&gitdir);
diff --combined t/t0060-path-utils.sh
index 71a5d370cc7bc7d369b7e3099c064bc8cb114d7d,96f0123cca14a43257571439156f2eb8b04ecd84..2fe6ae6a4e544cb4f58ad96e22ee6b24c076de94
@@@ -55,12 -55,15 +55,15 @@@ f
  ancestor() {
        # We do some math with the expected ancestor length.
        expected=$3
-       if test -n "$rootoff" && test "x$expected" != x-1; then
-               expected=$(($expected-$rootslash))
-               test $expected -lt 0 ||
-               expected=$(($expected+$rootoff))
-       fi
-       test_expect_success "longest ancestor: $1 $2 => $expected" \
+       case "$rootoff,$expected,$2" in
+       *,*,//*) ;; # leave UNC paths alone
+       [0-9]*,[0-9]*,/*)
+               # On Windows, expect MSYS2 pseudo root translation for
+               # Unix-style absolute paths
+               expected=$(($expected-$rootslash+$rootoff))
+               ;;
+       esac
+       test_expect_success $4 "longest ancestor: $1 $2 => $expected" \
        "actual=\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&
         test \"\$actual\" = '$expected'"
  }
@@@ -156,6 -159,11 +159,11 @@@ ancestor /foo/bar /foo 
  ancestor /foo/bar /foo:/bar 4
  ancestor /foo/bar /bar -1
  
+ # Windows-specific: DOS drives, network shares
+ ancestor C:/Users/me C:/ 2 MINGW
+ ancestor D:/Users/me C:/ -1 MINGW
+ ancestor //server/share/my-directory //server/share/ 14 MINGW
  test_expect_success 'strip_path_suffix' '
        test c:/msysgit = $(test-tool path-utils strip_path_suffix \
                c:/msysgit/libexec//git-core libexec/git-core)
@@@ -216,7 -224,7 +224,7 @@@ test_expect_success SYMLINKS 'real pat
        mkdir second &&
        ln -s ../first second/other &&
        mkdir third &&
 -      dir="$(cd .git; pwd -P)" &&
 +      dir="$(cd .git && pwd -P)" &&
        dir2=third/../second/other/.git &&
        test "$dir" = "$(test-tool path-utils real_path $dir2)" &&
        file="$dir"/index &&
        basename=blub &&
        test "$dir/$basename" = "$(cd .git && test-tool path-utils real_path "$basename")" &&
        ln -s ../first/file .git/syml &&
 -      sym="$(cd first; pwd -P)"/file &&
 +      sym="$(cd first && pwd -P)"/file &&
        test "$sym" = "$(test-tool path-utils real_path "$dir2/syml")"
  '