Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What methods make it possible to access the source code?

There are several ways to access the source code of a library from within a Ruby code that require/loads that library. Among these ways, some read the library file directly and parse it. Others access the source through some built in methods that provide information about the source (such as the abstract syntax tree). In a situation where I have no access to directly read the content of the file (as in the former ways), the only way to access the source would be through accessing the built-in methods that provide the information. By redefining these methods to do something else, I will completely loose access to the source code. What are the minimum set of methods such that if I redefine them to something else, I will completely loose access to the source code of the library on an external file?


To rephrase the question

Suppose:

  • There is a user that can write any Ruby code in file A.
  • There is a static Ruby file B written by me, which loads file A and calls the main routine defined in A, and also defines some classes/methods that the user can use in A.
  • The user does not have +r (read) or +w (write) permission to B.

Which (standard Ruby) methods do I have to redefine (nullify) or remove by writing so in file B in order to make it impossible for the user to access the source written in file B (via whatever code the user can write in file A) when I run file B?

There are some libraries like sorcerer, pry, that can extract the source code of the methods it has access to. There must be some primitive commands within plain Ruby that these libraries rely upon to make it possible for them to access the source code. What are the methods that make this kind of things possible?

If you don't know the full answer but know how a particular library extracts the source of some method, then that will still help.

like image 522
sawa Avatar asked Apr 14 '13 18:04

sawa


1 Answers

TL;DR: Ruby-only solutions can only use source_location, so just redefine this to return something like ['/some/empty/file', 1]. C hacks to the interpreter don't use source_location, but you can prevent any use of C extensions by blocking/white-listing require and friends.


For one, to be able to execute a Ruby script, you have to be able to read it...

But back to the question. I know Sourcify doesn't use any mystical method besides a little method on Proc and Method called source_location, which gives the filename and line number were a method/proc is defined. I know from experience that this approach is very fragile, requires writing some sort of parser, and only sometimes works in legitimate situations. So, Sourcify is already out if you redefine source_location in B to return something like /dev/null, line 0 and let Sourcify throw a not-Ruby-source exception.

From Pry's source, it seems that Pry uses the same source_location approach, so two birds with one stone.

Now, there is another option for all of these libraries, which is to drop down to C and hack the interpreter to record source code. This is almost flawless. But we can still avoid the danger in one very simple way. Someone could include all of the code for Pry's method source in A. But you can't include inline C/C extensions without requiring a C library. So, the solution is obvious: Redefine require and require_relative and load to either not work, or to only allow certain libraries. This way, you can keep out the C hacks.

On MRI, there is no way (from Ruby code) besides source_location to do this. So there you go!

Edit: According to @banister, from MRI 2.0+ there is a binding_of_caller method builtin that could replace source location. Nuke this too. ;)

Warning: Ruby is not a good language for this. If you can metaprogram them, they can probably metaprogram you unless you're in a different process.

like image 69
Linuxios Avatar answered Oct 09 '22 19:10

Linuxios