Re: [PATCH] xgethostname: handle long hostnames

2017-04-13 Thread René Scharfe
Am 13.04.2017 um 21:23 schrieb David Turner:
> If the full hostname doesn't fit in the buffer supplied to
> gethostname, POSIX does not specify whether the buffer will be
> null-terminated, so to be safe, we should do it ourselves.  Introduce
> new function, xgethostname, which ensures that there is always a \0
> at the end of the buffer.
> 
> Signed-off-by: David Turner 
> ---

> diff --git a/wrapper.c b/wrapper.c
> index 0542fc7582..d837417709 100644
> --- a/wrapper.c
> +++ b/wrapper.c
> @@ -655,3 +655,16 @@ void sleep_millisec(int millisec)
>   {
>   poll(NULL, 0, millisec);
>   }
> +
> +int xgethostname(char *buf, size_t len)
> +{
> + /*
> +  * If the full hostname doesn't fit in buf, POSIX does not
> +  * specify whether the buffer will be null-terminated, so to
> +  * be safe, do it ourselves.
> +  */
> + int ret = gethostname(buf, len);
> + if (!ret)
> + buf[len - 1] = 0;
> + return ret;
> +}

Silent truncation is not ideal, no matter if it's done by the wrapper or
the original function.  It would be better to use a properly sized
buffer.

POSIX requires hostnames to have a maximum length of HOST_NAME_MAX.  So
how about just adding an assert to make sure len is big enough?  Or
evaluate the condition at compile time with BUILD_ASSERT_OR_ZERO?

Downside: Not all platforms define HOST_NAME_MAX.  daemon.c uses 256 as
a fallback.  On Windows a buffer size of 256 is documented to suffice
in all cases [1].  The Linux manpage [2] mentions a hostname length
limit of 255 (plus NUL) as well, even though HOST_NAME_MAX is 64 there.

Another possibility: Die (or at least warn) if the buffer doesn't
contain a NUL byte after calling gethostname().  That only works for
platforms that don't NUL-terminate on truncation, though, so silent
truncation would still go unnoticed.

Anyway, the buffer in builtin/gc.c with its 128 bytes seems to be too
short; the others are at least 256 bytes long.  Replacing the magic
buffer size number with HOST_NAME_MAX + 1 might be a good idea (after
moving the fallback definition to git-compat-util.h).

René


[1] 
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738527(v=vs.85).aspx
[2] http://man7.org/linux/man-pages/man2/gethostname.2.html


RE: [PATCH] xgethostname: handle long hostnames

2017-04-13 Thread David Turner
> -Original Message-
> From: Jonathan Nieder [mailto:jrnie...@gmail.com]
> Sent: Thursday, April 13, 2017 6:05 PM
> To: David Turner 
> Cc: git@vger.kernel.org
> Subject: Re: [PATCH] xgethostname: handle long hostnames
> 
> Hi,
> 
> David Turner wrote:
> 
> > If the full hostname doesn't fit in the buffer supplied to
> > gethostname, POSIX does not specify whether the buffer will be
> > null-terminated, so to be safe, we should do it ourselves.
> [...]
> > +++ b/wrapper.c
> > @@ -655,3 +655,16 @@ void sleep_millisec(int millisec)  {
> > poll(NULL, 0, millisec);
> >  }
> > +
> > +int xgethostname(char *buf, size_t len) {
> > +   /*
> > +* If the full hostname doesn't fit in buf, POSIX does not
> > +* specify whether the buffer will be null-terminated, so to
> > +* be safe, do it ourselves.
> > +*/
> > +   int ret = gethostname(buf, len);
> > +   if (!ret)
> > +   buf[len - 1] = 0;
> > +   return ret;
> 
> I wonder if after null-terminating we would want to report this as an error,
> instead of silently using a truncated result.  I.e. something like
> 
> > +   if (!ret)
> > +   buf[len - 1] = 0;
> > +   if (strlen(buf) >= len - 1) {
> > +   errno = ENAMETOOLONG;
> > +   return -1;
> > +   }
>
> (or EINVAL --- either is equally descriptive).

Looking at the users of this function, I think most would be happier with a 
truncated buffer than an error:
gc.c: used to see if we are the same machine as the machine that locked the 
repo. Unlikely that two machines have hostnames that differ only in the 
256th-or-above character.
fetch-pack.c, receive-pack.c: similar to gc.c; the hostname is a note in the 
.keep file
Ident.c: used to make up a fake email address. On my laptop, gethostname 
returns "corey" (no domain part), so the email address is not likely to be 
valid anyway.

> Also POSIX requires that hostnames are <= 255 bytes.  Maybe we can force the
> buffer to be large enough.

That is now how I read it.  I read the limit as HOST_NAME_MAX, which has a 
*minimum* value of 255, but which might be larger.

The existing hostname buffers are 128, 256, and 1024 bytes, so they're pretty 
arbitrary.  



Re: [PATCH] xgethostname: handle long hostnames

2017-04-13 Thread Jonathan Nieder
Hi,

David Turner wrote:

> If the full hostname doesn't fit in the buffer supplied to
> gethostname, POSIX does not specify whether the buffer will be
> null-terminated, so to be safe, we should do it ourselves.
[...]
> +++ b/wrapper.c
> @@ -655,3 +655,16 @@ void sleep_millisec(int millisec)
>  {
>   poll(NULL, 0, millisec);
>  }
> +
> +int xgethostname(char *buf, size_t len)
> +{
> + /*
> +  * If the full hostname doesn't fit in buf, POSIX does not
> +  * specify whether the buffer will be null-terminated, so to
> +  * be safe, do it ourselves.
> +  */
> + int ret = gethostname(buf, len);
> + if (!ret)
> + buf[len - 1] = 0;
> + return ret;

I wonder if after null-terminating we would want to report this as
an error, instead of silently using a truncated result.  I.e. something
like

> + if (!ret)
> + buf[len - 1] = 0;
> + if (strlen(buf) >= len - 1) {
> + errno = ENAMETOOLONG;
> + return -1;
> + }

(or EINVAL --- either is equally descriptive).

Also POSIX requires that hostnames are <= 255 bytes.  Maybe we can
force the buffer to be large enough.

Thoughts?
Jonathan


Re: [PATCH] xgethostname: handle long hostnames

2017-04-13 Thread Jeff King
On Thu, Apr 13, 2017 at 03:23:35PM -0400, David Turner wrote:

> If the full hostname doesn't fit in the buffer supplied to
> gethostname, POSIX does not specify whether the buffer will be
> null-terminated

Wow, TIL. What an utterly terrible and error-prone interface (I always
just assumed we'd get ENAMETOOLONG, which is what glibc does).

> so to be safe, we should do it ourselves.  Introduce
> new function, xgethostname, which ensures that there is always a \0
> at the end of the buffer.

Your patch looks good to me.

-Peff