This is the mail archive of the mailing list for the glibc project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] gshadow: Handle the parser's full buffer error code

    * gshadow/fgetsgent_r.c (__fgetsgent_r): Return ERANGE when the
    parse_line function returns its out-of-space error.


The fgetgsent function isn't handling errors from parse_line.  That
means it can run out of buffer space when adding pointers to group
members and exit early without setting all members of the static result
struct.  The static result's members will remain pointing at buffer
locations from the previous line, which have been overwritten with
incompatible data, causing segfaults after it is returned normally.

This was detected due to systemd segfaulting.  See:

If you don't want to mess with your /etc/gshadow to test it, the
following program will also segfault (tested on Fedora and CoreOS).



#include <gshadow.h>
#include <stdio.h>
int main() {
  struct sgrp *entry;
  char **member;
  FILE *input = fdopen (0, "rb");
  while (entry = fgetsgent (input))
      printf ("%s", entry->sg_namp);
      for (member = entry->sg_mem; *member; member++)
        printf(", %s", *member);
      printf ("\n");
  fclose (input);
  return 0;

Feed this through stdin.  It should fit in the allocated buffer on
x86_64 and succeed if you delete the last character from the second


 gshadow/fgetsgent_r.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/gshadow/fgetsgent_r.c b/gshadow/fgetsgent_r.c
index b70f6fa..8c13c55 100644
--- a/gshadow/fgetsgent_r.c
+++ b/gshadow/fgetsgent_r.c
@@ -37,6 +37,7 @@ __fgetsgent_r (FILE *stream, struct sgrp *resbuf, char *buffer, size_t buflen,
 	       struct sgrp **result)
   char *p;
+  int rc;
   _IO_flockfile (stream);
@@ -64,11 +65,18 @@ __fgetsgent_r (FILE *stream, struct sgrp *resbuf, char *buffer, size_t buflen,
     } while (*p == '\0' || *p == '#' ||	/* Ignore empty and comment lines.  */
 	     /* Parse the line.  If it is invalid, loop to
 		get the next line of the file to parse.  */
-	     ! parse_line (buffer, (void *) resbuf, (void *) buffer, buflen,
-			   &errno));
+	     !(rc = parse_line (buffer, (void *) resbuf,
+				(void *) buffer, buflen, &errno)));
   _IO_funlockfile (stream);
+  if (rc < 0)
+    {
+      *result = NULL;
+      __set_errno (ERANGE);
+      return errno;
+    }
   *result = resbuf;
   return 0;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]