Commit e2801b51 authored by Anton Blanchard's avatar Anton Blanchard

[PATCH] ppc64: fix kernel access of user pages

Set the ks bit on userspace segments otherwise the kernel can read/write
into userspace mprotected pages.
parent 565a552f
...@@ -826,7 +826,14 @@ SystemCall_common: ...@@ -826,7 +826,14 @@ SystemCall_common:
_GLOBAL(do_hash_page_ISI) _GLOBAL(do_hash_page_ISI)
li r4,0 li r4,0
_GLOBAL(do_hash_page_DSI) _GLOBAL(do_hash_page_DSI)
rlwimi r4,r23,32-13,30,30 /* Insert MSR_PR as _PAGE_USER */ /*
* We need to set the _PAGE_USER bit if MSR_PR is set or if we are
* accessing a userspace segment (even from the kernel). We assume
* kernel addresses always have the high bit set.
*/
rotldi r0,r3,15 /* Move high bit into MSR_PR position */
orc r0,r23,r0
rlwimi r4,r0,32-13,30,30 /* Insert into _PAGE_USER */
ori r4,r4,1 /* add _PAGE_PRESENT */ ori r4,r4,1 /* add _PAGE_PRESENT */
mflr r21 /* Save LR in r21 */ mflr r21 /* Save LR in r21 */
......
...@@ -77,6 +77,8 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) ...@@ -77,6 +77,8 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
unsigned long entry, group, old_esid, castout_entry, i; unsigned long entry, group, old_esid, castout_entry, i;
unsigned int global_entry; unsigned int global_entry;
STE *ste, *castout_ste; STE *ste, *castout_ste;
unsigned long kernel_segment = (REGION_ID(esid << SID_SHIFT) !=
USER_REGION_ID);
/* Search the primary group first. */ /* Search the primary group first. */
global_entry = (esid & 0x1f) << 3; global_entry = (esid & 0x1f) << 3;
...@@ -89,6 +91,8 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) ...@@ -89,6 +91,8 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
ste->dw1.dw1.vsid = vsid; ste->dw1.dw1.vsid = vsid;
ste->dw0.dw0.esid = esid; ste->dw0.dw0.esid = esid;
ste->dw0.dw0.kp = 1; ste->dw0.dw0.kp = 1;
if (!kernel_segment)
ste->dw0.dw0.ks = 1;
asm volatile("eieio":::"memory"); asm volatile("eieio":::"memory");
ste->dw0.dw0.v = 1; ste->dw0.dw0.v = 1;
return (global_entry | entry); return (global_entry | entry);
...@@ -135,6 +139,8 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) ...@@ -135,6 +139,8 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
old_esid = castout_ste->dw0.dw0.esid; old_esid = castout_ste->dw0.dw0.esid;
castout_ste->dw0.dw0.esid = esid; castout_ste->dw0.dw0.esid = esid;
castout_ste->dw0.dw0.kp = 1; castout_ste->dw0.dw0.kp = 1;
if (!kernel_segment)
castout_ste->dw0.dw0.ks = 1;
asm volatile("eieio" : : : "memory"); /* Order update */ asm volatile("eieio" : : : "memory"); /* Order update */
castout_ste->dw0.dw0.v = 1; castout_ste->dw0.dw0.v = 1;
asm volatile("slbie %0" : : "r" (old_esid << SID_SHIFT)); asm volatile("slbie %0" : : "r" (old_esid << SID_SHIFT));
...@@ -344,6 +350,8 @@ static void make_slbe(unsigned long esid, unsigned long vsid, int large, ...@@ -344,6 +350,8 @@ static void make_slbe(unsigned long esid, unsigned long vsid, int large,
vsid_data.data.l = 1; vsid_data.data.l = 1;
if (kernel_segment) if (kernel_segment)
vsid_data.data.c = 1; vsid_data.data.c = 1;
else
vsid_data.data.ks = 1;
esid_data.word0 = 0; esid_data.word0 = 0;
esid_data.data.esid = esid; esid_data.data.esid = esid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment