[BUG/PATCH] backend crashes during authentication if data/global/pg_pwd is empty

Started by Michael Wildpanerabout 22 years ago4 messages
#1Michael Wildpaner
mike@rainbow.studorg.tuwien.ac.at

Hi,

on Solaris 9 with PostgreSQL 7.4:

when you

- 'initdb' a fresh database,
- _don't_ set a password for user 'postgres',
- convert the 'trust' lines in data/pg_hba.conf to 'md5' or 'password'

and then try to connect as user 'postgres', the backend crashes in
backend/libpq/hba.c:372:

368 static int
369 user_group_bsearch_cmp(const void *user, const void *list)
370 {
371 /* first node is line number */
372 char *user2 = lfirst(lnext(*(List **) list));

due to 'list' being NULL, which might mean that 'user_sorted' was never
allocated, due to user_length being zero for an missing or empty
global/pg_pwd:

916 /* create sorted lines for binary searching */
917 user_length = length(user_lines);
918 if (user_length)
919 {
920 int i = 0;
921
922 user_sorted = palloc(user_length * sizeof(List *));

I know this is looks like a case of "don't do it, then", but since it's a
backend crash, I would suggest the following fix:

--- postgresql-7.4.orig/src/backend/libpq/hba.c	2003-10-25 05:48:46.000001000 +0200
+++ postgresql-7.4/src/backend/libpq/hba.c	2003-12-05 15:21:54.000003000 +0100
@@ -62,7 +62,7 @@
 static List **user_sorted = NULL;		/* sorted user list, for bsearch() */
 static List **group_sorted = NULL;		/* sorted group list, for
 										 * bsearch() */
-static int	user_length;
+static int	user_length = 0;
 static int	group_length;
 static List *tokenize_file(FILE *file);
@@ -395,6 +395,10 @@
 List	  **
 get_user_line(const char *user)
 {
+	/* fail if there is nothing to search in */
+	if ((user_sorted == NULL) || (user_length == 0))
+		return NULL;
+
 	return (List **) bsearch((void *) user,
 							 (void *) user_sorted,
 							 user_length,

The initialization of user_length might not be necessary.

Best wishes, Mike

PS: This might be related to
http://archives.postgresql.org/pgsql-admin/2003-03/msg00413.php

--
Life is like a fire. DI Michael Wildpaner
Flames which the passer-by forgets. Ph.D. Student
Ashes which the wind scatters.
A man lived. -- Omar Khayyam

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Michael Wildpaner (#1)
Re: [BUG/PATCH] backend crashes during authentication if data/global/pg_pwd is empty

Michael Wildpaner <mike@rainbow.studorg.tuwien.ac.at> writes:

+	/* fail if there is nothing to search in */
+	if ((user_sorted == NULL) || (user_length == 0))
+		return NULL;

Hm, Solaris' bsearch() fails on empty input? How bizarre.
Easily worked around though --- thanks for the report!

I suspect we'd better put a defense in get_group_line as well.
It looks like there are no other places at risk in the backend.

regards, tom lane

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#2)
Re: [BUG/PATCH] backend crashes during authentication if data/global/pg_pwd is empty

Hm, Solaris' bsearch() fails on empty input? How bizarre.

I was skeptical but apparently this is a known bug ...
googling turned up a couple of references, eg
http://www.opencm.org/pipermail/opencm-dev/2002-July/001077.html

regards, tom lane

#4Michael Wildpaner
mike@rainbow.studorg.tuwien.ac.at
In reply to: Tom Lane (#3)
Re: [BUG/PATCH] backend crashes during authentication if

Hi,

On Fri, 5 Dec 2003, Tom Lane wrote:

Hm, Solaris' bsearch() fails on empty input? How bizarre.

I was skeptical but apparently this is a known bug ...
googling turned up a couple of references, eg
http://www.opencm.org/pipermail/opencm-dev/2002-July/001077.html

in defense of Solaris' bsearch it should be said that it only breaks if
one passes NULL as the array base, a decidedly undefined (and unfriendly)
case. Passing an array with zero elements works as advertised. Btw, the
same happens on IRIX.

Best wishes, Mike

PS: A little program to demonstrate this: array with elements, empty
array, NULL pointer as base:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char strings[][4] = { "abc", "efg", "hij", "klm" };

typedef int (*cmp_t)(const void*, const void*);

int main(int argc, char**argv) {
char *s, *term = "hij";

s = bsearch(term, strings, sizeof(strings)/sizeof(char[4]),
sizeof(char*), (cmp_t) strcmp);
fprintf(stderr, "1: %s\n", (s != NULL) ? s : "<not found>");

s = bsearch(term, strings, 0, sizeof(char*), (cmp_t) strcmp);
fprintf(stderr, "2: %s\n", (s != NULL) ? s : "<not found>");

s = bsearch(term, NULL, 0, sizeof(char*), (cmp_t) strcmp);
fprintf(stderr, "3: %s\n", (s != NULL) ? s : "<not found>");

return 0;
}

Results:

$ ./a.out # Solaris 9
1: hij
2: <not found>
Segmentation Fault (core dumped)

$ ./a.out # IRIX 6.5
1: hij
2: <not found>
Segmentation fault (core dumped)

$ ./a.out # Linux with glibc 2.2.5
1: hij
2: <not found>
3: <not found>

$ ./a.out # OpenBSD 3.2
1: hij
2: <not found>
3: <not found>

--
Life is like a fire. DI Michael Wildpaner
Flames which the passer-by forgets. Ph.D. Student
Ashes which the wind scatters.
A man lived. -- Omar Khayyam