Skip to content

Commit 99f725b

Browse files
committed
updating OkJson due to CVE-2014-9490
1 parent bf6dc2f commit 99f725b

File tree

1 file changed

+91
-90
lines changed

1 file changed

+91
-90
lines changed

lib/rack/utils/okjson.rb

+91-90
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,14 @@
2121
# THE SOFTWARE.
2222

2323
# See https://github.com/kr/okjson for updates.
24-
# Imported from the above repo @ d4e8643ad92e14b37d11326855499c7e4108ed17
25-
# Namespace modified for vendoring under Rack::Utils
2624

2725
require 'stringio'
2826

2927
# Some parts adapted from
30-
# http://golang.org/src/pkg/json/decode.go and
31-
# http://golang.org/src/pkg/utf8/utf8.go
28+
# https://golang.org/src/encoding/json/decode.go and
29+
# https://golang.org/src/unicode/utf8/utf8.go
3230
module Rack::Utils::OkJson
33-
Upstream = 'LTD7LBKLZWFF7OZK'
31+
Upstream = '43'
3432
extend self
3533

3634

@@ -52,12 +50,49 @@ def decode(s)
5250
end
5351

5452

53+
# Encodes x into a json text. It may contain only
54+
# Array, Hash, String, Numeric, true, false, nil.
55+
# (Note, this list excludes Symbol.)
56+
# X itself must be an Array or a Hash.
57+
# No other value can be encoded, and an error will
58+
# be raised if x contains any other value, such as
59+
# Nan, Infinity, Symbol, and Proc, or if a Hash key
60+
# is not a String.
61+
# Strings contained in x must be valid UTF-8.
62+
def encode(x)
63+
case x
64+
when Hash then objenc(x)
65+
when Array then arrenc(x)
66+
else
67+
raise Error, 'root value must be an Array or a Hash'
68+
end
69+
end
70+
71+
72+
def valenc(x)
73+
case x
74+
when Hash then objenc(x)
75+
when Array then arrenc(x)
76+
when String then strenc(x)
77+
when Numeric then numenc(x)
78+
when true then "true"
79+
when false then "false"
80+
when nil then "null"
81+
else
82+
raise Error, "cannot encode #{x.class}: #{x.inspect}"
83+
end
84+
end
85+
86+
87+
private
88+
89+
5590
# Parses a "json text" in the sense of RFC 4627.
5691
# Returns the parsed value and any trailing tokens.
5792
# Note: this is almost the same as valparse,
5893
# except that it does not accept atomic values.
5994
def textparse(ts)
60-
if ts.length < 0
95+
if ts.length <= 0
6196
raise Error, 'empty'
6297
end
6398

@@ -74,7 +109,7 @@ def textparse(ts)
74109
# Parses a "value" in the sense of RFC 4627.
75110
# Returns the parsed value and any trailing tokens.
76111
def valparse(ts)
77-
if ts.length < 0
112+
if ts.length <= 0
78113
raise Error, 'empty'
79114
end
80115

@@ -203,21 +238,19 @@ def lex(s)
203238
# it is the lexeme.
204239
def tok(s)
205240
case s[0]
206-
when ?{ then ['{', s[0,1], s[0,1]]
207-
when ?} then ['}', s[0,1], s[0,1]]
208-
when ?: then [':', s[0,1], s[0,1]]
209-
when ?, then [',', s[0,1], s[0,1]]
210-
when ?[ then ['[', s[0,1], s[0,1]]
211-
when ?] then [']', s[0,1], s[0,1]]
212-
when ?n then nulltok(s)
213-
when ?t then truetok(s)
214-
when ?f then falsetok(s)
215-
when ?" then strtok(s)
216-
when Spc then [:space, s[0,1], s[0,1]]
217-
when ?\t then [:space, s[0,1], s[0,1]]
218-
when ?\n then [:space, s[0,1], s[0,1]]
219-
when ?\r then [:space, s[0,1], s[0,1]]
220-
else numtok(s)
241+
when ?{ then ['{', s[0,1], s[0,1]]
242+
when ?} then ['}', s[0,1], s[0,1]]
243+
when ?: then [':', s[0,1], s[0,1]]
244+
when ?, then [',', s[0,1], s[0,1]]
245+
when ?[ then ['[', s[0,1], s[0,1]]
246+
when ?] then [']', s[0,1], s[0,1]]
247+
when ?n then nulltok(s)
248+
when ?t then truetok(s)
249+
when ?f then falsetok(s)
250+
when ?" then strtok(s)
251+
when Spc, ?\t, ?\n, ?\r then [:space, s[0,1], s[0,1]]
252+
else
253+
numtok(s)
221254
end
222255
end
223256

