mirror of https://github.com/proxmox/mirror_qemu
added verr, verw, arpl - more precise segment rights checks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@453 c046a42c-6fe2-441c-8c8c-71466251a162master
parent
3e25f9515a
commit
3ab493de4c
|
@ -170,6 +170,8 @@ void helper_rdmsr(void);
|
||||||
void helper_wrmsr(void);
|
void helper_wrmsr(void);
|
||||||
void helper_lsl(void);
|
void helper_lsl(void);
|
||||||
void helper_lar(void);
|
void helper_lar(void);
|
||||||
|
void helper_verr(void);
|
||||||
|
void helper_verw(void);
|
||||||
|
|
||||||
void check_iob_T0(void);
|
void check_iob_T0(void);
|
||||||
void check_iow_T0(void);
|
void check_iow_T0(void);
|
||||||
|
|
|
@ -1037,13 +1037,15 @@ void helper_ltr_T0(void)
|
||||||
env->tr.selector = selector;
|
env->tr.selector = selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only works if protected mode and not VM86. Calling load_seg with
|
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
|
||||||
seg_reg == R_CS is discouraged */
|
|
||||||
/* XXX: add ring level checks */
|
|
||||||
void load_seg(int seg_reg, int selector, unsigned int cur_eip)
|
void load_seg(int seg_reg, int selector, unsigned int cur_eip)
|
||||||
{
|
{
|
||||||
uint32_t e1, e2;
|
uint32_t e1, e2;
|
||||||
|
int cpl, dpl, rpl;
|
||||||
|
SegmentCache *dt;
|
||||||
|
int index;
|
||||||
|
uint8_t *ptr;
|
||||||
|
|
||||||
if ((selector & 0xfffc) == 0) {
|
if ((selector & 0xfffc) == 0) {
|
||||||
/* null selector case */
|
/* null selector case */
|
||||||
if (seg_reg == R_SS) {
|
if (seg_reg == R_SS) {
|
||||||
|
@ -1053,26 +1055,51 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip)
|
||||||
cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
|
cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (load_segment(&e1, &e2, selector) != 0) {
|
|
||||||
EIP = cur_eip;
|
if (selector & 0x4)
|
||||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
dt = &env->ldt;
|
||||||
}
|
else
|
||||||
if (!(e2 & DESC_S_MASK) ||
|
dt = &env->gdt;
|
||||||
(e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
|
index = selector & ~7;
|
||||||
|
if ((index + 7) > dt->limit) {
|
||||||
EIP = cur_eip;
|
EIP = cur_eip;
|
||||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||||
}
|
}
|
||||||
|
ptr = dt->base + index;
|
||||||
|
e1 = ldl_kernel(ptr);
|
||||||
|
e2 = ldl_kernel(ptr + 4);
|
||||||
|
|
||||||
|
if (!(e2 & DESC_S_MASK)) {
|
||||||
|
EIP = cur_eip;
|
||||||
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||||
|
}
|
||||||
|
rpl = selector & 3;
|
||||||
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||||
|
cpl = env->hflags & HF_CPL_MASK;
|
||||||
if (seg_reg == R_SS) {
|
if (seg_reg == R_SS) {
|
||||||
|
/* must be writable segment */
|
||||||
if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
|
if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
|
||||||
EIP = cur_eip;
|
EIP = cur_eip;
|
||||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||||
}
|
}
|
||||||
|
if (rpl != cpl || dpl != cpl) {
|
||||||
|
EIP = cur_eip;
|
||||||
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* must be readable segment */
|
||||||
if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
|
if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
|
||||||
EIP = cur_eip;
|
EIP = cur_eip;
|
||||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
|
||||||
|
/* if not conforming code, test rights */
|
||||||
|
if (dpl < cpl || dpl < rpl) {
|
||||||
|
EIP = cur_eip;
|
||||||
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(e2 & DESC_P_MASK)) {
|
if (!(e2 & DESC_P_MASK)) {
|
||||||
|
@ -1082,6 +1109,13 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip)
|
||||||
else
|
else
|
||||||
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
|
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the access bit if not already set */
|
||||||
|
if (!(e2 & DESC_A_MASK)) {
|
||||||
|
e2 |= DESC_A_MASK;
|
||||||
|
stl_kernel(ptr + 4, e2);
|
||||||
|
}
|
||||||
|
|
||||||
cpu_x86_load_seg_cache(env, seg_reg, selector,
|
cpu_x86_load_seg_cache(env, seg_reg, selector,
|
||||||
get_seg_base(e1, e2),
|
get_seg_base(e1, e2),
|
||||||
get_seg_limit(e1, e2),
|
get_seg_limit(e1, e2),
|
||||||
|
@ -1696,14 +1730,38 @@ void helper_lsl(void)
|
||||||
{
|
{
|
||||||
unsigned int selector, limit;
|
unsigned int selector, limit;
|
||||||
uint32_t e1, e2;
|
uint32_t e1, e2;
|
||||||
|
int rpl, dpl, cpl, type;
|
||||||
|
|
||||||
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
||||||
selector = T0 & 0xffff;
|
selector = T0 & 0xffff;
|
||||||
if (load_segment(&e1, &e2, selector) != 0)
|
if (load_segment(&e1, &e2, selector) != 0)
|
||||||
return;
|
return;
|
||||||
limit = (e1 & 0xffff) | (e2 & 0x000f0000);
|
rpl = selector & 3;
|
||||||
if (e2 & (1 << 23))
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||||
limit = (limit << 12) | 0xfff;
|
cpl = env->hflags & HF_CPL_MASK;
|
||||||
|
if (e2 & DESC_S_MASK) {
|
||||||
|
if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
|
||||||
|
/* conforming */
|
||||||
|
} else {
|
||||||
|
if (dpl < cpl || dpl < rpl)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
|
||||||
|
switch(type) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 9:
|
||||||
|
case 11:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dpl < cpl || dpl < rpl)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
limit = get_seg_limit(e1, e2);
|
||||||
T1 = limit;
|
T1 = limit;
|
||||||
CC_SRC |= CC_Z;
|
CC_SRC |= CC_Z;
|
||||||
}
|
}
|
||||||
|
@ -1712,15 +1770,105 @@ void helper_lar(void)
|
||||||
{
|
{
|
||||||
unsigned int selector;
|
unsigned int selector;
|
||||||
uint32_t e1, e2;
|
uint32_t e1, e2;
|
||||||
|
int rpl, dpl, cpl, type;
|
||||||
|
|
||||||
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
||||||
selector = T0 & 0xffff;
|
selector = T0 & 0xffff;
|
||||||
|
if ((selector & 0xfffc) == 0)
|
||||||
|
return;
|
||||||
if (load_segment(&e1, &e2, selector) != 0)
|
if (load_segment(&e1, &e2, selector) != 0)
|
||||||
return;
|
return;
|
||||||
|
rpl = selector & 3;
|
||||||
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||||
|
cpl = env->hflags & HF_CPL_MASK;
|
||||||
|
if (e2 & DESC_S_MASK) {
|
||||||
|
if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
|
||||||
|
/* conforming */
|
||||||
|
} else {
|
||||||
|
if (dpl < cpl || dpl < rpl)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
|
||||||
|
switch(type) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 9:
|
||||||
|
case 11:
|
||||||
|
case 12:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dpl < cpl || dpl < rpl)
|
||||||
|
return;
|
||||||
|
}
|
||||||
T1 = e2 & 0x00f0ff00;
|
T1 = e2 & 0x00f0ff00;
|
||||||
CC_SRC |= CC_Z;
|
CC_SRC |= CC_Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void helper_verr(void)
|
||||||
|
{
|
||||||
|
unsigned int selector;
|
||||||
|
uint32_t e1, e2;
|
||||||
|
int rpl, dpl, cpl;
|
||||||
|
|
||||||
|
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
||||||
|
selector = T0 & 0xffff;
|
||||||
|
if ((selector & 0xfffc) == 0)
|
||||||
|
return;
|
||||||
|
if (load_segment(&e1, &e2, selector) != 0)
|
||||||
|
return;
|
||||||
|
if (!(e2 & DESC_S_MASK))
|
||||||
|
return;
|
||||||
|
rpl = selector & 3;
|
||||||
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||||
|
cpl = env->hflags & HF_CPL_MASK;
|
||||||
|
if (e2 & DESC_CS_MASK) {
|
||||||
|
if (!(e2 & DESC_R_MASK))
|
||||||
|
return;
|
||||||
|
if (!(e2 & DESC_C_MASK)) {
|
||||||
|
if (dpl < cpl || dpl < rpl)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dpl < cpl || dpl < rpl)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* ok */
|
||||||
|
}
|
||||||
|
|
||||||
|
void helper_verw(void)
|
||||||
|
{
|
||||||
|
unsigned int selector;
|
||||||
|
uint32_t e1, e2;
|
||||||
|
int rpl, dpl, cpl;
|
||||||
|
|
||||||
|
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
||||||
|
selector = T0 & 0xffff;
|
||||||
|
if ((selector & 0xfffc) == 0)
|
||||||
|
return;
|
||||||
|
if (load_segment(&e1, &e2, selector) != 0)
|
||||||
|
return;
|
||||||
|
if (!(e2 & DESC_S_MASK))
|
||||||
|
return;
|
||||||
|
rpl = selector & 3;
|
||||||
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||||
|
cpl = env->hflags & HF_CPL_MASK;
|
||||||
|
if (e2 & DESC_CS_MASK) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (dpl < cpl || dpl < rpl)
|
||||||
|
return;
|
||||||
|
if (!(e2 & DESC_W_MASK))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* ok */
|
||||||
|
}
|
||||||
|
|
||||||
/* FPU helpers */
|
/* FPU helpers */
|
||||||
|
|
||||||
void helper_fldt_ST0_A0(void)
|
void helper_fldt_ST0_A0(void)
|
||||||
|
|
|
@ -936,6 +936,35 @@ void OPPROTO op_lar(void)
|
||||||
helper_lar();
|
helper_lar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_verr(void)
|
||||||
|
{
|
||||||
|
helper_verr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_verw(void)
|
||||||
|
{
|
||||||
|
helper_verw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_arpl(void)
|
||||||
|
{
|
||||||
|
if ((T0 & 3) < (T1 & 3)) {
|
||||||
|
/* XXX: emulate bug or 0xff3f0000 oring as in bochs ? */
|
||||||
|
T0 = (T0 & ~3) | (T1 & 3);
|
||||||
|
T1 = CC_Z;
|
||||||
|
} else {
|
||||||
|
T1 = 0;
|
||||||
|
}
|
||||||
|
FORCE_RET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_arpl_update(void)
|
||||||
|
{
|
||||||
|
int eflags;
|
||||||
|
eflags = cc_table[CC_OP].compute_all();
|
||||||
|
CC_SRC = (eflags & ~CC_Z) | T1;
|
||||||
|
}
|
||||||
|
|
||||||
/* T0: segment, T1:eip */
|
/* T0: segment, T1:eip */
|
||||||
void OPPROTO op_ljmp_protected_T0_T1(void)
|
void OPPROTO op_ljmp_protected_T0_T1(void)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue