Skip to content

Commit 3f63787

Browse files
committed
Guard against send-lots-and-lots-of-data DoS attack from unauthenticated
users, by limiting the length of string we will accept for a password. Patch by Serguei Mokhov, some editorializing by Tom Lane.
1 parent c5214b9 commit 3f63787

File tree

6 files changed

+38
-24
lines changed

6 files changed

+38
-24
lines changed

src/backend/libpq/auth.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.90 2002/09/04 20:31:18 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.91 2002/09/04 23:31:34 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -563,12 +563,11 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_re
563563
{
564564
sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD);
565565
if (pq_eof() == EOF || pq_getint(&len, 4) == EOF)
566-
{
567566
return PAM_CONV_ERR; /* client didn't want to send password */
568-
}
569567

570568
initStringInfo(&buf);
571-
pq_getstr(&buf);
569+
if (pq_getstr_bounded(&buf, 1000) == EOF)
570+
return PAM_CONV_ERR; /* EOF while reading password */
572571

573572
/* Do not echo failed password to logs, for security. */
574573
elog(DEBUG5, "received PAM packet");
@@ -707,7 +706,7 @@ recv_and_check_password_packet(Port *port)
707706
return STATUS_EOF; /* client didn't want to send password */
708707

709708
initStringInfo(&buf);
710-
if (pq_getstr(&buf) == EOF) /* receive password */
709+
if (pq_getstr_bounded(&buf, 1000) == EOF) /* receive password */
711710
{
712711
pfree(buf.data);
713712
return STATUS_EOF;

src/backend/libpq/be-secure.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*-------------------------------------------------------------------------
22
*
3-
* be-connect.c
3+
* be-secure.c
44
* functions related to setting up a secure connection to the frontend.
55
* Secure connections are expected to provide confidentiality,
66
* message integrity and endpoint authentication.
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.13 2002/09/04 20:31:19 momjian Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.14 2002/09/04 23:31:34 tgl Exp $
1515
*
1616
* Since the server static private key ($DataDir/server.key)
1717
* will normally be stored unencrypted so that the database

src/backend/libpq/pqcomm.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
3030
* Portions Copyright (c) 1994, Regents of the University of California
3131
*
32-
* $Id: pqcomm.c,v 1.140 2002/09/04 20:31:19 momjian Exp $
32+
* $Id: pqcomm.c,v 1.141 2002/09/04 23:31:34 tgl Exp $
3333
*
3434
*-------------------------------------------------------------------------
3535
*/
@@ -555,24 +555,32 @@ pq_getbytes(char *s, size_t len)
555555
* The return value is placed in an expansible StringInfo.
556556
* Note that space allocation comes from the current memory context!
557557
*
558+
* If maxlen is not zero, it is an upper limit on the length of the
559+
* string we are willing to accept. We abort the connection (by
560+
* returning EOF) if client tries to send more than that. Note that
561+
* since we test maxlen in the outer per-bufferload loop, the limit
562+
* is fuzzy: we might accept up to PQ_BUFFER_SIZE more bytes than
563+
* specified. This is fine for the intended purpose, which is just
564+
* to prevent DoS attacks from not-yet-authenticated clients.
565+
*
558566
* NOTE: this routine does not do any character set conversion,
559567
* even though it is presumably useful only for text, because
560568
* no code in this module should depend on the encoding.
561-
* See pq_getstr in pqformat.c for that.
569+
* See pq_getstr_bounded in pqformat.c for that.
562570
*
563571
* returns 0 if OK, EOF if trouble
564572
* --------------------------------
565573
*/
566574
int
567-
pq_getstring(StringInfo s)
575+
pq_getstring(StringInfo s, int maxlen)
568576
{
569577
int i;
570578

571579
/* Reset string to empty */
572580
s->len = 0;
573581
s->data[0] = '\0';
574582

575-
/* Read until we get the terminating '\0' */
583+
/* Read until we get the terminating '\0' or overrun maxlen */
576584
for (;;)
577585
{
578586
while (PqRecvPointer >= PqRecvLength)
@@ -594,10 +602,13 @@ pq_getstring(StringInfo s)
594602
}
595603

596604
/* If we're here we haven't got the \0 in the buffer yet. */
597-
598605
appendBinaryStringInfo(s, PqRecvBuffer + PqRecvPointer,
599606
PqRecvLength - PqRecvPointer);
600607
PqRecvPointer = PqRecvLength;
608+
609+
/* If maxlen is specified, check for overlength input. */
610+
if (maxlen > 0 && s->len > maxlen)
611+
return EOF;
601612
}
602613
}
603614

src/backend/libpq/pqformat.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
1717
* Portions Copyright (c) 1994, Regents of the University of California
1818
*
19-
* $Id: pqformat.c,v 1.24 2002/09/03 21:45:42 petere Exp $
19+
* $Id: pqformat.c,v 1.25 2002/09/04 23:31:35 tgl Exp $
2020
*
2121
*-------------------------------------------------------------------------
2222
*/
@@ -38,10 +38,10 @@
3838
* pq_puttextmessage - generate a character set-converted message in one step
3939
*
4040
* Message input:
41-
* pq_getint - get an integer from connection
42-
* pq_getstr - get a null terminated string from connection
43-
* pq_getstr performs character set conversion on the collected string.
44-
* Use the raw pqcomm.c routines pq_getstring or pq_getbytes
41+
* pq_getint - get an integer from connection
42+
* pq_getstr_bounded - get a null terminated string from connection
43+
* pq_getstr_bounded performs character set conversion on the collected
44+
* string. Use the raw pqcomm.c routines pq_getstring or pq_getbytes
4545
* to fetch data without conversion.
4646
*/
4747

@@ -247,21 +247,23 @@ pq_getint(int *result, int b)
247247
}
248248

249249
/* --------------------------------
250-
* pq_getstr - get a null terminated string from connection
250+
* pq_getstr_bounded - get a null terminated string from connection
251251
*
252252
* The return value is placed in an expansible StringInfo.
253253
* Note that space allocation comes from the current memory context!
254254
*
255+
* The maxlen parameter is interpreted as per pq_getstring.
256+
*
255257
* returns 0 if OK, EOF if trouble
256258
* --------------------------------
257259
*/
258260
int
259-
pq_getstr(StringInfo s)
261+
pq_getstr_bounded(StringInfo s, int maxlen)
260262
{
261263
int result;
262264
char *p;
263265

264-
result = pq_getstring(s);
266+
result = pq_getstring(s, maxlen);
265267

266268
p = (char *) pg_client_to_server((unsigned char *) s->data, s->len);
267269
if (p != s->data) /* actual conversion has been done? */

src/include/libpq/libpq.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: libpq.h,v 1.51 2002/06/20 20:29:49 momjian Exp $
10+
* $Id: libpq.h,v 1.52 2002/09/04 23:31:35 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -50,7 +50,7 @@ extern int StreamConnection(int server_fd, Port *port);
5050
extern void StreamClose(int sock);
5151
extern void pq_init(void);
5252
extern int pq_getbytes(char *s, size_t len);
53-
extern int pq_getstring(StringInfo s);
53+
extern int pq_getstring(StringInfo s, int maxlen);
5454
extern int pq_getbyte(void);
5555
extern int pq_peekbyte(void);
5656
extern int pq_putbytes(const char *s, size_t len);

src/include/libpq/pqformat.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: pqformat.h,v 1.12 2002/06/20 20:29:49 momjian Exp $
9+
* $Id: pqformat.h,v 1.13 2002/09/04 23:31:35 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -27,6 +27,8 @@ extern void pq_endmessage(StringInfo buf);
2727
extern int pq_puttextmessage(char msgtype, const char *str);
2828

2929
extern int pq_getint(int *result, int b);
30-
extern int pq_getstr(StringInfo s);
30+
extern int pq_getstr_bounded(StringInfo s, int maxlen);
31+
32+
#define pq_getstr(s) pq_getstr_bounded(s, 0)
3133

3234
#endif /* PQFORMAT_H */

0 commit comments

Comments
 (0)