# [Janitors] value could be NULL in config parser

15 messages from 2008-02-08 to 2008-02-09. Participants: Junio C Hamano, Miklos Vajna, Michele Ballabio, Govind Salinas, Christian Couder.
Thread: https://gitlist.dev/t/11962

## Junio C Hamano, 2008-02-08 06:43

Subject: [Janitors] value could be NULL in config parser
Message-ID: <7v63x0lzhw.fsf@gitster.siamese.dyndns.org>
URL: https://gitlist.dev/e/7v63x0lzhw.fsf%40gitster.siamese.dyndns.org

```
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, 2008-02-08 14:26

Subject: [PATCH] archive-tar.c: guard config parser from value=NULL
Message-ID: <20080208142602.GV25954@genesis.frugalware.org>
URL: https://gitlist.dev/e/20080208142602.GV25954%40genesis.frugalware.org
In-Reply-To: <7v63x0lzhw.fsf@gitster.siamese.dyndns.org>

```
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, 2008-02-08 14:26

Subject: [PATCH] builtin-gc.c: guard config parser from value=NULL
Message-ID: <20080208142618.GW25954@genesis.frugalware.org>
URL: https://gitlist.dev/e/20080208142618.GW25954%40genesis.frugalware.org
In-Reply-To: <7v63x0lzhw.fsf@gitster.siamese.dyndns.org>

```
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, 2008-02-08 14:26

Subject: [PATCH] remote.c: guard config parser from value=NULL
Message-ID: <20080208142640.GX25954@genesis.frugalware.org>
URL: https://gitlist.dev/e/20080208142640.GX25954%40genesis.frugalware.org
In-Reply-To: <7v63x0lzhw.fsf@gitster.siamese.dyndns.org>

```
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

```

## Miklos Vajna, 2008-02-08 14:27

Subject: [PATCH] setup.c: guard config parser from value=NULL
Message-ID: <20080208142702.GY25954@genesis.frugalware.org>
URL: https://gitlist.dev/e/20080208142702.GY25954%40genesis.frugalware.org
In-Reply-To: <7v63x0lzhw.fsf@gitster.siamese.dyndns.org>

```
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, 2008-02-08 16:34

Subject: Re: [PATCH] setup.c: guard config parser from value=NULL
Message-ID: <200802081734.24967.barra_cuda@katamail.com>
URL: https://gitlist.dev/e/200802081734.24967.barra_cuda%40katamail.com
In-Reply-To: <20080208142702.GY25954@genesis.frugalware.org>

```
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.

>  		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)

```

## Michele Ballabio, 2008-02-08 16:34

Subject: Re: [PATCH] remote.c: guard config parser from value=NULL
Message-ID: <200802081734.37715.barra_cuda@katamail.com>
URL: https://gitlist.dev/e/200802081734.37715.barra_cuda%40katamail.com
In-Reply-To: <20080208142640.GX25954@genesis.frugalware.org>

```
On Friday 08 February 2008, Miklos Vajna wrote:
> 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.

```

## Govind Salinas, 2008-02-08 17:07

Subject: Re: [Janitors] value could be NULL in config parser
Message-ID: <5d46db230802080907i2a13c4fep6d4c0af436fd9704@mail.gmail.com>
URL: https://gitlist.dev/e/5d46db230802080907i2a13c4fep6d4c0af436fd9704%40mail.gmail.com
In-Reply-To: <7v63x0lzhw.fsf@gitster.siamese.dyndns.org>

```
On 2/8/08, Junio C Hamano <gitster@pobox.com> wrote:
> 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

```

## Miklos Vajna, 2008-02-08 21:29

Subject: Re: [PATCH] setup.c: guard config parser from value=NULL
Message-ID: <20080208212947.GA25954@genesis.frugalware.org>
URL: https://gitlist.dev/e/20080208212947.GA25954%40genesis.frugalware.org
In-Reply-To: <200802081734.24967.barra_cuda@katamail.com>

```
On Fri, Feb 08, 2008 at 05:34:24PM +0100, Michele Ballabio <barra_cuda@katamail.com> wrote:
> 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, 2008-02-09 01:20

Subject: Re: [Janitors] value could be NULL in config parser
Message-ID: <5d46db230802081720x122a807do6c63b6b3e435b4c5@mail.gmail.com>
URL: https://gitlist.dev/e/5d46db230802081720x122a807do6c63b6b3e435b4c5%40mail.gmail.com
In-Reply-To: <7v63x0lzhw.fsf@gitster.siamese.dyndns.org>

```
On 2/8/08, Junio C Hamano <gitster@pobox.com> wrote:
> 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, 2008-02-09 05:41

Subject: Re: [Janitors] value could be NULL in config parser
Message-ID: <200802090641.20171.chriscool@tuxfamily.org>
URL: https://gitlist.dev/e/200802090641.20171.chriscool%40tuxfamily.org
In-Reply-To: <5d46db230802081720x122a807do6c63b6b3e435b4c5@mail.gmail.com>

```
Le samedi 9 février 2008, Govind Salinas a écrit :
> 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.

> 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, 2008-02-09 06:04

Subject: Re: [Janitors] value could be NULL in config parser
Message-ID: <7v63wyfyx1.fsf@gitster.siamese.dyndns.org>
URL: https://gitlist.dev/e/7v63wyfyx1.fsf%40gitster.siamese.dyndns.org
In-Reply-To: <200802090641.20171.chriscool@tuxfamily.org>

```
Christian Couder <chriscool@tuxfamily.org> writes:

> 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, 2008-02-09 10:18

Subject: Re: [Janitors] value could be NULL in config parser
Message-ID: <200802091118.11174.chriscool@tuxfamily.org>
URL: https://gitlist.dev/e/200802091118.11174.chriscool%40tuxfamily.org
In-Reply-To: <5d46db230802081720x122a807do6c63b6b3e435b4c5@mail.gmail.com>

```
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, 2008-02-09 13:15

Subject: Re: [Janitors] value could be NULL in config parser
Message-ID: <200802091415.20295.chriscool@tuxfamily.org>
URL: https://gitlist.dev/e/200802091415.20295.chriscool%40tuxfamily.org
In-Reply-To: <200802091118.11174.chriscool@tuxfamily.org>

```
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

Thanks,
Christian.

```

## Govind Salinas, 2008-02-09 20:11

Subject: Re: [Janitors] value could be NULL in config parser
Message-ID: <5d46db230802091211k304197e2i2556c82494c0852f@mail.gmail.com>
URL: https://gitlist.dev/e/5d46db230802091211k304197e2i2556c82494c0852f%40mail.gmail.com
In-Reply-To: <200802091415.20295.chriscool@tuxfamily.org>

```
On 2/9/08, Christian Couder <chriscool@tuxfamily.org> wrote:
> 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

```
