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
target-i386/helper.c
| ... | ... | @@ -1037,13 +1037,15 @@ void helper_ltr_T0(void) |
| 1037 | 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 | 1041 | void load_seg(int seg_reg, int selector, unsigned int cur_eip) |
| 1044 | 1042 | { |
| 1045 | 1043 | uint32_t e1, e2; |
| 1046 | - | |
| 1044 | + int cpl, dpl, rpl; | |
| 1045 | + SegmentCache *dt; | |
| 1046 | + int index; | |
| 1047 | + uint8_t *ptr; | |
| 1048 | + | |
| 1047 | 1049 | if ((selector & 0xfffc) == 0) { |
| 1048 | 1050 | /* null selector case */ |
| 1049 | 1051 | if (seg_reg == R_SS) { |
| ... | ... | @@ -1053,26 +1055,51 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) |
| 1053 | 1055 | cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); |
| 1054 | 1056 | } |
| 1055 | 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 | 1065 | EIP = cur_eip; |
| 1058 | 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 | 1073 | EIP = cur_eip; |
| 1063 | 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 | 1079 | if (seg_reg == R_SS) { |
| 1080 | + /* must be writable segment */ | |
| 1067 | 1081 | if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { |
| 1068 | 1082 | EIP = cur_eip; |
| 1069 | 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 | 1089 | } else { |
| 1090 | + /* must be readable segment */ | |
| 1072 | 1091 | if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { |
| 1073 | 1092 | EIP = cur_eip; |
| 1074 | 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 | 1105 | if (!(e2 & DESC_P_MASK)) { |
| ... | ... | @@ -1082,6 +1109,13 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) |
| 1082 | 1109 | else |
| 1083 | 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 | 1119 | cpu_x86_load_seg_cache(env, seg_reg, selector, |
| 1086 | 1120 | get_seg_base(e1, e2), |
| 1087 | 1121 | get_seg_limit(e1, e2), |
| ... | ... | @@ -1696,14 +1730,38 @@ void helper_lsl(void) |
| 1696 | 1730 | { |
| 1697 | 1731 | unsigned int selector, limit; |
| 1698 | 1732 | uint32_t e1, e2; |
| 1733 | + int rpl, dpl, cpl, type; | |
| 1699 | 1734 | |
| 1700 | 1735 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
| 1701 | 1736 | selector = T0 & 0xffff; |
| 1702 | 1737 | if (load_segment(&e1, &e2, selector) != 0) |
| 1703 | 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 | 1765 | T1 = limit; |
| 1708 | 1766 | CC_SRC |= CC_Z; |
| 1709 | 1767 | } |
| ... | ... | @@ -1712,15 +1770,105 @@ void helper_lar(void) |
| 1712 | 1770 | { |
| 1713 | 1771 | unsigned int selector; |
| 1714 | 1772 | uint32_t e1, e2; |
| 1773 | + int rpl, dpl, cpl, type; | |
| 1715 | 1774 | |
| 1716 | 1775 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
| 1717 | 1776 | selector = T0 & 0xffff; |
| 1777 | + if ((selector & 0xfffc) == 0) | |
| 1778 | + return; | |
| 1718 | 1779 | if (load_segment(&e1, &e2, selector) != 0) |
| 1719 | 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 | 1809 | T1 = e2 & 0x00f0ff00; |
| 1721 | 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 | 1872 | /* FPU helpers */ |
| 1725 | 1873 | |
| 1726 | 1874 | void helper_fldt_ST0_A0(void) | ... | ... |
target-i386/op.c
| ... | ... | @@ -936,6 +936,35 @@ void OPPROTO op_lar(void) |
| 936 | 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 | 968 | /* T0: segment, T1:eip */ |
| 940 | 969 | void OPPROTO op_ljmp_protected_T0_T1(void) |
| 941 | 970 | { | ... | ... |