Edit report at https://bugs.php.net/bug.php?id=80460&edit=1
ID: 80460
User updated by: mirish at ibm dot com
Reported by: mirish at ibm dot com
Summary: ODBC doesn't account for SQL_NO_TOTAL indicator,
causing segmentation fault
-Status: Feedback
+Status: Assigned
Type: Bug
Package: ODBC related
Operating System: RHEL 7.9
PHP Version: Irrelevant
Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
It doesn't look like they are related. Bug #44618 seems to note that it should handle
SQL_NO_DATA, but that is a cursor indicator different from SQL_NO_TOTAL, which indicates that there
is data left to retrieve, but the driver doesn't know (or doesn't want to calculate) how
much data is left. As written, SQL_NO_TOTAL indicator (-4) is passed as a length to string
functions.
I can confirm that this segmentation fault occurs on 7.4.13.
Previous Comments:
------------------------------------------------------------------------
[2020-12-02 10:55:01] cmb@php.net
Isn't the second part basically a duplicate of bug #44618, which
is supposed to be fixed as of PHP 7.3.25 and 7.4.13?
------------------------------------------------------------------------
[2020-12-02 02:46:36] mirish at ibm dot com
Description:
------------
The ODBC extension (ext/odbc/php_odbc.c) causes a segmentation fault when SQL_NO_TOTAL indicator is
returned to a bound column from a call to SQLFetch and similar functions.
There are two major issues:
1. There is an assumption that the number of bytes returned from a call to SQLColAttribute with a
type of SQL_DESC_OCTET_LENGTH will return the number of bytes required to store the value. There are
cases when data is stored in an encoding which stores character data in a single byte, which then
needs to be converted to variable multi-byte when SQLFetch is actually called (eg. EBCDIC 278 to
UTF8 conversion). This might be a broken driver implementation on our part, but the ODBC docs are
rather thin and at times seem contradictory on this point.
This will cause a buffer to be allocated of size X, where up to X * 4 may be needed to store a
string. There is a variable in the code (charextraalloc) to allocate buffers of this size, but none
of the checks work for ODBC v 3.0+ drivers. When the buffer is too small, the driver may return
SQL_NO_TOTAL when in the StrLen_or_IndPtr, as it didn't have enough space for the column, and
might not know how many bytes are left.
2. The bigger issue is that calls to SQLFetch can return SQL_NO_TOTAL to the StrLen_or_IndPtr stored
on SQLBindCol when the buffer bound isn't large enough for the data, but the code isn't
checking for this. Instead, the code checks if the value of StrLen_or_IndPtr is SQL_NULL_DATA and
assigns a value to null. If it isn't SQL_NULL_DATA, it assumes that it holds the length of the
string, then calls functions like ZVAL_STRINGL and RETURN_STRINGL with SQL_NO_TOTAL (which evaluates
to -4) as the length. Trying to create a string with length of -4 causes a segmentation fault, which
causes the program to crash.
As mentioned, the first issue might be a problem in driver implementation, but the second definitely
needs to be fixed. SQL_NO_TOTAL is definitely a valid StrLen_or_IndPtr value, and there are no
checks for it in the code, causing a segfault.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=80460&edit=1