summaryrefslogtreecommitdiff
path: root/sys/src/9/port/devproc.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2014-05-26 00:27:06 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2014-05-26 00:27:06 +0200
commit15fc6c1cc05249f342ff4279688f1f9c4e162dec (patch)
tree83107cc9f75eae10160fa63e27ef1f0bf9606cc0 /sys/src/9/port/devproc.c
parentb672403c6d9ad0029782a71c2b9e4bbb8fe7fbf1 (diff)
devproc: handle 64bit address writes to /proc/n/mem files
procwrite() did truncate the offset to 32bit ulong. introduce off2addr() function that does the sign extension hack and use it conststently for Qmem reads and writes.
Diffstat (limited to 'sys/src/9/port/devproc.c')
-rw-r--r--sys/src/9/port/devproc.c48
1 files changed, 29 insertions, 19 deletions
diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c
index db229802d..6befe3e23 100644
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -691,6 +691,19 @@ prochaswaitq(void *x)
return p->pid != PID(c->qid) || p->waitq != 0;
}
+/*
+ * userspace can't pass negative file offset for a
+ * 64 bit kernel address, so we use 63 bit and sign
+ * extend to 64 bit.
+ */
+static uintptr
+off2addr(vlong off)
+{
+ off <<= 1;
+ off >>= 1;
+ return off;
+}
+
static long
procread(Chan *c, void *va, long n, vlong off)
{
@@ -699,7 +712,8 @@ procread(Chan *c, void *va, long n, vlong off)
int i, j, m, navail, ne, rsize;
long l;
uchar *rptr;
- uintptr offset;
+ uintptr addr;
+ ulong offset;
Confmem *cm;
Mntwalk *mw;
Proc *p;
@@ -708,12 +722,7 @@ procread(Chan *c, void *va, long n, vlong off)
Waitq *wq;
a = va;
-
- /* sign extend 63 bit to 64 bit */
- off <<= 1;
- off >>= 1;
offset = off;
-
if(c->qid.type & QTDIR)
return devdirread(c, a, n, 0, 0, procgen);
@@ -763,26 +772,27 @@ procread(Chan *c, void *va, long n, vlong off)
return n;
case Qmem:
- if(offset < KZERO)
- return procctlmemio(p, offset, n, va, 1);
+ addr = off2addr(off);
+ if(addr < KZERO)
+ return procctlmemio(p, addr, n, va, 1);
if(!iseve())
error(Eperm);
/* validate kernel addresses */
- if(offset < (uintptr)end) {
- if(offset+n > (uintptr)end)
- n = (uintptr)end - offset;
- memmove(a, (char*)offset, n);
+ if(addr < (uintptr)end) {
+ if(addr+n > (uintptr)end)
+ n = (uintptr)end - addr;
+ memmove(a, (char*)addr, n);
return n;
}
for(i=0; i<nelem(conf.mem); i++){
cm = &conf.mem[i];
/* klimit-1 because klimit might be zero! */
- if(cm->kbase <= offset && offset <= cm->klimit-1){
- if(offset+n >= cm->klimit-1)
- n = cm->klimit - offset;
- memmove(a, (char*)offset, n);
+ if(cm->kbase <= addr && addr <= cm->klimit-1){
+ if(addr+n >= cm->klimit-1)
+ n = cm->klimit - addr;
+ memmove(a, (char*)addr, n);
return n;
}
}
@@ -1057,9 +1067,10 @@ procwrite(Chan *c, void *va, long n, vlong off)
int id, m;
Proc *p, *t, *et;
char *a, *arg, buf[ERRMAX];
- ulong offset = off;
+ ulong offset;
a = va;
+ offset = off;
if(c->qid.type & QTDIR)
error(Eisdir);
@@ -1103,8 +1114,7 @@ procwrite(Chan *c, void *va, long n, vlong off)
case Qmem:
if(p->state != Stopped)
error(Ebadctl);
-
- n = procctlmemio(p, offset, n, va, 0);
+ n = procctlmemio(p, off2addr(off), n, va, 0);
break;
case Qregs: