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

Re: Ruby 1.9.1 Squeeze package for test



Hi Santiago,
On Wed, Jun 24, 2015 at 10:16:08PM +0200, Santiago Ruano Rincón wrote:
> 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

Minor nitpick: I think these can be dropped now that the CVEs are
fixed.

Apart from that I noticed this behaviour change due to the fix for
CVE-2013-0269 (based on [1]):

Squeeze version:
     # cat <<EOF | ruby1.9.1                                                                         
     require 'json'
     p JSON.parse('{"json_class":"foo"}')['json_class']
     EOF
     Outputs: /usr/lib/ruby/1.9.1/json/common.rb:39:in `const_defined?': wrong constant name foo (NameError)
	from /usr/lib/ruby/1.9.1/json/common.rb:39:in `block in deep_const_get'
	from /usr/lib/ruby/1.9.1/json/common.rb:36:in `each'
	from /usr/lib/ruby/1.9.1/json/common.rb:36:in `inject'
	from /usr/lib/ruby/1.9.1/json/common.rb:36:in `deep_const_get'
	from /usr/lib/ruby/1.9.1/json/common.rb:146:in `parse'
	from /usr/lib/ruby/1.9.1/json/common.rb:146:in `parse'
	from -:2:in `<main>'

Your fixed version:

    # cat <<EOF | ruby1.9.1 
    require 'json'
    p JSON.parse('{"json_class":"foo"}')['json_class']
    EOF
    Outputs: "foo"

I just wonder if there could be any code out there that relies on the
first version throwing NameError and if we'd need to mention this in the
DLA?

Cheers,
 -- Guido

[1]: https://www.ruby-lang.org/en/news/2013/02/22/json-dos-cve-2013-0269/



Reply to: