git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* Segfault in git_config_set_multivar_in_file_gently with direct_io in FUSE filesystem
@ 2016-12-16 18:41 Josh Bleecher Snyder
  2016-12-19  9:21 ` [PATCH] config.c: handle error case for fstat() calls Nguyễn Thái Ngọc Duy
  0 siblings, 1 reply; 7+ messages in thread
From: Josh Bleecher Snyder @ 2016-12-16 18:41 UTC (permalink / raw)
  To: git

I am using git with a simple in-memory FUSE filesystem. When I enable
direct_io, I get a segfault from
git_config_set_multivar_in_file_gently during git clone.

I have full reproduction instructions using Go and macOS at
https://github.com/josharian/gitbug. It also includes a stack trace in
case anyone wants to try blind debugging. Happy to provide more info
if it will help.

Thanks,
Josh

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] config.c: handle error case for fstat() calls
  2016-12-16 18:41 Segfault in git_config_set_multivar_in_file_gently with direct_io in FUSE filesystem Josh Bleecher Snyder
@ 2016-12-19  9:21 ` Nguyễn Thái Ngọc Duy
  2016-12-19 18:14   ` Junio C Hamano
  0 siblings, 1 reply; 7+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-12-19  9:21 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, josharian, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Will this fix the problem I'm replying to? I don't know. I found this
 while checking the code and it should be fixed regardless.

 config.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/config.c b/config.c
index 83fdecb..4973256 100644
--- a/config.c
+++ b/config.c
@@ -2194,7 +2194,12 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
 			goto out_free;
 		}
 
-		fstat(in_fd, &st);
+		if (fstat(in_fd, &st) == -1) {
+			error_errno(_("fstat on %s failed"), config_filename);
+			ret = CONFIG_INVALID_FILE;
+			goto out_free;
+		}
+
 		contents_sz = xsize_t(st.st_size);
 		contents = xmmap_gently(NULL, contents_sz, PROT_READ,
 					MAP_PRIVATE, in_fd, 0);
@@ -2414,7 +2419,10 @@ int git_config_rename_section_in_file(const char *config_filename,
 		goto unlock_and_out;
 	}
 
-	fstat(fileno(config_file), &st);
+	if (fstat(fileno(config_file), &st) == -1) {
+		ret = error_errno(_("fstat on %s failed"), config_filename);
+		goto out;
+	}
 
 	if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) {
 		ret = error_errno("chmod on %s failed",
-- 
2.8.2.524.g6ff3d78


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] config.c: handle error case for fstat() calls
  2016-12-19  9:21 ` [PATCH] config.c: handle error case for fstat() calls Nguyễn Thái Ngọc Duy
@ 2016-12-19 18:14   ` Junio C Hamano
  2016-12-20  9:47     ` Duy Nguyen
  0 siblings, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2016-12-19 18:14 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, josharian

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  Will this fix the problem I'm replying to? I don't know. I found this
>  while checking the code and it should be fixed regardless.

Yeah, from a cursory read, it is a step in the right direction to
check the return value of fstat().  

Shouldn't the error-return path in the second hunk rollback the
lockfile to clean after itself?  The existing "Oh, we cannot chmod
to match the original" check that comes immediately after shares the
same issue, so this is not a new problem, but making an existing one
worse.

>  config.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/config.c b/config.c
> index 83fdecb..4973256 100644
> --- a/config.c
> +++ b/config.c
> @@ -2194,7 +2194,12 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
>  			goto out_free;
>  		}
>  
> -		fstat(in_fd, &st);
> +		if (fstat(in_fd, &st) == -1) {
> +			error_errno(_("fstat on %s failed"), config_filename);
> +			ret = CONFIG_INVALID_FILE;
> +			goto out_free;
> +		}
> +
>  		contents_sz = xsize_t(st.st_size);
>  		contents = xmmap_gently(NULL, contents_sz, PROT_READ,
>  					MAP_PRIVATE, in_fd, 0);
> @@ -2414,7 +2419,10 @@ int git_config_rename_section_in_file(const char *config_filename,
>  		goto unlock_and_out;
>  	}
>  
> -	fstat(fileno(config_file), &st);
> +	if (fstat(fileno(config_file), &st) == -1) {
> +		ret = error_errno(_("fstat on %s failed"), config_filename);
> +		goto out;
> +	}
>  
>  	if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) {
>  		ret = error_errno("chmod on %s failed",

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] config.c: handle error case for fstat() calls
  2016-12-19 18:14   ` Junio C Hamano
@ 2016-12-20  9:47     ` Duy Nguyen
  2016-12-20  9:48       ` [PATCH 1/2] config.c: rename label unlock_and_out Nguyễn Thái Ngọc Duy
  0 siblings, 1 reply; 7+ messages in thread
From: Duy Nguyen @ 2016-12-20  9:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, josharian

On Mon, Dec 19, 2016 at 10:14:27AM -0800, Junio C Hamano wrote:
> Shouldn't the error-return path in the second hunk rollback the
> lockfile to clean after itself?  The existing "Oh, we cannot chmod
> to match the original" check that comes immediately after shares the
> same issue, so this is not a new problem, but making an existing one
> worse.

OK. How about two more patches on top (or bottom, does not matter)?
The second one should fix this. The first is sort of "good to do".

[PATCH 1/2] config.c: rename label unlock_and_out
[PATCH 2/2] config.c: handle lock file in error case in git_config_rename_...
--
Duy

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] config.c: rename label unlock_and_out
  2016-12-20  9:47     ` Duy Nguyen
@ 2016-12-20  9:48       ` Nguyễn Thái Ngọc Duy
  2016-12-20  9:48         ` [PATCH 2/2] config.c: handle lock file in error case in git_config_rename_ Nguyễn Thái Ngọc Duy
  0 siblings, 1 reply; 7+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-12-20  9:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, josharian, Nguyễn Thái Ngọc Duy

There are two ways to unlock a file: commit, or revert. Rename it to
commit_and_out to avoid confusion.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 config.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.c b/config.c
index 4973256..505e0d0 100644
--- a/config.c
+++ b/config.c
@@ -2416,7 +2416,7 @@ int git_config_rename_section_in_file(const char *config_filename,
 
 	if (!(config_file = fopen(config_filename, "rb"))) {
 		/* no config file means nothing to rename, no error */
-		goto unlock_and_out;
+		goto commit_and_out;
 	}
 
 	if (fstat(fileno(config_file), &st) == -1) {
@@ -2478,7 +2478,7 @@ int git_config_rename_section_in_file(const char *config_filename,
 		}
 	}
 	fclose(config_file);
-unlock_and_out:
+commit_and_out:
 	if (commit_lock_file(lock) < 0)
 		ret = error_errno("could not write config file %s",
 				  config_filename);
-- 
2.8.2.524.g6ff3d78


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] config.c: handle lock file in error case in git_config_rename_...
  2016-12-20  9:48       ` [PATCH 1/2] config.c: rename label unlock_and_out Nguyễn Thái Ngọc Duy
@ 2016-12-20  9:48         ` Nguyễn Thái Ngọc Duy
  2016-12-20 20:09           ` Junio C Hamano
  0 siblings, 1 reply; 7+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-12-20  9:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, josharian, Nguyễn Thái Ngọc Duy

We could rely on atexit() to clean up everything, but let's be
explicit when we can. And it's good anyway because the function is
called the second time in the same process, we're in trouble.

This function should not affect the successful case because after
commit_lock_file() is called, rollback_lock_file() becomes no-op.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 config.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.c b/config.c
index 505e0d0..e02def4 100644
--- a/config.c
+++ b/config.c
@@ -2483,6 +2483,7 @@ int git_config_rename_section_in_file(const char *config_filename,
 		ret = error_errno("could not write config file %s",
 				  config_filename);
 out:
+	rollback_lock_file(lock);
 	free(filename_buf);
 	return ret;
 }
-- 
2.8.2.524.g6ff3d78


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] config.c: handle lock file in error case in git_config_rename_...
  2016-12-20  9:48         ` [PATCH 2/2] config.c: handle lock file in error case in git_config_rename_ Nguyễn Thái Ngọc Duy
@ 2016-12-20 20:09           ` Junio C Hamano
  0 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2016-12-20 20:09 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, josharian

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> We could rely on atexit() to clean up everything, but let's be
> explicit when we can. And it's good anyway because the function is
> called the second time in the same process, we're in trouble.
>
> This function should not affect the successful case because after
> commit_lock_file() is called, rollback_lock_file() becomes no-op.

Not really.  At the point of the first "goto out" in this function,
lock is merely an uninitialized pointer.

>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---


>  config.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/config.c b/config.c
> index 505e0d0..e02def4 100644
> --- a/config.c
> +++ b/config.c
> @@ -2483,6 +2483,7 @@ int git_config_rename_section_in_file(const char *config_filename,
>  		ret = error_errno("could not write config file %s",
>  				  config_filename);
>  out:
> +	rollback_lock_file(lock);
>  	free(filename_buf);
>  	return ret;
>  }

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-12-20 20:10 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-16 18:41 Segfault in git_config_set_multivar_in_file_gently with direct_io in FUSE filesystem Josh Bleecher Snyder
2016-12-19  9:21 ` [PATCH] config.c: handle error case for fstat() calls Nguyễn Thái Ngọc Duy
2016-12-19 18:14   ` Junio C Hamano
2016-12-20  9:47     ` Duy Nguyen
2016-12-20  9:48       ` [PATCH 1/2] config.c: rename label unlock_and_out Nguyễn Thái Ngọc Duy
2016-12-20  9:48         ` [PATCH 2/2] config.c: handle lock file in error case in git_config_rename_ Nguyễn Thái Ngọc Duy
2016-12-20 20:09           ` Junio C Hamano

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).