@@ -230,12 +263,12 @@ def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
230263
def numtok(s)
231264
m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
232265
if m && m.begin(0) == 0
233-
if m[3] && !m[2]
234-
[:val, m[0], Integer(m[1])*(10**Integer(m[3][1..-1]))]
266+
if !m[2] && !m[3]
267+
[:val, m[0], Integer(m[0])]
235268
elsif m[2]
236269
[:val, m[0], Float(m[0])]
237270
else
238-
[:val, m[0], Integer(m[0])]
271+
[:val, m[0], Integer(m[1])*(10**m[3][1..-1].to_i(10))]
239272
end
240273
else
241274
[]
@@ -267,17 +300,14 @@ def abbrev(s)
267300
def unquote(q)
268301
q = q[1...-1]
269302
a = q.dup # allocate a big enough string
270-
rubydoesenc = false
271303
# In ruby >= 1.9, a[w] is a codepoint, not a byte.
272-
if a.class.method_defined?(:force_encoding)
304+
if rubydoesenc?
273305
a.force_encoding('UTF-8')
274-
rubydoesenc = true
275306
end
276307
r, w = 0, 0
277308
while r < q.length
278309
c = q[r]
279-
case true
280-
when c == ?\\
310+
if c == ?\\
281311
r += 1
282312
if r >= q.length
283313
raise Error, "string literal ends with a \"\\\": \"#{q}\""
@@ -310,7 +340,7 @@ def unquote(q)
310340
end
311341
end
312342
end
313-
if rubydoesenc
343+
if rubydoesenc?
314344
a[w] = '' << uchar
315345
w += 1
316346
else
@@ -319,7 +349,7 @@ def unquote(q)
319349
else
320350
raise Error, "invalid escape char #{q[r]} in \"#{q}\""
321351
end
322-
when c == ?", c < Spc
352+
elsif c == ?" || c < Spc
323353
raise Error, "invalid character in string literal \"#{q}\""
324354
else
325355
# Copy anything else byte-for-byte.
@@ -340,15 +370,14 @@ def unquote(q)
340370
# bytes in string a at position i.
341371
# Returns the number of bytes written.
342372
def ucharenc(a, i, u)
343-
case true
344-
when u <= Uchar1max
373+
if u <= Uchar1max
345374
a[i] = (u & 0xff).chr
346375
1
347-
when u <= Uchar2max
376+
elsif u <= Uchar2max
348377
a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
349378
a[i+1] = (Utagx | (u&Umaskx)).chr
350379
2
351-
when u <= Uchar3max
380+
elsif u <= Uchar3max
352381
a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
353382
a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
354383
a[i+2] = (Utagx | (u&Umaskx)).chr
@@ -385,50 +414,15 @@ def surrogate?(u)
385414

386415

387416
def nibble(c)
388-
case true
389-
when ?0 <= c && c <= ?9 then c.ord - ?0.ord
390-
when ?a <= c && c <= ?z then c.ord - ?a.ord + 10
391-
when ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
417+
if ?0 <= c && c <= ?9 then c.ord - ?0.ord
418+
elsif ?a <= c && c <= ?z then c.ord - ?a.ord + 10
419+
elsif ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
392420
else
393421
raise Error, "invalid hex code #{c}"
394422
end
395423
end
396424

