PHP :: Bug #76322 :: Strings containing NULL-byte get truncated
php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76322 Strings containing NULL-byte get truncated
Submitted: 2018-05-10 02:18 UTC Modified: 2018-08-10 16:59 UTC
From: morozov at tut dot by Assigned:
Status: Open Package: ibm_db2 (PECL)
PHP Version: 7.2.5 OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: morozov at tut dot by
New email:
PHP Version: OS:

 

 [2018-05-10 02:18 UTC] morozov at tut dot by
Description:
------------
If a value of a (VAR)?CHAR FOR BIT DATA field contains NULL-bytes, the value gets truncated after the first one.

Test script:
---------------
$stmt = db2_prepare($conn, 'CREATE TABLE TEST_TABLE(VAL VARCHAR(16) FOR BIT DATA NOT NULL)');
db2_execute($stmt);

$stmt = db2_prepare($conn, 'INSERT INTO TEST_TABLE VALUES(X\'410042\')');
db2_execute($stmt);

$stmt = db2_prepare($conn, 'SELECT VAL, LENGTH(VAL) LEN FROM test_table');
db2_execute($stmt);
$row = db2_fetch_assoc($stmt);

var_dump($row);

Expected result:
----------------
array(2) {
  'VAL' =>
  string(3) "A.B"
  'LEN' =>
  int(3)
}


Actual result:
--------------
array(2) {
  'VAL' =>
  string(1) "A"
  'LEN' =>
  int(3)
}


Patches

fix_for_defect (last revision 2018-08-10 08:39 UTC) by vnkbabu@php.net)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-05-10 03:48 UTC] morozov at tut dot by
Combined with other issues, it can lead to a security hole like:

function register_user($email) {
    if (substr($email, -12) !== '@company.com') {
        die('Employees only');
    }

    $id = create_user($email);

    // later
    $email = get_user_email($id);
    send_activation($email);
}

register_user("evil@hacker.org\0@company.com");
 [2018-08-09 05:41 UTC] vnkbabu@php.net
Hi,
This is expected behavior, 
we are storing A"NULL" B in our database, while printing we are only printing A since after that we are encountering "NULL" hence not able to print B. From output we can check length retrieved from DB is 3.
Actual result:
--------------
array(2) {
  'VAL' =>
  string(1) "A"
  'LEN' =>
  int(3)

in HEX 00 corrosponds to "NULL" if you want to give "." then please use "2e".
 [2018-08-09 06:37 UTC] morozov at tut dot by
Could you please elaborate why this is expected behavior? The column definition contains "FOR BIT DATA" meaning it's just bytes, not printable characters. As far as the DB driver is concerned, strings in PHP are binary-safe, so it doesn't matter which bytes it contains. These bytes don't even have to be printed, they could be used as a binary representation of a structure (e.g. UUID) or a hash.

Other drivers (e.g. JDBC in IntelliJ IDEA) and other DB extensions in PHP (including mysqli, pdo_*, oci8 and sqlsrv) work with null-bytes correctly.

The dot in the output is to display the null byte, not the actual dot.
 [2018-08-09 09:19 UTC] vnkbabu@php.net
Hi,
What I meant was, when X'410042' is stored while printing PHP is truncating it as it encountered null, data is properly stored in application buffer after fetch.

var_dump() is not able to print beyond "NULL" but buffer holds complete data.
pasting below gdb output.
(gdb) p str
$15 = 0x7ffff6801118 "A"
(gdb) p/x *(str+1)
$16 = 0x0
(gdb) p/x *(str+2)
$17 = 0x42
and output also shows retrieved data is 3 length string.
array(2) {
  'VAL' =>
  string(1) "A"
  'LEN' =>
  int(3)  <<<<<<<<<<<<<<< 3 byte string.
}

Please let me know if I am misinterpreting something.

Thanks,
 [2018-08-09 16:49 UTC] morozov at tut dot by
Hi,

> What I meant was, when X'410042' is stored while printing PHP is truncating it as it encountered null, data is properly stored in application buffer after fetch.

Yes and no. A print/echo would truncate it but var_dump() wouldn't. The fact that var_dump() displays only one character means that the variable has one character. For example:
<?php

$a = "\x41\x00\x42"; // this is the same value as stored in the DB
var_dump($a);
// string(3) "A\000B" (this should be expected output in the original description, not sure if I can update it).

echo $a, PHP_EOL;
// A (even without the line feed)
?>

> var_dump() is not able to print beyond "NULL" but buffer holds complete data.

As you can see, it's not true.

> Please let me know if I am misinterpreting something.

Yes. The LEN() function is executed in the DB to show that the actual value stored in the DB is intact and is 3 bytes long. It doesn't mean that the PHP variable contains a 3-byte value.

The problem in the extension seems to be somewhere around:

https://github.com/php/pecl-database-ibm_db2/blob/a24fa9b37d658ea578b8483bddc8ad3d6f1b4262/ibm_db2.c#L6496

It uses the strlen() function to determine the string length but it stops on the first NULL-byte.
 [2018-08-10 08:36 UTC] vnkbabu@php.net
Thank you for clarification, as you mentioned in comment, use of strlen() was the issue. 

we need to replace strlen((char *)row_data->str_val) with out_length which holds the fetched output length.

will attach the path with the defect.

Thanks,
Abhinav
 [2018-08-10 08:39 UTC] vnkbabu@php.net
The following patch has been added/updated:

Patch Name: fix_for_defect
Revision:   1533890340
URL:        https://bugs.php.net/patch-display.php?bug=76322&patch=fix_for_defect&revision=1533890340
 [2018-08-10 16:59 UTC] morozov at tut dot by
Thank you, Abhinav! With the patch, the value is no longer truncated.
 
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Fri Aug 17 18:01:26 2018 UTC