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 <santiagorr@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 <james@yob.id.au>
+Reviewed-By: Antonio Terceiro <terceiro@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 <usa@ruby-lang.org>
+Origin: https://github.com/ruby/ruby/commit/e9e9ec43f5f601782fe841d7364723d6e4975fa7
+Reviewed-by: Cédric Boutillier <boutil@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
Attachment:
signature.asc
Description: Digital signature