2023.09.06

CVE-2021-39659 A-208267659 DoS 10、11、12

patch

Fix sorting issue during emergency call attempt.

Fix the integer overflow/underflow caused by sorting of duplicate phoneaccounts during emergency call attempt.

分析

是我孤陋寡闻了,以前没注意过Java还会整数溢出:

Java的int是32位有符号整数类型,其最大值是0x7fffffff,最小值则是0x80000000,和C语言一样。即int表示的数的范围是-2147483648 ~ 2147483647之间。

下面的代码会根据package、label和hashcode等进行排序,但是在根据hashcode排序的时候,直接返回account1.hashCode() - account2.hashCode() ,这就可能导致整数上溢/下溢,从而导致排序出错。

// hashCode 返回的是int类型的值
public int hashCode()

比如:

  • account1.hashCode() < account2.hashCode() ,但是两者相减可能导致整数下溢,返回正数(表示前者大于后者,与真实情况不符)
    • 极端情况举例:Integer.MIN_VALUE - 1 == 2147483647
  • account1.hashCode() > account2.hashCode() ,但是两者相加可能导致整数上溢,返回负数(表示前者小于后者,与真实情况不符)
    • 极端情况举例:Integer.MAX_VALUE + 1 == -2147483648
    public void sortSimPhoneAccountsForEmergency(List<PhoneAccount> accounts,
            PhoneAccount userPreferredAccount) {
        // Sort the accounts according to how we want to display them (ascending order).
        accounts.sort((account1, account2) -> {
            ......
              
            // Then order by package
            String pkg1 = account1.getAccountHandle().getComponentName().getPackageName();
            String pkg2 = account2.getAccountHandle().getComponentName().getPackageName();
            retval = pkg1.compareTo(pkg2);
            if (retval != 0) {
                return retval;
            }
            // then order by label
            String label1 = nullToEmpty(account1.getLabel().toString());
            String label2 = nullToEmpty(account2.getLabel().toString());
            retval = label1.compareTo(label2);
            if (retval != 0) {
                return retval;
            }
            // then by hashcode
            return account1.hashCode() - account2.hashCode(); // 漏洞点
        });
    }
    private static String nullToEmpty(String str) {
        return str == null ? "" : str;
    }
}