CVE-2018-7485: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: The SQLWriteFileDSN function in odbcinst/SQLWriteFileDSN.c in unixODBC 2.3.5 has strncpy arguments in the wrong order, which allows attackers to cause a denial of service or possibly have unspecified other impact.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
CVSS v3 base score: 9.8
Published: 2018-02-26T14:29Z
Repository: https://github.com/lurcher/unixODBC
Language: C
Files changed: ChangeLog, DriverManager/SQLGetDiagRecW.c, DriverManager/SQLSetDescField.c, DriverManager/SQLSetDescFieldW.c, configure.ac, exe/iusql.c, odbcinst/SQLCreateDataSource.c, odbcinst/SQLWriteFileDSN.c
Commit date: 2018-01-08 11:12:39 +0000
Commit message: New Pre Source

Diff: diff --git a/ChangeLog b/ChangeLog
index cce9fd0..28a4e7f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
+2.3.6pre
+
+    * Fix order of arguments in SQLWriteFileDSN.c, fix unwanted free() in iusql.c
+
 2-Jan-2018
 2.3.5
 
     * Add configure option --enable-setlibversion set mark the libs with VERS_3.52
       Linux only, so any driver built with the libs will work with closed source 
diff --git a/DriverManager/SQLGetDiagRecW.c b/DriverManager/SQLGetDiagRecW.c
index a6368d7..be89120 100644
--- a/DriverManager/SQLGetDiagRecW.c
+++ b/DriverManager/SQLGetDiagRecW.c
@@ -96,10 +96,12 @@
 #include <config.h>
 #include "drivermanager.h"
 
 static char const rcsid[]= "$RCSfile: SQLGetDiagRecW.c,v $";
 
+extern int __is_env( EHEAD * head );        /* in SQLGetDiagRec.c */
+
 static SQLRETURN extract_sql_error_rec_w( EHEAD *head,
         SQLWCHAR *sqlstate,
         SQLINTEGER rec_number,
         SQLINTEGER *native_error,
         SQLWCHAR *message_text,
diff --git a/DriverManager/SQLSetDescField.c b/DriverManager/SQLSetDescField.c
index 333d786..0e2f67c 100644
--- a/DriverManager/SQLSetDescField.c
+++ b/DriverManager/SQLSetDescField.c
@@ -304,22 +304,22 @@ SQLRETURN SQLSetDescField( SQLHDESC descriptor_handle,
             descriptor -> connection -> environment -> requested_version );
 
         return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
     }
 
-    if ( field_identifier == SQL_DESC_COUNT && (SQLINTEGER)value < 0 )
+    if ( field_identifier == SQL_DESC_COUNT && (intptr_t)value < 0 )
     {
         __post_internal_error( &descriptor -> error,
                 ERROR_07009, NULL,
                 descriptor -> connection -> environment -> requested_version );
 
         return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
     }
     
-    if ( field_identifier == SQL_DESC_PARAMETER_TYPE && value != SQL_PARAM_INPUT
-        && value != SQL_PARAM_OUTPUT && value != SQL_PARAM_INPUT_OUTPUT &&
-        value != SQL_PARAM_INPUT_OUTPUT_STREAM && value != SQL_PARAM_OUTPUT_STREAM )
+    if ( field_identifier == SQL_DESC_PARAMETER_TYPE && (intptr_t)value != SQL_PARAM_INPUT
+        && (intptr_t)value != SQL_PARAM_OUTPUT && (intptr_t)value != SQL_PARAM_INPUT_OUTPUT &&
+        (intptr_t)value != SQL_PARAM_INPUT_OUTPUT_STREAM && (intptr_t)value != SQL_PARAM_OUTPUT_STREAM )
     {
         __post_internal_error( &descriptor -> error,
                 ERROR_HY105, NULL,
                 descriptor -> connection -> environment -> requested_version );
 
diff --git a/DriverManager/SQLSetDescFieldW.c b/DriverManager/SQLSetDescFieldW.c
index 5e066ac..45125ff 100644
--- a/DriverManager/SQLSetDescFieldW.c
+++ b/DriverManager/SQLSetDescFieldW.c
@@ -286,22 +286,22 @@ SQLRETURN SQLSetDescFieldW( SQLHDESC descriptor_handle,
             descriptor -> connection -> environment -> requested_version );
 
         return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
     }
 
