From 9db05711c98efc14f414d4c87135a34c13586e0b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 9 Mar 2023 16:02:54 +0100 Subject: apply --reject: overwrite existing `.rej` symlink if it exists The `git apply --reject` is expected to write out `.rej` files in case one or more hunks fail to apply cleanly. Historically, the command overwrites any existing `.rej` files. The idea being that apply/reject/edit cycles are relatively common, and the generated `.rej` files are not considered precious. But the command does not overwrite existing `.rej` symbolic links, and instead follows them. This is unsafe because the same patch could potentially create such a symbolic link and point at arbitrary paths outside the current worktree, and `git apply` would write the contents of the `.rej` file into that location. Therefore, let's make sure that any existing `.rej` file or symbolic link is removed before writing it. Reported-by: RyotaK Helped-by: Taylor Blau Helped-by: Junio C Hamano Helped-by: Linus Torvalds Signed-off-by: Johannes Schindelin --- apply.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'apply.c') diff --git a/apply.c b/apply.c index d80382c940..6634e9c510 100644 --- a/apply.c +++ b/apply.c @@ -4558,7 +4558,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) { @@ -4598,7 +4598,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); -- cgit v1.2.3