Hi there, I've prepared a ruby 1.9.1 package to fix the two open CVEs CVE-2012-5371 and CVE-2013-0269. As usual, test are more than welcome. The package is available at the repository:
deb https://people.debian.org/~santiago/debian santiago-squeeze-lts/ Debdiff against current package attached. Cheers, Santiago
diff -Nru ruby1.9.1-1.9.2.0/debian/changelog ruby1.9.1-1.9.2.0/debian/changelog --- ruby1.9.1-1.9.2.0/debian/changelog 2015-05-30 19:47:29.000000000 +0200 +++ ruby1.9.1-1.9.2.0/debian/changelog 2015-06-23 23:04:10.000000000 +0200 @@ -1,3 +1,16 @@ +ruby1.9.1 (1.9.2.0-2+deb6u5~2) santiago-squeeze-lts; urgency=medium + + * Non-maintainer upload by the Squeeze LTS Team. + * Fix CVE-2012-5371, Ruby computed hash values without properly restricting the + ability to trigger hash collisions predictably, allowing context-dependent + attackers to cause a denial of service (CPU consumption). + * Fix CVE-2013-0269, the JSON gem before allows remote attackers to cause a denial of + service (resource consumption) or bypass the mass assignment protection + mechanism via a crafted JSON document that triggers the creation of arbitrary + Ruby symbols or certain internal objects. + + -- Santiago Ruano Rincón <santiag...@riseup.net> Tue, 23 Jun 2015 22:47:39 +0200 + ruby1.9.1 (1.9.2.0-2+deb6u4) squeeze-lts; urgency=high * Non-maintainer upload by the Squeeze LTS Team. diff -Nru ruby1.9.1-1.9.2.0/debian/patches/CVE-2012-5371.patch ruby1.9.1-1.9.2.0/debian/patches/CVE-2012-5371.patch --- ruby1.9.1-1.9.2.0/debian/patches/CVE-2012-5371.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby1.9.1-1.9.2.0/debian/patches/CVE-2012-5371.patch 2015-06-23 22:46:32.000000000 +0200 @@ -0,0 +1,625 @@ +Description: replace hash implementation to avoid DOS attacks + This patch fixes CVE-2012-5371 +Bug-Debian: http://bugs.debian.org/693024 +Origin: upstream, https://github.com/ruby/ruby/commit/5e45af463cca6f062a986d5e686350e17ea653bb +Backported-By: James Healy <ja...@yob.id.au> +Reviewed-By: Antonio Terceiro <terce...@debian.org> + +--- a/common.mk ++++ b/common.mk +@@ -584,7 +584,8 @@ + process.$(OBJEXT): {$(VPATH)}process.c $(RUBY_H_INCLUDES) \ + {$(VPATH)}util.h {$(VPATH)}io.h $(ENCODING_H_INCLUDES) {$(VPATH)}dln.h \ + $(VM_CORE_H_INCLUDES) {$(VPATH)}debug.h +-random.$(OBJEXT): {$(VPATH)}random.c $(RUBY_H_INCLUDES) ++random.$(OBJEXT): {$(VPATH)}random.c $(RUBY_H_INCLUDES) \ ++ {$(VPATH)}siphash.c {$(VPATH)}siphash.h + range.$(OBJEXT): {$(VPATH)}range.c $(RUBY_H_INCLUDES) \ + $(ENCODING_H_INCLUDES) + rational.$(OBJEXT): {$(VPATH)}rational.c $(RUBY_H_INCLUDES) +--- a/random.c ++++ b/random.c +@@ -1146,7 +1146,15 @@ + return r; + } + ++#define SIP_HASH_STREAMING 0 ++#define sip_hash24 ruby_sip_hash24 ++#include "siphash.c" ++ + static st_index_t hashseed; ++static union { ++ uint8_t key[16]; ++ uint32_t u32[(16 * sizeof(uint8_t) - 1) / sizeof(uint32_t)]; ++} sipseed; + + static VALUE + init_randomseed(struct MT *mt, unsigned int initial[DEFAULT_SEED_CNT]) +@@ -1166,6 +1174,7 @@ + unsigned int initial[DEFAULT_SEED_CNT]; + struct MT *mt = &r->mt; + VALUE seed = init_randomseed(mt, initial); ++ int i; + + hashseed = genrand_int32(mt); + #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8 +@@ -1181,6 +1190,9 @@ + hashseed |= genrand_int32(mt); + #endif + ++ for (i = 0; i < numberof(sipseed.u32); ++i) ++ sipseed.u32[i] = genrand_int32(mt); ++ + rb_global_variable(&r->seed); + r->seed = seed; + } +@@ -1191,6 +1203,17 @@ + return st_hash_start(hashseed + h); + } + ++st_index_t ++rb_memhash(const void *ptr, long len) ++{ ++ sip_uint64_t h = sip_hash24(sipseed.key, ptr, len); ++#ifdef HAVE_UINT64_T ++ return (st_index_t)h; ++#else ++ return (st_index_t)(h.u32[0] ^ h.u32[1]); ++#endif ++} ++ + static void + Init_RandomSeed2(void) + { +--- /dev/null ++++ b/siphash.c +@@ -0,0 +1,483 @@ ++#include <string.h> ++#include <stdio.h> ++#include "siphash.h" ++#ifndef SIP_HASH_STREAMING ++ #define SIP_HASH_STREAMING 1 ++#endif ++ ++#ifdef _WIN32 ++ #define BYTE_ORDER __LITTLE_ENDIAN ++#elif !defined BYTE_ORDER ++ #include <endian.h> ++#endif ++#ifndef LITTLE_ENDIAN ++#define LITTLE_ENDIAN __LITTLE_ENDIAN ++#endif ++#ifndef BIG_ENDIAN ++#define BIG_ENDIAN __BIG_ENDIAN ++#endif ++ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ #define lo u32[0] ++ #define hi u32[1] ++#elif BYTE_ORDER == BIG_ENDIAN ++ #define hi u32[0] ++ #define lo u32[1] ++#else ++ #error "Only strictly little or big endian supported" ++#endif ++ ++#ifndef UNALIGNED_WORD_ACCESS ++# if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ ++ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD86) || \ ++ defined(__mc68020__) ++# define UNALIGNED_WORD_ACCESS 1 ++# endif ++#endif ++#ifndef UNALIGNED_WORD_ACCESS ++# define UNALIGNED_WORD_ACCESS 0 ++#endif ++ ++#define U8TO32_LE(p) \ ++ (((uint32_t)((p)[0]) ) | ((uint32_t)((p)[1]) << 8) | \ ++ ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) \ ++ ++#define U32TO8_LE(p, v) \ ++do { \ ++ (p)[0] = (uint8_t)((v) ); \ ++ (p)[1] = (uint8_t)((v) >> 8); \ ++ (p)[2] = (uint8_t)((v) >> 16); \ ++ (p)[3] = (uint8_t)((v) >> 24); \ ++} while (0) ++ ++#ifdef HAVE_UINT64_T ++#define U8TO64_LE(p) \ ++ ((uint64_t)U8TO32_LE(p) | ((uint64_t)U8TO32_LE((p) + 4)) << 32 ) ++ ++#define U64TO8_LE(p, v) \ ++do { \ ++ U32TO8_LE((p), (uint32_t)((v) )); \ ++ U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); \ ++} while (0) ++ ++#define ROTL64(v, s) \ ++ ((v) << (s)) | ((v) >> (64 - (s))) ++ ++#define ROTL64_TO(v, s) ((v) = ROTL64((v), (s))) ++ ++#define ADD64_TO(v, s) ((v) += (s)) ++#define XOR64_TO(v, s) ((v) ^= (s)) ++#define XOR64_INT(v, x) ((v) ^= (x)) ++#else ++#define U8TO64_LE(p) u8to64_le(p) ++static inline uint64_t ++u8to64_le(const uint8_t *p) ++{ ++ uint64_t ret; ++ ret.lo = U8TO32_LE(p); ++ ret.hi = U8TO32_LE(p + 4); ++ return ret; ++} ++ ++#define U64TO8_LE(p, v) u64to8_le(p, v) ++static inline void ++u64to8_le(uint8_t *p, uint64_t v) ++{ ++ U32TO8_LE(p, v.lo); ++ U32TO8_LE(p + 4, v.hi); ++} ++ ++#define ROTL64_TO(v, s) ((s) > 32 ? rotl64_swap(rotl64_to(&(v), (s) - 32)) : \ ++ (s) == 32 ? rotl64_swap(&(v)) : rotl64_to(&(v), (s))) ++static inline uint64_t * ++rotl64_to(uint64_t *v, unsigned int s) ++{ ++ uint32_t uhi = (v->hi << s) | (v->lo >> (32 - s)); ++ uint32_t ulo = (v->lo << s) | (v->hi >> (32 - s)); ++ v->hi = uhi; ++ v->lo = ulo; ++ return v; ++} ++ ++static inline uint64_t * ++rotl64_swap(uint64_t *v) ++{ ++ uint32_t t = v->lo; ++ v->lo = v->hi; ++ v->hi = t; ++ return v; ++} ++ ++#define ADD64_TO(v, s) add64_to(&(v), (s)) ++static inline uint64_t * ++add64_to(uint64_t *v, const uint64_t s) ++{ ++ v->lo += s.lo; ++ v->hi += s.hi; ++ if (v->lo < s.lo) v->hi++; ++ return v; ++} ++ ++#define XOR64_TO(v, s) xor64_to(&(v), (s)) ++static inline uint64_t * ++xor64_to(uint64_t *v, const uint64_t s) ++{ ++ v->lo ^= s.lo; ++ v->hi ^= s.hi; ++ return v; ++} ++ ++#define XOR64_INT(v, x) ((v).lo ^= (x)) ++#endif ++ ++static const union { ++ char bin[32]; ++ uint64_t u64[4]; ++} sip_init_state_bin = {"uespemos""modnarod""arenegyl""setybdet"}; ++#define sip_init_state sip_init_state_bin.u64 ++ ++#if SIP_HASH_STREAMING ++struct sip_interface_st { ++ void (*init)(sip_state *s, const uint8_t *key); ++ void (*update)(sip_state *s, const uint8_t *data, size_t len); ++ void (*final)(sip_state *s, uint64_t *digest); ++}; ++ ++static void int_sip_init(sip_state *state, const uint8_t *key); ++static void int_sip_update(sip_state *state, const uint8_t *data, size_t len); ++static void int_sip_final(sip_state *state, uint64_t *digest); ++ ++static const sip_interface sip_methods = { ++ int_sip_init, ++ int_sip_update, ++ int_sip_final ++}; ++#endif /* SIP_HASH_STREAMING */ ++ ++#define SIP_COMPRESS(v0, v1, v2, v3) \ ++do { \ ++ ADD64_TO((v0), (v1)); \ ++ ADD64_TO((v2), (v3)); \ ++ ROTL64_TO((v1), 13); \ ++ ROTL64_TO((v3), 16); \ ++ XOR64_TO((v1), (v0)); \ ++ XOR64_TO((v3), (v2)); \ ++ ROTL64_TO((v0), 32); \ ++ ADD64_TO((v2), (v1)); \ ++ ADD64_TO((v0), (v3)); \ ++ ROTL64_TO((v1), 17); \ ++ ROTL64_TO((v3), 21); \ ++ XOR64_TO((v1), (v2)); \ ++ XOR64_TO((v3), (v0)); \ ++ ROTL64_TO((v2), 32); \ ++} while(0) ++ ++#if SIP_HASH_STREAMING ++static void ++int_sip_dump(sip_state *state) ++{ ++ int v; ++ ++ for (v = 0; v < 4; v++) { ++#if HAVE_UINT64_T ++ printf("v%d: %" PRIx64 "\n", v, state->v[v]); ++#else ++ printf("v%d: %" PRIx32 "%.8" PRIx32 "\n", v, state->v[v].hi, state->v[v].lo); ++#endif ++ } ++} ++ ++static void ++int_sip_init(sip_state *state, const uint8_t key[16]) ++{ ++ uint64_t k0, k1; ++ ++ k0 = U8TO64_LE(key); ++ k1 = U8TO64_LE(key + sizeof(uint64_t)); ++ ++ state->v[0] = k0; XOR64_TO(state->v[0], sip_init_state[0]); ++ state->v[1] = k1; XOR64_TO(state->v[1], sip_init_state[1]); ++ state->v[2] = k0; XOR64_TO(state->v[2], sip_init_state[2]); ++ state->v[3] = k1; XOR64_TO(state->v[3], sip_init_state[3]); ++} ++ ++static inline void ++int_sip_round(sip_state *state, int n) ++{ ++ int i; ++ ++ for (i = 0; i < n; i++) { ++ SIP_COMPRESS(state->v[0], state->v[1], state->v[2], state->v[3]); ++ } ++} ++ ++static inline void ++int_sip_update_block(sip_state *state, uint64_t m) ++{ ++ XOR64_TO(state->v[3], m); ++ int_sip_round(state, state->c); ++ XOR64_TO(state->v[0], m); ++} ++ ++static inline void ++int_sip_pre_update(sip_state *state, const uint8_t **pdata, size_t *plen) ++{ ++ int to_read; ++ uint64_t m; ++ ++ if (!state->buflen) return; ++ ++ to_read = sizeof(uint64_t) - state->buflen; ++ memcpy(state->buf + state->buflen, *pdata, to_read); ++ m = U8TO64_LE(state->buf); ++ int_sip_update_block(state, m); ++ *pdata += to_read; ++ *plen -= to_read; ++ state->buflen = 0; ++} ++ ++static inline void ++int_sip_post_update(sip_state *state, const uint8_t *data, size_t len) ++{ ++ uint8_t r = len % sizeof(uint64_t); ++ if (r) { ++ memcpy(state->buf, data + len - r, r); ++ state->buflen = r; ++ } ++} ++ ++static void ++int_sip_update(sip_state *state, const uint8_t *data, size_t len) ++{ ++ uint64_t *end; ++ uint64_t *data64; ++ ++ state->msglen_byte = state->msglen_byte + (len % 256); ++ data64 = (uint64_t *) data; ++ ++ int_sip_pre_update(state, &data, &len); ++ ++ end = data64 + (len / sizeof(uint64_t)); ++ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ while (data64 != end) { ++ int_sip_update_block(state, *data64++); ++ } ++#elif BYTE_ORDER == BIG_ENDIAN ++ { ++ uint64_t m; ++ uint8_t *data8 = data; ++ for (; data8 != (uint8_t *) end; data8 += sizeof(uint64_t)) { ++ m = U8TO64_LE(data8); ++ int_sip_update_block(state, m); ++ } ++ } ++#endif ++ ++ int_sip_post_update(state, data, len); ++} ++ ++static inline void ++int_sip_pad_final_block(sip_state *state) ++{ ++ int i; ++ /* pad with 0's and finalize with msg_len mod 256 */ ++ for (i = state->buflen; i < sizeof(uint64_t); i++) { ++ state->buf[i] = 0x00; ++ } ++ state->buf[sizeof(uint64_t) - 1] = state->msglen_byte; ++} ++ ++static void ++int_sip_final(sip_state *state, uint64_t *digest) ++{ ++ uint64_t m; ++ ++ int_sip_pad_final_block(state); ++ ++ m = U8TO64_LE(state->buf); ++ int_sip_update_block(state, m); ++ ++ XOR64_INT(state->v[2], 0xff); ++ ++ int_sip_round(state, state->d); ++ ++ *digest = state->v[0]; ++ XOR64_TO(*digest, state->v[1]); ++ XOR64_TO(*digest, state->v[2]); ++ XOR64_TO(*digest, state->v[3]); ++} ++ ++sip_hash * ++sip_hash_new(const uint8_t key[16], int c, int d) ++{ ++ sip_hash *h = NULL; ++ ++ if (!(h = (sip_hash *) malloc(sizeof(sip_hash)))) return NULL; ++ return sip_hash_init(h, key, c, d); ++} ++ ++sip_hash * ++sip_hash_init(sip_hash *h, const uint8_t key[16], int c, int d) ++{ ++ h->state->c = c; ++ h->state->d = d; ++ h->state->buflen = 0; ++ h->state->msglen_byte = 0; ++ h->methods = &sip_methods; ++ h->methods->init(h->state, key); ++ return h; ++} ++ ++int ++sip_hash_update(sip_hash *h, const uint8_t *msg, size_t len) ++{ ++ h->methods->update(h->state, msg, len); ++ return 1; ++} ++ ++int ++sip_hash_final(sip_hash *h, uint8_t **digest, size_t* len) ++{ ++ uint64_t digest64; ++ uint8_t *ret; ++ ++ h->methods->final(h->state, &digest64); ++ if (!(ret = (uint8_t *)malloc(sizeof(uint64_t)))) return 0; ++ U64TO8_LE(ret, digest64); ++ *len = sizeof(uint64_t); ++ *digest = ret; ++ ++ return 1; ++} ++ ++int ++sip_hash_final_integer(sip_hash *h, uint64_t *digest) ++{ ++ h->methods->final(h->state, digest); ++ return 1; ++} ++ ++int ++sip_hash_digest(sip_hash *h, const uint8_t *data, size_t data_len, uint8_t **digest, size_t *digest_len) ++{ ++ if (!sip_hash_update(h, data, data_len)) return 0; ++ return sip_hash_final(h, digest, digest_len); ++} ++ ++int ++sip_hash_digest_integer(sip_hash *h, const uint8_t *data, size_t data_len, uint64_t *digest) ++{ ++ if (!sip_hash_update(h, data, data_len)) return 0; ++ return sip_hash_final_integer(h, digest); ++} ++ ++void ++sip_hash_free(sip_hash *h) ++{ ++ free(h); ++} ++ ++void ++sip_hash_dump(sip_hash *h) ++{ ++ int_sip_dump(h->state); ++} ++#endif /* SIP_HASH_STREAMING */ ++ ++#define SIP_2_ROUND(m, v0, v1, v2, v3) \ ++do { \ ++ XOR64_TO((v3), (m)); \ ++ SIP_COMPRESS(v0, v1, v2, v3); \ ++ SIP_COMPRESS(v0, v1, v2, v3); \ ++ XOR64_TO((v0), (m)); \ ++} while (0) ++ ++uint64_t ++sip_hash24(const uint8_t key[16], const uint8_t *data, size_t len) ++{ ++ uint64_t k0, k1; ++ uint64_t v0, v1, v2, v3; ++ uint64_t m, last; ++ const uint8_t *end = data + len - (len % sizeof(uint64_t)); ++ ++ k0 = U8TO64_LE(key); ++ k1 = U8TO64_LE(key + sizeof(uint64_t)); ++ ++ v0 = k0; XOR64_TO(v0, sip_init_state[0]); ++ v1 = k1; XOR64_TO(v1, sip_init_state[1]); ++ v2 = k0; XOR64_TO(v2, sip_init_state[2]); ++ v3 = k1; XOR64_TO(v3, sip_init_state[3]); ++ ++#if BYTE_ORDER == LITTLE_ENDIAN && UNALIGNED_WORD_ACCESS ++ { ++ uint64_t *data64 = (uint64_t *)data; ++ while (data64 != (uint64_t *) end) { ++ m = *data64++; ++ SIP_2_ROUND(m, v0, v1, v2, v3); ++ } ++ } ++#elif BYTE_ORDER == BIG_ENDIAN ++ for (; data != end; data += sizeof(uint64_t)) { ++ m = U8TO64_LE(data); ++ SIP_2_ROUND(m, v0, v1, v2, v3); ++ } ++#endif ++ ++#ifdef HAVE_UINT64_T ++ last = (uint64_t)len << 56; ++#define OR_BYTE(n) (last |= ((uint64_t) end[n]) << ((n) * 8)) ++#else ++ last.hi = len << 24; ++ last.lo = 0; ++#define OR_BYTE(n) do { \ ++ if (n >= 4) \ ++ last.hi |= ((uint32_t) end[n]) << ((n) >= 4 ? (n) * 8 - 32 : 0); \ ++ else \ ++ last.lo |= ((uint32_t) end[n]) << ((n) >= 4 ? 0 : (n) * 8); \ ++ } while (0) ++#endif ++ ++ switch (len % sizeof(uint64_t)) { ++ case 7: ++ OR_BYTE(6); ++ case 6: ++ OR_BYTE(5); ++ case 5: ++ OR_BYTE(4); ++ case 4: ++#if BYTE_ORDER == LITTLE_ENDIAN && UNALIGNED_WORD_ACCESS ++ #if HAVE_UINT64_T ++ last |= (uint64_t) ((uint32_t *) end)[0]; ++ #else ++ last.lo |= ((uint32_t *) end)[0]; ++ #endif ++ break; ++#elif BYTE_ORDER == BIG_ENDIAN ++ OR_BYTE(3); ++#endif ++ case 3: ++ OR_BYTE(2); ++ case 2: ++ OR_BYTE(1); ++ case 1: ++ OR_BYTE(0); ++ break; ++ case 0: ++ break; ++ } ++ ++ SIP_2_ROUND(last, v0, v1, v2, v3); ++ ++ XOR64_INT(v2, 0xff); ++ ++ SIP_COMPRESS(v0, v1, v2, v3); ++ SIP_COMPRESS(v0, v1, v2, v3); ++ SIP_COMPRESS(v0, v1, v2, v3); ++ SIP_COMPRESS(v0, v1, v2, v3); ++ ++ XOR64_TO(v0, v1); ++ XOR64_TO(v0, v2); ++ XOR64_TO(v0, v3); ++ return v0; ++} +--- /dev/null ++++ b/siphash.h +@@ -0,0 +1,48 @@ ++#ifndef SIPHASH_H ++#define SIPHASH_H 1 ++#include <stdlib.h> ++#ifdef HAVE_STDINT_H ++#include <stdint.h> ++#endif ++#ifdef HAVE_INTTYPES_H ++#include <inttypes.h> ++#endif ++ ++#ifndef HAVE_UINT64_T ++typedef struct { ++ uint32_t u32[2]; ++} sip_uint64_t; ++#define uint64_t sip_uint64_t ++#else ++typedef uint64_t sip_uint64_t; ++#endif ++ ++typedef struct { ++ int c; ++ int d; ++ uint64_t v[4]; ++ uint8_t buf[sizeof(uint64_t)]; ++ uint8_t buflen; ++ uint8_t msglen_byte; ++} sip_state; ++ ++typedef struct sip_interface_st sip_interface; ++ ++typedef struct { ++ sip_state state[1]; ++ const sip_interface *methods; ++} sip_hash; ++ ++sip_hash *sip_hash_new(const uint8_t key[16], int c, int d); ++sip_hash *sip_hash_init(sip_hash *h, const uint8_t key[16], int c, int d); ++int sip_hash_update(sip_hash *h, const uint8_t *data, size_t len); ++int sip_hash_final(sip_hash *h, uint8_t **digest, size_t *len); ++int sip_hash_final_integer(sip_hash *h, uint64_t *digest); ++int sip_hash_digest(sip_hash *h, const uint8_t *data, size_t data_len, uint8_t **digest, size_t *digest_len); ++int sip_hash_digest_integer(sip_hash *h, const uint8_t *data, size_t data_len, uint64_t *digest); ++void sip_hash_free(sip_hash *h); ++void sip_hash_dump(sip_hash *h); ++ ++uint64_t sip_hash24(const uint8_t key[16], const uint8_t *data, size_t len); ++ ++#endif +--- a/string.c ++++ b/string.c +@@ -2028,12 +2028,6 @@ + } + + st_index_t +-rb_memhash(const void *ptr, long len) +-{ +- return st_hash(ptr, len, rb_hash_start(0)); +-} +- +-st_index_t + rb_str_hash(VALUE str) + { + int e = ENCODING_GET(str); diff -Nru ruby1.9.1-1.9.2.0/debian/patches/CVE-2013-0269.patch ruby1.9.1-1.9.2.0/debian/patches/CVE-2013-0269.patch --- ruby1.9.1-1.9.2.0/debian/patches/CVE-2013-0269.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby1.9.1-1.9.2.0/debian/patches/CVE-2013-0269.patch 2015-06-23 23:16:22.000000000 +0200 @@ -0,0 +1,563 @@ +Description: fix denial of service and unsafe object creation + vulnerability in JSON. [CVE-2013-0269] +From: NAKAMURA Usaku <u...@ruby-lang.org> +Origin: https://github.com/ruby/ruby/commit/e9e9ec43f5f601782fe841d7364723d6e4975fa7 +Reviewed-by: Cédric Boutillier <bou...@debian.org> +Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=700471 +Last-Update: 2013-02-13 + +--- a/ext/json/lib/json/add/core.rb ++++ b/ext/json/lib/json/add/core.rb +@@ -7,40 +7,64 @@ + end + require 'date' + ++# Symbol serialization/deserialization + class Symbol +- def to_json(*a) ++ # Returns a hash, that will be turned into a JSON object and represent this ++ # object. ++ def as_json(*) + { + JSON.create_id => self.class.name, +- 's' => to_s, +- }.to_json(*a) ++ 's' => to_s, ++ } + end + ++ # Stores class name (Symbol) with String representation of Symbol as a JSON string. ++ def to_json(*a) ++ as_json.to_json(*a) ++ end ++ ++ # Deserializes JSON string by converting the <tt>string</tt> value stored in the object to a Symbol + def self.json_create(o) + o['s'].to_sym + end + end + ++# Time serialization/deserialization + class Time ++ ++ # Deserializes JSON string by converting time since epoch to Time + def self.json_create(object) + if usec = object.delete('u') # used to be tv_usec -> tv_nsec + object['n'] = usec * 1000 + end +- if respond_to?(:tv_nsec) +- at(*object.values_at('s', 'n')) ++ if instance_methods.include?(:tv_nsec) ++ at(object['s'], Rational(object['n'], 1000)) + else + at(object['s'], object['n'] / 1000) + end + end + +- def to_json(*args) ++ # Returns a hash, that will be turned into a JSON object and represent this ++ # object. ++ def as_json(*) ++ nanoseconds = [ tv_usec * 1000 ] ++ respond_to?(:tv_nsec) and nanoseconds << tv_nsec ++ nanoseconds = nanoseconds.max + { + JSON.create_id => self.class.name, +- 's' => tv_sec, +- 'n' => respond_to?(:tv_nsec) ? tv_nsec : tv_usec * 1000 +- }.to_json(*args) ++ 's' => tv_sec, ++ 'n' => nanoseconds, ++ } ++ end ++ ++ # Stores class name (Time) with number of seconds since epoch and number of ++ # microseconds for Time as JSON string ++ def to_json(*args) ++ as_json.to_json(*args) + end + end + ++# Date serialization/deserialization + class Date + def self.json_create(object) + civil(*object.values_at('y', 'm', 'd', 'sg')) +@@ -48,14 +72,22 @@ + + alias start sg unless method_defined?(:start) + +- def to_json(*args) ++ # Returns a hash, that will be turned into a JSON object and represent this ++ # object. ++ def as_json(*) + { + JSON.create_id => self.class.name, + 'y' => year, + 'm' => month, + 'd' => day, + 'sg' => start, +- }.to_json(*args) ++ } ++ end ++ ++ # Stores class name (Date) with Julian year <tt>y</tt>, month <tt>m</tt>, day ++ # <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string ++ def to_json(*args) ++ as_json.to_json(*args) + end + end + +@@ -74,7 +106,9 @@ + + alias start sg unless method_defined?(:start) + +- def to_json(*args) ++ # Returns a hash, that will be turned into a JSON object and represent this ++ # object. ++ def as_json(*) + { + JSON.create_id => self.class.name, + 'y' => year, +@@ -85,7 +119,14 @@ + 'S' => sec, + 'of' => offset.to_s, + 'sg' => start, +- }.to_json(*args) ++ } ++ end ++ ++ # Stores class name (DateTime) with Julian year <tt>y</tt>, month <tt>m</tt>, ++ # day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>, ++ # offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string ++ def to_json(*args) ++ as_json.to_json(*args) + end + end + +@@ -94,11 +135,20 @@ + new(*object['a']) + end + +- def to_json(*args) ++ # Returns a hash, that will be turned into a JSON object and represent this ++ # object. ++ def as_json(*) + { +- JSON.create_id => self.class.name, +- 'a' => [ first, last, exclude_end? ] +- }.to_json(*args) ++ JSON.create_id => self.class.name, ++ 'a' => [ first, last, exclude_end? ] ++ } ++ end ++ ++ # Stores class name (Range) with JSON array of arguments <tt>a</tt> which ++ # include <tt>first</tt> (integer), <tt>last</tt> (integer), and ++ # <tt>exclude_end?</tt> (boolean) as JSON string. ++ def to_json(*args) ++ as_json.to_json(*args) + end + end + +@@ -107,13 +157,21 @@ + new(*object['v']) + end + +- def to_json(*args) ++ # Returns a hash, that will be turned into a JSON object and represent this ++ # object. ++ def as_json(*) + klass = self.class.name + klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" + { + JSON.create_id => klass, +- 'v' => values, +- }.to_json(*args) ++ 'v' => values, ++ } ++ end ++ ++ # Stores class name (Struct) with Struct values <tt>v</tt> as a JSON string. ++ # Only named structs are supported. ++ def to_json(*args) ++ as_json.to_json(*args) + end + end + +@@ -124,12 +182,20 @@ + result + end + +- def to_json(*args) ++ # Returns a hash, that will be turned into a JSON object and represent this ++ # object. ++ def as_json(*) + { + JSON.create_id => self.class.name, +- 'm' => message, +- 'b' => backtrace, +- }.to_json(*args) ++ 'm' => message, ++ 'b' => backtrace, ++ } ++ end ++ ++ # Stores class name (Exception) with message <tt>m</tt> and backtrace array ++ # <tt>b</tt> as JSON string ++ def to_json(*args) ++ as_json.to_json(*args) + end + end + +@@ -138,11 +204,19 @@ + new(object['s'], object['o']) + end + +- def to_json(*) ++ # Returns a hash, that will be turned into a JSON object and represent this ++ # object. ++ def as_json(*) + { + JSON.create_id => self.class.name, +- 'o' => options, +- 's' => source, +- }.to_json ++ 'o' => options, ++ 's' => source, ++ } ++ end ++ ++ # Stores class name (Regexp) with options <tt>o</tt> and source <tt>s</tt> ++ # (Regexp or String) as JSON string ++ def to_json(*) ++ as_json.to_json + end + end +--- a/ext/json/lib/json/common.rb ++++ b/ext/json/lib/json/common.rb +@@ -11,9 +11,9 @@ + # generate and parse for their documentation. + def [](object, opts = {}) + if object.respond_to? :to_str +- JSON.parse(object.to_str, opts => {}) ++ JSON.parse(object.to_str, opts) + else +- JSON.generate(object, opts => {}) ++ JSON.generate(object, opts) + end + end + +@@ -139,7 +139,7 @@ + # the default. + # * *create_additions*: If set to false, the Parser doesn't create + # additions even if a matchin class and create_id was found. This option +- # defaults to true. ++ # defaults to false. + # * *object_class*: Defaults to Hash + # * *array_class*: Defaults to Array + def parse(source, opts = {}) +@@ -160,7 +160,7 @@ + # to true. + # * *create_additions*: If set to false, the Parser doesn't create + # additions even if a matchin class and create_id was found. This option +- # defaults to true. ++ # defaults to false. + def parse!(source, opts = {}) + opts = { + :max_nesting => false, +@@ -279,11 +279,18 @@ + # Load a ruby data structure from a JSON _source_ and return it. A source can + # either be a string-like object, an IO like object, or an object responding + # to the read method. If _proc_ was given, it will be called with any nested +- # Ruby object as an argument recursively in depth first order. ++ # Ruby object as an argument recursively in depth first order. To modify the ++ # default options pass in the optional _options_ argument as well. + # + # This method is part of the implementation of the load/dump interface of + # Marshal and YAML. +- def load(source, proc = nil) ++ def load(source, proc = nil, options = {}) ++ load_default_options = { ++ :max_nesting => false, ++ :allow_nan => true, ++ :create_additions => false ++ } ++ opts = load_default_options.merge options + if source.respond_to? :to_str + source = source.to_str + elsif source.respond_to? :to_io +@@ -291,7 +298,7 @@ + else + source = source.read + end +- result = parse(source, :max_nesting => false, :allow_nan => true) ++ result = parse(source, opts) + recurse_proc(result, &proc) if proc + result + end +@@ -377,11 +384,11 @@ + # + # The _opts_ argument is passed through to generate/parse respectively, see + # generate and parse for their documentation. +- def JSON(object, opts = {}) ++ def JSON(object, *args) + if object.respond_to? :to_str +- JSON.parse(object.to_str, opts) ++ JSON.parse(object.to_str, args.first) + else +- JSON.generate(object, opts) ++ JSON.generate(object, args.first) + end + end + end +--- a/ext/json/parser/parser.c ++++ b/ext/json/parser/parser.c +@@ -438,7 +438,7 @@ + #line 160 "parser.rl" + + if (cs >= JSON_object_first_final) { +- if (RTEST(json->create_id)) { ++ if (json->create_additions) { + VALUE klassname = rb_hash_aref(*result, json->create_id); + if (!NIL_P(klassname)) { + VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname); +@@ -1604,6 +1604,9 @@ + * defaults to true. + * * *object_class*: Defaults to Hash + * * *array_class*: Defaults to Array ++ * * *quirks_mode*: Enables quirks_mode for parser, that is for example ++ * parsing single JSON values instead of documents is possible. ++ * + */ + static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) + { +@@ -1648,12 +1651,15 @@ + } + tmp = ID2SYM(i_create_additions); + if (option_given_p(opts, tmp)) { +- VALUE create_additions = rb_hash_aref(opts, tmp); +- if (RTEST(create_additions)) { +- json->create_id = rb_funcall(mJSON, i_create_id, 0); +- } else { +- json->create_id = Qnil; +- } ++ json->create_additions = RTEST(rb_hash_aref(opts, tmp)); ++ json->create_id = rb_funcall(mJSON, i_create_id, 0); ++ } else { ++ json->create_additions = 0; ++ json->create_id = Qnil; ++ } ++ tmp = ID2SYM(i_create_id); ++ if (option_given_p(opts, tmp)) { ++ json->create_id = rb_hash_aref(opts, tmp); + } else { + json->create_id = rb_funcall(mJSON, i_create_id, 0); + } +@@ -1673,6 +1679,7 @@ + } else { + json->max_nesting = 19; + json->allow_nan = 0; ++ json->create_additions = 1; + json->create_id = rb_funcall(mJSON, i_create_id, 0); + json->object_class = Qnil; + json->array_class = Qnil; +--- a/ext/json/parser/parser.rl ++++ b/ext/json/parser/parser.rl +@@ -159,7 +159,7 @@ + %% write exec; + + if (cs >= JSON_object_first_final) { +- if (RTEST(json->create_id)) { ++ if (json->create_additions) { + VALUE klassname = rb_hash_aref(*result, json->create_id); + if (!NIL_P(klassname)) { + VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname); +@@ -602,6 +602,9 @@ + * defaults to true. + * * *object_class*: Defaults to Hash + * * *array_class*: Defaults to Array ++ * * *quirks_mode*: Enables quirks_mode for parser, that is for example ++ * parsing single JSON values instead of documents is possible. ++ * + */ + static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) + { +@@ -646,12 +649,15 @@ + } + tmp = ID2SYM(i_create_additions); + if (option_given_p(opts, tmp)) { +- VALUE create_additions = rb_hash_aref(opts, tmp); +- if (RTEST(create_additions)) { +- json->create_id = rb_funcall(mJSON, i_create_id, 0); +- } else { +- json->create_id = Qnil; +- } ++ json->create_additions = RTEST(rb_hash_aref(opts, tmp)); ++ json->create_id = rb_funcall(mJSON, i_create_id, 0); ++ } else { ++ json->create_additions = 0; ++ json->create_id = Qnil; ++ } ++ tmp = ID2SYM(i_create_id); ++ if (option_given_p(opts, tmp)) { ++ json->create_id = rb_hash_aref(opts, tmp); + } else { + json->create_id = rb_funcall(mJSON, i_create_id, 0); + } +@@ -671,6 +677,7 @@ + } else { + json->max_nesting = 19; + json->allow_nan = 0; ++ json->create_additions = 1; + json->create_id = rb_funcall(mJSON, i_create_id, 0); + json->object_class = Qnil; + json->array_class = Qnil; +--- a/test/json/test_json.rb ++++ b/test/json/test_json.rb +@@ -8,6 +8,7 @@ + else require 'json' + end + require 'stringio' ++require 'tempfile' + + unless Array.method_defined?(:permutation) + begin +@@ -309,6 +310,25 @@ + JSON.parse('{"foo":"bar", "baz":"quux"}', :symbolize_names => true)) + end + ++ def test_load ++ assert_equal @hash, JSON.load(@json) ++ tempfile = Tempfile.open('json') ++ tempfile.write @json ++ tempfile.rewind ++ assert_equal @hash, JSON.load(tempfile) ++ stringio = StringIO.new(@json) ++ stringio.rewind ++ assert_equal @hash, JSON.load(stringio) ++ assert_raise(NoMethodError) { JSON.load(nil) } ++ assert_raise(JSON::ParserError) {JSON.load('') } ++ end ++ ++ def test_load_with_options ++ small_hash = JSON("foo" => 'bar') ++ symbol_hash = { :foo => 'bar' } ++ assert_equal symbol_hash, JSON.load(small_hash, nil, :symbolize_names => true) ++ end ++ + def test_load_dump + too_deep = '[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]' + assert_equal too_deep, JSON.dump(eval(too_deep)) +--- a/test/json/test_json_addition.rb ++++ b/test/json/test_json_addition.rb +@@ -64,11 +64,19 @@ + a = A.new(666) + assert A.json_creatable? + json = generate(a) +- a_again = JSON.parse(json) ++ a_again = JSON.parse(json, :create_additions => true) + assert_kind_of a.class, a_again + assert_equal a, a_again + end + ++ def test_extended_json_default ++ a = A.new(666) ++ assert A.json_creatable? ++ json = generate(a) ++ a_hash = JSON.parse(json) ++ assert_kind_of Hash, a_hash ++ end ++ + def test_extended_json_disabled + a = A.new(666) + assert A.json_creatable? +@@ -95,7 +103,7 @@ + c = C.new + assert !C.json_creatable? + json = generate(c) +- assert_raises(ArgumentError, NameError) { JSON.parse(json) } ++ assert_raises(ArgumentError, NameError) { JSON.parse(json, :create_additions => true) } + end + + def test_raw_strings +@@ -113,7 +121,7 @@ + assert_match /\A\{.*\}\Z/, json + assert_match /"json_class":"String"/, json + assert_match /"raw":\[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255\]/, json +- raw_again = JSON.parse(json) ++ raw_again = JSON.parse(json, :create_additions => true) + assert_equal raw, raw_again + end + +@@ -121,17 +129,17 @@ + + def test_core + t = Time.now +- assert_equal t.inspect, JSON(JSON(t)).inspect ++ assert_equal t, JSON(JSON(t), :create_additions => true) + d = Date.today +- assert_equal d, JSON(JSON(d)) ++ assert_equal d, JSON(JSON(d), :create_additions => true) + d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161) +- assert_equal d, JSON(JSON(d)) +- assert_equal 1..10, JSON(JSON(1..10)) +- assert_equal 1...10, JSON(JSON(1...10)) +- assert_equal "a".."c", JSON(JSON("a".."c")) +- assert_equal "a"..."c", JSON(JSON("a"..."c")) ++ assert_equal d, JSON(JSON(d), :create_additions => true) ++ assert_equal 1..10, JSON(JSON(1..10), :create_additions => true) ++ assert_equal 1...10, JSON(JSON(1...10), :create_additions => true) ++ assert_equal "a".."c", JSON(JSON("a".."c"), :create_additions => true) ++ assert_equal "a"..."c", JSON(JSON("a"..."c"), :create_additions => true) + s = MyJsonStruct.new 4711, 'foot' +- assert_equal s, JSON(JSON(s)) ++ assert_equal s, JSON(JSON(s), :create_additions => true) + struct = Struct.new :foo, :bar + s = struct.new 4711, 'foot' + assert_raises(JSONError) { JSON(s) } +@@ -139,24 +147,24 @@ + raise TypeError, "test me" + rescue TypeError => e + e_json = JSON.generate e +- e_again = JSON e_json ++ e_again = JSON e_json, :create_additions => true + assert_kind_of TypeError, e_again + assert_equal e.message, e_again.message + assert_equal e.backtrace, e_again.backtrace + end +- assert_equal(/foo/, JSON(JSON(/foo/))) +- assert_equal(/foo/i, JSON(JSON(/foo/i))) ++ assert_equal(/foo/, JSON(JSON(/foo/), :create_additions => true)) ++ assert_equal(/foo/i, JSON(JSON(/foo/i), :create_additions => true)) + end + + def test_utc_datetime + now = Time.now +- d = DateTime.parse(now.to_s) # usual case +- assert_equal d, JSON.parse(d.to_json) ++ d = DateTime.parse(now.to_s, :create_additions => true) # usual case ++ assert_equal d, JSON.parse(d.to_json, :create_additions => true) + d = DateTime.parse(now.utc.to_s) # of = 0 +- assert_equal d, JSON.parse(d.to_json) ++ assert_equal d, JSON.parse(d.to_json, :create_additions => true) + d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(1,24)) +- assert_equal d, JSON.parse(d.to_json) ++ assert_equal d, JSON.parse(d.to_json, :create_additions => true) + d = DateTime.civil(2008, 6, 17, 11, 48, 32, Rational(12,24)) +- assert_equal d, JSON.parse(d.to_json) ++ assert_equal d, JSON.parse(d.to_json, :create_additions => true) + end + end +--- a/ext/json/parser/parser.h ++++ b/ext/json/parser/parser.h +@@ -39,8 +39,10 @@ + int allow_nan; + int parsing_name; + int symbolize_names; ++ int quirks_mode; + VALUE object_class; + VALUE array_class; ++ int create_additions; + } JSON_Parser; + + #define GET_PARSER \ diff -Nru ruby1.9.1-1.9.2.0/debian/patches/series ruby1.9.1-1.9.2.0/debian/patches/series --- ruby1.9.1-1.9.2.0/debian/patches/series 2015-05-30 19:47:58.000000000 +0200 +++ ruby1.9.1-1.9.2.0/debian/patches/series 2015-06-23 22:44:07.000000000 +0200 @@ -68,3 +68,5 @@ #XXX todo: CVE-2012-5371 #XXX todo: CVE-2013-0269 +CVE-2013-0269.patch +CVE-2012-5371.patch
signature.asc
Description: Digital signature