Fix unportable disregard of alignment requirements in RADIUS code.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 26 Mar 2017 21:35:35 +0000 (17:35 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 26 Mar 2017 21:35:35 +0000 (17:35 -0400)
The compiler is entitled to store a char[] local variable with no
particular alignment requirement.  Our RADIUS code cavalierly took such
a local variable and cast its address to a struct type that does have
alignment requirements.  On an alignment-picky machine this would lead
to bus errors.  To fix, declare the local variable honestly, and then
cast its address to char * for use in the I/O calls.

Given the lack of field complaints, there must be very few if any
people affected; but nonetheless this is a clear portability issue,
so back-patch to all supported branches.

Noted while looking at a Coverity complaint in the same code.

src/backend/libpq/auth.c

index 8f77deae6cea4746500facb444087f5587e37fe6..a3c6c6d8b35fa2acd1c5f11b2d0f55e4730f093c 100644 (file)
@@ -2570,14 +2570,16 @@ CheckCertAuth(Port *port)
  */
 
 /*
- * RADIUS authentication is described in RFC2865 (and several
- * others).
+ * RADIUS authentication is described in RFC2865 (and several others).
  */
 
 #define RADIUS_VECTOR_LENGTH 16
 #define RADIUS_HEADER_LENGTH 20
 #define RADIUS_MAX_PASSWORD_LENGTH 128
 
+/* Maximum size of a RADIUS packet we will create or accept */
+#define RADIUS_BUFFER_SIZE 1024
+
 typedef struct
 {
    uint8       attribute;
@@ -2591,6 +2593,8 @@ typedef struct
    uint8       id;
    uint16      length;
    uint8       vector[RADIUS_VECTOR_LENGTH];
+   /* this is a bit longer than strictly necessary: */
+   char        pad[RADIUS_BUFFER_SIZE - RADIUS_VECTOR_LENGTH];
 } radius_packet;
 
 /* RADIUS packet types */
@@ -2607,9 +2611,6 @@ typedef struct
 /* RADIUS service types */
 #define RADIUS_AUTHENTICATE_ONLY   8
 
-/* Maximum size of a RADIUS packet we will create or accept */
-#define RADIUS_BUFFER_SIZE 1024
-
 /* Seconds to wait - XXX: should be in a config variable! */
 #define RADIUS_TIMEOUT 3
 
@@ -2734,10 +2735,12 @@ CheckRADIUSAuth(Port *port)
 static int
 PerformRadiusTransaction(char *server, char *secret, char *portstr, char *identifier, char *user_name, char *passwd)
 {
-   char        radius_buffer[RADIUS_BUFFER_SIZE];
-   char        receive_buffer[RADIUS_BUFFER_SIZE];
-   radius_packet *packet = (radius_packet *) radius_buffer;
-   radius_packet *receivepacket = (radius_packet *) receive_buffer;
+   radius_packet radius_send_pack;
+   radius_packet radius_recv_pack;
+   radius_packet *packet = &radius_send_pack;
+   radius_packet *receivepacket = &radius_recv_pack;
+   char       *radius_buffer = (char *) &radius_send_pack;
+   char       *receive_buffer = (char *) &radius_recv_pack;
    int32       service = htonl(RADIUS_AUTHENTICATE_ONLY);
    uint8      *cryptvector;
    int         encryptedpasswordlen;