Skip to content

Commit 8a1d3ea

Browse files
tenderloverafaelfranca
authored andcommitted
Change render "foo" to render a template and not a file.
Previously, calling `render "foo/bar"` in a controller action is equivalent to `render file: "foo/bar"`. This has been changed to mean `render template: "foo/bar"` instead. If you need to render a file, please change your code to use the explicit form (`render file: "foo/bar"`) instead. Test that we are not allowing you to grab a file with an absolute path outside of your application directory. This is dangerous because it could be used to retrieve files from the server like `/etc/passwd`. Fix CVE-2016-2097.
1 parent 31ab3aa commit 8a1d3ea

File tree

6 files changed

+43
-49
lines changed

6 files changed

+43
-49
lines changed

actionpack/test/controller/new_base/render_file_test.rb

-29
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@ def with_instance_variables
1313
render :file => File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar')
1414
end
1515

16-
def without_file_key
17-
render File.join(File.dirname(__FILE__), *%w[.. .. fixtures test hello_world])
18-
end
19-
20-
def without_file_key_with_instance_variable
21-
@secret = 'in the sauce'
22-
render File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar')
23-
end
24-
2516
def relative_path
2617
@secret = 'in the sauce'
2718
render :file => '../../fixtures/test/render_file_with_ivar'
@@ -41,11 +32,6 @@ def with_locals
4132
path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals')
4233
render :file => path, :locals => {:secret => 'in the sauce'}
4334
end
44-
45-
def without_file_key_with_locals
46-
path = FIXTURES.join('test/render_file_with_locals').to_s
47-
render path, :locals => {:secret => 'in the sauce'}
48-
end
4935
end
5036

5137
class TestBasic < Rack::TestCase
@@ -61,16 +47,6 @@ class TestBasic < Rack::TestCase
6147
assert_response "The secret is in the sauce\n"
6248
end
6349

64-
test "rendering path without specifying the :file key" do
65-
get :without_file_key
66-
assert_response "Hello world!"
67-
end
68-
69-
test "rendering path without specifying the :file key with ivar" do
70-
get :without_file_key_with_instance_variable
71-
assert_response "The secret is in the sauce\n"
72-
end
73-
7450
test "rendering a relative path" do
7551
get :relative_path
7652
assert_response "The secret is in the sauce\n"
@@ -90,10 +66,5 @@ class TestBasic < Rack::TestCase
9066
get :with_locals
9167
assert_response "The secret is in the sauce\n"
9268
end
93-
94-
test "rendering path without specifying the :file key with locals" do
95-
get :without_file_key_with_locals
96-
assert_response "The secret is in the sauce\n"
97-
end
9869
end
9970
end

actionpack/test/controller/new_base/render_template_test.rb

+9
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ def with_locals
4545
render :template => "locals", :locals => { :secret => 'area51' }
4646
end
4747

48+
def with_locals_without_key
49+
render "locals", :locals => { :secret => 'area51' }
50+
end
51+
4852
def builder_template
4953
render :template => "xml_template"
5054
end
@@ -101,6 +105,11 @@ class TestWithoutLayout < Rack::TestCase
101105
assert_response "The secret is area51"
102106
end
103107

108+
test "rendering a template with local variables without key" do
109+
get :with_locals
110+
assert_response "The secret is area51"
111+
end
112+
104113
test "rendering a builder template" do
105114
get :builder_template, "format" => "xml"
106115
assert_response "<html>\n <p>Hello</p>\n</html>\n"

actionpack/test/controller/render_test.rb

+17
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ def accessing_logger_in_template
261261
class ExpiresInRenderTest < ActionController::TestCase
262262
tests TestController
263263

264+
def setup
265+
super
266+
ActionController::Base.view_paths.paths.each(&:clear_cache)
267+
end
268+
264269
def test_dynamic_render_with_file
265270
# This is extremely bad, but should be possible to do.
266271
assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb'))
@@ -269,6 +274,18 @@ def test_dynamic_render_with_file
269274
response.body
270275
end
271276

