|
|
Message-ID: <20190725103333.GA30296@pirotess.home>
Date: Thu, 25 Jul 2019 12:33:33 +0200
From: Ismael Luceno <ismael@...ev.co.uk>
To: musl@...ts.openwall.com
Subject: Re: [PATCH v2] glob: implement GLOB_TILDE
On 24/Jul/2019 23:48, Rich Felker wrote:
<...>
> > + char *p = *pat + 1;
> > + size_t i = 0;
> > +
> > + char *name_end = strchrnul(p, '/');
> > + if (*name_end) *name_end++ = 0;
> > + *pat = name_end;
> > +
> > + char *home = (*p || issetugid()) ? NULL : getenv("HOME");
>
> I still don't see any justification for violating the semantics of ~
> because the program is suid.
I could only find a couple of implementations which don't check for
privileges:
- 4.3BSD
+ NetBSD
- uClibc
+ uClibc-ng
Almost everyone else does:
- FreeBSD
+ MidnightBSD
+ DragonFlyBSD
+ Android (Bionic)
- GNU
- Newlib
- OpenBSD
+ MirBSD
- Solaris
+ Illumos
I think most users/software would expect it.
> Also, issetugid isn't in the namespace we can use here. Rather than
> poking directly at libc.secure, if we needed this I think it would be
> better to make a namespace-protected alias, but I don't think it's the
> right behavior anyway.
I would go with that.
> > + if (!home) {
> > + struct passwd pw, *res;
> > + switch (*p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res)
> > + : getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res)) {
>
> Same here. I'm not actually sure what should happen if $HOME is unset,
> but it's probably whatever the Shell Command Language specification
> says.
All the implementations I could find fall back to getpw*.
> > + default:
> > + return GLOB_ABORTED;
> > + case ERANGE: case ENOMEM:
> > + return GLOB_NOSPACE;
> > + case 0:
> > + if (!res) return GLOB_NOMATCH;
>
> The man page says:
>
> If the username is invalid, or the home directory cannot be
> determined, then no substitution is performed.
>
> and the glibc manual says:
>
> If the user name is not valid or the home directory cannot be
> determined for some reason the pattern is left untouched and
> itself used as the result
>
> So I think this should not be an error. I'm not entirely clear if it's
> supposed to suppress all further glob expansion and just return a
> single literal result, or treat "~" or "~nosuchuser" as a literal
> component and search it.
It's supposed to continue; but IMO that's neither intuitive nor safe.
I guess that's why glibc added GLOB_TILDE_CHECK, but it should be the
only possibility.
However, if you feel strongly about it, I can add _CHECK instead.
I think:
- ENOMEM should map to NOSPACE.
- a closer look reveals that all other errors should map to NOMATCH.
> > + }
> > + home = pw.pw_dir;
> > + }
> > + while (i < PATH_MAX - 2 && *home)
> > + buf[i++] = *home++;
>
> This could be strnlen+memmove, but perhaps just open coding it like
> you've done is simpler and lighter.
>
> > + if (i > PATH_MAX - 2)
>
> Off-by-one. If it stopped due to reaching the limit in the above loop,
> you'll have equality not greater-than, then overflow below. Perhaps
> strnlen+memmove would be easier to ensure the safety of.
No overflow:
i++ => PATH_MAX - 2
i => PATH_MAX - 1
> > + return GLOB_NOSPACE;
>
> GLOB_NOSPACE is for allocation errors.
Right.
> This is a no-match case, since there can be no matches for a pattern
> PATH_MAX or longer.
It must work for "~\0".
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.