[SCM] 100% pure-Java implementation of Ruby branch, master, updated. debian/1.5.6-4-1-g269541e

Martin Quinson martin.quinson at loria.fr
Mon Dec 10 23:33:32 UTC 2012


The following commit has been merged in the master branch:
commit 269541e69d0471aaf41bcf8006feb5f434aa3be5
Author: Martin Quinson <martin.quinson at loria.fr>
Date:   Tue Dec 11 00:25:40 2012 +0100

    New patch to drop MurmurHash and use SipHash instead to fix CVE-2012-5370

diff --git a/debian/changelog b/debian/changelog
index cf38d87..3bf73b9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+jruby (1.5.6-5) UNRELEASED; urgency=low
+
+  * Team upload.
+  * Add patch for CVE-2012-5370: Use SipHash instead of MurmurHash
+    (that is vulnerable to DoS attacks). (Closes: #694694)
+
+ -- Martin Quinson <mquinson at debian.org>  Tue, 11 Dec 2012 00:07:45 +0100
+
 jruby (1.5.6-4) unstable; urgency=medium
 
   * Team upload.
diff --git a/debian/patches/0009-CVE-2012-5370.patch b/debian/patches/0009-CVE-2012-5370.patch
new file mode 100644
index 0000000..677a058
--- /dev/null
+++ b/debian/patches/0009-CVE-2012-5370.patch
@@ -0,0 +1,325 @@
+Drop the MurmurHash to compute hashes, as it is vulnerable to a DoS:
+A specially-crafted set of keys could trigger Murmur hash function
+collisions, which degrade hash table items insert performance by
+changing hash table operations complexity from an expected/average
+O(n) to the worst case O(n^2). Reporters were able to find colliding
+strings efficiently using equivalent substrings.
+
+Use SipHash instead, as it was done in the C implementation of Ruby.
+
+Index: jruby-1.5.6/src/org/jruby/util/MurmurHash.java
+===================================================================
+--- jruby-1.5.6.orig/src/org/jruby/util/MurmurHash.java	2012-12-10 23:38:21.827577622 +0100
++++ /dev/null	1970-01-01 00:00:00.000000000 +0000
+@@ -1,62 +0,0 @@
+-package org.jruby.util;
+-
+-public class MurmurHash {
+-    // Based on Murmurhash 2.0 Java port at http://dmy999.com/article/50/murmurhash-2-java-port
+-    // 2011-12-05: Modified by Hiroshi Nakamura <nahi at ruby-lang.org>
+-    // - signature change to use offset
+-    //   hash(byte[] data, int seed) to hash(byte[] src, int offset, int length, int seed)
+-    // - extract 'm' and 'r' as murmurhash2.0 constants
+-
+-    // Ported by Derek Young from the C version (specifically the endian-neutral
+-    // version) from:
+-    //   http://murmurhash.googlepages.com/
+-    //
+-    // released to the public domain - dmy999 at gmail.com
+-
+-    // 'm' and 'r' are mixing constants generated offline.
+-    // They're not really 'magic', they just happen to work well.
+-    private static final int MURMUR2_MAGIC = 0x5bd1e995;
+-    // CRuby 1.9 uses 16 but original C++ implementation uses 24 with above Magic.
+-    private static final int MURMUR2_R = 24;
+-
+-    @SuppressWarnings("fallthrough")
+-    public static int hash32(byte[] src, int offset, int length, int seed) {
+-        // Initialize the hash to a 'random' value
+-        int h = seed ^ length;
+-
+-        int i = offset;
+-        int len = length;
+-        while (len >= 4) {
+-            int k = src[i + 0] & 0xFF;
+-            k |= (src[i + 1] & 0xFF) << 8;
+-            k |= (src[i + 2] & 0xFF) << 16;
+-            k |= (src[i + 3] & 0xFF) << 24;
+-
+-            k *= MURMUR2_MAGIC;
+-            k ^= k >>> MURMUR2_R;
+-            k *= MURMUR2_MAGIC;
+-
+-            h *= MURMUR2_MAGIC;
+-            h ^= k;
+-
+-            i += 4;
+-            len -= 4;
+-        }
+-
+-        switch (len) {
+-        case 3:
+-            h ^= (src[i + 2] & 0xFF) << 16;
+-        case 2:
+-            h ^= (src[i + 1] & 0xFF) << 8;
+-        case 1:
+-            h ^= (src[i + 0] & 0xFF);
+-            h *= MURMUR2_MAGIC;
+-        }
+-
+-        h ^= h >>> 13;
+-        h *= MURMUR2_MAGIC;
+-        h ^= h >>> 15;
+-
+-        return h;
+-    }
+-}
+Index: jruby-1.5.6/src/org/jruby/RubyString.java
+===================================================================
+--- jruby-1.5.6.orig/src/org/jruby/RubyString.java	2012-12-10 23:38:21.827577622 +0100
++++ jruby-1.5.6/src/org/jruby/RubyString.java	2012-12-10 23:43:27.737909143 +0100
+@@ -91,7 +91,7 @@
+ import org.jruby.runtime.marshal.UnmarshalStream;
+ import org.jruby.util.ByteList;
+ import org.jruby.util.ConvertBytes;
+-import org.jruby.util.MurmurHash;
++import org.jruby.util.SipHash;
+ import org.jruby.util.Numeric;
+ import org.jruby.util.Pack;
+ import org.jruby.util.Sprintf;
+@@ -1025,7 +1025,7 @@
+     }
+ 
+     private int strHashCode(Ruby runtime) {
+-        int hash = MurmurHash.hash32(value.getUnsafeBytes(), value.getBegin(), value.getRealSize(), runtime.getHashSeed());
++        int hash = SipHash.hash32(value.getUnsafeBytes(), value.getBegin(), value.getRealSize(), runtime.getHashSeed());
+         if (runtime.is1_9()) {
+             hash ^= (value.getEncoding().isAsciiCompatible() && scanForCodeRange() == CR_7BIT ? 0 : value.getEncoding().getIndex());
+         }
+Index: jruby-1.5.6/src/org/jruby/util/SipHash.java
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ jruby-1.5.6/src/org/jruby/util/SipHash.java	2012-12-10 23:51:14.867456445 +0100
+@@ -0,0 +1,190 @@
++package org.jruby.util;
++
++/**
++ * Original author: <a href="mailto:Martin.Bosslet at googlemail.com">Martin Bosslet</a>
++ * Original license: 
++ *   Copyright (c) 2012 Martin Boßlet
++ *   
++ *   Permission is hereby granted, free of charge, to any person obtaining
++ *   a copy of this software and associated documentation files (the
++ *   "Software"), to deal in the Software without restriction, including
++ *   without limitation the rights to use, copy, modify, merge, publish,
++ *   distribute, sublicense, and/or sell copies of the Software, and to
++ *   permit persons to whom the Software is furnished to do so, subject to
++ *   the following conditions:
++ *   
++ *   The above copyright notice and this permission notice shall be
++ *   included in all copies or substantial portions of the Software.
++ *   
++ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++ *   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++ *   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++ *   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++ *   
++ * Adapted by Martin Quinson (mquinson at debian.org) to accept the hash32 prototype that is used in jruby.
++ *   (same license applies)
++ * 
++ */
++public class SipHash {
++    public static int hash32(byte[] src, int offset, int length, byte[] seed) {
++        long m;
++        State s = new State(new SipKey(seed));
++        int iter = length / 8;
++        
++        for(int i=0; i < iter; i++) {
++            m = UnsignedInt64.binToIntOffset(src, (i * 8) + offset);
++            s.processBlock(m);
++        }
++        
++        m = lastBlock(src, offset, length, iter);
++        s.processBlock(m);
++        s.finish();
++        return s.digest32();
++        
++    }
++    
++    private static long lastBlock(byte[] data, int offset, int length, int iter) {
++        long last = ((long) length) << 56;
++        int off = iter * 8+offset;
++
++        switch (length % 8) {
++            case 7: 
++                last |= ((long) data[off + 6]) << 48;
++            case 6:
++                last |= ((long) data[off + 5]) << 40;
++            case 5:
++                last |= ((long) data[off + 4]) << 32;
++            case 4:
++                last |= ((long) data[off + 3]) << 24;
++            case 3:
++                last |= ((long) data[off + 2]) << 16;
++            case 2:
++                last |= ((long) data[off + 1]) << 8;
++            case 1:
++                last |= (long) data[off];
++                break;
++            case 0:
++                break;
++        }
++        return last;
++    }
++    
++    private static class State {
++        private long v0;
++        private long v1;
++        private long v2;
++        private long v3;
++        
++        public State(SipKey key) {
++            v0 = 0x736f6d6570736575L;
++            v1 = 0x646f72616e646f6dL;
++            v2 = 0x6c7967656e657261L;
++            v3 = 0x7465646279746573L;
++            
++            long k0 = key.getLeftHalf();
++            long k1 = key.getRightHalf();
++            
++            v0 ^= k0;
++            v1 ^= k1;
++            v2 ^= k0;
++            v3 ^= k1;
++        }
++
++        private void compress() {
++            v0 += v1;
++            v2 += v3;
++            v1 = UnsignedInt64.rotateLeft(v1, 13);
++            v3 = UnsignedInt64.rotateLeft(v3, 16);
++            v1 ^= v0;
++            v3 ^= v2;
++            v0 = UnsignedInt64.rotateLeft(v0, 32);
++            v2 += v1;
++            v0 += v3;
++            v1 = UnsignedInt64.rotateLeft(v1, 17);
++            v3 = UnsignedInt64.rotateLeft(v3, 21);
++            v1 ^= v2;
++            v3 ^= v0;
++            v2 = UnsignedInt64.rotateLeft(v2, 32);
++        }
++        
++        private void compressTimes(int times) {
++            for (int i=0; i < times; i++) {
++                compress();
++            }
++        }
++        
++        public void processBlock(long m) {
++            v3 ^= m;
++            compressTimes(2);
++            v0 ^= m;
++        }
++        
++        public void finish() {
++            v2 ^= 0xff;
++            compressTimes(4);
++        }
++        
++        public long digest() {
++            return v0 ^ v1 ^ v2 ^ v3;
++        }
++        public int digest32() {
++            long res = digest();
++            return ((int) (res & 0xFFFFFFFF)) ^ ((int) (res >>> 32));
++        }
++    }   
++}
++
++class SipKey {
++    private final byte[] key;
++    
++    public SipKey(byte[] key) {
++        if (key == null || key.length != 16)
++            throw new RuntimeException("SipHash key must be 16 bytes");
++        this.key = key;
++    }
++    
++    long getLeftHalf() {
++       return UnsignedInt64.binToIntOffset(key, 0); 
++    }
++    
++    long getRightHalf() {
++        return UnsignedInt64.binToIntOffset(key, 8); 
++    }
++}
++
++class UnsignedInt64 {
++    private UnsignedInt64() {}
++    
++    public static long binToInt(byte[] b) {
++        return  binToIntOffset(b, 0);
++    }
++    
++    public static long binToIntOffset(byte[] b, int off) {
++        return ((long) b[off    ])       |
++               ((long) b[off + 1]) << 8  |
++               ((long) b[off + 2]) << 16 |
++               ((long) b[off + 3]) << 24 |
++               ((long) b[off + 4]) << 32 |
++               ((long) b[off + 5]) << 40 |
++               ((long) b[off + 6]) << 48 |
++               ((long) b[off + 7]) << 56;
++    }
++    
++    public static void intToBin(long l, byte[] b) {
++        b[0] = (byte) ( l         & 0xff);
++        b[1] = (byte) ((l >>> 8 ) & 0xff);
++        b[2] = (byte) ((l >>> 16) & 0xff);
++        b[3] = (byte) ((l >>> 24) & 0xff);
++        b[4] = (byte) ((l >>> 32) & 0xff);
++        b[5] = (byte) ((l >>> 40) & 0xff);
++        b[6] = (byte) ((l >>> 48) & 0xff);
++        b[7] = (byte) ((l >>> 56) & 0xff);
++    }
++    
++    public static long rotateLeft(long l, int shift) {
++        return (l << shift) | l >>> (64 - shift);
++    }
++}
+Index: jruby-1.5.6/src/org/jruby/Ruby.java
+===================================================================
+--- jruby-1.5.6.orig/src/org/jruby/Ruby.java	2012-12-10 23:38:21.827577622 +0100
++++ jruby-1.5.6/src/org/jruby/Ruby.java	2012-12-10 23:43:28.377922386 +0100
+@@ -270,7 +270,8 @@
+         this.jitCompiler        = new JITCompiler(this);
+         this.parserStats        = new ParserStats(this);
+ 
+-	this.hashSeed = this.random.nextInt();
++	this.hashSeed = new byte[16];
++	this.random.nextBytes(hashSeed);
+         
+         this.beanManager.register(new Config(this));
+         this.beanManager.register(parserStats);
+@@ -3707,7 +3708,7 @@
+         return jittedMethods;
+     }
+ 
+-    public int getHashSeed() {
++    public byte[] getHashSeed() {
+         return hashSeed;
+     }
+     
+@@ -3815,7 +3816,7 @@
+     private long randomSeedSequence = 0;
+     private Random random = new Random();
+     /** The runtime-local seed for hash randomization */
+-    private int hashSeed = 0;
++    private byte[] hashSeed;
+ 
+     private final List<EventHook> eventHooks = new Vector<EventHook>();
+     private boolean hasEventHooks;  
diff --git a/debian/patches/series b/debian/patches/series
index c0a8698..8068527 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -6,3 +6,4 @@
 0006-do-not-build-InvokeDynamicSupport.java.patch
 0007-use-unversioned-jarjar.jar.patch
 0008-CVE-2011-4838.patch
+0009-CVE-2012-5370.patch

-- 
100% pure-Java implementation of Ruby



More information about the pkg-java-commits mailing list