277+
def test_dynamic_render_with_absolute_path
278+
file = Tempfile.new('name')
279+
file.write "secrets!"
280+
file.flush
281+
assert_raises ActionView::MissingTemplate do
282+
get :dynamic_render, { id: file.path }
283+
end
284+
ensure
285+
file.close
286+
file.unlink
287+
end
288+
272289
def test_dynamic_render
273290
assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb'))
274291
assert_raises ActionView::MissingTemplate do

actionview/CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
* Changed the meaning of `render "foo/bar"`.
2+
3+
Previously, calling `render "foo/bar"` in a controller action is equivalent
4+
to `render file: "foo/bar"`. This has been changed to mean
5+
`render template: "foo/bar"` instead. If you need to render a file, please
6+
change your code to use the explicit form (`render file: "foo/bar"`) instead.
7+
8+
*Eileen Uchitelle*
9+
10+
111
## Rails 4.1.14 (November 12, 2015) ##
212

313
* Fix `mail_to` when called with `nil` as argument.

actionview/lib/action_view/rendering.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def _process_format(format, options = {}) #:nodoc:
107107
end
108108

109109
# Normalize args by converting render "foo" to render :action => "foo" and
110-
# render "foo/bar" to render :file => "foo/bar".
110+
# render "foo/bar" to render :template => "foo/bar".
111111
# :api: private
112112
def _normalize_args(action=nil, options={})
113113
options = super(action, options)
@@ -117,7 +117,7 @@ def _normalize_args(action=nil, options={})
117117
options = action
118118
when String, Symbol
119119
action = action.to_s
120-
key = action.include?(?/) ? :file : :action
120+
key = action.include?(?/) ? :template : :action
121121
options[key] = action
122122
else
123123
options[:partial] = action

actionview/test/actionpack/controller/render_test.rb

+5-18
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,17 @@ def hello_world_file
9191

9292
# :ported:
9393
def render_hello_world
94-
render :template => "test/hello_world"
94+
render "test/hello_world"
9595
end
9696

9797
def render_hello_world_with_last_modified_set
9898
response.last_modified = Date.new(2008, 10, 10).to_time
99-
render :template => "test/hello_world"
99+
render "test/hello_world"
100100
end
101101

102102
# :ported: compatibility
103103
def render_hello_world_with_forward_slash
104-
render :template => "/test/hello_world"
104+
render "/test/hello_world"
105105
end
106106

107107
# :ported:
@@ -111,7 +111,7 @@ def render_template_in_top_directory
111111

112112
# :deprecated:
113113
def render_template_in_top_directory_with_slash
114-
render :template => '/shared'
114+
render '/shared'
115115
end
116116

117117
# :ported:
@@ -159,13 +159,6 @@ def render_file_with_instance_variables
159159
render :file => path
160160
end
161161

162-
# :ported:
163-
def render_file_as_string_with_instance_variables
164-
@secret = 'in the sauce'
165-
path = File.expand_path(File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar'))
166-
render path
167-
end
168-
169162
# :ported:
170163
def render_file_not_using_full_path
171164
@secret = 'in the sauce'
@@ -194,7 +187,7 @@ def render_file_with_locals
194187

195188
def render_file_as_string_with_locals
196189
path = File.expand_path(File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals'))
197-
render path, :locals => {:secret => 'in the sauce'}
190+
render file: path, :locals => {:secret => 'in the sauce'}
198191
end
199192

200193
def accessing_request_in_template
@@ -780,12 +773,6 @@ def test_render_file
780773
assert_equal "Hello world!", @response.body
781774
end
782775

783-
# :ported:
784-
def test_render_file_as_string_with_instance_variables
785-
get :render_file_as_string_with_instance_variables
786-
assert_equal "The secret is in the sauce\n", @response.body
787-
end
788-
789776
# :ported:
790777
def test_render_file_not_using_full_path
791778
get :render_file_not_using_full_path

0 commit comments

Comments
 (0)