mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 20:58:22 +00:00
5360edb9c7
Currently, pipe2 both closes the fds and releases references to the pipe vnode on failure. However, closing the fds already causes the vnode references to be dropped. Make pipe2 only release the vnode references when the respective file_t were not closed. Found by syzkaller fuzzing.
72 lines
1.5 KiB
C
72 lines
1.5 KiB
C
#include <kernel/syscalls.h>
|
|
#include <kernel/file.h>
|
|
#include <kernel/vfs.h>
|
|
#include <arch/cpu.h>
|
|
#include <kernel/pipefs.h>
|
|
#include <logging.h>
|
|
#include <errno.h>
|
|
|
|
static void open(file_t *file, vnode_t *node, int flags) {
|
|
file->vnode = node;
|
|
file->flags = flags;
|
|
file->offset = 0;
|
|
file->mode = 0777;
|
|
VOP_LOCK(node);
|
|
VOP_OPEN(&node, fileflagstovnodeflags(flags) | V_FFLAGS_NONBLOCKING, ¤t_thread()->proc->cred);
|
|
VOP_UNLOCK(node);
|
|
}
|
|
|
|
syscallret_t syscall_pipe2(context_t *, int flags) {
|
|
syscallret_t ret = {
|
|
.ret = -1
|
|
};
|
|
|
|
if (flags & ~(O_CLOEXEC | O_NONBLOCK))
|
|
printf("pipe2: unknown %x\n", flags);
|
|
|
|
vnode_t *node = NULL;
|
|
int readfd, writefd;
|
|
file_t *readfile = NULL;
|
|
file_t *writefile = NULL;
|
|
|
|
ret.errno = pipefs_newpipe(&node);
|
|
if (ret.errno)
|
|
goto error;
|
|
|
|
// node held again because two files will point to the same node
|
|
VOP_HOLD(node);
|
|
|
|
ret.errno = fd_new(flags & O_CLOEXEC, &readfile, &readfd);
|
|
if (ret.errno)
|
|
goto error;
|
|
|
|
open(readfile, node, FILE_READ | (flags & O_NONBLOCK));
|
|
|
|
ret.errno = fd_new(flags & O_CLOEXEC, &writefile, &writefd);
|
|
if (ret.errno)
|
|
goto error;
|
|
|
|
open(writefile, node, FILE_WRITE | (flags & O_NONBLOCK));
|
|
|
|
ret.errno = 0;
|
|
ret.ret = (uint64_t)readfd | ((uint64_t)writefd << 32);
|
|
|
|
return ret;
|
|
error:
|
|
if (readfile) {
|
|
fd_release(readfile);
|
|
fd_close(readfd);
|
|
} else if (node) {
|
|
VOP_RELEASE(node);
|
|
}
|
|
|
|
if (writefile) {
|
|
fd_release(writefile);
|
|
fd_close(writefd);
|
|
} if (node) {
|
|
VOP_RELEASE(node);
|
|
}
|
|
|
|
return ret;
|
|
}
|