php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #54169 Garbage Pointers returned for (n)varchar(max) columns (SQL Server)
Submitted: 2011-03-05 17:06 UTC Modified: 2020-02-04 08:57 UTC
Votes:39
Avg. Score:4.7 ± 0.6
Reproduced:39 of 39 (100.0%)
Same Version:23 (59.0%)
Same OS:24 (61.5%)
From: auroraeosrose@php.net Assigned: cmb (profile)
Status: Closed Package: PDO ODBC
PHP Version: Irrelevant OS: Any
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: auroraeosrose@php.net
New email:
PHP Version: OS:

 

 [2011-03-05 17:06 UTC] auroraeosrose@php.net
Description:
------------
I found an issue this week that exists in both odbc and pdo_odbc with
SQL Server.  The ODBC implemention of Windows returns 0 as the length
for for varchar(max) and nvarchar(max).  This makes the allocation of
the strings incorrect and you get back garbage pointers for the
contents.

This was a pretty easy fix for pdo_odbc, simply check if the colsize
is returned as 0 and the type is one of the varchar types, if so
always treat it as a column with "long" data.  This works perfectly
without breaking things.  Attached is a patch that works for both 5.3
and trunk, includes an additional test for the issue.

ODBC shows the same issue - don't have a fix for that

Occurs in all versions of PHP

There are multiple bug reports concerning this and related to it - I'll try to gather them all up (later)

