diff --git a/kernel-src/arch/x86-64/e9.c b/kernel-src/arch/x86-64/e9.c index f1f07202..7c01f239 100644 --- a/kernel-src/arch/x86-64/e9.c +++ b/kernel-src/arch/x86-64/e9.c @@ -1,6 +1,7 @@ #include #include #include +#include void arch_e9_putc(char c) { #ifdef X86_64_ENABLE_E9 @@ -16,11 +17,18 @@ void arch_e9_puts(char *c) { #endif } +#ifdef X86_64_ENABLE_E9 static int devwrite(int minor, void *bufferp, size_t count, uintmax_t offset, int flags, size_t *wcount) { uint8_t *buffer = bufferp; - for (uintmax_t i = 0; i < count; ++i) - outb(0xe9, buffer[i]); + for (uintmax_t i = 0; i < count; ++i) { + char c; + int error = USERCOPY_POSSIBLY_FROM_USER(&c, &buffer[i], 1); + if (error) + return error; + + outb(0xe9, c); + } *wcount = count; return 0; @@ -29,6 +37,7 @@ static int devwrite(int minor, void *bufferp, size_t count, uintmax_t offset, in static devops_t devops = { .write = devwrite }; +#endif void arch_e9_initdev() { #ifdef X86_64_ENABLE_E9 diff --git a/kernel-src/fs/ext2.c b/kernel-src/fs/ext2.c index d9e3f75c..240e66e1 100644 --- a/kernel-src/fs/ext2.c +++ b/kernel-src/fs/ext2.c @@ -1317,6 +1317,8 @@ static int ext2_readlink(vnode_t *vnode, char **link, cred_t *cred) { return err; } +// this *should*, by the rules of the vnode ops, accept a user buffer. however, this will never be the case. all I/O will +// go through the page cache static int ext2_read(vnode_t *vnode, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) { if (vnode->type == V_TYPE_DIR) return EISDIR; @@ -1356,6 +1358,8 @@ static int ext2_read(vnode_t *vnode, void *buffer, size_t size, uintmax_t offset return err; } +// this *should*, by the rules of the vnode ops, accept a user buffer. however, this will never be the case. all I/O will +// go through the page cache int ext2_write(vnode_t *vnode, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec, cred_t *cred) { if (vnode->type == V_TYPE_DIR) return EISDIR; diff --git a/kernel-src/fs/pipefs.c b/kernel-src/fs/pipefs.c index d5ddb62a..9b8bf319 100644 --- a/kernel-src/fs/pipefs.c +++ b/kernel-src/fs/pipefs.c @@ -130,6 +130,7 @@ static int internalpoll(vnode_t *node, polldata_t *data, int events) { return revents; } +// buffer can possibly be a user address int pipefs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) { pipenode_t *pipenode = (pipenode_t *)node; INTERNAL_LOCK(node); @@ -171,6 +172,8 @@ int pipefs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int } *readc = ringbuffer_read(&pipenode->data, buffer, size); + if (*readc == RINGBUFFER_USER_COPY_FAILED) + error = EFAULT; // signal that there is space to write for any threads blocked on this pipe if (RINGBUFFER_DATACOUNT(&pipenode->data) < BUFFER_SIZE - PIPE_ATOMIC_SIZE) @@ -190,6 +193,8 @@ static int writetopipe(pipenode_t *pipenode, void *buffer, size_t size, size_t * } *writec = ringbuffer_write(&pipenode->data, buffer, size); + if (*writec == RINGBUFFER_USER_COPY_FAILED) + return EFAULT; __assert(*writec); poll_event(&pipenode->pollheader, POLLIN); diff --git a/kernel-src/io/acpi/dev.c b/kernel-src/io/acpi/dev.c index 02957c3e..1702a20a 100644 --- a/kernel-src/io/acpi/dev.c +++ b/kernel-src/io/acpi/dev.c @@ -7,15 +7,11 @@ static ringbuffer_t ringbuffer; static pollheader_t pollheader; -static spinlock_t lock; +static mutex_t mutex; void acpi_signaldevice(char c) { - long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC); - if (ringbuffer_write(&ringbuffer, &c, 1)) poll_event(&pollheader, POLLIN); - - spinlock_releaseloweripl(&lock, ipl); } static int internalpoll(polldata_t *data, int events) { @@ -43,13 +39,11 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag if (error) return error; + MUTEX_ACQUIRE(&mutex, false); + for (;;) { - long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC); - int revents = internalpoll(&desc.data[0], POLLIN); - spinlock_releaseloweripl(&lock, ipl); - if (revents) break; @@ -66,13 +60,14 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag poll_leave(&desc); } - long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC); - + // this abuses a behavior of how the ringbuffer works to not need a lock for reading + // (as it would need interrupts to be off) *readc = ringbuffer_read(&ringbuffer, buffer, size); - - spinlock_releaseloweripl(&lock, ipl); + if (*readc == RINGBUFFER_USER_COPY_FAILED) + error = EFAULT; leave: + MUTEX_RELEASE(&mutex); poll_leave(&desc); poll_destroydesc(&desc); return error; @@ -98,11 +93,9 @@ static int write(int minor, void *buffer, size_t size, uintmax_t offset, int fla } static int poll(int minor, polldata_t *data, int events) { - long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC); - + MUTEX_ACQUIRE(&mutex, false); int revents = internalpoll(data, events); - - spinlock_releaseloweripl(&lock, ipl); + MUTEX_RELEASE(&mutex); return revents; } diff --git a/kernel-src/io/fb.c b/kernel-src/io/fb.c index a555d32b..f149a15d 100644 --- a/kernel-src/io/fb.c +++ b/kernel-src/io/fb.c @@ -99,7 +99,10 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag if(size + offset > end) size = end - offset; - memcpy(buffer, (void *)((uintptr_t)fbs[minor]->address + offset), size); + int error = USERCOPY_POSSIBLY_TO_USER(buffer, (void *)((uintptr_t)fbs[minor]->address + offset), size); + if (error) + return error; + *readc = size; return 0; @@ -118,7 +121,10 @@ static int write(int minor, void *buffer, size_t size, uintmax_t offset, int fla if(size + offset > end) size = end - offset; - memcpy((void *)((uintptr_t)fbs[minor]->address + offset), buffer, size); + int error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)fbs[minor]->address + offset), buffer, size); + if (error) + return error; + *writec = size; return 0; diff --git a/kernel-src/io/keyboard.c b/kernel-src/io/keyboard.c index ae344438..aae9333f 100644 --- a/kernel-src/io/keyboard.c +++ b/kernel-src/io/keyboard.c @@ -5,6 +5,7 @@ #include #include #include +#include #define BUFFER_PACKET_CAPACITY 100 #define BUFFER_SIZE (BUFFER_PACKET_CAPACITY * sizeof(kbpacket_t)) @@ -165,25 +166,34 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag for (int i = 0; i < count; ++i) { kbpacket_t *buff = (kbpacket_t *)((uintptr_t)buffer + i * sizeof(kbpacket_t)); - bool ok = keyboard_get(kb, buff); + kbpacket_t packet; + + bool ok = keyboard_get(kb, &packet); if (ok == false) { if (i == 0 && (flags & V_FFLAGS_NONBLOCKING) == 0) { - int err = keyboard_wait(kb, buff); - *readc += err ? 0 : sizeof(kbpacket_t); - return err; + int error = keyboard_wait(kb, &packet); + if (error) + return error; + + error = USERCOPY_POSSIBLY_TO_USER(buff, &packet, sizeof(kbpacket_t)); + + *readc += error ? 0 : sizeof(kbpacket_t); + return error; } break; } + int error = USERCOPY_POSSIBLY_TO_USER(buff, &packet, sizeof(kbpacket_t)); + if (error) + return error; + *readc += sizeof(kbpacket_t); } return 0; } - - static int poll(int minor, polldata_t *data, int events) { int revents = 0; keyboard_t *kb = getkb(minor); diff --git a/kernel-src/io/mouse.c b/kernel-src/io/mouse.c index 73f038a9..61abeb2b 100644 --- a/kernel-src/io/mouse.c +++ b/kernel-src/io/mouse.c @@ -122,6 +122,11 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag } *readc = ringbuffer_read(&mouse->packetbuffer, buffer, sizeof(mousepacket_t) * packetcount); + if (*readc == RINGBUFFER_USER_COPY_FAILED) { + error = EFAULT; + goto leave; + } + __assert(*readc); leave: diff --git a/kernel-src/io/net/localsocket.c b/kernel-src/io/net/localsocket.c index 915723cc..8787fbf6 100644 --- a/kernel-src/io/net/localsocket.c +++ b/kernel-src/io/net/localsocket.c @@ -365,6 +365,11 @@ static int localsock_send(socket_t *socket, sockdesc_t *sockdesc) { } sockdesc->donecount = ringbuffer_write(&peer->ringbuffer, sockdesc->buffer, sockdesc->count); + if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { + error = EFAULT; + goto leave; + } + __assert(sockdesc->donecount > 0); error = sendctrl(socket, sockdesc->ctrl, sockdesc->ctrllen, sockdesc->donecount); @@ -465,8 +470,17 @@ static int localsock_recv(socket_t *socket, sockdesc_t *sockdesc) { if (flags & SOCKET_RECV_FLAGS_PEEK) { sockdesc->donecount = ringbuffer_peek(&localsocket->ringbuffer, sockdesc->buffer, 0, recvcount); + if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { + error = EFAULT; + goto leave; + } } else { sockdesc->donecount = ringbuffer_read(&localsocket->ringbuffer, sockdesc->buffer, recvcount); + if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { + error = EPIPE; + goto leave; + } + localsocket_t *peer = pair->client == localsocket ? pair->server : pair->client; // signal that there is space to write for any threads blocked on this socket if (peer && sockdesc->donecount) diff --git a/kernel-src/io/net/tcp.c b/kernel-src/io/net/tcp.c index 783895ac..88597c61 100644 --- a/kernel-src/io/net/tcp.c +++ b/kernel-src/io/net/tcp.c @@ -1305,8 +1305,13 @@ static int tcp_send(socket_t *socket, sockdesc_t *sockdesc) { size_t writesize = min(TCB_RINGBUFFER_SIZE - RINGBUFFER_DATACOUNT(&tcb->transmitbuffer), sockdesc->count); __assert(writesize); - __assert(ringbuffer_write(&tcb->transmitbuffer, sockdesc->buffer, writesize) == writesize); - sockdesc->donecount = writesize; + sockdesc->donecount = ringbuffer_write(&tcb->transmitbuffer, sockdesc->buffer, writesize); + if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { + error = EFAULT; + goto leave; + } + + __assert(sockdesc->donecount == writesize); if (tcb->sndnext == tcb->sndunack) error = tcp_transmitnextsegment(tcb); @@ -1381,14 +1386,24 @@ static int tcp_recv(socket_t *socket, sockdesc_t *sockdesc) { size_t copycount = min(RINGBUFFER_DATACOUNT(&tcb->receivebuffer), sockdesc->count); if (flags & SOCKET_RECV_FLAGS_PEEK) { - __assert(ringbuffer_peek(&tcb->receivebuffer, sockdesc->buffer, 0, copycount) == copycount); + sockdesc->donecount = ringbuffer_peek(&tcb->receivebuffer, sockdesc->buffer, 0, copycount); + if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { + error = EFAULT; + goto cleanup; + } } else { - __assert(ringbuffer_read(&tcb->receivebuffer, sockdesc->buffer, copycount) == copycount); + sockdesc->donecount = ringbuffer_read(&tcb->receivebuffer, sockdesc->buffer, copycount); + if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { + error = EFAULT; + goto cleanup; + } + tcb->rcvwindow += copycount; // notify about the window increase tcp_ack(tcb); } - sockdesc->donecount = copycount; + + __assert(sockdesc->donecount == copycount); cleanup: MUTEX_RELEASE(&tcb->mutex); diff --git a/kernel-src/io/net/udp.c b/kernel-src/io/net/udp.c index 6cc0b61d..f4d50948 100644 --- a/kernel-src/io/net/udp.c +++ b/kernel-src/io/net/udp.c @@ -262,6 +262,7 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) { bool intstate = interrupt_set(false); spinlock_acquire(&udpsocket->ringbufferlock); + // TODO rewrite this to handle a possible sleep in the ringbuffer size_t copycount; dataheader_t header; if (flags & SOCKET_RECV_FLAGS_PEEK) { diff --git a/kernel-src/io/pty.c b/kernel-src/io/pty.c index 2494df39..9402dfca 100644 --- a/kernel-src/io/pty.c +++ b/kernel-src/io/pty.c @@ -132,10 +132,10 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag if (pty == NULL) return ENODEV; - + int e = 0; for (;;) { polldesc_t desc = {0}; - int e = poll_initdesc(&desc, 1); + e = poll_initdesc(&desc, 1); if (e) return e; @@ -146,6 +146,8 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag if (revents) { *readc = ringbuffer_read(&pty->ringbuffer, buffer, size); + if (*readc == RINGBUFFER_USER_COPY_FAILED) + e = EFAULT; spinlock_release(&pty->lock); interrupt_set(intstatus); @@ -173,7 +175,7 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag return e; } - return 0; + return e; } static int poll(int minor, polldata_t *data, int events) { @@ -215,8 +217,15 @@ static int write(int minor, void *buffer, size_t size, uintmax_t offset, int fla char *str = buffer; - for (int i = 0; i < size; ++i) - tty_process(pty->tty, str[i]); + for (int i = 0; i < size; ++i) { + // bruh + char c; + int error = USERCOPY_POSSIBLY_FROM_USER(&c, &str[i], sizeof(char)); + if (error) + return error; + + tty_process(pty->tty, c); + } *writec = size; return 0; diff --git a/kernel-src/io/tty.c b/kernel-src/io/tty.c index 8ea3cd85..7ca3fd8e 100644 --- a/kernel-src/io/tty.c +++ b/kernel-src/io/tty.c @@ -195,8 +195,13 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag if (min == 0 && time == 0) { MUTEX_ACQUIRE(&tty->readmutex, false); *readc = ringbuffer_read(&tty->readbuffer, buffer, size); + + int error = 0; + if (*readc == RINGBUFFER_USER_COPY_FAILED) + error = EFAULT; + MUTEX_RELEASE(&tty->readmutex); - return 0; + return error; } // time is in 1/10 of a second @@ -207,8 +212,6 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag size_t readcount = 0; size_t spaceleft = size; - // TODO hangup stuff - for (;;) { // for VMIN > 0 and VTIME > 0, the timeout is inter byte only. size_t effectivetimeout = (min > 0 && time > 0 && spins == 0) ? 0 : timeoutus; @@ -225,13 +228,19 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag MUTEX_ACQUIRE(&tty->readmutex, false); size_t actuallyread = ringbuffer_read(&tty->readbuffer, (void *)((uintptr_t)buffer + readcount), spaceleft); - readcount += actuallyread; - spaceleft -= actuallyread; + MUTEX_RELEASE(&tty->readmutex); - // XXX is this valid? - if (spaceleft > 0 && readcount < min) - continue; + if (actuallyread == RINGBUFFER_USER_COPY_FAILED) { + error = EFAULT; + } else { + readcount += actuallyread; + spaceleft -= actuallyread; + + // XXX is this valid? + if (spaceleft > 0 && readcount < min && (revents & POLLHUP) == 0) + continue; + } poll_leave(&desc); poll_destroydesc(&desc); @@ -276,11 +285,18 @@ static int write(int minor, void *_buffer, size_t size, uintmax_t offset, int fl *writec = size; for (int i = 0; i < size; ++i) { - if (buffer[i] == '\n' && (tty->termios.c_oflag & ONLCR)) { + // bruh + char c; + int error = USERCOPY_POSSIBLY_FROM_USER(&c, &buffer[i], sizeof(char)); + if (error) + return error; + + if (c == '\n' && (tty->termios.c_oflag & ONLCR)) { char cr = '\r'; tty->writetodevice(tty->deviceinternal, &cr, 1); } - tty->writetodevice(tty->deviceinternal, &buffer[i], 1); + + tty->writetodevice(tty->deviceinternal, &c, 1); } return 0;