jeremyevans/sequel — Issue #385: Postgres adapter causes SecurityError
Author: efedel
Created: 2011-10-19 02:49:40+00:00
State: open

Attempting to connect to a PostgreSQL database with $SAFE=1 causes the following exception:

SecurityError: Insecure: can't intern tainted string
Backtrace:
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:324:in `to_sym'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:324:in `get_conversion_procs'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:323:in `times'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:323:in `get_conversion_procs'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:182:in `execute'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:322:in `get_conversion_procs'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:237:in `connect'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/database/misc.rb:45:in `initialize'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool.rb:92:in `call'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool.rb:92:in `make_new'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool/threaded.rb:126:in `make_new'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool/threaded.rb:112:in `available'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool/threaded.rb:102:in `acquire'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool/threaded.rb:146:in `sync'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool/threaded.rb:146:in `synchronize'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool/threaded.rb:146:in `sync'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool/threaded.rb:101:in `acquire'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/connection_pool/threaded.rb:74:in `hold'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/database/connecting.rb:226:in `synchronize'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:250:in `execute'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:271:in `check_database_errors'
/usr/local/rvm/rubies/ruby-1.8.7-head/lib/ruby/gems/1.8/gems/sequel-3.24.1/lib/sequel/adapters/postgres.rb:248:in `execute'
# ... application code ...

This appears to be because Ruby treats the strings coming from the database as tainted -- while the adapter assumes they are untainted as they come from a system table:

conn.execute("SELECT oid, typname FROM pg_type where typtype = 'b'") do |res|
res.ntuples.times do |recnum|
if pr = PG_NAMED_TYPES[res.getvalue(recnum, 1).to_sym]
...

The following patch untaints the strings and allows the PostgreSQL driver t be used in safe mode:

diff -Naur sequel-3.24.1/lib/sequel/adapters/postgres.rb sequel-3.24.1-pg-untaint-patch/lib/sequel/adapters/postgres.rb
--- sequel-3.24.1/lib/sequel/adapters/postgres.rb	2011-10-18 22:34:13.581809084 -0400
+++ sequel-3.24.1-pg-untaint-patch/lib/sequel/adapters/postgres.rb	2011-10-18 22:34:31.761809080 -0400
@@ -321,7 +321,9 @@
procs = PG_TYPES.dup
conn.execute("SELECT oid, typname FROM pg_type where typtype = 'b'") do |res|
res.ntuples.times do |recnum|
- if pr = PG_NAMED_TYPES[res.getvalue(recnum, 1).to_sym]
+ name = res.getvalue(recnum, 1)
+ name.untaint
+ if pr = PG_NAMED_TYPES[name.to_sym]
procs[res.getvalue(recnum, 0).to_i] ||= pr
end
end