397425

398-
# Encodes x into a json text. It may contain only
399-
# Array, Hash, String, Numeric, true, false, nil.
400-
# (Note, this list excludes Symbol.)
401-
# X itself must be an Array or a Hash.
402-
# No other value can be encoded, and an error will
403-
# be raised if x contains any other value, such as
404-
# Nan, Infinity, Symbol, and Proc, or if a Hash key
405-
# is not a String.
406-
# Strings contained in x must be valid UTF-8.
407-
def encode(x)
408-
case x
409-
when Hash then objenc(x)
410-
when Array then arrenc(x)
411-
else
412-
raise Error, 'root value must be an Array or a Hash'
413-
end
414-
end
415-
416-
417-
def valenc(x)
418-
case x
419-
when Hash then objenc(x)
420-
when Array then arrenc(x)
421-
when String then strenc(x)
422-
when Numeric then numenc(x)
423-
when true then "true"
424-
when false then "false"
425-
when nil then "null"
426-
else
427-
raise Error, "cannot encode #{x.class}: #{x.inspect}"
428-
end
429-
end
430-
431-
432426
def objenc(x)
433427
'{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
434428
end
@@ -453,9 +447,6 @@ def strenc(s)
453447
t.putc(?")
454448
r = 0
455449

456-
# In ruby >= 1.9, s[r] is a codepoint, not a byte.
457-
rubydoesenc = s.class.method_defined?(:encoding)
458-
459450
while r < s.length
460451
case s[r]
461452
when ?" then t.print('\\"')
@@ -467,15 +458,20 @@ def strenc(s)
467458
when ?\t then t.print('\\t')
468459
else
469460
c = s[r]
470-
case true
471-
when rubydoesenc
461+
# In ruby >= 1.9, s[r] is a codepoint, not a byte.
462+
if rubydoesenc?
472463
begin
473-
c.ord # will raise an error if c is invalid UTF-8
464+
# c.ord will raise an error if c is invalid UTF-8
465+
if c.ord < Spc.ord
466+
c = "\\u%04x" % [c.ord]
467+
end
474468
t.write(c)
475469
rescue
476470
t.write(Ustrerr)
477471
end
478-
when Spc <= c && c <= ?~
472+
elsif c < Spc
473+
t.write("\\u%04x" % c)
474+
elsif Spc <= c && c <= ?~
479475
t.putc(c)
480476
else
481477
n = ucharcopy(t, s, r) # ensure valid UTF-8 output
@@ -567,6 +563,11 @@ def ucharcopy(t, s, i)
567563
end
568564

569565

566+
def rubydoesenc?
567+
::String.method_defined?(:force_encoding)
568+
end
569+
570+
570571
class Utf8Error < ::StandardError
571572
end
572573

@@ -575,15 +576,15 @@ class Error < ::StandardError
575576
end
576577

577578

578-
Utagx = 0x80 # 1000 0000
579-
Utag2 = 0xc0 # 1100 0000
580-
Utag3 = 0xe0 # 1110 0000
581-
Utag4 = 0xf0 # 1111 0000
582-
Utag5 = 0xF8 # 1111 1000
583-
Umaskx = 0x3f # 0011 1111
584-
Umask2 = 0x1f # 0001 1111
585-
Umask3 = 0x0f # 0000 1111
586-
Umask4 = 0x07 # 0000 0111
579+
Utagx = 0b1000_0000
580+
Utag2 = 0b1100_0000
581+
Utag3 = 0b1110_0000
582+
Utag4 = 0b1111_0000
583+
Utag5 = 0b1111_1000
584+
Umaskx = 0b0011_1111
585+
Umask2 = 0b0001_1111
586+
Umask3 = 0b0000_1111
587+
Umask4 = 0b0000_0111
587588
Uchar1max = (1<<7) - 1
588589
Uchar2max = (1<<11) - 1
589590
Uchar3max = (1<<16) - 1

0 commit comments

Comments
 (0)