mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
5 hours ago bfed0b8f320aa15d24da84ffe117d166a5b062bd
Fix java/tainted-arithmetic CodeQL alerts (#765)
6 files modified
81 ■■■■ changed files
opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteSequenceReader.java 6 ●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/GeneralizedTime.java 27 ●●●● patch | view | raw | blame | history
opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteSequenceReaderTest.java 9 ●●●●● patch | view | raw | blame | history
opendj-core/src/test/java/org/forgerock/opendj/ldap/GeneralizedTimeTest.java 7 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/replication/common/CSN.java 5 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/common/CSNTest.java 27 ●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteSequenceReader.java
@@ -499,7 +499,11 @@
     *             of the underlying byte sequence.
     */
    public void skip(final int length) {
        position(pos + length);
        final long newPos = (long) pos + length;
        if (newPos < 0 || newPos > sequence.length()) {
            throw new IndexOutOfBoundsException();
        }
        position((int) newPos);
    }
    @Override
opendj-core/src/main/java/org/forgerock/opendj/ldap/GeneralizedTime.java
@@ -12,6 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2012-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.forgerock.opendj.ldap;
@@ -653,15 +654,35 @@
            throw new LocalizedIllegalArgumentException(message);
        }
        final Double fractionValue = Double.parseDouble(fractionBuffer.toString());
        final int additionalMilliseconds = (int) Math.round(fractionValue * multiplier);
        final double fractionValue;
        try {
            fractionValue = Double.parseDouble(fractionBuffer.toString());
        } catch (final NumberFormatException e) {
            final LocalizableMessage message =
                    WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME.get(value, fractionBuffer);
            throw new LocalizedIllegalArgumentException(message, e);
        }
        if (fractionValue < 0.0d || fractionValue >= 1.0d) {
            // "0." followed by 17 nines parses as exactly 1.0, so reject before scaling.
            final LocalizableMessage message =
                    WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME.get(value, fractionBuffer);
            throw new LocalizedIllegalArgumentException(message);
        }
        final long additionalMilliseconds = Math.round(fractionValue * multiplier);
        if (additionalMilliseconds >= multiplier) {
            // 16 nines: 0.9999999999999999 * 1000 still rounds up to 1000. The calendar below
            // only validates lazily, so reject the out-of-range value here.
            final LocalizableMessage message =
                    WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME.get(value, fractionBuffer);
            throw new LocalizedIllegalArgumentException(message);
        }
        try {
            final GregorianCalendar calendar = new GregorianCalendar();
            calendar.setLenient(false);
            calendar.setTimeZone(timeZone);
            calendar.set(year, month, day, hour, minute, second);
            calendar.set(Calendar.MILLISECOND, additionalMilliseconds);
            calendar.set(Calendar.MILLISECOND, (int) additionalMilliseconds);
            return new GeneralizedTime(calendar, null, Long.MIN_VALUE, value);
        } catch (final Exception e) {
            // This should only happen if the provided date wasn't legal
opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteSequenceReaderTest.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2009 Sun Microsystems, Inc.
 * Portions Copyright 2014-2015 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.forgerock.opendj.ldap;
@@ -347,6 +348,14 @@
        reader.skip(1);
    }
    @Test(dataProvider = "readerProvider", expectedExceptions = IndexOutOfBoundsException.class)
    public void testSkipOverflow(ByteSequenceReader reader, byte[] ba) {
        reader.rewind();
        reader.skip(ba.length);
        // pos + Integer.MAX_VALUE overflows int; must throw, not wrap around.
        reader.skip(Integer.MAX_VALUE);
    }
    @Test(dataProvider = "readerProvider")
    public void testPeek(ByteSequenceReader reader, byte[] ba) {
        reader.rewind();
opendj-core/src/test/java/org/forgerock/opendj/ldap/GeneralizedTimeTest.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2009 Sun Microsystems, Inc.
 * Portions copyright 2012-2015 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.forgerock.opendj.ldap;
@@ -67,7 +68,11 @@
            { "2006122a235959Z" }, { "20060031235959Z" }, { "20061331235959Z" },
            { "20062231235959Z" }, { "20061232235959Z" }, { "2006123123595aZ" },
            { "200a1231235959Z" }, { "2006j231235959Z" }, { "200612-1235959Z" },
            { "20061231#35959Z" }, { "2006" }, };
            { "20061231#35959Z" }, { "2006" },
            // Double.parseDouble rounds 17 nines up to exactly 1.0.
            { "20240101000000.99999999999999999Z" },
            // 16 nines stay below 1.0 but scale and round to 1000 milliseconds.
            { "20240101000000.9999999999999999Z" }, };
    }
    @Test
opendj-server-legacy/src/main/java/org/opends/server/replication/common/CSN.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2006-2009 Sun Microsystems, Inc.
 * Portions Copyright 2013-2015 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.replication.common;
@@ -319,11 +320,11 @@
    }
    else if (csn1.seqnum != csn2.seqnum)
    {
      return csn1.seqnum - csn2.seqnum;
      return Integer.compare(csn1.seqnum, csn2.seqnum);
    }
    else
    {
      return csn1.serverId - csn2.serverId;
      return Integer.compare(csn1.serverId, csn2.serverId);
    }
  }
opendj-server-legacy/src/test/java/org/opends/server/replication/common/CSNTest.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2006-2009 Sun Microsystems, Inc.
 * Portions Copyright 2013-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.replication.common;
@@ -77,9 +78,9 @@
  @DataProvider(name = "createCSN")
  public Object[][] createCSNData()
  {
    long time[] = {1, TimeThread.getTime()};
    int seq[] = {0,  123};
    int id [] = {1,  45};
    long time[] = {1, TimeThread.getTime(), 1, 1};
    int seq[] = {0,  123, Integer.MIN_VALUE, Integer.MAX_VALUE - 1};
    int id [] = {1,  45, 1, 1};
    Object[][] obj = new Object[time.length][5];
    for (int i=0; i<time.length; i++)
@@ -140,6 +141,26 @@
    assertTrue(CSN.compare(csn5, csn1) > 0);
  }
  /**
   * Test that {@link CSN#compare(CSN, CSN)} orders extreme seqnums correctly and
   * transitively: subtraction-based comparison overflowed for MIN_VALUE vs
   * MAX_VALUE at equal timestamps and inverted the sign, which is fatal for
   * TreeMaps keyed on CSN.
   */
  @Test
  public void csnCompareExtremeSeqnums() throws Exception
  {
    final CSN minSeqnum = new CSN(1, Integer.MIN_VALUE, 1);
    final CSN zeroSeqnum = new CSN(1, 0, 1);
    final CSN maxSeqnum = new CSN(1, Integer.MAX_VALUE, 1);
    assertTrue(CSN.compare(minSeqnum, zeroSeqnum) < 0);
    assertTrue(CSN.compare(zeroSeqnum, maxSeqnum) < 0);
    assertTrue(CSN.compare(minSeqnum, maxSeqnum) < 0);
    assertTrue(CSN.compare(maxSeqnum, minSeqnum) > 0);
    assertEquals(CSN.compare(maxSeqnum, maxSeqnum), 0);
  }
  /** Test {@link CSN#isOlderThan(CSN)} method. */
  @Test(dataProvider = "createCSN")
  public void csnOlder(CSN csn1, CSN csn2, CSN csn3, CSN csn4, CSN csn5) throws Exception