Test script:
---------------
$db = new PDO('odbc:yourdsnhere', 'username', 'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec('CREATE TABLE testing(id INT NOT NULL PRIMARY KEY, data varchar(max))');
$insert = $db->prepare('INSERT INTO testing VALUES (?, ?)');
$insert->execute(array(1, str_repeat('i', 500)));
$stmt = $db->query('select * from testing');
var_dump($stmt->fetchAll());

unset($db, $insert, $smt);

// This shows the same issue in odbc
$db = odbc_connect ('yourdsnhere', 'username', 'password');
$stmt = odbc_exec($db, 'select * from testing');
var_dump(odbc_fetch_array($stmt));

Expected result:
----------------
array(1) { [0]=> array(4) { ["id"]=> string(1) "1" [0]=> string(1) "1" ["data"]=> string(500) "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii" [1]=> string(500) "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii" } }


Same for the odbc call

Actual result:
--------------
array(1) { [0]=> array(4) { ["id"]=> string(1) "1" [0]=> string(1) "1" ["data"]=> string(500) "�-\p-\!������ˆòE�������ii����iiii!���!���select * from foo�iiiiii���!�������hall�iiiiiii!������ÀùE�������ii��������1���!���­|a���ìòEáE����ðE��������stmt����!���1���(áE����������������1���!�������������������`óEàõE$E ©"���1���1�����������óE����àõE������������€������1���1�������������������óE�������@éEøëE���!���1���àóEô������������������!���iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii" [1]=> string(500) "�-\p-\!������ˆòE�������ii����iiii!���!���select * from foo�iiiiii���!�������hall�iiiiiii!������ÀùE�������ii��������1���!���­|a���ìòEáE����ðE��������stmt����!���1���(áE����������������1���!�������������������`óEàõE$E ©"���1���1�����������óE����àõE������������€������1���1�������������������óE�������@éEøëE���!���1���àóEô������������������!���iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii" } } array(2) { ["id"]=> string(1) "1" ["data"]=> string(500) "�èE8öEp�����HöEHöE$.\päE����icrosoft][SQL Server Native Client 10.0]String data, right truncation�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������" } 

Patches

pdo_odbc-varchar (last revision 2011-03-05 16:08 UTC by auroraeosrose at gmail dot com)

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-03-05 20:43 UTC] felipe@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: auroraeosrose
 [2011-05-12 10:58 UTC] bugs dot php at pixbox dot co dot uk
I'm experiencing the same issue, using PHP 5, a Microsoft SQL Server 2008, and a 
direct ODBC connection.

My workaround was to alter the nvarchar(max) columns to nvarchar(n) where n is 
whatever the suitable size for that column was, or text.

The really strange thing was that when it was returning gibberish, it returned 
snippets of PHP code from the page that ran the query!
 [2013-01-28 16:16 UTC] a dot schilder at gmx dot de
This bug is really evil and should be treated as a security issue.

In one case I got the content of a previously loaded PHP file instead of the requested field data, so it's possible that the content of sensitive files is returned and shown.
 [2014-01-01 12:45 UTC] felipe@php.net
-Package: PDO related +Package: PDO ODBC
 [2015-02-05 18:38 UTC] trapper at coremr dot com
This bug is still in the latest version of PHP at this moment (5.6). It affects all the versions of the SQL Server Native Client ODBC drivers and makes them unfeasible to use because of it.

As its a problem inside ODBC, it is currently affecting both raw odbc_* functions as well as any PDO connections.
 [2015-05-26 23:53 UTC] jlongo at kastle dot com
Hey guys... this bug has been sitting for far too long IMO.  This needs to be identified as a security issue.  The garbage pointers that I get back when testing this flaw more times than not will contain the contents of the script source that I am running.  I have verified that the patch that was submitted works, so really it should just be a matter of folks merging it into the supported PHP versions for the next patch release.
 [2015-05-27 00:05 UTC] jlongo at kastle dot com
@trapper - it isn't necessarily a "problem" in ODBC... it is a change in behavior for Microsoft's ODBC Driver 11 implementation.  As of ODBC Driver 11, they are returning the length as 0 for max fields. They used to return a very large number for the column size, such as 2147483647 when running on a 32 bit platform, when using varchar(max) fields in prior versions of their driver.

As an effect, the pure odbc extension will also need this kind of update to work with Microsoft's ODBC Driver 11 and max fields.
 [2015-12-17 20:15 UTC] deankearney at gmail dot com
This bug still exists in php7. The fix works. Can we get this merged in?
 [2015-12-30 16:53 UTC] robshelby at icloud dot com
It would be great if this was merged into PHP 5.6 as well.
 [2016-04-07 02:49 UTC] calioptrix at gmail dot com
I just spent three hours chasing down this bug. I'm using php 5.6.0 with sql server 2014. Does the proposed patch have issues? 

As a band-aid, I got around the issue by casting to a varchar of length 8000, the maximum length of a "regular" varchar. In this particular case, truncating the field won't be an issue.

SELECT CAST(ColumnName AS VARCHAR(8000)) AS ColumnFixed FROM Table
 [2016-04-07 03:44 UTC] jlongo at kastle dot com
no issues with the patch.  Apparently PHP is happy to keep security vulnerabilities in multiple versions of their code base for years on end after a patch is submitted.  someone who is an official php developer is gonna have to kick this.

we have pulled the patch in and have applied it to our builds of PHP that we use with no issue except that it requires extra effort to do a custom patch and compile of source.
 [2016-07-28 15:35 UTC] cmb@php.net
> The fix works.

According to dpayne it doesn't, see
<https://github.com/php/php-src/pull/348#issuecomment-19565798>.
 [2016-07-28 16:11 UTC] cmb@php.net
This issue has been fixed as of PHP 5.6.23 and PHP 7.0.6 with
commit <https://github.com/php/php-src/commit/4df5f79> (if it has
been fixed[1]), but it is neither mentioned in NEWS nor the
changelog.

Anyway, I'm pretty sure that this is the same issue that has been
reported as bug #69975 for ODBC (but not for PDO_ODBC). As such it
is a vulnerability, as already been pointed out in comments to
this reports, and would require a CVE. Therefore I'm marking this
as security issue (not because it would make sense to hide this
report now).

[1] <https://github.com/php/php-src/pull/348#issuecomment-19565798>
 [2016-07-28 16:11 UTC] cmb@php.net
-Type: Bug +Type: Security -Private report: No +Private report: Yes
 [2017-10-24 06:00 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: auroraeosrose +Assigned To:
 [2020-02-01 17:01 UTC] cmb@php.net
-Type: Security +Type: Bug
 [2020-02-01 17:01 UTC] cmb@php.net
Since issuing a CVE now would not make sense, I'm re-categorizing
as bug.
 [2020-02-04 08:57 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 16:01:29 2024 UTC