php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69981 Segmentation Fault with streams over SSH2
Submitted: 2015-07-02 18:45 UTC Modified: 2021-02-21 04:22 UTC
Votes:11
Avg. Score:4.3 ± 1.4
Reproduced:9 of 10 (90.0%)
Same Version:2 (22.2%)
Same OS:2 (22.2%)
From: info at josephcrawford dot com Assigned: cmb (profile)
Status: No Feedback Package: ssh2 (PECL)
PHP Version: Irrelevant OS: Mac OSX 10.10
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: info at josephcrawford dot com
New email:
PHP Version: OS:

 

 [2015-07-02 18:45 UTC] info at josephcrawford dot com
Description:
------------
I am using the following library

https://github.com/ideaconnect/idct-sftp-client

When I try to get a directory listing of files from an SFTP connection I am getting the following error.

Segmentation fault: 11

I am using PHP 5.6.9 that was installed via Homebrew.  However I also tried using the PHP version that shipped with Zend Server (uninstalled after testing) which I believe was 5.6.x and I was getting the same results.

Test script:
---------------
<?php
use \IDCT\Networking\Ssh\SftpClient;

$sftp = new SftpClient();
$credentials = Credentials::withPassword('username', 'password');
$sftp->setCredentials($credentials);
$sftp->connect('hostname.goes.here', 22);
$remote_files = $sftp->getFileList('your_path_here/');

Expected result:
----------------
I expect an array of filenames that reside on the server path that I specify in the getFileList method.

Actual result:
--------------
Segmentation Fault: 11

This is the line that causes the actual segmentation fault which I verified with var_dump before the loop, inside the loop and after the loop.  The only place the var_dump worked was before the loop.

https://github.com/ideaconnect/idct-sftp-client/blob/master/src/SftpClient.php#L521

Patches

ssh2_getpath (last revision 2019-03-20 20:01 UTC by ken at pardiac dot com)
ssh2_findpath (last revision 2019-03-20 19:48 UTC by ken at pardiac dot om)
ssh2_sftp_pathfix (last revision 2015-11-06 17:10 UTC by ken at pardiac dot com)

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-07-02 18:49 UTC] info at josephcrawford dot com
I should also note that everything else is working properly.  I can connect, upload, download files without any issues.  It is solely when I tried to list the directory contents that the segmentation fault is thrown.
 [2015-07-02 18:58 UTC] info at josephcrawford dot com
Also here is a directory listing showing the permissions for the folder in which I am trying to get a directory listing from.

dr-xr--r--   1 user     group           0 Jul  2 12:00 Images
 [2015-07-02 19:42 UTC] info at josephcrawford dot com
Since I was using the ssh2 extension that was installed via homebrew I was led through the process of using pecl to reinstall the ssh2 extension.  I used the following command.

sudo pecl install ssh2

When I tested my application I received the same segmentation fault as using the homebrew installed version of the extension.

jcrawford@Josephs-Mac-mini:~/TraderTools (dev *) # ./traders.php --action=import
Execution started at 3:26 PM
Segmentation fault: 11
 [2015-07-02 19:58 UTC] info at josephcrawford dot com
I believe this is an issue with the ssh2_lib and the report may need to be moved from Stream Related to SSH2 Lib.
 [2015-07-02 19:59 UTC] langemeijer@php.net
What is your libssh2 version? You can find that information with

 php -i | grep "libssh2 version"
 [2015-07-02 20:00 UTC] info at josephcrawford dot com
The version of libssh2 is currently

libssh2 version => 1.5.0
 [2015-07-02 20:01 UTC] langemeijer@php.net
-Package: Streams related +Package: ssh2
 [2015-07-02 20:07 UTC] langemeijer@php.net
You can help progress on this bug report by making a minimal test case using only the ssh2 functions and not using a library. Also, upgrading libssh2 to the latest version will improve your chances.

The ssh2 extension is only a really thin wrapper over the libssh2 library. It might well be that libssh2 is at fault in this case.

It might also be relevant to state make and version of the ssh server you are talking to.
 [2015-07-02 20:39 UTC] info at josephcrawford dot com
I wouldn't have the first clue on how to upgrade libssh2 on Mac OSX as for the make/version of the ssh software I am not sure.  I do not have ssh access only sftp access.
 [2015-07-02 20:41 UTC] info at josephcrawford dot com
Also homebrew doesn't have a version > 1.5.0 so to get the latest I am sure that would require compiling and I haven't a clue where all this stuff is stored (paths, etc) on mac osx as I know it's not usually the same as on linux.
 [2015-07-02 21:29 UTC] info at josephcrawford dot com
Does PHP's implementation of readdir care how many files are in the directory?  I was able to get this code to work perfectly fine with a directory of about 5 files.  However the directory I am trying to get a directory listing for has around 60,000 image files in the directory and it's causing the segmentation fault.
 [2015-07-02 22:09 UTC] info at josephcrawford dot com
I am also going to add that I have tried to use the following work-arounds and they also fail when it comes time to read the directory.

<?php
// Segmentation Fault: 11
$files = scandir("ssh2.sftp://$sftp/$remotePath");

// This works
$handle = dir("ssh2.sftp://$sftp/$remotePath");

// UNTIL you do this
while (false !== ($entry = $handle->read())) {

It would appear that it is something in the lower level C programming for the PHP core or the ssh2 extension which would segmentation fault when it comes to memory issues.

I verified the total number of files in the directory is 29,516 and not 60,000 like I first estimated.  My resized images folder has 60,000 images in it but I am not trying to list that directory.
 [2015-07-02 22:54 UTC] info at josephcrawford dot com
I also upgraded my libssh2 to 1.6.0 and received the same segmentation fault results.

I am thinking that the problem is with the ssh2_ extension as if this was in the core it would have been encountered by now.  Since the ssh2 extension is used far less than the php core stream related code.
 [2015-07-03 00:46 UTC] pajoye@php.net
Thanks for the report!

Could you provide a self contained script please? Single file using ossh? ssh?
 [2015-07-03 00:46 UTC] pajoye@php.net
-Status: Open +Status: Feedback
 [2015-07-03 00:46 UTC] pajoye@php.net
Update status
 [2015-07-03 00:55 UTC] info at josephcrawford dot com
-Status: Feedback +Status: Open
 [2015-07-03 00:55 UTC] info at josephcrawford dot com
This is about as simple as you can get.  The following code provides me with the Segmentation Fault as seen below..

// RESPONSE
jcrawford@Josephs-Mac-mini:~/TraderTools (dev *%) # php sftp_test.php 
Segmentation fault: 11

// CODE
<?php
$ssh2 = ssh2_connect(‘you.domain.here’, 8022);
ssh2_auth_password($ssh2, ‘username’, ‘password’);
$sftp = ssh2_sftp($ssh2);
$handle = opendir("ssh2.sftp://$sftp/YourDirHere/”);

$files = array();

while (false != ($entry = readdir($handle))){
    $files[] = $entry;
}

var_dump($files);
 [2015-07-03 00:56 UTC] info at josephcrawford dot com
Here is some output of what I get when I use the base directory that only has a few files in the directory.  Again the images folder has 29,516 images and the directory structure and server management are not under my control.

jcrawford@Josephs-Mac-mini:~/TraderTools (dev *%) # php sftp_test.php 
array(4) {
  [0]=>
  string(14) "CatInfoJSC.zip"
  [1]=>
  string(16) "ItemAvailJSC.zip"
  [2]=>
  string(15) "METADataJSC.txt"
  [3]=>
  string(6) "Images"
}
 [2015-11-06 16:50 UTC] ken at pardiac dot com
This bug was introduced as a by-product of bug # 59794.  I have re-written the fix for that bug in the pecl ssh2-0.12 package source.  Here is my patch to the ssh2_fopen_wrappers.c module.  This fix re-constructs the filename from the path, query and fragment components after the URL is parsed.  The problem was that if the path component matched any previous part of the URL string which is the case when just a "/" is the path.  It matches the first "/" in the URL. Chaos ensues.  Perhaps one of the developers can take a look at this.

Ken Pardiac

--- ssh2_fopen_wrappers.c       2012-10-02 16:18:07.000000000 -0400
+++ ssh2_fopen_wrappers.c       2015-11-06 11:20:40.436490279 -0500
@@ -219,12 +219,29 @@
        }

        /*
-               Find resource->path in the path string, then copy the entire string from the original path.
-               This includes ?query#fragment in the path string
+               Put path, query and fragment from the url back together to get a filename
+               that may have contained ? or #.
        */
-       s = resource->path;
-       resource->path = estrdup(strstr(path, resource->path));
-       efree(s);
+       if ( resource->query || resource->fragment ) {
+               char *p;
+               int len = strlen(resource->path) + 1;
+               if ( resource->query )
+                       len +=  strlen(resource->query) + 1;
+               if ( resource->fragment )
+                       len += strlen(resource->fragment) + 1;
+               p = emalloc( len );
+               strcpy( p, resource->path );
+               if ( resource->query ) {
+                       strcat( p, "?" );
+                       strcat( p, resource->query );
+               }
+               if ( resource->fragment ) {
+                       strcat( p, "#" );
+                       strcat( p, resource->fragment );
+               }
+               efree( resource->path );
+               resource->path = p;
+       }

        /* Look for a resource ID to reuse a session */
        s = resource->host;
 [2017-02-13 10:38 UTC] bartosz at idct dot pl
The problem occurs when using resource in the ssh2.sftp stream. When using full path with credentials and host seems to work.

Made a dirty patch for `idct/sftp-client` as a workaround:
https://github.com/ideaconnect/idct-sftp-client/commits/master
 [2017-03-13 02:08 UTC] fernando_pacheco at outlook dot com
I had the same issue after update my php. 

Try to use intval() function:

$handle = opendir("ssh2.sftp://".intval($sftp)."/path/to/directory");
 [2017-08-22 11:35 UTC] ky at werk21 dot de
FYI: This bug occurs in Ubuntu 14.04 with PHP 5.5 since Update from 2017-08-04.
See: http://changelogs.ubuntu.com/changelogs/pool/main/p/php5/php5_5.5.9+dfsg-1ubuntu4.22/changelog
So this may be a problem with the backported url-check in url.c, see
http://launchpadlibrarian.net/331960286/php5_5.5.9+dfsg-1ubuntu4.21_5.5.9+dfsg-1ubuntu4.22.diff.gz

So with Ubuntu 14.04 you have to use the solution from fernando_pacheco:
$handle = opendir("ssh2.sftp://".intval($sftp)."/path/to/directory");

good luck.
 [2019-03-20 16:14 UTC] ken at pardiac dot com
I will try to explain this bug further since my patch from 2015 has not been incorporated into the source.

Here is a line of code from ssh2_fopen_wrappers.c that causes this bug: (comment included)

/*
       Find resource->path in the path string, then copy the entire string from the original path.
       This includes ?query#fragment in the path string
*/
    resource->path = estrdup(strstr(path, resource->path));

This line of code -- and therefore this bug -- was introduced as a fix for bug #59794. That line of code is attempting to get a string containing the part, query and fragment from the path variable.
Consider this value for the path variable:

    ssh2.sftp://Resource id #5/topdir?a=something#heading1

When resource->path is "/topdir", the result is that "/topdir?a=something#heading1" gets assigned to resource->path. The intent is that resource->path gets a string which includes the query and fragment part of the url.

Now consider the case when resource->path is "/". After the line of code is executed, resource->path becomes "//Resource id#5/topdir#heading1". This is clearly not what you want.

A better solution is to build up the path by using resource->path, resource->query and resource->fragment. (The resource struct is returned by php_url_parse) That is what the patch I posted years ago does. It *fixes* the bug. It does not just provide a workaround.

You may also need to apply the patch for bug #73597 which removes "Resource id #" from the path string before calling php_url_parse().
 [2019-03-20 20:10 UTC] ken at pardiac dot com
I have added a better patch to fix this issue that will work with pathnames containing '#' and '?'. Building up the original path from the resource struct was not a good idea as it's not possible because there may be multiple '#' or '?' characters. The ssh2_getpath patch uses a more general scan to find the pathname part of the url. Here's the significant difference:

-       resource->path = estrdup(strstr(path, resource->path));
+       resource->path = estrdup( strstr( strstr( path, "//" ) + 2, "/" ) );
 [2021-02-10 16:02 UTC] cmb@php.net
-Status: Open +Status: Feedback -Assigned To: +Assigned To: cmb
 [2021-02-10 16:02 UTC] cmb@php.net
@ken, the 'Resource id #' is stripped out as of ssh2 1.1, so I
don't see why this would be an issue in 2019.
 [2021-02-21 04:22 UTC] pecl-dev at lists dot php dot net
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Re-Opened". Thank you.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 17:01:32 2024 UTC