[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Ruby 1.9.1 Squeeze package for test



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


Reply to: