public
Description: Phusion Passenger (mod_rails)
Homepage: http://www.modrails.com/
Clone URL: git://github.com/FooBarWidget/passenger.git
Click here to lend your support to: passenger and make a donation at www.pledgie.com !
Improve security by imposing a maximum limit on the HTTP header size.
Hongli Lai (Phusion) (author)
Fri Mar 21 08:12:46 -0700 2008
commit  8afe632772c173e0cb9e788b56fb35143bc6164f
tree    b7d6588786b59d0b634a74888e36d2908d709c85
parent  0ebafd98deaddae4311c98068ab3260d53e554f4
...
103
104
105
106
 
 
 
 
 
107
108
109
...
113
114
115
 
 
 
 
116
117
118
...
103
104
105
 
106
107
108
109
110
111
112
113
...
117
118
119
120
121
122
123
124
125
126
0
@@ -103,7 +103,11 @@ class MessageChannel
0
   #
0
   # Might raise SystemCallError, IOError or SocketError when something
0
   # goes wrong.
0
- def read_scalar
0
+ #
0
+ # The +max_size+ argument allows one to specify the maximum allowed
0
+ # size for the scalar message. If the received scalar message's size
0
+ # is larger than +max_size+, then a SecurityError will be raised.
0
+ def read_scalar(max_size = nil)
0
     buffer = ''
0
     temp = ''
0
     while buffer.size < 4
0
@@ -113,6 +117,10 @@ class MessageChannel
0
     if size == 0
0
       return ''
0
     else
0
+ if !max_size.nil? && size > max_size
0
+ raise SecurityError, "Scalar message size (#{size}) " <<
0
+ "exceeds maximum allowed size (#{max_size})."
0
+ end
0
       buffer = ''
0
       while buffer.size < size
0
         buffer << @io.readpartial(size - buffer.size, temp)
...
74
75
76
 
77
78
79
...
239
240
241
242
243
244
 
245
246
247
...
74
75
76
77
78
79
80
...
240
241
242
 
 
 
243
244
245
246
0
@@ -74,6 +74,7 @@ class RequestHandler
0
   # Signal which will cause the Rails application to exit as soon as it's done processing a request.
0
   SOFT_TERMINATION_SIGNAL = "SIGUSR1"
0
   BACKLOG_SIZE = 50
0
+ MAX_HEADER_SIZE = 128 * 1024
0
   
0
   # String constants which exist to relieve Ruby's garbage collector.
0
   IGNORE = 'IGNORE' # :nodoc:
0
@@ -239,9 +240,7 @@ private
0
   
0
   def process_request(socket)
0
     channel = MessageChannel.new(socket)
0
- # TODO: We should check the size of the header data. We don't want attackers to
0
- # make the server swap storm to dead by sending a header of 4 GB.
0
- headers_data = channel.read_scalar
0
+ headers_data = channel.read_scalar(MAX_HEADER_SIZE)
0
     if headers_data.nil?
0
       socket.close
0
       return
...
115
116
117
 
118
119
120
...
115
116
117
118
119
120
121
0
@@ -115,6 +115,7 @@ shared_examples_for "MyCook(tm) beta" do
0
   
0
   it "should not make the web server crash if the app crashes" do
0
     post('/welcome/terminate')
0
+ sleep(0.25) # Give the app the time to terminate itself.
0
     get('/').should =~ /Welcome to MyCook/
0
   end
0
   
...
62
63
64
 
 
 
 
 
65
66
67
...
62
63
64
65
66
67
68
69
70
71
72
0
@@ -62,6 +62,11 @@ describe MessageChannel do
0
       @writer.close
0
       @reader.read_scalar.should be_nil
0
     end
0
+
0
+ it "should raise SecurityError when a received scalar message's size is larger than a specified maximum" do
0
+ @writer.write_scalar(" " * 100)
0
+ lambda { @reader.read_scalar(99) }.should raise_error(SecurityError)
0
+ end
0
   end
0
   
0
   describe "scenarios with 2 channels and 2 concurrent processes" do

Comments

    No one has commented yet.