Headline
CVE-2022-23596: [BUG]A carefully crafted RAR archive can trigger an infinite loop while parsing. · Issue #73 · junrar/junrar
Junrar is an open source java RAR archive library. In affected versions A carefully crafted RAR archive can trigger an infinite loop while extracting said archive. The impact depends solely on how the application uses the library, and whether files can be provided by malignant users. The problem is patched in 7.4.1. There are no known workarounds and users are advised to upgrade as soon as possible.
while (true) {
VMPreparedCommand cmd = preparedCode.get(IP);
int op1 = getOperand(cmd.getOp1());
int op2 = getOperand(cmd.getOp2());
switch (cmd.getOpCode()) {
case VM_MOV:
setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(),
mem, op2)); // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2));
break;
case VM_MOVB:
setValue(true, mem, op1, getValue(true, mem, op2));
break;
case VM_MOVD:
setValue(false, mem, op1, getValue(false, mem, op2));
break;
case VM_CMP: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
int result = value1 - getValue(cmd.isByteMode(), mem, op2);
if (result == 0) {
flags = VMFlags.VM_FZ.getFlag();
} else {
flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS
.getFlag());
}
}
break;
case VM_CMPB: {
int value1 = getValue(true, mem, op1);
int result = value1 - getValue(true, mem, op2);
if (result == 0) {
flags = VMFlags.VM_FZ.getFlag();
} else {
flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS
.getFlag());
}
}
break;
case VM_CMPD: {
int value1 = getValue(false, mem, op1);
int result = value1 - getValue(false, mem, op2);
if (result == 0) {
flags = VMFlags.VM_FZ.getFlag();
} else {
flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS
.getFlag());
}
}
break;
case VM_ADD: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
int result = (int) ((((long) value1 + (long) getValue(cmd
.isByteMode(), mem, op2))) & 0xffffffff);
if (cmd.isByteMode()) {
result &= 0xff;
flags = (result < value1) ? 1
: 0 | (result == 0 ? VMFlags.VM_FZ.getFlag()
: ((result & 0x80) != 0) ? VMFlags.VM_FS
.getFlag() : 0);
// Flags=(Result<Value1)|(Result==0 ? VM_FZ:((Result&0x80) ?
// VM_FS:0));
} else {
flags = (result < value1) ? 1
: 0 | (result == 0 ? VMFlags.VM_FZ.getFlag()
: (result & VMFlags.VM_FS.getFlag()));
}
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_ADDB:
setValue(true, mem, op1,
(int) ((long) getValue(true, mem, op1) & 0xFFffFFff
- (long) getValue(true, mem, op2) & 0xFFffFFff));
break;
case VM_ADDD:
setValue(
false,
mem,
op1,
(int) ((long) getValue(false, mem, op1) & 0xFFffFFff
- (long) getValue(false, mem, op2) & 0xFFffFFff));
break;
case VM_SUB: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
int result = (int) ((long) value1 & 0xffFFffFF
- (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff);
flags = (result == 0) ? VMFlags.VM_FZ.getFlag()
: (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS
.getFlag());
setValue(cmd.isByteMode(), mem, op1, result); // (Cmd->ByteMode,Op1,Result);
}
break;
case VM_SUBB:
setValue(true, mem, op1,
(int) ((long) getValue(true, mem, op1) & 0xFFffFFff
- (long) getValue(true, mem, op2) & 0xFFffFFff));
break;
case VM_SUBD:
setValue(
false,
mem,
op1,
(int) ((long) getValue(false, mem, op1) & 0xFFffFFff
- (long) getValue(false, mem, op2) & 0xFFffFFff));
break;
case VM_JZ:
if ((flags & VMFlags.VM_FZ.getFlag()) != 0) {
setIP(getValue(false, mem, op1));
continue;
}
break;
case VM_JNZ:
if ((flags & VMFlags.VM_FZ.getFlag()) == 0) {
setIP(getValue(false, mem, op1));
continue;
}
break;
case VM_INC: {
int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff + 1);
if (cmd.isByteMode()) {
result &= 0xff;
}
setValue(cmd.isByteMode(), mem, op1, result);
flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result
& VMFlags.VM_FS.getFlag();
}
break;
case VM_INCB:
setValue(
true,
mem,
op1,
(int) ((long) getValue(true, mem, op1) & 0xFFffFFff + 1));
break;
case VM_INCD:
setValue(false, mem, op1, (int) ((long) getValue(false, mem,
op1) & 0xFFffFFff + 1));
break;
case VM_DEC: {
int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff - 1);
setValue(cmd.isByteMode(), mem, op1, result);
flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result
& VMFlags.VM_FS.getFlag();
}
break;
case VM_DECB:
setValue(
true,
mem,
op1,
(int) ((long) getValue(true, mem, op1) & 0xFFffFFff - 1));
break;
case VM_DECD:
setValue(false, mem, op1, (int) ((long) getValue(false, mem,
op1) & 0xFFffFFff - 1));
break;
case VM_JMP:
setIP(getValue(false, mem, op1));
continue;
case VM_XOR: {
int result = getValue(cmd.isByteMode(), mem, op1)
^ getValue(cmd.isByteMode(), mem, op2);
flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result
& VMFlags.VM_FS.getFlag();
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_AND: {
int result = getValue(cmd.isByteMode(), mem, op1)
& getValue(cmd.isByteMode(), mem, op2);
flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result
& VMFlags.VM_FS.getFlag();
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_OR: {
int result = getValue(cmd.isByteMode(), mem, op1)
| getValue(cmd.isByteMode(), mem, op2);
flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result
& VMFlags.VM_FS.getFlag();
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_TEST: {
int result = getValue(cmd.isByteMode(), mem, op1)
& getValue(cmd.isByteMode(), mem, op2);
flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result
& VMFlags.VM_FS.getFlag();
}
break;
case VM_JS:
if ((flags & VMFlags.VM_FS.getFlag()) != 0) {
setIP(getValue(false, mem, op1));
continue;
}
break;
case VM_JNS:
if ((flags & VMFlags.VM_FS.getFlag()) == 0) {
setIP(getValue(false, mem, op1));
continue;
}
break;
case VM_JB:
if ((flags & VMFlags.VM_FC.getFlag()) != 0) {
setIP(getValue(false, mem, op1));
continue;
}
break;
case VM_JBE:
if ((flags & (VMFlags.VM_FC.getFlag() | VMFlags.VM_FZ.getFlag())) != 0) {
setIP(getValue(false, mem, op1));
continue;
}
break;
case VM_JA:
if ((flags & (VMFlags.VM_FC.getFlag() | VMFlags.VM_FZ.getFlag())) == 0) {
setIP(getValue(false, mem, op1));
continue;
}
break;
case VM_JAE:
if ((flags & VMFlags.VM_FC.getFlag()) == 0) {
setIP(getValue(false, mem, op1));
continue;
}
break;
case VM_PUSH:
R[7] -= 4;
setValue(false, mem, R[7] & VM_MEMMASK, getValue(false, mem,
op1));
break;
case VM_POP:
setValue(false, mem, op1, getValue(false, mem, R[7]
& VM_MEMMASK));
R[7] += 4;
break;
case VM_CALL:
R[7] -= 4;
setValue(false, mem, R[7] & VM_MEMMASK, IP + 1);
setIP(getValue(false, mem, op1));
continue;
case VM_NOT:
setValue(cmd.isByteMode(), mem, op1, ~getValue(
cmd.isByteMode(), mem, op1));
break;
case VM_SHL: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
int value2 = getValue(cmd.isByteMode(), mem, op2);
int result = value1 << value2;
flags = (result == 0 ? VMFlags.VM_FZ.getFlag()
: (result & VMFlags.VM_FS.getFlag()))
| (((value1 << (value2 - 1)) & 0x80000000) != 0 ? VMFlags.VM_FC
.getFlag()
: 0);
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_SHR: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
int value2 = getValue(cmd.isByteMode(), mem, op2);
int result = value1 >>> value2;
flags = (result == 0 ? VMFlags.VM_FZ.getFlag()
: (result & VMFlags.VM_FS.getFlag()))
| ((value1 >>> (value2 - 1)) & VMFlags.VM_FC.getFlag());
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_SAR: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
int value2 = getValue(cmd.isByteMode(), mem, op2);
int result = ((int) value1) >>> value2;
flags = (result == 0 ? VMFlags.VM_FZ.getFlag()
: (result & VMFlags.VM_FS.getFlag()))
| ((value1 >>> (value2 - 1)) & VMFlags.VM_FC.getFlag());
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_NEG: {
int result = -getValue(cmd.isByteMode(), mem, op1);
flags = result == 0 ? VMFlags.VM_FZ.getFlag() : VMFlags.VM_FC
.getFlag()
| (result & VMFlags.VM_FS.getFlag());
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_NEGB:
setValue(true, mem, op1, -getValue(true, mem, op1));
break;
case VM_NEGD:
setValue(false, mem, op1, -getValue(false, mem, op1));
break;
case VM_PUSHA: {
for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) {
setValue(false, mem, SP & VM_MEMMASK, R[i]);
}
R[7] -= regCount * 4;
}
break;
case VM_POPA: {
for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) {
R[7 - i] = getValue(false, mem, SP & VM_MEMMASK);
}
}
break;
case VM_PUSHF:
R[7] -= 4;
setValue(false, mem, R[7] & VM_MEMMASK, flags);
break;
case VM_POPF:
flags = getValue(false, mem, R[7] & VM_MEMMASK);
R[7] += 4;
break;
case VM_MOVZX:
setValue(false, mem, op1, getValue(true, mem, op2));
break;
case VM_MOVSX:
setValue(false, mem, op1, (byte) getValue(true, mem, op2));
break;
case VM_XCHG: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(),
mem, op2));
setValue(cmd.isByteMode(), mem, op2, value1);
}
break;
case VM_MUL: {
int result = (int) (((long) getValue(cmd.isByteMode(), mem, op1)
& 0xFFffFFff
* (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff) & 0xFFffFFff);
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_DIV: {
int divider = getValue(cmd.isByteMode(), mem, op2);
if (divider != 0) {
int result = getValue(cmd.isByteMode(), mem, op1) / divider;
setValue(cmd.isByteMode(), mem, op1, result);
}
}
break;
case VM_ADC: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
int FC = (flags & VMFlags.VM_FC.getFlag());
int result = (int) ((long) value1 & 0xFFffFFff
- (long) getValue(cmd.isByteMode(), mem, op2)
& 0xFFffFFff + (long) FC & 0xFFffFFff);
if (cmd.isByteMode()) {
result &= 0xff;
}
flags = (result < value1 || result == value1 && FC != 0) ? 1
: 0 | (result == 0 ? VMFlags.VM_FZ.getFlag()
: (result & VMFlags.VM_FS.getFlag()));
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_SBB: {
int value1 = getValue(cmd.isByteMode(), mem, op1);
int FC = (flags & VMFlags.VM_FC.getFlag());
int result = (int) ((long) value1 & 0xFFffFFff
- (long) getValue(cmd.isByteMode(), mem, op2)
& 0xFFffFFff - (long) FC & 0xFFffFFff);
if (cmd.isByteMode()) {
result &= 0xff;
}
flags = (result > value1 || result == value1 && FC != 0) ? 1
: 0 | (result == 0 ? VMFlags.VM_FZ.getFlag()
: (result & VMFlags.VM_FS.getFlag()));
setValue(cmd.isByteMode(), mem, op1, result);
}
break;
case VM_RET:
if (R[7] >= VM_MEMSIZE) {
return (true);
}
setIP(getValue(false, mem, R[7] & VM_MEMMASK));
R[7] += 4;
continue;
case VM_STANDARD:
ExecuteStandardFilter(VMStandardFilters.findFilter(cmd.getOp1()
.getData()));
break;
case VM_PRINT:
break;
}
IP++;
–maxOpCount;
}