Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0e7f707

Browse files
committed
Fix low-risk potential denial of service against RADIUS login.
Corrupt RADIUS responses were treated as errors and not ignored(which the RFC2865 states they should be). This meant that auser with unfiltered access to the network of the PostgreSQLor RADIUS server could send a spoofed RADIUS responseto the PostgreSQL server causing it to reject a valid login,provided the attacker could also guess (or brute-force) thecorrect port number.Fix is to simply retry the receive in a loop until the timeouthas expired or a valid (signed by the correct RADIUS server)packet arrives.Reported by Alan DeKok in bug #5687.
1 parent915116b commit0e7f707

File tree

1 file changed

+126
-94
lines changed

1 file changed

+126
-94
lines changed

‎src/backend/libpq/auth.c

Lines changed: 126 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -2619,7 +2619,7 @@ CheckRADIUSAuth(Port *port)
26192619
charportstr[128];
26202620
ACCEPT_TYPE_ARG3addrsize;
26212621
fd_setfdset;
2622-
structtimevaltimeout;
2622+
structtimevalendtime;
26232623
inti,
26242624
r;
26252625

@@ -2777,14 +2777,36 @@ CheckRADIUSAuth(Port *port)
27772777
/* Don't need the server address anymore */
27782778
pg_freeaddrinfo_all(hint.ai_family,serveraddrs);
27792779

2780-
/* Wait for a response */
2781-
timeout.tv_sec=RADIUS_TIMEOUT;
2782-
timeout.tv_usec=0;
2783-
FD_ZERO(&fdset);
2784-
FD_SET(sock,&fdset);
2780+
/*
2781+
* Figure out at what time we should time out. We can't just use
2782+
* a single call to select() with a timeout, since somebody can
2783+
* be sending invalid packets to our port thus causing us to
2784+
* retry in a loop and never time out.
2785+
*/
2786+
gettimeofday(&endtime,NULL);
2787+
endtime.tv_sec+=RADIUS_TIMEOUT;
27852788

27862789
while (true)
27872790
{
2791+
structtimevaltimeout;
2792+
structtimevalnow;
2793+
int64timeoutval;
2794+
2795+
gettimeofday(&now,NULL);
2796+
timeoutval= (endtime.tv_sec*1000000+endtime.tv_usec)- (now.tv_sec*1000000+now.tv_usec);
2797+
if (timeoutval <=0)
2798+
{
2799+
ereport(LOG,
2800+
(errmsg("timeout waiting for RADIUS response")));
2801+
closesocket(sock);
2802+
returnSTATUS_ERROR;
2803+
}
2804+
timeout.tv_sec=timeoutval /1000000;
2805+
timeout.tv_usec=timeoutval %1000000;
2806+
2807+
FD_ZERO(&fdset);
2808+
FD_SET(sock,&fdset);
2809+
27882810
r=select(sock+1,&fdset,NULL,NULL,&timeout);
27892811
if (r<0)
27902812
{
@@ -2805,107 +2827,117 @@ CheckRADIUSAuth(Port *port)
28052827
returnSTATUS_ERROR;
28062828
}
28072829

2808-
/* else we actually have a packet ready to read */
2809-
break;
2810-
}
2811-
2812-
/* Read the response packet */
2813-
addrsize=sizeof(remoteaddr);
2814-
packetlength=recvfrom(sock,receive_buffer,RADIUS_BUFFER_SIZE,0,
2815-
(structsockaddr*)&remoteaddr,&addrsize);
2816-
if (packetlength<0)
2817-
{
2818-
ereport(LOG,
2819-
(errmsg("could not read RADIUS response: %m")));
2820-
closesocket(sock);
2821-
returnSTATUS_ERROR;
2822-
}
2830+
/*
2831+
* Attempt to read the response packet, and verify the contents.
2832+
*
2833+
* Any packet that's not actually a RADIUS packet, or otherwise
2834+
* does not validate as an explicit reject, is just ignored and
2835+
* we retry for another packet (until we reach the timeout). This
2836+
* is to avoid the possibility to denial-of-service the login by
2837+
* flooding the server with invalid packets on the port that
2838+
* we're expecting the RADIUS response on.
2839+
*/
28232840

2824-
closesocket(sock);
2841+
addrsize=sizeof(remoteaddr);
2842+
packetlength=recvfrom(sock,receive_buffer,RADIUS_BUFFER_SIZE,0,
2843+
(structsockaddr*)&remoteaddr,&addrsize);
2844+
if (packetlength<0)
2845+
{
2846+
ereport(LOG,
2847+
(errmsg("could not read RADIUS response: %m")));
2848+
returnSTATUS_ERROR;
2849+
}
28252850

28262851
#ifdefHAVE_IPV6
2827-
if (remoteaddr.sin6_port!=htons(port->hba->radiusport))
2852+
if (remoteaddr.sin6_port!=htons(port->hba->radiusport))
28282853
#else
2829-
if (remoteaddr.sin_port!=htons(port->hba->radiusport))
2854+
if (remoteaddr.sin_port!=htons(port->hba->radiusport))
28302855
#endif
2831-
{
2856+
{
28322857
#ifdefHAVE_IPV6
2833-
ereport(LOG,
2834-
(errmsg("RADIUS response was sent from incorrect port: %i",
2835-
ntohs(remoteaddr.sin6_port))));
2858+
ereport(LOG,
2859+
(errmsg("RADIUS response was sent from incorrect port: %i",
2860+
ntohs(remoteaddr.sin6_port))));
28362861
#else
2837-
ereport(LOG,
2838-
(errmsg("RADIUS response was sent from incorrect port: %i",
2839-
ntohs(remoteaddr.sin_port))));
2862+
ereport(LOG,
2863+
(errmsg("RADIUS response was sent from incorrect port: %i",
2864+
ntohs(remoteaddr.sin_port))));
28402865
#endif
2841-
returnSTATUS_ERROR;
2842-
}
2843-
2844-
if (packetlength<RADIUS_HEADER_LENGTH)
2845-
{
2846-
ereport(LOG,
2847-
(errmsg("RADIUS response too short: %i",packetlength)));
2848-
returnSTATUS_ERROR;
2849-
}
2850-
2851-
if (packetlength!=ntohs(receivepacket->length))
2852-
{
2853-
ereport(LOG,
2854-
(errmsg("RADIUS response has corrupt length: %i (actual length %i)",
2855-
ntohs(receivepacket->length),packetlength)));
2856-
returnSTATUS_ERROR;
2857-
}
2866+
continue;
2867+
}
28582868

2859-
if (packet->id!=receivepacket->id)
2860-
{
2861-
ereport(LOG,
2862-
(errmsg("RADIUS response is to a different request: %i (should be %i)",
2863-
receivepacket->id,packet->id)));
2864-
returnSTATUS_ERROR;
2865-
}
2869+
if (packetlength<RADIUS_HEADER_LENGTH)
2870+
{
2871+
ereport(LOG,
2872+
(errmsg("RADIUS response too short: %i",packetlength)));
2873+
continue;
2874+
}
28662875

2867-
/*
2868-
* Verify the response authenticator, which is calculated as
2869-
* MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
2870-
*/
2871-
cryptvector=palloc(packetlength+strlen(port->hba->radiussecret));
2876+
if (packetlength!=ntohs(receivepacket->length))
2877+
{
2878+
ereport(LOG,
2879+
(errmsg("RADIUS response has corrupt length: %i (actual length %i)",
2880+
ntohs(receivepacket->length),packetlength)));
2881+
continue;
2882+
}
28722883

