Skip to content

Commit 85bc4be

Browse files
committed
Merge branch 'master-2.2' into dist/2.2/xenial
2 parents 855200f + 63f42b1 commit 85bc4be

31 files changed

+1031
-107
lines changed

ChangeLog

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,242 @@
1+
Wed Mar 28 23:48:24 2018 Eric Wong <[email protected]>
2+
3+
webrick: prevent response splitting and header injection
4+
5+
Original patch by tenderlove (with minor style adjustments).
6+
7+
* lib/webrick/httpresponse.rb (send_header): call check_header
8+
(check_header): raise on embedded CRLF in header value
9+
* test/webrick/test_httpresponse.rb
10+
(test_prevent_response_splitting_headers): new test
11+
* (test_prevent_response_splitting_cookie_headers): ditto
12+
13+
Wed Mar 28 23:45:36 2018 Eric Wong <[email protected]>
14+
15+
webrick: use IO.copy_stream for multipart response
16+
17+
Use the new Proc response body feature to generate a multipart
18+
range response dynamically. We use a flat array to minimize
19+
object overhead as much as possible; as many ranges may fit
20+
into an HTTP request header.
21+
22+
* lib/webrick/httpservlet/filehandler.rb (multipart_body): new method
23+
(make_partial_content): use multipart_body
24+
25+
webrick/httprequest: limit request headers size
26+
27+
We use the same 112 KB limit started (AFAIK) by Mongrel, Thin,
28+
and Puma to prevent malicious users from using up all the memory
29+
with a single request. This also limits the damage done by
30+
excessive ranges in multipart Range: requests.
31+
32+
Due to the way we rely on IO#gets and the desire to keep
33+
the code simple, the actual maximum header may be 4093 bytes
34+
larger than 112 KB, but we're splitting hairs at that point.
35+
36+
* lib/webrick/httprequest.rb: define MAX_HEADER_LENGTH
37+
(read_header): raise when headers exceed max length
38+
39+
webrick/httpservlet/cgihandler: reduce memory use
40+
41+
WEBrick::HTTPRequest#body can be passed a block to process the
42+
body in chunks. Use this feature to avoid building a giant
43+
string in memory.
44+
45+
* lib/webrick/httpservlet/cgihandler.rb (do_GET):
46+
avoid reading entire request body into memory
47+
(do_POST is aliased to do_GET, so it handles bodies)
48+
49+
webrick/httprequest: raise correct exception
50+
51+
"BadRequest" alone does not resolve correctly, it is in the
52+
HTTPStatus namespace.
53+
54+
* lib/webrick/httprequest.rb (read_chunked): use correct exception
55+
* test/webrick/test_httpserver.rb (test_eof_in_chunk): new test
56+
57+
webrick/httprequest: use InputBufferSize for chunked requests
58+
59+
While WEBrick::HTTPRequest#body provides a Proc interface
60+
for streaming large request bodies, clients must not force
61+
the server to use an excessively large chunk size.
62+
63+
* lib/webrick/httprequest.rb (read_chunk_size): limit each
64+
read and block.call to :InputBufferSize in config.
65+
* test/webrick/test_httpserver.rb (test_big_chunks): new test
66+
67+
webrick: add test for Digest auth-int
68+
69+
No changes to the actual code, this is a new test for
70+
a feature for which no tests existed. I don't understand
71+
the Digest authentication code well at all, but this is
72+
necessary for the subsequent change.
73+
74+
* test/webrick/test_httpauth.rb (test_digest_auth_int): new test
75+
(credentials_for_request): support bodies with POST
76+
77+
webrick/httpauth/digestauth: stream req.body
78+
79+
WARNING! WARNING! WARNING! LIKELY BROKEN CHANGE
80+
81+
Pass a proc to WEBrick::HTTPRequest#body to avoid reading a
82+
potentially large request body into memory during
83+
authentication.
84+
85+
WARNING! this will break apps completely which want to do
86+
something with the body besides calculating the MD5 digest
87+
of it.
88+
89+
Also, keep in mind that probably nobody uses "auth-int".
90+
Servers such as Apache, lighttpd, nginx don't seem to
91+
support it; nor does curl when using POST/PUT bodies;
92+
and we didn't have tests for it until now...
93+
94+
* lib/webrick/httpauth/digestauth.rb (_authenticate): stream req.body
95+
96+
Wed Mar 28 23:41:53 2018 NAKAMURA Usaku <[email protected]>
97+
98+
get rid of test error/failure on Windows introduced at r62955
99+
100+
* lib/webrick/httpresponse.rb (send_body_io): use seek if
101+
NotImplementedError is raised in IO.copy_stream with offset.
102+
103+
* lib/webrick/httpservlet/filehandler.rb (multipart_body): ditto.
104+
105+
Wed Mar 28 23:41:53 2018 Eric Wong <[email protected]>
106+
107+
webrick: support Proc objects as body responses
108+
109+
* lib/webrick/httpresponse.rb (send_body): call send_body_proc
110+
(send_body_proc): new method
111+
(class ChunkedWrapper): new class
112+
113+
* test/webrick/test_httpresponse.rb (test_send_body_proc): new test
114+
(test_send_body_proc_chunked): ditto
115+
[Feature #855]
116+
117+
webrick: favor .write over << method
118+
119+
This will make the next change to use IO.copy_stream
120+
easier-to-read. When we can drop Ruby 2.4 support in a few
121+
years, this will allow us to use writev(2) with multiple
122+
arguments for headers and chunked responses.
123+
124+
* lib/webrick/cgi.rb (write): new wrapper method
125+
lib/webrick/httpresponse.rb: (send_header): use socket.write
126+
(send_body_io): ditto
127+
(send_body_string): ditto
128+
(send_body_proc): ditto
129+
(_write_data): ditto
130+
(ChunkedWrapper#write): ditto
131+
(_send_file): ditto
132+
133+
webrick/httpresponse: IO.copy_stream for regular files
134+
135+
Remove the redundant _send_file method since its functionality
136+
is unnecessary with IO.copy_stream. IO.copy_stream also allows
137+
the use of sendfile under some OSes to speed up copies to
138+
non-TLS sockets.
139+
140+
Testing with "curl >/dev/null" and "ruby -run -e httpd" to
141+
read a 1G file over Linux loopback reveals a reduction from
142+
around ~0.770 to ~0.490 seconds on the client side.
143+
144+
* lib/webrick/httpresponse.rb (send_body_io): use IO.copy_stream
145+
(_send_file): remove
146+
[Feature #14237]
147+
148+
webrick: use IO.copy_stream for single range response
149+
150+
This is also compatible with range responses generated
151+
by Rack::File (tested with rack 2.0.3).
152+
153+
* lib/webrick/httpresponse.rb (send_body_io): use Content-Range
154+
* lib/webrick/httpservlet/filehandler.rb (make_partial_content):
155+
use File object for the single range case
156+
* test/webrick/test_filehandler.rb (get_res_body): use send_body
157+
to test result
158+
159+
test/webrick/test_filehandler.rb: stricter multipart range test
160+
161+
We need to ensure we generate compatibile output in
162+
the face of future changes
163+
164+
* test/webrick/test_filehandler.rb (test_make_partial_content):
165+
check response body
166+
167+
webrick: quiet warning for multi-part ranges
168+
169+
Content-Length is ignored by WEBrick::HTTPResponse even if we
170+
calculate it, so instead we chunk responses to HTTP/1.1 clients
171+
and terminate HTTP/1.0 connections.
172+
173+
* lib/webrick/httpservlet/filehandler.rb (make_partial_content):
174+
quiet warning
175+
176+
webrick/httpresponse: make ChunkedWrapper copy_stream-compatible
177+
178+
The .write method needs to return the number of bytes written
179+
to avoid confusing IO.copy_stream.
180+
181+
* lib/webrick/httpresponse.rb (ChunkedWrapper#write): return bytes written
182+
(ChunkedWrapper#<<): return self
183+
184+
webrick: use IO.copy_stream for multipart response
185+
186+
Use the new Proc response body feature to generate a multipart
187+
range response dynamically. We use a flat array to minimize
188+
object overhead as much as possible; as many ranges may fit
189+
into an HTTP request header.
190+
191+
* lib/webrick/httpservlet/filehandler.rb (multipart_body): new method
192+
(make_partial_content): use multipart_body
193+
194+
Wed Mar 28 23:37:18 2018 Nobuyoshi Nakada <[email protected]>
195+
196+
pack.c: fix underflow
197+
198+
* pack.c (pack_unpack_internal): get rid of underflow.
199+
https://hackerone.com/reports/298246
200+
201+
Wed Mar 28 23:35:28 2018 Nobuyoshi Nakada <[email protected]>
202+
203+
unixsocket.c: check NUL bytes
204+
205+
* ext/socket/unixsocket.c (rsock_init_unixsock): check NUL bytes.
206+
https://hackerone.com/reports/302997
207+
208+
unixsocket.c: abstract namespace
209+
210+
* ext/socket/unixsocket.c (unixsock_path_value): fix r62991 for
211+
Linux abstract namespace.
212+
213+
Wed Mar 28 23:30:32 2018 SHIBATA Hiroshi <[email protected]>
214+
215+
Ignore file separator from tmpfile/tmpdir name.
216+
217+
Wed Mar 28 23:27:23 2018 Nobuyoshi Nakada <[email protected]>
218+
219+
dir.c: check NUL bytes
220+
221+
* dir.c (GlobPathValue): should be used in rb_push_glob only.
222+
other methods should use FilePathValue.
223+
https://hackerone.com/reports/302338
224+
225+
* dir.c (rb_push_glob): expand GlobPathValue
226+
227+
Sat Feb 17 01:24:49 2018 SHIBATA Hiroshi <[email protected]>
228+
229+
Merge RubyGems 2.7.6 from upstream.
230+
231+
It fixed some security vulnerabilities.
232+
233+
http://blog.rubygems.org/2018/02/15/2.7.6-released.html
234+
235+
fix regexp literal warning.
236+
237+
* test/rubygems/test_gem_server.rb: eliminate duplicated character class warning.
238+
[Bug #14481]
239+
1240
Fri Dec 15 00:08:26 2017 NAKAMURA Usaku <[email protected]>
2241

3242
* test/net/ftp/test_ftp.rb (process_port_or_eprt): merge a part of

debian/changelog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
ruby2.2 (2.2.10-0nkmi1) unstable; urgency=medium
2+
3+
* Ruby 2.2.10
4+
5+
-- Sorah Fukumori <[email protected]> Thu, 29 Mar 2018 00:10:42 +0000
6+
17
ruby2.2 (2.2.9-0nkmi1~xenial) xenial; urgency=medium
28

39
* new upstream version

dir.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -423,15 +423,6 @@ static const rb_data_type_t dir_data_type = {
423423

424424
static VALUE dir_close(VALUE);
425425

426-
#define GlobPathValue(str, safe) \
427-
/* can contain null bytes as separators */ \
428-
(!RB_TYPE_P((str), T_STRING) ? \
429-
(void)FilePathValue(str) : \
430-
(void)(check_safe_glob((str), (safe)), \
431-
check_glob_encoding(str), (str)))
432-
#define check_safe_glob(str, safe) ((safe) ? rb_check_safe_obj(str) : (void)0)
433-
#define check_glob_encoding(str) rb_enc_check((str), rb_enc_from_encoding(rb_usascii_encoding()))
434-
435426
static VALUE
436427
dir_s_alloc(VALUE klass)
437428
{
@@ -480,7 +471,7 @@ dir_initialize(int argc, VALUE *argv, VALUE dir)
480471
}
481472
}
482473

483-
GlobPathValue(dirname, FALSE);
474+
FilePathValue(dirname);
484475
orig = rb_str_dup_frozen(dirname);
485476
dirname = rb_str_encode_ospath(dirname);
486477
dirname = rb_str_dup_frozen(dirname);
@@ -2050,7 +2041,14 @@ rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
20502041
long offset = 0;
20512042
VALUE ary;
20522043

2053-
GlobPathValue(str, TRUE);
2044+
/* can contain null bytes as separators */
2045+
if (!RB_TYPE_P((str), T_STRING)) {
2046+
FilePathValue(str);
2047+
}
2048+
else {
2049+
rb_check_safe_obj(str);
2050+
rb_enc_check(str, rb_enc_from_encoding(rb_usascii_encoding()));
2051+
}
20542052
ary = rb_ary_new();
20552053

20562054
while (offset < RSTRING_LEN(str)) {
@@ -2080,7 +2078,7 @@ dir_globs(long argc, const VALUE *argv, int flags)
20802078
for (i = 0; i < argc; ++i) {
20812079
int status;
20822080
VALUE str = argv[i];
2083-
GlobPathValue(str, TRUE);
2081+
FilePathValue(str);
20842082
status = push_glob(ary, str, flags);
20852083
if (status) GLOB_JUMP_TAG(status);
20862084
}

ext/socket/unixsocket.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,28 @@ unixsock_connect_internal(VALUE a)
2525
arg->sockaddrlen, 0);
2626
}
2727

28+
static VALUE
29+
unixsock_path_value(VALUE path)
30+
{
31+
#ifdef __linux__
32+
#define TO_STR_FOR_LINUX_ABSTRACT_NAMESPACE 0
33+
34+
VALUE name = path;
35+
#if TO_STR_FOR_LINUX_ABSTRACT_NAMESPACE
36+
const int isstr = !NIL_P(name = rb_check_string_type(name));
37+
#else
38+
const int isstr = RB_TYPE_P(name, T_STRING);
39+
#endif
40+
if (isstr) {
41+
if (RSTRING_LEN(name) == 0 || RSTRING_PTR(name)[0] == '\0') {
42+
rb_check_safe_obj(name);
43+
return name; /* ignore encoding */
44+
}
45+
}
46+
#endif
47+
return rb_get_path(path);
48+
}
49+
2850
VALUE
2951
rsock_init_unixsock(VALUE sock, VALUE path, int server)
3052
{
@@ -33,7 +55,7 @@ rsock_init_unixsock(VALUE sock, VALUE path, int server)
3355
int fd, status;
3456
rb_io_t *fptr;
3557

36-
SafeStringValue(path);
58+
path = unixsock_path_value(path);
3759

3860
INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
3961
if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {

lib/rubygems.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
require 'thread'
1010

1111
module Gem
12-
VERSION = '2.4.5.4'
12+
VERSION = '2.4.5.5'
1313
end
1414

1515
# Must be first since it unloads the prelude from 1.9.2

lib/rubygems/package.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ def install_location filename, destination_dir # :nodoc:
408408
destination = File.expand_path destination
409409

410410
raise Gem::Package::PathError.new(destination, destination_dir) unless
411-
destination.start_with? destination_dir
411+
destination.start_with? destination_dir + '/'
412412

413413
destination.untaint
414414
destination
@@ -587,6 +587,10 @@ def verify_files gem
587587
raise Gem::Package::FormatError.new \
588588
'package content (data.tar.gz) is missing', @gem
589589
end
590+
591+
if duplicates = @files.group_by {|f| f }.select {|k,v| v.size > 1 }.map(&:first) and duplicates.any?
592+
raise Gem::Security::Exception, "duplicate files in the package: (#{duplicates.map(&:inspect).join(', ')})"
593+
end
590594
end
591595

592596
##

0 commit comments

Comments
 (0)