src/share/classes/com/sun/jndi/dns/ResourceRecord.java

Print this page
rev 9296 : Detect compression loops in the JNDI DNS client

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -82,10 +82,15 @@
      */
     static final String rrClassNames[] = {
         null, "IN", null, null, "HS"
     };
 
+    /*
+     * Maximum number of compression references in labels.
+     * Used to detect compression loops.
+     */
+    private static final int MAXIMUM_COMPRESSION_REFERENCES = 16;
 
     byte[] msg;                 // DNS message
     int msgLen;                 // msg size (in octets)
     boolean qSection;           // true if this RR is part of question section
                                 // and therefore has no ttl or rdata

@@ -237,11 +242,11 @@
      */
     private void decode(boolean decodeRdata) throws InvalidNameException {
         int pos = offset;       // index of next unread octet
 
         name = new DnsName();                           // NAME
-        pos = decodeName(pos, name);
+        pos = decodeName(pos, name, 0);
 
         rrtype = getUShort(pos);                        // TYPE
         rrtypeName = (rrtype < rrTypeNames.length)
             ? rrTypeNames[rrtype]
             : null;

@@ -316,33 +321,37 @@
     /*
      * Returns the name encoded at msg[pos], including the root label.
      */
     private DnsName decodeName(int pos) throws InvalidNameException {
         DnsName n = new DnsName();
-        decodeName(pos, n);
+        decodeName(pos, n, 0);
         return n;
     }
 
     /*
      * Prepends to "n" the domain name encoded at msg[pos], including the root
      * label.  Returns the index into "msg" following the name.
      */
-    private int decodeName(int pos, DnsName n) throws InvalidNameException {
+    private int decodeName(int pos, DnsName n, int level)
+        throws InvalidNameException {
+        if (level > MAXIMUM_COMPRESSION_REFERENCES) {
+            throw new InvalidNameException("Too many compression references");
+        }
         if (msg[pos] == 0) {                            // end of name
             n.add(0, "");
             return (pos + 1);
         } else if ((msg[pos] & 0xC0) != 0) {            // name compression
-            decodeName(getUShort(pos) & 0x3FFF, n);
+            decodeName(getUShort(pos) & 0x3FFF, n, level + 1);
             return (pos + 2);
         } else {                                        // append a label
             int len = msg[pos++];
             try {
                 n.add(0, new String(msg, pos, len, "ISO-8859-1"));
             } catch (java.io.UnsupportedEncodingException e) {
                 // assert false : "ISO-Latin-1 charset unavailable";
             }
-            return decodeName(pos + len, n);
+            return decodeName(pos + len, n, level);
         }
     }
 
     /*
      * Returns the rdata encoded at msg[pos].  The format is dependent

@@ -396,13 +405,13 @@
     /*
      * Returns the rdata of an SOA record that is encoded at msg[pos].
      */
     private String decodeSoa(int pos) throws InvalidNameException {
         DnsName mname = new DnsName();
-        pos = decodeName(pos, mname);
+        pos = decodeName(pos, mname, 0);
         DnsName rname = new DnsName();
-        pos = decodeName(pos, rname);
+        pos = decodeName(pos, rname, 0);
 
         long serial = getUInt(pos);
         pos += 4;
         long refresh = getUInt(pos);
         pos += 4;