ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:67766] [ruby-trunk - Bug #10776] [Open] Ruby Chooses Incorrect Load Path For rubygems.rb
       [not found] <redmine.issue-10776.20150123183830@ruby-lang.org>
@ 2015-01-23 18:38 ` alex
  2015-01-24  3:02 ` [ruby-core:67779] [ruby-trunk - Bug #10776] [Feedback] " nobu
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: alex @ 2015-01-23 18:38 UTC (permalink / raw
  To: ruby-core

Issue #10776 has been reported by Alex Coomans.

----------------------------------------
Bug #10776: Ruby Chooses Incorrect Load Path For rubygems.rb
https://bugs.ruby-lang.org/issues/10776

* Author: Alex Coomans
* Status: Open
* Priority: Normal
* Assignee: 
* ruby -v: 2.0.0p598
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
### Problem

I believe this problem affects version 1.9.3 and up based on a git blame, but I haven't actually checked them.

The following conditions need to all be met:

1. Ruby must be compiled without `--enable-shared` 
2. argv[0] to ruby must simply be `ruby`

And either one of the following need to be met:

1. Your PATH path must include a directory that has a directory named ruby before where ruby is located
2. The ruby binary is located in a directory named ruby (or any set of subdirectories). Eg: `/test/ruby/bin/ruby`

When you then try and execute ruby, it detects the wrong ruby install directory and fails to correctly load `rubygems.rb` - an example strace:

~~~
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(2, "<internal:gem_prelude>:1:in `req"..., 37<internal:gem_prelude>:1:in `require') = 37
write(2, ": ", 2: )                       = 2
write(2, "cannot load such file -- rubygem"..., 36cannot load such file -- rubygems.rb) = 36
~~~

(Notice it is looking in `/home/vagrant/compiled/lib` instead of `/home/vagrant/compiled/ruby/lib`)

### Reproduction

~~~
$ LDFLAGS='-Wl,-rpath=\$$ORIGIN/../lib' ./configure --with-out-ext=tk --with-out-ext=tcl --disable-pthread --enable-load-relative --disable-install-doc --prefix=/home/vagrant/compiled/ruby
$ make
$ make test
$ make install

$ cd /home/vagrant/compiled
$ PATH=":/home/vagrant/appinstall/ruby/bin" ruby
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'
~~~

FYI this bug cannot be reproduced through GDB by looking directly at `/home/vagrant/appinstall/ruby/bin/ruby` because GDB forces `argv[0]` to be the full path. You'll need to either patch GDB or use the C program in the `Ongoing Problem` section to use GDB to debug.

### Patch

The following patch fixes the 99% case:

~~~
diff --git a/dln_find.c b/dln_find.c
index 56a1981..74beddd 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -278,11 +278,10 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
        }
 #endif /* _WIN32 or __EMX__ */

-       if (stat(fbuf, &st) == 0) {
+       if (stat(fbuf, &st) == 0 && !S_ISDIR(st.st_mode)) {
            if (exe_flag == 0) return fbuf;
            /* looking for executable */
-           if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
-               return fbuf;
+           if (eaccess(fbuf, X_OK) == 0) return fbuf;
        }
       next:
        /* if not, and no other alternatives, life is bleak */
~~~

How? `dln_find_file_r` is called by `ruby_init_loadpath_safe` to locate where the ruby binary itself is located. However `dln_find_file_r` calls `dln_find_1` which in turn can return a directory. This patch changes `dln_find_1` to only ever return a file. I couldn't find a case of `dln_find_file_r` being expected to return a directory.

### Ongoing Problem

As I mentioned, the patch only fixes the 99% case - the code inherently is broken by relying on path. Take for example this C program:

~~~
#include <unistd.h>

int main() {
  char *const argv[] = {"ruby", NULL};

  execve("/home/vagrant/compiled/ruby/bin/ruby", argv, NULL);
  return 0; // not reached
}
~~~

Compile and run it inside of `/home/vagrant/compiled` to reproduce. 

It would probably be better to look at `/proc/self/exe` when possible, but that would be more of a serious change




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [ruby-core:67779] [ruby-trunk - Bug #10776] [Feedback] Ruby Chooses Incorrect Load Path For rubygems.rb
       [not found] <redmine.issue-10776.20150123183830@ruby-lang.org>
  2015-01-23 18:38 ` [ruby-core:67766] [ruby-trunk - Bug #10776] [Open] Ruby Chooses Incorrect Load Path For rubygems.rb alex
@ 2015-01-24  3:02 ` nobu
  2015-01-24  3:26 ` [ruby-core:67780] [ruby-trunk - Bug #10776] [Assigned] " nobu
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: nobu @ 2015-01-24  3:02 UTC (permalink / raw
  To: ruby-core

Issue #10776 has been updated by Nobuyoshi Nakada.

Status changed from Open to Feedback

Alex Coomans wrote:
> The following conditions need to all be met:
> 
> 1. Ruby must be compiled without `--enable-shared` 
> 2. argv[0] to ruby must simply be `ruby`
> 
> And either one of the following need to be met:
> 
> 1. Your PATH path must include a directory that has a directory named ruby before where ruby is located
> 2. The ruby binary is located in a directory named ruby (or any set of subdirectories). Eg: `/test/ruby/bin/ruby`
> 
> When you then try and execute ruby, it detects the wrong ruby install directory and fails to correctly load `rubygems.rb` - an example strace:

I can't reproduce it with the latest 2.2
$ ls ~/ruby
2.2.0
$ (PATH=$HOME exec -a ruby ./ruby/2.2.0/bin/ruby -ve 'p RbConfig::CONFIG["configure_args"]')
ruby 2.2.0p36 (2015-01-22 revision 49375) [x86_64-linux]
" '-C' '--enable-shared' '--enable-load-relative' '--prefix=/' '--with-destdir=$(HOME)/ruby/$(RUBY_PROGRAM_VERSION)' '--disable-install-doc' '--without-ext=*win32*'"


----------------------------------------
Bug #10776: Ruby Chooses Incorrect Load Path For rubygems.rb
https://bugs.ruby-lang.org/issues/10776#change-51196

* Author: Alex Coomans
* Status: Feedback
* Priority: Normal
* Assignee: 
* ruby -v: 2.0.0p598
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
### Problem

I believe this problem affects version 1.9.3 and up based on a git blame, but I haven't actually checked them.

The following conditions need to all be met:

1. Ruby must be compiled without `--enable-shared` 
2. argv[0] to ruby must simply be `ruby`

And either one of the following need to be met:

1. Your PATH path must include a directory that has a directory named ruby before where ruby is located
2. The ruby binary is located in a directory named ruby (or any set of subdirectories). Eg: `/test/ruby/bin/ruby`

When you then try and execute ruby, it detects the wrong ruby install directory and fails to correctly load `rubygems.rb` - an example strace:

~~~
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(2, "<internal:gem_prelude>:1:in `req"..., 37<internal:gem_prelude>:1:in `require') = 37
write(2, ": ", 2: )                       = 2
write(2, "cannot load such file -- rubygem"..., 36cannot load such file -- rubygems.rb) = 36
~~~

(Notice it is looking in `/home/vagrant/compiled/lib` instead of `/home/vagrant/compiled/ruby/lib`)

### Reproduction

~~~
$ LDFLAGS='-Wl,-rpath=\$$ORIGIN/../lib' ./configure --with-out-ext=tk --with-out-ext=tcl --disable-pthread --enable-load-relative --disable-install-doc --prefix=/home/vagrant/compiled/ruby
$ make
$ make test
$ make install

$ cd /home/vagrant/compiled
$ PATH=":/home/vagrant/appinstall/ruby/bin" ruby
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'
~~~

FYI this bug cannot be reproduced through GDB by looking directly at `/home/vagrant/appinstall/ruby/bin/ruby` because GDB forces `argv[0]` to be the full path. You'll need to either patch GDB or use the C program in the `Ongoing Problem` section to use GDB to debug.

### Patch

The following patch fixes the 99% case:

~~~
diff --git a/dln_find.c b/dln_find.c
index 56a1981..74beddd 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -278,11 +278,10 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
        }
 #endif /* _WIN32 or __EMX__ */

-       if (stat(fbuf, &st) == 0) {
+       if (stat(fbuf, &st) == 0 && !S_ISDIR(st.st_mode)) {
            if (exe_flag == 0) return fbuf;
            /* looking for executable */
-           if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
-               return fbuf;
+           if (eaccess(fbuf, X_OK) == 0) return fbuf;
        }
       next:
        /* if not, and no other alternatives, life is bleak */
~~~

How? `dln_find_file_r` is called by `ruby_init_loadpath_safe` to locate where the ruby binary itself is located. However `dln_find_file_r` calls `dln_find_1` which in turn can return a directory. This patch changes `dln_find_1` to only ever return a file. I couldn't find a case of `dln_find_file_r` being expected to return a directory.

### Ongoing Problem

As I mentioned, the patch only fixes the 99% case - the code inherently is broken by relying on path. Take for example this C program:

~~~
#include <unistd.h>

int main() {
  char *const argv[] = {"ruby", NULL};

  execve("/home/vagrant/compiled/ruby/bin/ruby", argv, NULL);
  return 0; // not reached
}
~~~

Compile and run it inside of `/home/vagrant/compiled` to reproduce. 

It would probably be better to look at `/proc/self/exe` when possible, but that would be more of a serious change




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [ruby-core:67780] [ruby-trunk - Bug #10776] [Assigned] Ruby Chooses Incorrect Load Path For rubygems.rb
       [not found] <redmine.issue-10776.20150123183830@ruby-lang.org>
  2015-01-23 18:38 ` [ruby-core:67766] [ruby-trunk - Bug #10776] [Open] Ruby Chooses Incorrect Load Path For rubygems.rb alex
  2015-01-24  3:02 ` [ruby-core:67779] [ruby-trunk - Bug #10776] [Feedback] " nobu
@ 2015-01-24  3:26 ` nobu
  2015-01-24  8:40 ` [ruby-core:67787] [ruby-trunk - Bug #10776] [Feedback] " nobu
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: nobu @ 2015-01-24  3:26 UTC (permalink / raw
  To: ruby-core

Issue #10776 has been updated by Nobuyoshi Nakada.

Status changed from Feedback to Assigned
Assignee set to Usaku NAKAMURA
Backport changed from 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN to 2.0.0: REQUIRED, 2.1: DONTNEED, 2.2: DONTNEED

It could reproduced only with 2.0, but not 2.1 or later.

~~~
$ (PATH=$HOME exec -a ruby ./ruby/2.0.0/bin/ruby -ve 'p RbConfig::CONFIG["configure_args"]')
ruby 2.0.0p617 (2015-01-22 revision 49382) [x86_64-linux]
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'
~~~

----------------------------------------
Bug #10776: Ruby Chooses Incorrect Load Path For rubygems.rb
https://bugs.ruby-lang.org/issues/10776#change-51197

* Author: Alex Coomans
* Status: Assigned
* Priority: Normal
* Assignee: Usaku NAKAMURA
* ruby -v: 2.0.0p598
* Backport: 2.0.0: REQUIRED, 2.1: DONTNEED, 2.2: DONTNEED
----------------------------------------
### Problem

I believe this problem affects version 1.9.3 and up based on a git blame, but I haven't actually checked them.

The following conditions need to all be met:

1. Ruby must be compiled without `--enable-shared` 
2. argv[0] to ruby must simply be `ruby`

And either one of the following need to be met:

1. Your PATH path must include a directory that has a directory named ruby before where ruby is located
2. The ruby binary is located in a directory named ruby (or any set of subdirectories). Eg: `/test/ruby/bin/ruby`

When you then try and execute ruby, it detects the wrong ruby install directory and fails to correctly load `rubygems.rb` - an example strace:

~~~
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(2, "<internal:gem_prelude>:1:in `req"..., 37<internal:gem_prelude>:1:in `require') = 37
write(2, ": ", 2: )                       = 2
write(2, "cannot load such file -- rubygem"..., 36cannot load such file -- rubygems.rb) = 36
~~~

(Notice it is looking in `/home/vagrant/compiled/lib` instead of `/home/vagrant/compiled/ruby/lib`)

### Reproduction

~~~
$ LDFLAGS='-Wl,-rpath=\$$ORIGIN/../lib' ./configure --with-out-ext=tk --with-out-ext=tcl --disable-pthread --enable-load-relative --disable-install-doc --prefix=/home/vagrant/compiled/ruby
$ make
$ make test
$ make install

$ cd /home/vagrant/compiled
$ PATH=":/home/vagrant/appinstall/ruby/bin" ruby
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'
~~~

FYI this bug cannot be reproduced through GDB by looking directly at `/home/vagrant/appinstall/ruby/bin/ruby` because GDB forces `argv[0]` to be the full path. You'll need to either patch GDB or use the C program in the `Ongoing Problem` section to use GDB to debug.

### Patch

The following patch fixes the 99% case:

~~~
diff --git a/dln_find.c b/dln_find.c
index 56a1981..74beddd 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -278,11 +278,10 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
        }
 #endif /* _WIN32 or __EMX__ */

-       if (stat(fbuf, &st) == 0) {
+       if (stat(fbuf, &st) == 0 && !S_ISDIR(st.st_mode)) {
            if (exe_flag == 0) return fbuf;
            /* looking for executable */
-           if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
-               return fbuf;
+           if (eaccess(fbuf, X_OK) == 0) return fbuf;
        }
       next:
        /* if not, and no other alternatives, life is bleak */
~~~

How? `dln_find_file_r` is called by `ruby_init_loadpath_safe` to locate where the ruby binary itself is located. However `dln_find_file_r` calls `dln_find_1` which in turn can return a directory. This patch changes `dln_find_1` to only ever return a file. I couldn't find a case of `dln_find_file_r` being expected to return a directory.

### Ongoing Problem

As I mentioned, the patch only fixes the 99% case - the code inherently is broken by relying on path. Take for example this C program:

~~~
#include <unistd.h>

int main() {
  char *const argv[] = {"ruby", NULL};

  execve("/home/vagrant/compiled/ruby/bin/ruby", argv, NULL);
  return 0; // not reached
}
~~~

Compile and run it inside of `/home/vagrant/compiled` to reproduce. 

It would probably be better to look at `/proc/self/exe` when possible, but that would be more of a serious change




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [ruby-core:67787] [ruby-trunk - Bug #10776] [Feedback] Ruby Chooses Incorrect Load Path For rubygems.rb
       [not found] <redmine.issue-10776.20150123183830@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2015-01-24  3:26 ` [ruby-core:67780] [ruby-trunk - Bug #10776] [Assigned] " nobu
@ 2015-01-24  8:40 ` nobu
  2015-01-24  8:50 ` [ruby-core:67788] [ruby-trunk - Bug #10776] " nobu
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: nobu @ 2015-01-24  8:40 UTC (permalink / raw
  To: ruby-core

Issue #10776 has been updated by Nobuyoshi Nakada.

Status changed from Assigned to Feedback
Assignee deleted (Usaku NAKAMURA)
Priority changed from Normal to Low
Backport changed from 2.0.0: REQUIRED, 2.1: DONTNEED, 2.2: DONTNEED to 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN

Sorry, it was my configuration miss, `--prefix=/` doesn't work for 2.0 and should be `--prefix=/.`.
So I can't reproduce it totally.

----------------------------------------
Bug #10776: Ruby Chooses Incorrect Load Path For rubygems.rb
https://bugs.ruby-lang.org/issues/10776#change-51199

* Author: Alex Coomans
* Status: Feedback
* Priority: Low
* Assignee: 
* ruby -v: 2.0.0p598
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
### Problem

I believe this problem affects version 1.9.3 and up based on a git blame, but I haven't actually checked them.

The following conditions need to all be met:

1. Ruby must be compiled without `--enable-shared` 
2. argv[0] to ruby must simply be `ruby`

And either one of the following need to be met:

1. Your PATH path must include a directory that has a directory named ruby before where ruby is located
2. The ruby binary is located in a directory named ruby (or any set of subdirectories). Eg: `/test/ruby/bin/ruby`

When you then try and execute ruby, it detects the wrong ruby install directory and fails to correctly load `rubygems.rb` - an example strace:

~~~
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(2, "<internal:gem_prelude>:1:in `req"..., 37<internal:gem_prelude>:1:in `require') = 37
write(2, ": ", 2: )                       = 2
write(2, "cannot load such file -- rubygem"..., 36cannot load such file -- rubygems.rb) = 36
~~~

(Notice it is looking in `/home/vagrant/compiled/lib` instead of `/home/vagrant/compiled/ruby/lib`)

### Reproduction

~~~
$ LDFLAGS='-Wl,-rpath=\$$ORIGIN/../lib' ./configure --with-out-ext=tk --with-out-ext=tcl --disable-pthread --enable-load-relative --disable-install-doc --prefix=/home/vagrant/compiled/ruby
$ make
$ make test
$ make install

$ cd /home/vagrant/compiled
$ PATH=":/home/vagrant/appinstall/ruby/bin" ruby
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'
~~~

FYI this bug cannot be reproduced through GDB by looking directly at `/home/vagrant/appinstall/ruby/bin/ruby` because GDB forces `argv[0]` to be the full path. You'll need to either patch GDB or use the C program in the `Ongoing Problem` section to use GDB to debug.

### Patch

The following patch fixes the 99% case:

~~~
diff --git a/dln_find.c b/dln_find.c
index 56a1981..74beddd 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -278,11 +278,10 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
        }
 #endif /* _WIN32 or __EMX__ */

-       if (stat(fbuf, &st) == 0) {
+       if (stat(fbuf, &st) == 0 && !S_ISDIR(st.st_mode)) {
            if (exe_flag == 0) return fbuf;
            /* looking for executable */
-           if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
-               return fbuf;
+           if (eaccess(fbuf, X_OK) == 0) return fbuf;
        }
       next:
        /* if not, and no other alternatives, life is bleak */
~~~

How? `dln_find_file_r` is called by `ruby_init_loadpath_safe` to locate where the ruby binary itself is located. However `dln_find_file_r` calls `dln_find_1` which in turn can return a directory. This patch changes `dln_find_1` to only ever return a file. I couldn't find a case of `dln_find_file_r` being expected to return a directory.

### Ongoing Problem

As I mentioned, the patch only fixes the 99% case - the code inherently is broken by relying on path. Take for example this C program:

~~~
#include <unistd.h>

int main() {
  char *const argv[] = {"ruby", NULL};

  execve("/home/vagrant/compiled/ruby/bin/ruby", argv, NULL);
  return 0; // not reached
}
~~~

Compile and run it inside of `/home/vagrant/compiled` to reproduce. 

It would probably be better to look at `/proc/self/exe` when possible, but that would be more of a serious change




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [ruby-core:67788] [ruby-trunk - Bug #10776] Ruby Chooses Incorrect Load Path For rubygems.rb
       [not found] <redmine.issue-10776.20150123183830@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2015-01-24  8:40 ` [ruby-core:67787] [ruby-trunk - Bug #10776] [Feedback] " nobu
@ 2015-01-24  8:50 ` nobu
  2015-01-24 10:48 ` [ruby-core:67790] " nobu
  2015-01-26 18:00 ` [ruby-core:67817] " alex
  6 siblings, 0 replies; 7+ messages in thread
From: nobu @ 2015-01-24  8:50 UTC (permalink / raw
  To: ruby-core

Issue #10776 has been updated by Nobuyoshi Nakada.


It seems a very platform (OS, libc) dependent issue.

What's your OS, kernel version, and libc version?

----------------------------------------
Bug #10776: Ruby Chooses Incorrect Load Path For rubygems.rb
https://bugs.ruby-lang.org/issues/10776#change-51200

* Author: Alex Coomans
* Status: Feedback
* Priority: Low
* Assignee: 
* ruby -v: 2.0.0p598
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
### Problem

I believe this problem affects version 1.9.3 and up based on a git blame, but I haven't actually checked them.

The following conditions need to all be met:

1. Ruby must be compiled without `--enable-shared` 
2. argv[0] to ruby must simply be `ruby`

And either one of the following need to be met:

1. Your PATH path must include a directory that has a directory named ruby before where ruby is located
2. The ruby binary is located in a directory named ruby (or any set of subdirectories). Eg: `/test/ruby/bin/ruby`

When you then try and execute ruby, it detects the wrong ruby install directory and fails to correctly load `rubygems.rb` - an example strace:

~~~
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(2, "<internal:gem_prelude>:1:in `req"..., 37<internal:gem_prelude>:1:in `require') = 37
write(2, ": ", 2: )                       = 2
write(2, "cannot load such file -- rubygem"..., 36cannot load such file -- rubygems.rb) = 36
~~~

(Notice it is looking in `/home/vagrant/compiled/lib` instead of `/home/vagrant/compiled/ruby/lib`)

### Reproduction

~~~
$ LDFLAGS='-Wl,-rpath=\$$ORIGIN/../lib' ./configure --with-out-ext=tk --with-out-ext=tcl --disable-pthread --enable-load-relative --disable-install-doc --prefix=/home/vagrant/compiled/ruby
$ make
$ make test
$ make install

$ cd /home/vagrant/compiled
$ PATH=":/home/vagrant/appinstall/ruby/bin" ruby
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'
~~~

FYI this bug cannot be reproduced through GDB by looking directly at `/home/vagrant/appinstall/ruby/bin/ruby` because GDB forces `argv[0]` to be the full path. You'll need to either patch GDB or use the C program in the `Ongoing Problem` section to use GDB to debug.

### Patch

The following patch fixes the 99% case:

~~~
diff --git a/dln_find.c b/dln_find.c
index 56a1981..74beddd 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -278,11 +278,10 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
        }
 #endif /* _WIN32 or __EMX__ */

-       if (stat(fbuf, &st) == 0) {
+       if (stat(fbuf, &st) == 0 && !S_ISDIR(st.st_mode)) {
            if (exe_flag == 0) return fbuf;
            /* looking for executable */
-           if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
-               return fbuf;
+           if (eaccess(fbuf, X_OK) == 0) return fbuf;
        }
       next:
        /* if not, and no other alternatives, life is bleak */
~~~

How? `dln_find_file_r` is called by `ruby_init_loadpath_safe` to locate where the ruby binary itself is located. However `dln_find_file_r` calls `dln_find_1` which in turn can return a directory. This patch changes `dln_find_1` to only ever return a file. I couldn't find a case of `dln_find_file_r` being expected to return a directory.

### Ongoing Problem

As I mentioned, the patch only fixes the 99% case - the code inherently is broken by relying on path. Take for example this C program:

~~~
#include <unistd.h>

int main() {
  char *const argv[] = {"ruby", NULL};

  execve("/home/vagrant/compiled/ruby/bin/ruby", argv, NULL);
  return 0; // not reached
}
~~~

Compile and run it inside of `/home/vagrant/compiled` to reproduce. 

It would probably be better to look at `/proc/self/exe` when possible, but that would be more of a serious change




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [ruby-core:67790] [ruby-trunk - Bug #10776] Ruby Chooses Incorrect Load Path For rubygems.rb
       [not found] <redmine.issue-10776.20150123183830@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2015-01-24  8:50 ` [ruby-core:67788] [ruby-trunk - Bug #10776] " nobu
@ 2015-01-24 10:48 ` nobu
  2015-01-26 18:00 ` [ruby-core:67817] " alex
  6 siblings, 0 replies; 7+ messages in thread
From: nobu @ 2015-01-24 10:48 UTC (permalink / raw
  To: ruby-core

Issue #10776 has been updated by Nobuyoshi Nakada.


Alex Coomans wrote:
> 1. Ruby must be compiled without `--enable-shared` 

Sorry, I misread this "without" as "with".


----------------------------------------
Bug #10776: Ruby Chooses Incorrect Load Path For rubygems.rb
https://bugs.ruby-lang.org/issues/10776#change-51201

* Author: Alex Coomans
* Status: Feedback
* Priority: Low
* Assignee: 
* ruby -v: 2.0.0p598
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
### Problem

I believe this problem affects version 1.9.3 and up based on a git blame, but I haven't actually checked them.

The following conditions need to all be met:

1. Ruby must be compiled without `--enable-shared` 
2. argv[0] to ruby must simply be `ruby`

And either one of the following need to be met:

1. Your PATH path must include a directory that has a directory named ruby before where ruby is located
2. The ruby binary is located in a directory named ruby (or any set of subdirectories). Eg: `/test/ruby/bin/ruby`

When you then try and execute ruby, it detects the wrong ruby install directory and fails to correctly load `rubygems.rb` - an example strace:

~~~
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(2, "<internal:gem_prelude>:1:in `req"..., 37<internal:gem_prelude>:1:in `require') = 37
write(2, ": ", 2: )                       = 2
write(2, "cannot load such file -- rubygem"..., 36cannot load such file -- rubygems.rb) = 36
~~~

(Notice it is looking in `/home/vagrant/compiled/lib` instead of `/home/vagrant/compiled/ruby/lib`)

### Reproduction

~~~
$ LDFLAGS='-Wl,-rpath=\$$ORIGIN/../lib' ./configure --with-out-ext=tk --with-out-ext=tcl --disable-pthread --enable-load-relative --disable-install-doc --prefix=/home/vagrant/compiled/ruby
$ make
$ make test
$ make install

$ cd /home/vagrant/compiled
$ PATH=":/home/vagrant/appinstall/ruby/bin" ruby
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'
~~~

FYI this bug cannot be reproduced through GDB by looking directly at `/home/vagrant/appinstall/ruby/bin/ruby` because GDB forces `argv[0]` to be the full path. You'll need to either patch GDB or use the C program in the `Ongoing Problem` section to use GDB to debug.

### Patch

The following patch fixes the 99% case:

~~~
diff --git a/dln_find.c b/dln_find.c
index 56a1981..74beddd 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -278,11 +278,10 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
        }
 #endif /* _WIN32 or __EMX__ */

-       if (stat(fbuf, &st) == 0) {
+       if (stat(fbuf, &st) == 0 && !S_ISDIR(st.st_mode)) {
            if (exe_flag == 0) return fbuf;
            /* looking for executable */
-           if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
-               return fbuf;
+           if (eaccess(fbuf, X_OK) == 0) return fbuf;
        }
       next:
        /* if not, and no other alternatives, life is bleak */
~~~

How? `dln_find_file_r` is called by `ruby_init_loadpath_safe` to locate where the ruby binary itself is located. However `dln_find_file_r` calls `dln_find_1` which in turn can return a directory. This patch changes `dln_find_1` to only ever return a file. I couldn't find a case of `dln_find_file_r` being expected to return a directory.

### Ongoing Problem

As I mentioned, the patch only fixes the 99% case - the code inherently is broken by relying on path. Take for example this C program:

~~~
#include <unistd.h>

int main() {
  char *const argv[] = {"ruby", NULL};

  execve("/home/vagrant/compiled/ruby/bin/ruby", argv, NULL);
  return 0; // not reached
}
~~~

Compile and run it inside of `/home/vagrant/compiled` to reproduce. 

It would probably be better to look at `/proc/self/exe` when possible, but that would be more of a serious change




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [ruby-core:67817] [ruby-trunk - Bug #10776] Ruby Chooses Incorrect Load Path For rubygems.rb
       [not found] <redmine.issue-10776.20150123183830@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2015-01-24 10:48 ` [ruby-core:67790] " nobu
@ 2015-01-26 18:00 ` alex
  6 siblings, 0 replies; 7+ messages in thread
From: alex @ 2015-01-26 18:00 UTC (permalink / raw
  To: ruby-core

Issue #10776 has been updated by Alex Coomans.


Awesome, thank you for looking at this so quickly!

----------------------------------------
Bug #10776: Ruby Chooses Incorrect Load Path For rubygems.rb
https://bugs.ruby-lang.org/issues/10776#change-51225

* Author: Alex Coomans
* Status: Closed
* Priority: Low
* Assignee: 
* ruby -v: 2.0.0p598
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
### Problem

I believe this problem affects version 1.9.3 and up based on a git blame, but I haven't actually checked them.

The following conditions need to all be met:

1. Ruby must be compiled without `--enable-shared` 
2. argv[0] to ruby must simply be `ruby`

And either one of the following need to be met:

1. Your PATH path must include a directory that has a directory named ruby before where ruby is located
2. The ruby binary is located in a directory named ruby (or any set of subdirectories). Eg: `/test/ruby/bin/ruby`

When you then try and execute ruby, it detects the wrong ruby install directory and fails to correctly load `rubygems.rb` - an example strace:

~~~
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/site_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/vendor_ruby/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/vagrant/compiled/lib/ruby/2.0.0/x86_64-linux/rubygems.rb", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(2, "<internal:gem_prelude>:1:in `req"..., 37<internal:gem_prelude>:1:in `require') = 37
write(2, ": ", 2: )                       = 2
write(2, "cannot load such file -- rubygem"..., 36cannot load such file -- rubygems.rb) = 36
~~~

(Notice it is looking in `/home/vagrant/compiled/lib` instead of `/home/vagrant/compiled/ruby/lib`)

### Reproduction

~~~
$ LDFLAGS='-Wl,-rpath=\$$ORIGIN/../lib' ./configure --with-out-ext=tk --with-out-ext=tcl --disable-pthread --enable-load-relative --disable-install-doc --prefix=/home/vagrant/compiled/ruby
$ make
$ make test
$ make install

$ cd /home/vagrant/compiled
$ PATH=":/home/vagrant/appinstall/ruby/bin" ruby
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'
~~~

FYI this bug cannot be reproduced through GDB by looking directly at `/home/vagrant/appinstall/ruby/bin/ruby` because GDB forces `argv[0]` to be the full path. You'll need to either patch GDB or use the C program in the `Ongoing Problem` section to use GDB to debug.

### Patch

The following patch fixes the 99% case:

~~~
diff --git a/dln_find.c b/dln_find.c
index 56a1981..74beddd 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -278,11 +278,10 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
        }
 #endif /* _WIN32 or __EMX__ */

-       if (stat(fbuf, &st) == 0) {
+       if (stat(fbuf, &st) == 0 && !S_ISDIR(st.st_mode)) {
            if (exe_flag == 0) return fbuf;
            /* looking for executable */
-           if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
-               return fbuf;
+           if (eaccess(fbuf, X_OK) == 0) return fbuf;
        }
       next:
        /* if not, and no other alternatives, life is bleak */
~~~

How? `dln_find_file_r` is called by `ruby_init_loadpath_safe` to locate where the ruby binary itself is located. However `dln_find_file_r` calls `dln_find_1` which in turn can return a directory. This patch changes `dln_find_1` to only ever return a file. I couldn't find a case of `dln_find_file_r` being expected to return a directory.

### Ongoing Problem

As I mentioned, the patch only fixes the 99% case - the code inherently is broken by relying on path. Take for example this C program:

~~~
#include <unistd.h>

int main() {
  char *const argv[] = {"ruby", NULL};

  execve("/home/vagrant/compiled/ruby/bin/ruby", argv, NULL);
  return 0; // not reached
}
~~~

Compile and run it inside of `/home/vagrant/compiled` to reproduce. 

It would probably be better to look at `/proc/self/exe` when possible, but that would be more of a serious change




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-01-26 18:02 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <redmine.issue-10776.20150123183830@ruby-lang.org>
2015-01-23 18:38 ` [ruby-core:67766] [ruby-trunk - Bug #10776] [Open] Ruby Chooses Incorrect Load Path For rubygems.rb alex
2015-01-24  3:02 ` [ruby-core:67779] [ruby-trunk - Bug #10776] [Feedback] " nobu
2015-01-24  3:26 ` [ruby-core:67780] [ruby-trunk - Bug #10776] [Assigned] " nobu
2015-01-24  8:40 ` [ruby-core:67787] [ruby-trunk - Bug #10776] [Feedback] " nobu
2015-01-24  8:50 ` [ruby-core:67788] [ruby-trunk - Bug #10776] " nobu
2015-01-24 10:48 ` [ruby-core:67790] " nobu
2015-01-26 18:00 ` [ruby-core:67817] " alex

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).