-    if ( field_identifier == SQL_DESC_COUNT && (SQLINTEGER)value < 0 )
+    if ( field_identifier == SQL_DESC_COUNT && (intptr_t)value < 0 )
     {
         __post_internal_error( &descriptor -> error,
                 ERROR_07009, NULL,
                 descriptor -> connection -> environment -> requested_version );
 
         return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
     }
 
-    if ( field_identifier == SQL_DESC_PARAMETER_TYPE && value != SQL_PARAM_INPUT
-        && value != SQL_PARAM_OUTPUT && value != SQL_PARAM_INPUT_OUTPUT &&
-        value != SQL_PARAM_INPUT_OUTPUT_STREAM && value != SQL_PARAM_OUTPUT_STREAM )
+    if ( field_identifier == SQL_DESC_PARAMETER_TYPE && (intptr_t)value != SQL_PARAM_INPUT
+        && (intptr_t)value != SQL_PARAM_OUTPUT && (intptr_t)value != SQL_PARAM_INPUT_OUTPUT &&
+        (intptr_t)value != SQL_PARAM_INPUT_OUTPUT_STREAM && (intptr_t)value != SQL_PARAM_OUTPUT_STREAM )
     {
         __post_internal_error( &descriptor -> error,
                 ERROR_HY105, NULL,
                 descriptor -> connection -> environment -> requested_version );
 
diff --git a/configure.ac b/configure.ac
index 1a5b6e0..3c0cc3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
 dnl Process this file with autoconf to produce a configure script.
 
-AC_INIT([unixODBC], [2.3.5], nick@unixodbc.org, [unixODBC])
+AC_INIT([unixODBC], [2.3.6pre], nick@unixodbc.org, [unixODBC])
 AM_INIT_AUTOMAKE
 
 dnl Checks for programs.
 AC_PROG_AWK
 AC_PROG_YACC
diff --git a/exe/iusql.c b/exe/iusql.c
index aac5329..484a889 100644
--- a/exe/iusql.c
+++ b/exe/iusql.c
@@ -411,11 +411,10 @@ static int ExecuteSQL( SQLHDBC hDbc, char *szSQL, char cDelimiter, int bColumnNa
         else if ( ret != SQL_SUCCESS )
         {
             if ( bVerbose ) DumpODBCLog( hEnv, hDbc, hStmt );
             fprintf( stderr, "[ISQL]ERROR: Could not SQLExecDirect\n" );
             SQLFreeStmt( hStmt, SQL_DROP );
-            free(szSepLine);
             return 0;
         }
     }
     else {
         if ( SQLPrepare( hStmt, szUcSQL, SQL_NTS ) != SQL_SUCCESS )
diff --git a/odbcinst/SQLCreateDataSource.c b/odbcinst/SQLCreateDataSource.c
index a9fa735..83a1e9e 100644
--- a/odbcinst/SQLCreateDataSource.c
+++ b/odbcinst/SQLCreateDataSource.c
@@ -24,11 +24,11 @@ char* _multi_string_alloc_and_copy( LPCWSTR in )
     char *chr;
     int len = 0;
 
     if ( !in )
     {
-        return in;
+        return NULL;
     }
 
     while ( in[ len ] != 0 || in[ len + 1 ] != 0 )
     {
         len ++;
@@ -53,11 +53,11 @@ char* _single_string_alloc_and_copy( LPCWSTR in )
     char *chr;
     int len = 0;
 
     if ( !in )
     {
-        return in;
+        return NULL;
     }
 
     while ( in[ len ] != 0 )
     {
         len ++;
@@ -81,11 +81,11 @@ SQLWCHAR* _multi_string_alloc_and_expand( LPCSTR in )
     SQLWCHAR *chr;
     int len = 0;
 
     if ( !in )
     {
-        return in;
+        return NULL;
     }
     
     while ( in[ len ] != 0 || in[ len + 1 ] != 0 )
     {
         len ++;
@@ -110,11 +110,11 @@ SQLWCHAR* _single_string_alloc_and_expand( LPCSTR in )
     SQLWCHAR *chr;
     int len = 0;
 
     if ( !in )
     {
-        return in;
+        return NULL;
     }
 
     while ( in[ len ] != 0 )
     {
         len ++;
diff --git a/odbcinst/SQLWriteFileDSN.c b/odbcinst/SQLWriteFileDSN.c
index c2f987b..e225796 100644
--- a/odbcinst/SQLWriteFileDSN.c
+++ b/odbcinst/SQLWriteFileDSN.c
@@ -19,11 +19,11 @@ BOOL SQLWriteFileDSN(			LPCSTR	pszFileName,
 	HINI	hIni;
 	char	szFileName[ODBC_FILENAME_MAX+1];
 
 	if ( pszFileName[0] == '/' )
 	{
-		strncpy( szFileName, sizeof(szFileName) - 5, pszFileName );
+		strncpy( szFileName, pszFileName, sizeof(szFileName) - 5 );
 	}
 	else
 	{	
 		char szPath[ODBC_FILENAME_MAX+1];
 		*szPath = '\0';

Vulnerable code:     if ( field_identifier == SQL_DESC_COUNT && (SQLINTEGER)value < 0 )
    if ( field_identifier == SQL_DESC_PARAMETER_TYPE && value != SQL_PARAM_INPUT
        && value != SQL_PARAM_OUTPUT && value != SQL_PARAM_INPUT_OUTPUT &&
        value != SQL_PARAM_INPUT_OUTPUT_STREAM && value != SQL_PARAM_OUTPUT_STREAM )
    if ( field_identifier == SQL_DESC_COUNT && (SQLINTEGER)value < 0 )
    if ( field_identifier == SQL_DESC_PARAMETER_TYPE && value != SQL_PARAM_INPUT
        && value != SQL_PARAM_OUTPUT && value != SQL_PARAM_INPUT_OUTPUT &&
        value != SQL_PARAM_INPUT_OUTPUT_STREAM && value != SQL_PARAM_OUTPUT_STREAM )
AC_INIT([unixODBC], [2.3.5], nick@unixodbc.org, [unixODBC])
            free(szSepLine);
        return in;
        return in;
        return in;
        return in;
		strncpy( szFileName, sizeof(szFileName) - 5, pszFileName );
Fixed code: 2.3.6pre

    * Fix order of arguments in SQLWriteFileDSN.c, fix unwanted free() in iusql.c

extern int __is_env( EHEAD * head );        /* in SQLGetDiagRec.c */

    if ( field_identifier == SQL_DESC_COUNT && (intptr_t)value < 0 )
    if ( field_identifier == SQL_DESC_PARAMETER_TYPE && (intptr_t)value != SQL_PARAM_INPUT
        && (intptr_t)value != SQL_PARAM_OUTPUT && (intptr_t)value != SQL_PARAM_INPUT_OUTPUT &&
        (intptr_t)value != SQL_PARAM_INPUT_OUTPUT_STREAM && (intptr_t)value != SQL_PARAM_OUTPUT_STREAM )
    if ( field_identifier == SQL_DESC_COUNT && (intptr_t)value < 0 )
    if ( field_identifier == SQL_DESC_PARAMETER_TYPE && (intptr_t)value != SQL_PARAM_INPUT
        && (intptr_t)value != SQL_PARAM_OUTPUT && (intptr_t)value != SQL_PARAM_INPUT_OUTPUT &&
        (intptr_t)value != SQL_PARAM_INPUT_OUTPUT_STREAM && (intptr_t)value != SQL_PARAM_OUTPUT_STREAM )
AC_INIT([unixODBC], [2.3.6pre], nick@unixodbc.org, [unixODBC])
        return NULL;
        return NULL;
        return NULL;
        return NULL;
		strncpy( szFileName, pszFileName, sizeof(szFileName) - 5 );