threads / discuss / 11962

[Janitors] value could be NULL in config parser

Subject: [Janitors] value could be NULL in config parser

## tl;dr

15 messages between Feb 8, 2008 and Feb 9, 2008.

replies: 14people: 6as markdown or json

Junio C Hamano· Feb 8, 2008, 06:43 UTC · lore

If somebody wants to dip his or her toe in git hacking, and is tempted to send in a "clean up" patch (e.g. whitespace, coding style) that does not really _fix_ anything, please don't.

I have a task of similar complexity (meaning, reasonably easy) that is much more useful and appreciated than clean-up patches for you.

The callback functions that are passed to git_config() need to be audited so that they do not barf when given NULL. Currently, many of them are not safe.

A callback function of git_config() is called when the command reads value from .git/config and friends. The function takes two parameters, var and value. var is never NULL and it is the name of the configuration variable found in the file being read. value could be either string or NULL.

A NULL value is boolean "true". For example, on MS-DOS, you may have something like this:

	[core]
 		autocrlf

and your callback will be called with var = "core.autocrlf" and value = NULL in such a case.

If you want to fix them (you do not have to do all of them, and if you would like to help, please make one patch per function fixed), the procedure is:

 (1) Find calling sites for git_config().  For example, we find
     one in archive-tar.c::write_tar_archive().
        int write_tar_archive(struct archiver_args *args)
        {
                int plen = args->base ? strlen(args->base) : 0;
                git_config(git_tar_config);
                archive_time = args->time;
                verbose = args->verbose;
	...
 (2) Look at the function that is passed to git_config().
        static int git_tar_config(const char *var, const char *value)
        {
                if (!strcmp(var, "tar.umask")) {
                        if (!strcmp(value, "user")) {
                                tar_umask = umask(0);
                                umask(tar_umask);
                        } else {
                                tar_umask = git_config_int(var, value);
                        }
                        return 0;
                }
                return git_default_config(var, value);
        }
 (3) Let's fix it.  If the user's configuration has:
	[tar]
        	umask
     it is an illegal configuration, but the code above does not
     check for NULL, and the second strcmp() would fail.  If we
     guard that strcmp() with a check against NULL, we would be
     Ok.  git_config_int() will correctly barf telling the user
     that "tar.umask" configuration is wrong.
 (4) Then send in a patch.  Again, one patch per fixed function,
     please.  The message may look like this:

-- >8 -- [PATCH] archive-tar.c: guard config parser from value=NULL

Signed-off-by: A U Thor <author@example.com>
 archive-tar.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/archive-tar.c b/archive-tar.c
index e1bced5..30aa2e2 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -222,7 +222,7 @@ static void write_global_extended_header(const unsigned char *sha1)
 static int git_tar_config(const char *var, const char *value)
 {
 	if (!strcmp(var, "tar.umask")) {
-		if (!strcmp(value, "user")) {
+		if (value && !strcmp(value, "user")) {
 			tar_umask = umask(0);
 			umask(tar_umask);
 		} else {
Miklos Vajna· Feb 8, 2008, 14:26 UTC · re: Junio C Hamano · lore

[PATCH] archive-tar.c: guard config parser from value=NULL

Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
 archive-tar.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/archive-tar.c b/archive-tar.c
index e1bced5..30aa2e2 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -222,7 +222,7 @@ static void write_global_extended_header(const unsigned char *sha1)
 static int git_tar_config(const char *var, const char *value)
 {
 	if (!strcmp(var, "tar.umask")) {
-		if (!strcmp(value, "user")) {
+		if (value && !strcmp(value, "user")) {
 			tar_umask = umask(0);
 			umask(tar_umask);
 		} else {
-- 
1.5.4
Miklos Vajna· Feb 8, 2008, 14:26 UTC · re: Junio C Hamano · lore

[PATCH] builtin-gc.c: guard config parser from value=NULL

Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
 builtin-gc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/builtin-gc.c b/builtin-gc.c
index ac34788..ad4a75e 100644
--- a/builtin-gc.c
+++ b/builtin-gc.c
@@ -37,7 +37,7 @@ static const char *argv_rerere[] = {"rerere", "gc", NULL};
 static int gc_config(const char *var, const char *value)
 {
 	if (!strcmp(var, "gc.packrefs")) {
-		if (!strcmp(value, "notbare"))
+		if (value && !strcmp(value, "notbare"))
 			pack_refs = -1;
 		else
 			pack_refs = git_config_bool(var, value);
-- 
1.5.4
Miklos Vajna· Feb 8, 2008, 14:26 UTC · re: Junio C Hamano · lore

[PATCH] remote.c: guard config parser from value=NULL

Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
 remote.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/remote.c b/remote.c
index 0e00680..4765815 100644
--- a/remote.c
+++ b/remote.c
@@ -276,7 +276,7 @@ static int handle_config(const char *key, const char *value)
 		else
 			error("more than one uploadpack given, using the first");
 	} else if (!strcmp(subkey, ".tagopt")) {
-		if (!strcmp(value, "--no-tags"))
+		if (value && !strcmp(value, "--no-tags"))
 			remote->fetch_tags = -1;
 	} else if (!strcmp(subkey, ".proxy")) {
 		remote->http_proxy = xstrdup(value);
-- 
1.5.4
Michele Ballabio· Feb 8, 2008, 16:34 UTC · re: Miklos Vajna · lore

Re: [PATCH] remote.c: guard config parser from value=NULL

On Friday 08 February 2008, Miklos Vajna wrote:
Show 18 quoted lines
> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
> ---
>  remote.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/remote.c b/remote.c
> index 0e00680..4765815 100644
> --- a/remote.c
> +++ b/remote.c
> @@ -276,7 +276,7 @@ static int handle_config(const char *key, const char *value)
>  		else
>  			error("more than one uploadpack given, using the first");
>  	} else if (!strcmp(subkey, ".tagopt")) {
> -		if (!strcmp(value, "--no-tags"))
> +		if (value && !strcmp(value, "--no-tags"))
>  			remote->fetch_tags = -1;
>  	} else if (!strcmp(subkey, ".proxy")) {
>  		remote->http_proxy = xstrdup(value);
Function handle_config() has already returned 0 at this point.
Miklos Vajna· Feb 8, 2008, 14:27 UTC · re: Junio C Hamano · lore

[PATCH] setup.c: guard config parser from value=NULL

Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
 setup.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/setup.c b/setup.c
index adede16..361825f 100644
--- a/setup.c
+++ b/setup.c
@@ -346,13 +346,13 @@ int git_config_perm(const char *var, const char *value)
 {
 	if (value) {
 		int i;
-		if (!strcmp(value, "umask"))
+		if (value && !strcmp(value, "umask"))
 			return PERM_UMASK;
-		if (!strcmp(value, "group"))
+		if (value && !strcmp(value, "group"))
 			return PERM_GROUP;
-		if (!strcmp(value, "all") ||
+		if (value && (!strcmp(value, "all") ||
 		    !strcmp(value, "world") ||
-		    !strcmp(value, "everybody"))
+		    !strcmp(value, "everybody")))
 			return PERM_EVERYBODY;
 		i = atoi(value);
 		if (i > 1)
-- 
1.5.4
Michele Ballabio· Feb 8, 2008, 16:34 UTC · re: Miklos Vajna · lore

Re: [PATCH] setup.c: guard config parser from value=NULL

On Friday 08 February 2008, Miklos Vajna wrote:
Show 7 quoted lines
> diff --git a/setup.c b/setup.c
> index adede16..361825f 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -346,13 +346,13 @@ int git_config_perm(const char *var, const char *value)
>  {
>  	if (value) {
            ^^^^^
value is already checked here. No need to check further.
Show 15 quoted lines
>  		int i;
> -		if (!strcmp(value, "umask"))
> +		if (value && !strcmp(value, "umask"))
>  			return PERM_UMASK;
> -		if (!strcmp(value, "group"))
> +		if (value && !strcmp(value, "group"))
>  			return PERM_GROUP;
> -		if (!strcmp(value, "all") ||
> +		if (value && (!strcmp(value, "all") ||
>  		    !strcmp(value, "world") ||
> -		    !strcmp(value, "everybody"))
> +		    !strcmp(value, "everybody")))
>  			return PERM_EVERYBODY;
>  		i = atoi(value);
>  		if (i > 1)
Miklos Vajna· Feb 8, 2008, 21:29 UTC · re: Michele Ballabio · lore

Re: [PATCH] setup.c: guard config parser from value=NULL

On Fri, Feb 08, 2008 at 05:34:24PM +0100, Michele Ballabio <barra_cuda@katamail.com> wrote:
Show 10 quoted lines
> On Friday 08 February 2008, Miklos Vajna wrote:
> > diff --git a/setup.c b/setup.c
> > index adede16..361825f 100644
> > --- a/setup.c
> > +++ b/setup.c
> > @@ -346,13 +346,13 @@ int git_config_perm(const char *var, const char *value)
> >  {
> >  	if (value) {
>             ^^^^^
> value is already checked here. No need to check further.

ah, i missed it. should we add some comment about this or just it wasn't obvious to me only? (same true to the other patch where you pointed out the check was not necessary)

thanks,
- VMiklos
Govind Salinas· Feb 8, 2008, 17:07 UTC · re: Junio C Hamano · lore

Re: [Janitors] value could be NULL in config parser

On 2/8/08, Junio C Hamano <gitster@pobox.com> wrote:
Show 100 quoted lines
> If somebody wants to dip his or her toe in git hacking, and is
> tempted to send in a "clean up" patch (e.g. whitespace, coding
> style) that does not really _fix_ anything, please don't.
>
> I have a task of similar complexity (meaning, reasonably easy)
> that is much more useful and appreciated than clean-up patches
> for you.
>
> The callback functions that are passed to git_config() need to
> be audited so that they do not barf when given NULL.  Currently,
> many of them are not safe.
>
> A callback function of git_config() is called when the command
> reads value from .git/config and friends.  The function takes
> two parameters, var and value.  var is never NULL and it is the
> name of the configuration variable found in the file being
> read.  value could be either string or NULL.
>
> A NULL value is boolean "true".  For example, on MS-DOS, you may
> have something like this:
>
>         [core]
>                 autocrlf
>
> and your callback will be called with var = "core.autocrlf" and
> value = NULL in such a case.
>
> If you want to fix them (you do not have to do all of them, and
> if you would like to help, please make one patch per function
> fixed), the procedure is:
>
>  (1) Find calling sites for git_config().  For example, we find
>      one in archive-tar.c::write_tar_archive().
>
>         int write_tar_archive(struct archiver_args *args)
>         {
>                 int plen = args->base ? strlen(args->base) : 0;
>
>                 git_config(git_tar_config);
>
>                 archive_time = args->time;
>                 verbose = args->verbose;
>         ...
>
>  (2) Look at the function that is passed to git_config().
>
>         static int git_tar_config(const char *var, const char *value)
>         {
>                 if (!strcmp(var, "tar.umask")) {
>                         if (!strcmp(value, "user")) {
>                                 tar_umask = umask(0);
>                                 umask(tar_umask);
>                         } else {
>                                 tar_umask = git_config_int(var, value);
>                         }
>                         return 0;
>                 }
>                 return git_default_config(var, value);
>         }
>
>  (3) Let's fix it.  If the user's configuration has:
>
>         [tar]
>                 umask
>
>      it is an illegal configuration, but the code above does not
>      check for NULL, and the second strcmp() would fail.  If we
>      guard that strcmp() with a check against NULL, we would be
>      Ok.  git_config_int() will correctly barf telling the user
>      that "tar.umask" configuration is wrong.
>
>  (4) Then send in a patch.  Again, one patch per fixed function,
>      please.  The message may look like this:
>
> -- >8 --
> [PATCH] archive-tar.c: guard config parser from value=NULL
>
> Signed-off-by: A U Thor <author@example.com>
>
>  archive-tar.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/archive-tar.c b/archive-tar.c
> index e1bced5..30aa2e2 100644
> --- a/archive-tar.c
> +++ b/archive-tar.c
> @@ -222,7 +222,7 @@ static void write_global_extended_header(const unsigned char *sha1)
>  static int git_tar_config(const char *var, const char *value)
>  {
>         if (!strcmp(var, "tar.umask")) {
> -               if (!strcmp(value, "user")) {
> +               if (value && !strcmp(value, "user")) {
>                         tar_umask = umask(0);
>                         umask(tar_umask);
>                 } else {
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
I can try my hand at that.  I will send some patches later today (after work).
-Govind
Govind Salinas· Feb 9, 2008, 01:20 UTC · re: Junio C Hamano · lore

Re: [Janitors] value could be NULL in config parser

On 2/8/08, Junio C Hamano <gitster@pobox.com> wrote:
Show 19 quoted lines
> A callback function of git_config() is called when the command
> reads value from .git/config and friends.  The function takes
> two parameters, var and value.  var is never NULL and it is the
> name of the configuration variable found in the file being
> read.  value could be either string or NULL.
>
> A NULL value is boolean "true".  For example, on MS-DOS, you may
> have something like this:
>
>         [core]
>                 autocrlf
>
> and your callback will be called with var = "core.autocrlf" and
> value = NULL in such a case.
>
> If you want to fix them (you do not have to do all of them, and
> if you would like to help, please make one patch per function
> fixed), the procedure is:
>
I think I got all the erroneous ones.  I did

find . -name "*.c" | xargs grep git_config\( | awk '{ idx = index($2, ")"); p = substr($2, 12, idx - 12); print p }' | sort | uniq -u

To try and get a list of all the ones that might need updating. I did notice that most functions never check value for null, but they don't directly access them. They pass them off to other methods. As far as I can tell, some of these methods don't validate the NULL. So they will need to be updated.

Question. Wouldn't it reduce the amount of validation we have to do if whoever is calling back checked null and assigned an empty string? If so, we can probably replace all these patches with one patch.

-Govind
Christian Couder· Feb 9, 2008, 05:41 UTC · re: Govind Salinas · lore

Re: [Janitors] value could be NULL in config parser

Le samedi 9 février 2008, Govind Salinas a écrit :
Show 11 quoted lines
> On 2/8/08, Junio C Hamano <gitster@pobox.com> wrote:
> > If you want to fix them (you do not have to do all of them, and
> > if you would like to help, please make one patch per function
> > fixed), the procedure is:
>
> I think I got all the erroneous ones.  I did
>
> find . -name "*.c" | xargs grep git_config\( | awk '{ idx = index($2,
> ")"); p = substr($2, 12, idx - 12); print  p }' | sort | uniq -u
>
> To try and get a list of all the ones that might need updating. 
Thanks.
Show 9 quoted lines
> I did 
> notice that most functions never check value for null, but they don't
> directly access them.  They pass them off to other methods.  As far as
> I can tell, some of these methods don't validate the NULL.  So they
> will need to be updated.
>
> Question.  Wouldn't it reduce the amount of validation we have to do
> if whoever is calling back checked null and assigned an empty string?
> If so, we can probably replace all these patches with one patch.
This was discussed in this thread:
http://thread.gmane.org/gmane.comp.version-control.git/72107/

In short we can't do that now, but it may be possible latter, if we first deprecate using an empty string as boolean value "false" (while a NULL is boolean value "true").

Christian.
Junio C Hamano· Feb 9, 2008, 06:04 UTC · re: Christian Couder · lore

Re: [Janitors] value could be NULL in config parser

Christian Couder <chriscool@tuxfamily.org> writes:
Show 13 quoted lines
> Le samedi 9 février 2008, Govind Salinas a écrit :
>
>> Question.  Wouldn't it reduce the amount of validation we have to do
>> if whoever is calling back checked null and assigned an empty string?
>> If so, we can probably replace all these patches with one patch.
>
> This was discussed in this thread:
>
> http://thread.gmane.org/gmane.comp.version-control.git/72107/
>
> In short we can't do that now, but it may be possible latter, if we first 
> deprecate using an empty string as boolean value "false" (while a NULL is 
> boolean value "true").

It may be the case that many in-tree config parser functions are sloppy right now. It however is never an excuse to break user's existing repositories.

Christian Couder· Feb 9, 2008, 10:18 UTC · re: Govind Salinas · lore

Re: [Janitors] value could be NULL in config parser

Le samedi 9 février 2008, Govind Salinas a écrit :
> I think I got all the erroneous ones.  I did
>
> find . -name "*.c" | xargs grep git_config\( | awk '{ idx = index($2,
> ")"); p = substr($2, 12, idx - 12); print  p }' | sort | uniq -u

It seems the "uniq -u" should be only "uniq". This way, you will also get the following ones to check:

git_default_config git_diff_basic_config git_log_config git_pack_config

Thanks in advance, Christian.

Christian Couder· Feb 9, 2008, 13:15 UTC · re: Christian Couder · lore

Re: [Janitors] value could be NULL in config parser

Le samedi 9 février 2008, Christian Couder a écrit :
Show 13 quoted lines
> Le samedi 9 février 2008, Govind Salinas a écrit :
> > I think I got all the erroneous ones.  I did
> >
> > find . -name "*.c" | xargs grep git_config\( | awk '{ idx = index($2,
> > ")"); p = substr($2, 12, idx - 12); print  p }' | sort | uniq -u
>
> It seems the "uniq -u" should be only "uniq".
> This way, you will also get the following ones to check:
>
> git_default_config
> git_diff_basic_config
> git_log_config
> git_pack_config

I don't know awk so I cannot tell if there is something wrong with your script but with:

find . -name "*.c" | xargs perl -ne 'print "$1\n" if (m/git_config ? \(([^)]*)\)/)' | sort | uniq

I also get:

git_imap_config show_all_config

Thanks, Christian.

Govind Salinas· Feb 9, 2008, 20:11 UTC · re: Christian Couder · lore

Re: [Janitors] value could be NULL in config parser

On 2/9/08, Christian Couder <chriscool@tuxfamily.org> wrote:
Show 26 quoted lines
> Le samedi 9 février 2008, Christian Couder a écrit :
> > Le samedi 9 février 2008, Govind Salinas a écrit :
> > > I think I got all the erroneous ones.  I did
> > >
> > > find . -name "*.c" | xargs grep git_config\( | awk '{ idx = index($2,
> > > ")"); p = substr($2, 12, idx - 12); print  p }' | sort | uniq -u
> >
> > It seems the "uniq -u" should be only "uniq".
> > This way, you will also get the following ones to check:
> >
> > git_default_config
> > git_diff_basic_config
> > git_log_config
> > git_pack_config
>
> I don't know awk so I cannot tell if there is something wrong with your
> script but with:
>
> find . -name "*.c" | xargs perl -ne 'print "$1\n" if (m/git_config ?
> \(([^)]*)\)/)' | sort | uniq
>
> I also get:
>
> git_imap_config
> show_all_config
>

It appears only git_imap_config and git_default_config need patches. I will send them to the list.

Are any changes to the git_config_$type functions going to be made? It sounds like any change could break current configs so we are only going to stop the segfaults.

-Govind

← back to recent threads