mailing list of musl libc
 help / color / mirror / code / Atom feed
From: "Érico Nogueira" <ericonr@disroot.org>
To: <musl@lists.openwall.com>
Subject: Re: [musl] get/set*ent functions and real world applications
Date: Tue, 12 Oct 2021 12:58:43 -0300	[thread overview]
Message-ID: <CEXJWX5RRUMD.13LHQA50E3RQ3@mussels> (raw)
In-Reply-To: <0100017c71ef9e36-29a22d3f-22a5-495a-9d9e-0eac76c3ff4e-000000@email.amazonses.com>

On Mon Oct 11, 2021 at 9:38 PM -03, (GalaxyMaster) wrote:
> Enrico,
>
> On Mon, Oct 11, 2021 at 02:18:47PM -0300, ??rico Nogueira wrote:
> > On Mon Oct 11, 2021 at 10:32 AM -03, (GalaxyMaster) wrote:
> > >
> > > The whole parssing of password and group entires is quite "dumb", in
> > > terms that
> > > it always expects perfectly valid input and produces always correct
> > > output, but
> > > I would argue that these functions should be a bit smarter and should
> > > not make
> > > assumptions about the validity of the input, i.e treat it as untrusted
> > > user
> > > input.
> > 
> > There's a reason it's recommended that one only make changes to these
> > files using tools like the ones from the shadow suite. Things in /etc
> > can, theoretically, only be written to by root or at least trusted
> > users, so treating as entirely untrusted seems a bit over the top...
>
> Well, I prefer to treat anything external to my application as untrusted
> input,
> this saves time on troubleshooting weird issues later. In your statement
> above you put implicit trust into these abstract "trusted users", why
> guess
> what these could or could not do if we can handle the input in a safe
> and
> deterministic way? There was an argument on this list that libc should
> not
> treat/hide developer's mistakes and that's the reason you may see
> segfaults
> on a musl-based system more often (it is less forgiving to the poorly
> written
> code). Hoowever, I would argue that this particular case requires
> special
> treatment from libc since there is no way avoiding these functions if
> you
> are working with passwd/group based files.

It is untrusted input in that it shouldn't cause segfaults or other UB
when it's misconfigured, but expecting applications to treat
misconfigured entries the same way when you have applications using libc
functions, Go standard library ones, probably some Rust application
doing their own thing, means that the files really should be handled
with care. Most systems will have *some* application treating
misconfigured files in unexpected ways. However, this is not an argument
for not fixing musl, as I said right below the part you quoted:

	 That said, erroring out/skipping such entries sounds reasonable
	 either way.

>
> > It seems like both libraries are inconsistent in their own ways. glibc
> > skips malformed entries when some fields are missing, but fixes a
> > missing supplemental group entry. musl skips a missing supplemental
> > group entry, but "fixes" malformed entries with fields missing.
> > 
> > Maybe striving for consistency by either always skipping or always
> > fixing entries seems like a more reasonable choice to me, maybe?
>
> I am not defending Glibc, but I find their approach to this matter
> consistent
> and expected from the common sense point of view. I would rather see
> musl
> aligned with it than try to convince everyone of yet another way of
> doing this.

That's a fair point.

>
> > > With put*() functions the situation a bit better, but still could be
> > > improved to achieve better compatibility. putpwent() will output
> > > '(null)' for any NULL pointer passed for the string arguments (due to
> > > direct call to fprintf() and the UB for that situation), while Glibc
> > > would output an empty string instead.
> > 
> > It would seem the function returns EINVAL instead of outputting anything
> > at all, from my look at the code. I think that's reasonable behavior for
> > musl to implement, given how badly specified the function is.
>
> No, it is not behaving like that, it behaves exactly as I described:
> ===
> galaxy@musl:~/musl-tests $ cat test-putpwent.c
> #include <sys/types.h>
> #include <pwd.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <errno.h>
>
> int main() {
> struct passwd *pw;
> FILE *fp;
> errno = 0;
> fp = fopen("test-putpwent.output", "w");
> if (!fp || errno != 0) return errno;
> pw = malloc(sizeof(struct passwd));
> pw->pw_name = pw->pw_passwd = pw->pw_gecos = pw->pw_dir, pw->pw_shell =
> NULL;
> putpwent(pw, fp);
> fclose(fp);
> return 0;
> }
> galaxy@musl:~/musl-tests $ ls -ld test-putpwent.output
> ls: cannot access 'test-putpwent.output': No such file or directory
> galaxy@musl:~/musl-tests $ ./test-putpwent
> galaxy@musl:~/musl-tests $ cat test-putpwent.output
> (null):(null):0:0:(null):(null):(null)
> galaxy@musl:~/musl-tests $
> ===
>
> On a Glibc system, the putpwent() call with pw->pw_name being NULL will
> fail to
> produce a record. If the pw->pw_name field is not NULL, then it will
> produce a
> record with the name followed by empty string fields, like
> "user::0:0:::",
> which is more expected in my opinion.

Sorry, I wasn't clear. I was talking about glibc's implementation:

  if (p == NULL || stream == NULL
      || p->pw_name == NULL || !__nss_valid_field (p->pw_name)
      || !__nss_valid_field (p->pw_passwd)
      || !__nss_valid_field (p->pw_dir)
      || !__nss_valid_field (p->pw_shell))
    {
      __set_errno (EINVAL);
      return -1;
    }

It requires that all of pw_name, pw_passwd, pw_dir and pw_shell be non
null and only contain valid characters (that's what __nss_valid_field
checks for, and it seems they are checking for pw_name==NULL twice, so I
will see about sending a patch their way).

So, requiring some specific fields is compatible with glibc's impl, and
then for the other fields we should take care to print an empty string
instead of "(null)". I think that's a pretty valid change to implement.

>
> > > Moreover, putpwent() is inconsistent with putgrent() -- the latter
> > > locks the file before writing and unlocks afterwards, while the former
> > > is just going ahead with fprintf(). I know these funnctions are thread
> > > unsafe, but this lack of locking makes putpwent() plainly dangerous on
> > > a multiuser system.
> > 
> > I'm pretty sure these functions are always dangerous on multiuser
> > systems; flockfile(3) is FILE level locking, it just protects from other
> > threads touching a given FILE object. If you want to protect yourself
> > from multiple programs handling the file simultaneously, you need file
> > locking, such as done with fcntl(2).
>
> A fair point, I was not familiar with that function and somehow thought
> it was at
> the file level. I think that it is not libc's job to do file lockingi
> here, so I
> think we are fine in this regard. Thank you for explaining why there
> is an inconsistency, between putpwent() and putgrent() -- it makes
> sense.

No worries :)

>
> --
> (GM)


  reply	other threads:[~2021-10-12 16:11 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-11 13:32 (GalaxyMaster)
2021-10-11 17:18 ` Érico Nogueira
2021-10-12  0:38   ` (GalaxyMaster)
2021-10-12 15:58     ` Érico Nogueira [this message]
2021-10-12 17:38       ` Érico Nogueira
2021-10-13  6:16   ` A. Wilcox
2021-10-13 13:56     ` Rich Felker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CEXJWX5RRUMD.13LHQA50E3RQ3@mussels \
    --to=ericonr@disroot.org \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

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 NNTP newsgroup(s).