Commit 3ab493de4c524926bb75b04765b644f9189ccf01
1 parent
3e25f951
added verr, verw, arpl - more precise segment rights checks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@453 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
190 additions
and
11 deletions
target-i386/exec.h
@@ -170,6 +170,8 @@ void helper_rdmsr(void); | @@ -170,6 +170,8 @@ void helper_rdmsr(void); | ||
170 | void helper_wrmsr(void); | 170 | void helper_wrmsr(void); |
171 | void helper_lsl(void); | 171 | void helper_lsl(void); |
172 | void helper_lar(void); | 172 | void helper_lar(void); |
173 | +void helper_verr(void); | ||
174 | +void helper_verw(void); | ||
173 | 175 | ||
174 | void check_iob_T0(void); | 176 | void check_iob_T0(void); |
175 | void check_iow_T0(void); | 177 | void check_iow_T0(void); |
target-i386/helper.c
@@ -1037,13 +1037,15 @@ void helper_ltr_T0(void) | @@ -1037,13 +1037,15 @@ void helper_ltr_T0(void) | ||
1037 | env->tr.selector = selector; | 1037 | env->tr.selector = selector; |
1038 | } | 1038 | } |
1039 | 1039 | ||
1040 | -/* only works if protected mode and not VM86. Calling load_seg with | ||
1041 | - seg_reg == R_CS is discouraged */ | ||
1042 | -/* XXX: add ring level checks */ | 1040 | +/* only works if protected mode and not VM86. seg_reg must be != R_CS */ |
1043 | void load_seg(int seg_reg, int selector, unsigned int cur_eip) | 1041 | void load_seg(int seg_reg, int selector, unsigned int cur_eip) |
1044 | { | 1042 | { |
1045 | uint32_t e1, e2; | 1043 | uint32_t e1, e2; |
1046 | - | 1044 | + int cpl, dpl, rpl; |
1045 | + SegmentCache *dt; | ||
1046 | + int index; | ||
1047 | + uint8_t *ptr; | ||
1048 | + | ||
1047 | if ((selector & 0xfffc) == 0) { | 1049 | if ((selector & 0xfffc) == 0) { |
1048 | /* null selector case */ | 1050 | /* null selector case */ |
1049 | if (seg_reg == R_SS) { | 1051 | if (seg_reg == R_SS) { |
@@ -1053,26 +1055,51 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | @@ -1053,26 +1055,51 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | ||
1053 | cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); | 1055 | cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); |
1054 | } | 1056 | } |
1055 | } else { | 1057 | } else { |
1056 | - if (load_segment(&e1, &e2, selector) != 0) { | 1058 | + |
1059 | + if (selector & 0x4) | ||
1060 | + dt = &env->ldt; | ||
1061 | + else | ||
1062 | + dt = &env->gdt; | ||
1063 | + index = selector & ~7; | ||
1064 | + if ((index + 7) > dt->limit) { | ||
1057 | EIP = cur_eip; | 1065 | EIP = cur_eip; |
1058 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1066 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1059 | } | 1067 | } |
1060 | - if (!(e2 & DESC_S_MASK) || | ||
1061 | - (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { | 1068 | + ptr = dt->base + index; |
1069 | + e1 = ldl_kernel(ptr); | ||
1070 | + e2 = ldl_kernel(ptr + 4); | ||
1071 | + | ||
1072 | + if (!(e2 & DESC_S_MASK)) { | ||
1062 | EIP = cur_eip; | 1073 | EIP = cur_eip; |
1063 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1074 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1064 | } | 1075 | } |
1065 | - | 1076 | + rpl = selector & 3; |
1077 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
1078 | + cpl = env->hflags & HF_CPL_MASK; | ||
1066 | if (seg_reg == R_SS) { | 1079 | if (seg_reg == R_SS) { |
1080 | + /* must be writable segment */ | ||
1067 | if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { | 1081 | if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { |
1068 | EIP = cur_eip; | 1082 | EIP = cur_eip; |
1069 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1083 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1070 | } | 1084 | } |
1085 | + if (rpl != cpl || dpl != cpl) { | ||
1086 | + EIP = cur_eip; | ||
1087 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
1088 | + } | ||
1071 | } else { | 1089 | } else { |
1090 | + /* must be readable segment */ | ||
1072 | if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { | 1091 | if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { |
1073 | EIP = cur_eip; | 1092 | EIP = cur_eip; |
1074 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1093 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1075 | } | 1094 | } |
1095 | + | ||
1096 | + if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { | ||
1097 | + /* if not conforming code, test rights */ | ||
1098 | + if (dpl < cpl || dpl < rpl) { | ||
1099 | + EIP = cur_eip; | ||
1100 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
1101 | + } | ||
1102 | + } | ||
1076 | } | 1103 | } |
1077 | 1104 | ||
1078 | if (!(e2 & DESC_P_MASK)) { | 1105 | if (!(e2 & DESC_P_MASK)) { |
@@ -1082,6 +1109,13 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | @@ -1082,6 +1109,13 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | ||
1082 | else | 1109 | else |
1083 | raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | 1110 | raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
1084 | } | 1111 | } |
1112 | + | ||
1113 | + /* set the access bit if not already set */ | ||
1114 | + if (!(e2 & DESC_A_MASK)) { | ||
1115 | + e2 |= DESC_A_MASK; | ||
1116 | + stl_kernel(ptr + 4, e2); | ||
1117 | + } | ||
1118 | + | ||
1085 | cpu_x86_load_seg_cache(env, seg_reg, selector, | 1119 | cpu_x86_load_seg_cache(env, seg_reg, selector, |
1086 | get_seg_base(e1, e2), | 1120 | get_seg_base(e1, e2), |
1087 | get_seg_limit(e1, e2), | 1121 | get_seg_limit(e1, e2), |
@@ -1696,14 +1730,38 @@ void helper_lsl(void) | @@ -1696,14 +1730,38 @@ void helper_lsl(void) | ||
1696 | { | 1730 | { |
1697 | unsigned int selector, limit; | 1731 | unsigned int selector, limit; |
1698 | uint32_t e1, e2; | 1732 | uint32_t e1, e2; |
1733 | + int rpl, dpl, cpl, type; | ||
1699 | 1734 | ||
1700 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | 1735 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
1701 | selector = T0 & 0xffff; | 1736 | selector = T0 & 0xffff; |
1702 | if (load_segment(&e1, &e2, selector) != 0) | 1737 | if (load_segment(&e1, &e2, selector) != 0) |
1703 | return; | 1738 | return; |
1704 | - limit = (e1 & 0xffff) | (e2 & 0x000f0000); | ||
1705 | - if (e2 & (1 << 23)) | ||
1706 | - limit = (limit << 12) | 0xfff; | 1739 | + rpl = selector & 3; |
1740 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
1741 | + cpl = env->hflags & HF_CPL_MASK; | ||
1742 | + if (e2 & DESC_S_MASK) { | ||
1743 | + if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { | ||
1744 | + /* conforming */ | ||
1745 | + } else { | ||
1746 | + if (dpl < cpl || dpl < rpl) | ||
1747 | + return; | ||
1748 | + } | ||
1749 | + } else { | ||
1750 | + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; | ||
1751 | + switch(type) { | ||
1752 | + case 1: | ||
1753 | + case 2: | ||
1754 | + case 3: | ||
1755 | + case 9: | ||
1756 | + case 11: | ||
1757 | + break; | ||
1758 | + default: | ||
1759 | + return; | ||
1760 | + } | ||
1761 | + if (dpl < cpl || dpl < rpl) | ||
1762 | + return; | ||
1763 | + } | ||
1764 | + limit = get_seg_limit(e1, e2); | ||
1707 | T1 = limit; | 1765 | T1 = limit; |
1708 | CC_SRC |= CC_Z; | 1766 | CC_SRC |= CC_Z; |
1709 | } | 1767 | } |
@@ -1712,15 +1770,105 @@ void helper_lar(void) | @@ -1712,15 +1770,105 @@ void helper_lar(void) | ||
1712 | { | 1770 | { |
1713 | unsigned int selector; | 1771 | unsigned int selector; |
1714 | uint32_t e1, e2; | 1772 | uint32_t e1, e2; |
1773 | + int rpl, dpl, cpl, type; | ||
1715 | 1774 | ||
1716 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | 1775 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
1717 | selector = T0 & 0xffff; | 1776 | selector = T0 & 0xffff; |
1777 | + if ((selector & 0xfffc) == 0) | ||
1778 | + return; | ||
1718 | if (load_segment(&e1, &e2, selector) != 0) | 1779 | if (load_segment(&e1, &e2, selector) != 0) |
1719 | return; | 1780 | return; |
1781 | + rpl = selector & 3; | ||
1782 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
1783 | + cpl = env->hflags & HF_CPL_MASK; | ||
1784 | + if (e2 & DESC_S_MASK) { | ||
1785 | + if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { | ||
1786 | + /* conforming */ | ||
1787 | + } else { | ||
1788 | + if (dpl < cpl || dpl < rpl) | ||
1789 | + return; | ||
1790 | + } | ||
1791 | + } else { | ||
1792 | + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; | ||
1793 | + switch(type) { | ||
1794 | + case 1: | ||
1795 | + case 2: | ||
1796 | + case 3: | ||
1797 | + case 4: | ||
1798 | + case 5: | ||
1799 | + case 9: | ||
1800 | + case 11: | ||
1801 | + case 12: | ||
1802 | + break; | ||
1803 | + default: | ||
1804 | + return; | ||
1805 | + } | ||
1806 | + if (dpl < cpl || dpl < rpl) | ||
1807 | + return; | ||
1808 | + } | ||
1720 | T1 = e2 & 0x00f0ff00; | 1809 | T1 = e2 & 0x00f0ff00; |
1721 | CC_SRC |= CC_Z; | 1810 | CC_SRC |= CC_Z; |
1722 | } | 1811 | } |
1723 | 1812 | ||
1813 | +void helper_verr(void) | ||
1814 | +{ | ||
1815 | + unsigned int selector; | ||
1816 | + uint32_t e1, e2; | ||
1817 | + int rpl, dpl, cpl; | ||
1818 | + | ||
1819 | + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | ||
1820 | + selector = T0 & 0xffff; | ||
1821 | + if ((selector & 0xfffc) == 0) | ||
1822 | + return; | ||
1823 | + if (load_segment(&e1, &e2, selector) != 0) | ||
1824 | + return; | ||
1825 | + if (!(e2 & DESC_S_MASK)) | ||
1826 | + return; | ||
1827 | + rpl = selector & 3; | ||
1828 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
1829 | + cpl = env->hflags & HF_CPL_MASK; | ||
1830 | + if (e2 & DESC_CS_MASK) { | ||
1831 | + if (!(e2 & DESC_R_MASK)) | ||
1832 | + return; | ||
1833 | + if (!(e2 & DESC_C_MASK)) { | ||
1834 | + if (dpl < cpl || dpl < rpl) | ||
1835 | + return; | ||
1836 | + } | ||
1837 | + } else { | ||
1838 | + if (dpl < cpl || dpl < rpl) | ||
1839 | + return; | ||
1840 | + } | ||
1841 | + /* ok */ | ||
1842 | +} | ||
1843 | + | ||
1844 | +void helper_verw(void) | ||
1845 | +{ | ||
1846 | + unsigned int selector; | ||
1847 | + uint32_t e1, e2; | ||
1848 | + int rpl, dpl, cpl; | ||
1849 | + | ||
1850 | + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | ||
1851 | + selector = T0 & 0xffff; | ||
1852 | + if ((selector & 0xfffc) == 0) | ||
1853 | + return; | ||
1854 | + if (load_segment(&e1, &e2, selector) != 0) | ||
1855 | + return; | ||
1856 | + if (!(e2 & DESC_S_MASK)) | ||
1857 | + return; | ||
1858 | + rpl = selector & 3; | ||
1859 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
1860 | + cpl = env->hflags & HF_CPL_MASK; | ||
1861 | + if (e2 & DESC_CS_MASK) { | ||
1862 | + return; | ||
1863 | + } else { | ||
1864 | + if (dpl < cpl || dpl < rpl) | ||
1865 | + return; | ||
1866 | + if (!(e2 & DESC_W_MASK)) | ||
1867 | + return; | ||
1868 | + } | ||
1869 | + /* ok */ | ||
1870 | +} | ||
1871 | + | ||
1724 | /* FPU helpers */ | 1872 | /* FPU helpers */ |
1725 | 1873 | ||
1726 | void helper_fldt_ST0_A0(void) | 1874 | void helper_fldt_ST0_A0(void) |
target-i386/op.c
@@ -936,6 +936,35 @@ void OPPROTO op_lar(void) | @@ -936,6 +936,35 @@ void OPPROTO op_lar(void) | ||
936 | helper_lar(); | 936 | helper_lar(); |
937 | } | 937 | } |
938 | 938 | ||
939 | +void OPPROTO op_verr(void) | ||
940 | +{ | ||
941 | + helper_verr(); | ||
942 | +} | ||
943 | + | ||
944 | +void OPPROTO op_verw(void) | ||
945 | +{ | ||
946 | + helper_verw(); | ||
947 | +} | ||
948 | + | ||
949 | +void OPPROTO op_arpl(void) | ||
950 | +{ | ||
951 | + if ((T0 & 3) < (T1 & 3)) { | ||
952 | + /* XXX: emulate bug or 0xff3f0000 oring as in bochs ? */ | ||
953 | + T0 = (T0 & ~3) | (T1 & 3); | ||
954 | + T1 = CC_Z; | ||
955 | + } else { | ||
956 | + T1 = 0; | ||
957 | + } | ||
958 | + FORCE_RET(); | ||
959 | +} | ||
960 | + | ||
961 | +void OPPROTO op_arpl_update(void) | ||
962 | +{ | ||
963 | + int eflags; | ||
964 | + eflags = cc_table[CC_OP].compute_all(); | ||
965 | + CC_SRC = (eflags & ~CC_Z) | T1; | ||
966 | +} | ||
967 | + | ||
939 | /* T0: segment, T1:eip */ | 968 | /* T0: segment, T1:eip */ |
940 | void OPPROTO op_ljmp_protected_T0_T1(void) | 969 | void OPPROTO op_ljmp_protected_T0_T1(void) |
941 | { | 970 | { |