Files
Matheus 5360edb9c7 pipe2: properly clean up vnode references on error
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.
2026-10-09 02:11:50 -03:00

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, &current_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;
}