summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schindelin <johannes.schindelin@gmx.de>2023-03-11 19:24:34 +0100
committerJohannes Schindelin <johannes.schindelin@gmx.de>2023-04-17 21:15:49 +0200
commit31f7fe5e34612b4b8af3918d0b0cf2ea2545c2c4 (patch)
tree84caab407ab446f3179892bb2a48bf4ff14ee295
parent2aedeff35fde779b03b57125b1f50f6c528bfbea (diff)
parentea56f91275c1797776f10f4ac5d65671bb4f3e8b (diff)
downloadgit-31f7fe5e34612b4b8af3918d0b0cf2ea2545c2c4.tar.gz
Sync with 2.31.8
* maint-2.31: (25 commits) Git 2.31.8 tests: avoid using `test_i18ncmp` Git 2.30.9 gettext: avoid using gettext if the locale dir is not present apply --reject: overwrite existing `.rej` symlink if it exists http.c: clear the 'finished' member once we are done with it clone.c: avoid "exceeds maximum object size" error with GCC v12.x range-diff: use ssize_t for parsed "len" in read_patches() range-diff: handle unterminated lines in read_patches() range-diff: drop useless "offset" variable from read_patches() t5604: GETTEXT_POISON fix, conclusion t5604: GETTEXT_POISON fix, part 1 t5619: GETTEXT_POISON fix t0003: GETTEXT_POISON fix, conclusion t0003: GETTEXT_POISON fix, part 1 t0033: GETTEXT_POISON fix http: support CURLOPT_PROTOCOLS_STR http: prefer CURLOPT_SEEKFUNCTION to CURLOPT_IOCTLFUNCTION http-push: prefer CURLOPT_UPLOAD to CURLOPT_PUT ci: install python on ubuntu ci: use the same version of p4 on both Linux and macOS ...
-rw-r--r--.github/workflows/main.yml4
-rw-r--r--Documentation/RelNotes/2.30.9.txt43
-rw-r--r--Documentation/RelNotes/2.31.8.txt6
-rw-r--r--INSTALL4
-rw-r--r--apply.c14
-rw-r--r--builtin/clone.c9
-rwxr-xr-xci/install-dependencies.sh24
-rwxr-xr-xci/lib.sh7
-rw-r--r--compat/nedmalloc/nedmalloc.c1
-rw-r--r--compat/win32/syslog.c2
-rw-r--r--config.c36
-rw-r--r--gettext.c4
-rw-r--r--gettext.h6
-rw-r--r--http-push.c8
-rw-r--r--http.c105
-rw-r--r--http.h8
-rw-r--r--range-diff.c29
-rw-r--r--remote-curl.c32
-rwxr-xr-xt/t0033-safe-directory.sh2
-rwxr-xr-xt/t1300-config.sh30
-rwxr-xr-xt/t4115-apply-symlink.sh15
21 files changed, 291 insertions, 98 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 73856bafc9..158be9a83a 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -287,7 +287,7 @@ jobs:
pool: ubuntu-latest
- jobname: linux-gcc
cc: gcc
- pool: ubuntu-latest
+ pool: ubuntu-20.04
- jobname: osx-clang
cc: clang
pool: macos-latest
@@ -345,7 +345,7 @@ jobs:
if: needs.ci-config.outputs.enabled == 'yes'
env:
jobname: StaticAnalysis
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v1
- run: ci/install-dependencies.sh
diff --git a/Documentation/RelNotes/2.30.9.txt b/Documentation/RelNotes/2.30.9.txt
new file mode 100644
index 0000000000..708d626ce6
--- /dev/null
+++ b/Documentation/RelNotes/2.30.9.txt
@@ -0,0 +1,43 @@
+Git v2.30.9 Release Notes
+=========================
+
+This release addresses the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007.
+
+
+Fixes since v2.30.8
+-------------------
+
+ * CVE-2023-25652:
+
+ By feeding specially crafted input to `git apply --reject`, a
+ path outside the working tree can be overwritten with partially
+ controlled contents (corresponding to the rejected hunk(s) from
+ the given patch).
+
+ * CVE-2023-25815:
+
+ When Git is compiled with runtime prefix support and runs without
+ translated messages, it still used the gettext machinery to
+ display messages, which subsequently potentially looked for
+ translated messages in unexpected places. This allowed for
+ malicious placement of crafted messages.
+
+ * CVE-2023-29007:
+
+ When renaming or deleting a section from a configuration file,
+ certain malicious configuration values may be misinterpreted as
+ the beginning of a new configuration section, leading to arbitrary
+ configuration injection.
+
+Credit for finding CVE-2023-25652 goes to Ry0taK, and the fix was
+developed by Taylor Blau, Junio C Hamano and Johannes Schindelin,
+with the help of Linus Torvalds.
+
+Credit for finding CVE-2023-25815 goes to Maxime Escourbiac and
+Yassine BENGANA of Michelin, and the fix was developed by Johannes
+Schindelin.
+
+Credit for finding CVE-2023-29007 goes to André Baptista and Vítor Pinho
+of Ethiack, and the fix was developed by Taylor Blau, and Johannes
+Schindelin, with help from Jeff King, and Patrick Steinhardt.
diff --git a/Documentation/RelNotes/2.31.8.txt b/Documentation/RelNotes/2.31.8.txt
new file mode 100644
index 0000000000..0aa3080780
--- /dev/null
+++ b/Documentation/RelNotes/2.31.8.txt
@@ -0,0 +1,6 @@
+Git v2.31.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9 to address the
+security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007;
+see the release notes for that version for details.
diff --git a/INSTALL b/INSTALL
index 66389ce059..a108568555 100644
--- a/INSTALL
+++ b/INSTALL
@@ -145,6 +145,10 @@ Issues of note:
patches into an IMAP mailbox, you do not have to have them
(use NO_CURL).
+ Git requires version "7.19.5" or later of "libcurl" to build
+ without NO_CURL. This version requirement may be bumped in
+ the future.
+
- "expat" library; git-http-push uses it for remote lock
management over DAV. Similar to "curl" above, this is optional
(with NO_EXPAT).
diff --git a/apply.c b/apply.c
index f562f799d6..1f40330a7c 100644
--- a/apply.c
+++ b/apply.c
@@ -4560,7 +4560,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
FILE *rej;
char namebuf[PATH_MAX];
struct fragment *frag;
- int cnt = 0;
+ int fd, cnt = 0;
struct strbuf sb = STRBUF_INIT;
for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
@@ -4600,7 +4600,17 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch)
memcpy(namebuf, patch->new_name, cnt);
memcpy(namebuf + cnt, ".rej", 5);
- rej = fopen(namebuf, "w");
+ fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (fd < 0) {
+ if (errno != EEXIST)
+ return error_errno(_("cannot open %s"), namebuf);
+ if (unlink(namebuf))
+ return error_errno(_("cannot unlink '%s'"), namebuf);
+ fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (fd < 0)
+ return error_errno(_("cannot open %s"), namebuf);
+ }
+ rej = fdopen(fd, "w");
if (!rej)
return error_errno(_("cannot open %s"), namebuf);
diff --git a/builtin/clone.c b/builtin/clone.c
index 97de324e54..1f6338a223 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -255,6 +255,15 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
}
/*
+ * It should not be possible to overflow `ptrdiff_t` by passing in an
+ * insanely long URL, but GCC does not know that and will complain
+ * without this check.
+ */
+ if (end - start < 0)
+ die(_("No directory name could be guessed.\n"
+ "Please specify a directory on the command line"));
+
+ /*
* Strip trailing port number if we've got only a
* hostname (that is, there is no dir separator but a
* colon). This check is required such that we do not
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index 67852d0d37..340f51e9ec 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -5,7 +5,7 @@
. ${0%/*}/lib.sh
-P4WHENCE=http://filehost.perforce.com/perforce/r$LINUX_P4_VERSION
+P4WHENCE=https://cdist2.perforce.com/perforce/r21.2
LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION
UBUNTU_COMMON_PKGS="make libssl-dev libcurl4-openssl-dev libexpat-dev
tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl
@@ -16,7 +16,7 @@ linux-clang|linux-gcc)
sudo apt-add-repository -y "ppa:ubuntu-toolchain-r/test"
sudo apt-get -q update
sudo apt-get -q -y install language-pack-is libsvn-perl apache2 \
- $UBUNTU_COMMON_PKGS
+ $UBUNTU_COMMON_PKGS $PYTHON_PACKAGE
case "$jobname" in
linux-gcc)
sudo apt-get -q -y install gcc-8
@@ -44,13 +44,15 @@ osx-clang|osx-gcc)
test -z "$BREW_INSTALL_PACKAGES" ||
brew install $BREW_INSTALL_PACKAGES
brew link --force gettext
- brew install --cask --no-quarantine perforce || {
- # Update the definitions and try again
- cask_repo="$(brew --repository)"/Library/Taps/homebrew/homebrew-cask &&
- git -C "$cask_repo" pull --no-stat --ff-only &&
- brew install --cask --no-quarantine perforce
- } ||
- brew install homebrew/cask/perforce
+ mkdir -p $HOME/bin
+ (
+ cd $HOME/bin
+ wget -q "$P4WHENCE/bin.macosx1015x86_64/helix-core-server.tgz" &&
+ tar -xf helix-core-server.tgz &&
+ sudo xattr -d com.apple.quarantine p4 p4d 2>/dev/null || true
+ )
+ PATH="$PATH:${HOME}/bin"
+ export PATH
case "$jobname" in
osx-gcc)
brew install gcc@9
@@ -81,9 +83,9 @@ esac
if type p4d >/dev/null && type p4 >/dev/null
then
echo "$(tput setaf 6)Perforce Server Version$(tput sgr0)"
- p4d -V | grep Rev.
+ p4d -V
echo "$(tput setaf 6)Perforce Client Version$(tput sgr0)"
- p4 -V | grep Rev.
+ p4 -V
fi
if type git-lfs >/dev/null
then
diff --git a/ci/lib.sh b/ci/lib.sh
index d848c036c5..890b0bdfd0 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -184,13 +184,13 @@ export SKIP_DASHED_BUILT_INS=YesPlease
case "$jobname" in
linux-clang|linux-gcc)
+ PYTHON_PACKAGE=python2
if [ "$jobname" = linux-gcc ]
then
export CC=gcc-8
- MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python3"
- else
- MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python2"
+ PYTHON_PACKAGE=python3
fi
+ MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/$PYTHON_PACKAGE"
export GIT_TEST_HTTPD=true
@@ -199,7 +199,6 @@ linux-clang|linux-gcc)
# were recorded in the Homebrew database upon creating the OS X
# image.
# Keep that in mind when you encounter a broken OS X build!
- export LINUX_P4_VERSION="16.2"
export LINUX_GIT_LFS_VERSION="1.5.2"
P4_PATH="$HOME/custom/p4"
diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c
index 1cc31c3502..141c30f07f 100644
--- a/compat/nedmalloc/nedmalloc.c
+++ b/compat/nedmalloc/nedmalloc.c
@@ -323,7 +323,6 @@ static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned in
}
static void DestroyCaches(nedpool *p) THROWSPEC
{
- if(p->caches)
{
threadcache *tc;
int n;
diff --git a/compat/win32/syslog.c b/compat/win32/syslog.c
index 161978d720..1f8d8934cc 100644
--- a/compat/win32/syslog.c
+++ b/compat/win32/syslog.c
@@ -43,6 +43,7 @@ void syslog(int priority, const char *fmt, ...)
va_end(ap);
while ((pos = strstr(str, "%1")) != NULL) {
+ size_t offset = pos - str;
char *oldstr = str;
str = realloc(str, st_add(++str_len, 1));
if (!str) {
@@ -50,6 +51,7 @@ void syslog(int priority, const char *fmt, ...)
warning_errno("realloc failed");
return;
}
+ pos = str + offset;
memmove(pos + 2, pos + 1, strlen(pos));
pos[1] = ' ';
}
diff --git a/config.c b/config.c
index f9c400ad30..159ae9c72c 100644
--- a/config.c
+++ b/config.c
@@ -3198,9 +3198,10 @@ void git_config_set_multivar(const char *key, const char *value,
flags);
}
-static int section_name_match (const char *buf, const char *name)
+static size_t section_name_match (const char *buf, const char *name)
{
- int i = 0, j = 0, dot = 0;
+ size_t i = 0, j = 0;
+ int dot = 0;
if (buf[i] != '[')
return 0;
for (i = 1; buf[i] && buf[i] != ']'; i++) {
@@ -3253,6 +3254,8 @@ static int section_name_is_ok(const char *name)
return 1;
}
+#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
+
/* if new_name == NULL, the section is removed instead */
static int git_config_copy_or_rename_section_in_file(const char *config_filename,
const char *old_name,
@@ -3262,11 +3265,12 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
char *filename_buf = NULL;
struct lock_file lock = LOCK_INIT;
int out_fd;
- char buf[1024];
+ struct strbuf buf = STRBUF_INIT;
FILE *config_file = NULL;
struct stat st;
struct strbuf copystr = STRBUF_INIT;
struct config_store_data store;
+ uint32_t line_nr = 0;
memset(&store, 0, sizeof(store));
@@ -3303,16 +3307,25 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
goto out;
}
- while (fgets(buf, sizeof(buf), config_file)) {
- unsigned i;
- int length;
+ while (!strbuf_getwholeline(&buf, config_file, '\n')) {
+ size_t i, length;
int is_section = 0;
- char *output = buf;
- for (i = 0; buf[i] && isspace(buf[i]); i++)
+ char *output = buf.buf;
+
+ line_nr++;
+
+ if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) {
+ ret = error(_("refusing to work with overly long line "
+ "in '%s' on line %"PRIuMAX),
+ config_filename, (uintmax_t)line_nr);
+ goto out;
+ }
+
+ for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++)
; /* do nothing */
- if (buf[i] == '[') {
+ if (buf.buf[i] == '[') {
/* it's a section */
- int offset;
+ size_t offset;
is_section = 1;
/*
@@ -3329,7 +3342,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
strbuf_reset(&copystr);
}
- offset = section_name_match(&buf[i], old_name);
+ offset = section_name_match(&buf.buf[i], old_name);
if (offset > 0) {
ret++;
if (new_name == NULL) {
@@ -3404,6 +3417,7 @@ out:
out_no_rollback:
free(filename_buf);
config_store_data_clear(&store);
+ strbuf_release(&buf);
return ret;
}
diff --git a/gettext.c b/gettext.c
index af2413b47e..16caf5432a 100644
--- a/gettext.c
+++ b/gettext.c
@@ -101,6 +101,8 @@ static void init_gettext_charset(const char *domain)
setlocale(LC_CTYPE, "C");
}
+int git_gettext_enabled = 0;
+
void git_setup_gettext(void)
{
const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT);
@@ -120,6 +122,8 @@ void git_setup_gettext(void)
init_gettext_charset("git");
textdomain("git");
+ git_gettext_enabled = 1;
+
free(p);
}
diff --git a/gettext.h b/gettext.h
index c8b34fd612..5b42e458e5 100644
--- a/gettext.h
+++ b/gettext.h
@@ -29,9 +29,11 @@
#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
#ifndef NO_GETTEXT
+extern int git_gettext_enabled;
void git_setup_gettext(void);
int gettext_width(const char *s);
#else
+#define git_gettext_enabled (0)
static inline void git_setup_gettext(void)
{
}
@@ -45,12 +47,16 @@ static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
{
if (!*msgid)
return "";
+ if (!git_gettext_enabled)
+ return msgid;
return gettext(msgid);
}
static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
const char *Q_(const char *msgid, const char *plu, unsigned long n)
{
+ if (!git_gettext_enabled)
+ return n == 1 ? msgid : plu;
return ngettext(msgid, plu, n);
}
diff --git a/http-push.c b/http-push.c
index d7cb1675a2..b6db3b9043 100644
--- a/http-push.c
+++ b/http-push.c
@@ -198,14 +198,14 @@ static void curl_setup_http(CURL *curl, const char *url,
const char *custom_req, struct buffer *buffer,
curl_write_callback write_fn)
{
- curl_easy_setopt(curl, CURLOPT_PUT, 1);
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_INFILE, buffer);
curl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
-#ifndef NO_CURL_IOCTL
- curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
- curl_easy_setopt(curl, CURLOPT_IOCTLDATA, buffer);
+#ifndef NO_CURL_SEEK
+ curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_buffer);
+ curl_easy_setopt(curl, CURLOPT_SEEKDATA, buffer);
#endif
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_fn);
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
diff --git a/http.c b/http.c
index 8119247149..d43bb40100 100644
--- a/http.c
+++ b/http.c
@@ -186,22 +186,20 @@ size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
return size / eltsize;
}
-#ifndef NO_CURL_IOCTL
-curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp)
+#ifndef NO_CURL_SEEK
+int seek_buffer(void *clientp, curl_off_t offset, int origin)
{
struct buffer *buffer = clientp;
- switch (cmd) {
- case CURLIOCMD_NOP:
- return CURLIOE_OK;
-
- case CURLIOCMD_RESTARTREAD:
- buffer->posn = 0;
- return CURLIOE_OK;
-
- default:
- return CURLIOE_UNKNOWNCMD;
+ if (origin != SEEK_SET)
+ BUG("seek_buffer only handles SEEK_SET");
+ if (offset < 0 || offset >= buffer->buf.len) {
+ error("curl seek would be outside of buffer");
+ return CURL_SEEKFUNC_FAIL;
}
+
+ buffer->posn = offset;
+ return CURL_SEEKFUNC_OK;
}
#endif
@@ -810,20 +808,37 @@ void setup_curl_trace(CURL *handle)
}
#ifdef CURLPROTO_HTTP
-static long get_curl_allowed_protocols(int from_user)
+static void proto_list_append(struct strbuf *list, const char *proto)
+{
+ if (!list)
+ return;
+ if (list->len)
+ strbuf_addch(list, ',');
+ strbuf_addstr(list, proto);
+}
+
+static long get_curl_allowed_protocols(int from_user, struct strbuf *list)
{
- long allowed_protocols = 0;
+ long bits = 0;
- if (is_transport_allowed("http", from_user))
- allowed_protocols |= CURLPROTO_HTTP;
- if (is_transport_allowed("https", from_user))
- allowed_protocols |= CURLPROTO_HTTPS;
- if (is_transport_allowed("ftp", from_user))
- allowed_protocols |= CURLPROTO_FTP;
- if (is_transport_allowed("ftps", from_user))
- allowed_protocols |= CURLPROTO_FTPS;
+ if (is_transport_allowed("http", from_user)) {
+ bits |= CURLPROTO_HTTP;
+ proto_list_append(list, "http");
+ }
+ if (is_transport_allowed("https", from_user)) {
+ bits |= CURLPROTO_HTTPS;
+ proto_list_append(list, "https");
+ }
+ if (is_transport_allowed("ftp", from_user)) {
+ bits |= CURLPROTO_FTP;
+ proto_list_append(list, "ftp");
+ }
+ if (is_transport_allowed("ftps", from_user)) {
+ bits |= CURLPROTO_FTPS;
+ proto_list_append(list, "ftps");
+ }
- return allowed_protocols;
+ return bits;
}
#endif
@@ -981,10 +996,24 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_POST301, 1);
#endif
#ifdef CURLPROTO_HTTP
+#if LIBCURL_VERSION_NUM >= 0x075500
+ {
+ struct strbuf buf = STRBUF_INIT;
+
+ get_curl_allowed_protocols(0, &buf);
+ curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS_STR, buf.buf);
+ strbuf_reset(&buf);
+
+ get_curl_allowed_protocols(-1, &buf);
+ curl_easy_setopt(result, CURLOPT_PROTOCOLS_STR, buf.buf);
+ strbuf_release(&buf);
+ }
+#else
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS,
- get_curl_allowed_protocols(0));
+ get_curl_allowed_protocols(0, NULL));
curl_easy_setopt(result, CURLOPT_PROTOCOLS,
- get_curl_allowed_protocols(-1));
+ get_curl_allowed_protocols(-1, NULL));
+#endif
#else
warning(_("Protocol restrictions not supported with cURL < 7.19.4"));
#endif
@@ -1523,6 +1552,32 @@ void run_active_slot(struct active_request_slot *slot)
finish_active_slot(slot);
}
#endif
+
+ /*
+ * The value of slot->finished we set before the loop was used
+ * to set our "finished" variable when our request completed.
+ *
+ * 1. The slot may not have been reused for another requst
+ * yet, in which case it still has &finished.
+ *
+ * 2. The slot may already be in-use to serve another request,
+ * which can further be divided into two cases:
+ *
+ * (a) If call run_active_slot() hasn't been called for that
+ * other request, slot->finished would have been cleared
+ * by get_active_slot() and has NULL.
+ *
+ * (b) If the request did call run_active_slot(), then the
+ * call would have updated slot->finished at the beginning
+ * of this function, and with the clearing of the member
+ * below, we would find that slot->finished is now NULL.
+ *
+ * In all cases, slot->finished has no useful information to
+ * anybody at this point. Some compilers warn us for
+ * attempting to smuggle a pointer that is about to become
+ * invalid, i.e. &finished. We clear it here to assure them.
+ */
+ slot->finished = NULL;
}
static void release_active_slot(struct active_request_slot *slot)
diff --git a/http.h b/http.h
index bf3d1270ad..54084d92ac 100644
--- a/http.h
+++ b/http.h
@@ -41,8 +41,8 @@
#define CURLE_HTTP_RETURNED_ERROR CURLE_HTTP_NOT_FOUND
#endif
-#if LIBCURL_VERSION_NUM < 0x070c03
-#define NO_CURL_IOCTL
+#if LIBCURL_VERSION_NUM < 0x071200
+#define NO_CURL_SEEK
#endif
/*
@@ -82,8 +82,8 @@ struct buffer {
size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
-#ifndef NO_CURL_IOCTL
-curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);
+#ifndef NO_CURL_SEEK
+int seek_buffer(void *clientp, curl_off_t offset, int origin);
#endif
/* Slot lifecycle functions */
diff --git a/range-diff.c b/range-diff.c
index 1a4471fe4c..012b4ea6d2 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -26,17 +26,6 @@ struct patch_util {
struct object_id oid;
};
-static size_t find_end_of_line(char *buffer, unsigned long size)
-{
- char *eol = memchr(buffer, '\n', size);
-
- if (!eol)
- return size;
-
- *eol = '\0';
- return eol + 1 - buffer;
-}
-
/*
* Reads the patches into a string list, with the `util` field being populated
* as struct object_id (will need to be free()d).
@@ -49,7 +38,7 @@ static int read_patches(const char *range, struct string_list *list,
struct patch_util *util = NULL;
int in_header = 1;
char *line, *current_filename = NULL;
- int offset, len;
+ ssize_t len;
size_t size;
strvec_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges",
@@ -86,11 +75,18 @@ static int read_patches(const char *range, struct string_list *list,
line = contents.buf;
size = contents.len;
- for (offset = 0; size > 0; offset += len, size -= len, line += len) {
+ for (; size > 0; size -= len, line += len) {
const char *p;
+ char *eol;
+
+ eol = memchr(line, '\n', size);
+ if (eol) {
+ *eol = '\0';
+ len = eol + 1 - line;
+ } else {
+ len = size;
+ }
- len = find_end_of_line(line, size);
- line[len - 1] = '\0';
if (skip_prefix(line, "commit ", &p)) {
if (util) {
string_list_append(list, buf.buf)->util = util;
@@ -132,7 +128,8 @@ static int read_patches(const char *range, struct string_list *list,
strbuf_addch(&buf, '\n');
if (!util->diff_offset)
util->diff_offset = buf.len;
- line[len - 1] = '\n';
+ if (eol)
+ *eol = '\n';
orig_len = len;
len = parse_git_diff_header(&root, &linenr, 0, line,
len, size, &patch);
diff --git a/remote-curl.c b/remote-curl.c
index 9d432c299a..b26db93b31 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -709,26 +709,24 @@ static size_t rpc_out(void *ptr, size_t eltsize,
return avail;
}
-#ifndef NO_CURL_IOCTL
-static curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp)
+#ifndef NO_CURL_SEEK
+static int rpc_seek(void *clientp, curl_off_t offset, int origin)
{
struct rpc_state *rpc = clientp;
- switch (cmd) {
- case CURLIOCMD_NOP:
- return CURLIOE_OK;
+ if (origin != SEEK_SET)
+ BUG("rpc_seek only handles SEEK_SET, not %d", origin);
- case CURLIOCMD_RESTARTREAD:
- if (rpc->initial_buffer) {
- rpc->pos = 0;
- return CURLIOE_OK;
+ if (rpc->initial_buffer) {
+ if (offset < 0 || offset > rpc->len) {
+ error("curl seek would be outside of rpc buffer");
+ return CURL_SEEKFUNC_FAIL;
}
- error(_("unable to rewind rpc post data - try increasing http.postBuffer"));
- return CURLIOE_FAILRESTART;
-
- default:
- return CURLIOE_UNKNOWNCMD;
+ rpc->pos = offset;
+ return CURL_SEEKFUNC_OK;
}
+ error(_("unable to rewind rpc post data - try increasing http.postBuffer"));
+ return CURL_SEEKFUNC_FAIL;
}
#endif
@@ -949,9 +947,9 @@ retry:
rpc->initial_buffer = 1;
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out);
curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc);
-#ifndef NO_CURL_IOCTL
- curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, rpc_ioctl);
- curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, rpc);
+#ifndef NO_CURL_SEEK
+ curl_easy_setopt(slot->curl, CURLOPT_SEEKFUNCTION, rpc_seek);
+ curl_easy_setopt(slot->curl, CURLOPT_SEEKDATA, rpc);
#endif
if (options.verbosity > 1) {
fprintf(stderr, "POST %s (chunked)\n", rpc->service_name);
diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
index 239d93f4d2..22ae88398c 100755
--- a/t/t0033-safe-directory.sh
+++ b/t/t0033-safe-directory.sh
@@ -9,7 +9,7 @@ export GIT_TEST_ASSUME_DIFFERENT_OWNER
expect_rejected_dir () {
test_must_fail git status 2>err &&
- grep "safe.directory" err
+ grep "dubious ownership" err
}
test_expect_success 'safe.directory is not set' '
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 9ff46f3b04..b496ba057f 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -616,6 +616,36 @@ test_expect_success 'renaming to bogus section is rejected' '
test_must_fail git config --rename-section branch.zwei "bogus name"
'
+test_expect_success 'renaming a section with a long line' '
+ {
+ printf "[b]\\n" &&
+ printf " c = d %1024s [a] e = f\\n" " " &&
+ printf "[a] g = h\\n"
+ } >y &&
+ git config -f y --rename-section a xyz &&
+ test_must_fail git config -f y b.e
+'
+
+test_expect_success 'renaming an embedded section with a long line' '
+ {
+ printf "[b]\\n" &&
+ printf " c = d %1024s [a] [foo] e = f\\n" " " &&
+ printf "[a] g = h\\n"
+ } >y &&
+ git config -f y --rename-section a xyz &&
+ test_must_fail git config -f y foo.e
+'
+
+test_expect_success 'renaming a section with an overly-long line' '
+ {
+ printf "[b]\\n" &&
+ printf " c = d %525000s e" " " &&
+ printf "[a] g = h\\n"
+ } >y &&
+ test_must_fail git config -f y --rename-section a xyz 2>err &&
+ grep "refusing to work with overly long line in .y. on line 2" err
+'
+
cat >> .git/config << EOF
[branch "zwei"] a = 1 [branch "vier"]
EOF
diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
index 1acb7b2582..2b034ff771 100755
--- a/t/t4115-apply-symlink.sh
+++ b/t/t4115-apply-symlink.sh
@@ -125,4 +125,19 @@ test_expect_success SYMLINKS 'symlink escape when deleting file' '
test_path_is_file .git/delete-me
'
+test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' '
+ test_when_finished "git reset --hard && git clean -dfx" &&
+
+ test_commit file &&
+ echo modified >file.t &&
+ git diff -- file.t >patch &&
+ echo modified-again >file.t &&
+
+ ln -s foo file.t.rej &&
+ test_must_fail git apply patch --reject 2>err &&
+ test_i18ngrep "Rejected hunk" err &&
+ test_path_is_missing foo &&
+ test_path_is_file file.t.rej
+'
+
test_done