2873-
memcpy(cryptvector,receivepacket,4);/* code+id+length */
2874-
memcpy(cryptvector+4,packet->vector,RADIUS_VECTOR_LENGTH);/* request
2875-
* authenticator, from
2876-
* original packet */
2877-
if (packetlength>RADIUS_HEADER_LENGTH)/* there may be no attributes
2878-
* at all */
2879-
memcpy(cryptvector+RADIUS_HEADER_LENGTH,receive_buffer+RADIUS_HEADER_LENGTH,packetlength-RADIUS_HEADER_LENGTH);
2880-
memcpy(cryptvector+packetlength,port->hba->radiussecret,strlen(port->hba->radiussecret));
2884+
if (packet->id!=receivepacket->id)
2885+
{
2886+
ereport(LOG,
2887+
(errmsg("RADIUS response is to a different request: %i (should be %i)",
2888+
receivepacket->id,packet->id)));
2889+
continue;
2890+
}
28812891

2882-
if (!pg_md5_binary(cryptvector,
2883-
packetlength+strlen(port->hba->radiussecret),
2884-
encryptedpassword))
2885-
{
2886-
ereport(LOG,
2887-
(errmsg("could not perform MD5 encryption of received packet")));
2892+
/*
2893+
* Verify the response authenticator, which is calculated as
2894+
* MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
2895+
*/
2896+
cryptvector=palloc(packetlength+strlen(port->hba->radiussecret));
2897+
2898+
memcpy(cryptvector,receivepacket,4);/* code+id+length */
2899+
memcpy(cryptvector+4,packet->vector,RADIUS_VECTOR_LENGTH);/* request
2900+
* authenticator, from
2901+
* original packet */
2902+
if (packetlength>RADIUS_HEADER_LENGTH)/* there may be no attributes
2903+
* at all */
2904+
memcpy(cryptvector+RADIUS_HEADER_LENGTH,receive_buffer+RADIUS_HEADER_LENGTH,packetlength-RADIUS_HEADER_LENGTH);
2905+
memcpy(cryptvector+packetlength,port->hba->radiussecret,strlen(port->hba->radiussecret));
2906+
2907+
if (!pg_md5_binary(cryptvector,
2908+
packetlength+strlen(port->hba->radiussecret),
2909+
encryptedpassword))
2910+
{
2911+
ereport(LOG,
2912+
(errmsg("could not perform MD5 encryption of received packet")));
2913+
pfree(cryptvector);
2914+
continue;
2915+
}
28882916
pfree(cryptvector);
2889-
returnSTATUS_ERROR;
2890-
}
2891-
pfree(cryptvector);
28922917

2893-
if (memcmp(receivepacket->vector,encryptedpassword,RADIUS_VECTOR_LENGTH)!=0)
2894-
{
2895-
ereport(LOG,
2896-
(errmsg("RADIUS response has incorrect MD5 signature")));
2897-
returnSTATUS_ERROR;
2898-
}
2918+
if (memcmp(receivepacket->vector,encryptedpassword,RADIUS_VECTOR_LENGTH)!=0)
2919+
{
2920+
ereport(LOG,
2921+
(errmsg("RADIUS response has incorrect MD5 signature")));
2922+
continue;
2923+
}
28992924

2900-
if (receivepacket->code==RADIUS_ACCESS_ACCEPT)
2901-
returnSTATUS_OK;
2902-
elseif (receivepacket->code==RADIUS_ACCESS_REJECT)
2903-
returnSTATUS_ERROR;
2904-
else
2905-
{
2906-
ereport(LOG,
2907-
(errmsg("RADIUS response has invalid code (%i) for user \"%s\"",
2908-
receivepacket->code,port->user_name)));
2909-
returnSTATUS_ERROR;
2910-
}
2925+
if (receivepacket->code==RADIUS_ACCESS_ACCEPT)
2926+
{
2927+
closesocket(sock);
2928+
returnSTATUS_OK;
2929+
}
2930+
elseif (receivepacket->code==RADIUS_ACCESS_REJECT)
2931+
{
2932+
closesocket(sock);
2933+
returnSTATUS_ERROR;
2934+
}
2935+
else
2936+
{
2937+
ereport(LOG,
2938+
(errmsg("RADIUS response has invalid code (%i) for user \"%s\"",
2939+
receivepacket->code,port->user_name)));
2940+
continue;
2941+
}
2942+
}/* while (true) */
29112943
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp