diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-05-26 00:27:06 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-05-26 00:27:06 +0200 |
commit | 15fc6c1cc05249f342ff4279688f1f9c4e162dec (patch) | |
tree | 83107cc9f75eae10160fa63e27ef1f0bf9606cc0 /sys/src/9/port/devproc.c | |
parent | b672403c6d9ad0029782a71c2b9e4bbb8fe7fbf1 (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.c | 48 |
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: |