From 2229fd91f7230ae7068814ae029b733945852eb1 Mon Sep 17 00:00:00 2001
From: Anton Kling <anton@kling.gg>
Date: Tue, 2 Apr 2024 09:17:06 +0200
Subject: Kernel: Fix some memory leaks

---
 kernel/Makefile                    |  2 +-
 kernel/cpu/syscall.c               |  6 +++---
 kernel/fs/devfs.c                  |  3 ++-
 kernel/fs/ext2.c                   | 28 ++++++++++++++++------------
 kernel/fs/shm.c                    |  2 +-
 kernel/fs/tmpfs.c                  |  6 ++++--
 kernel/fs/vfs.c                    | 13 +++++++++++--
 kernel/fs/vfs.h                    |  5 ++++-
 kernel/includes/syscalls.h         |  1 +
 kernel/init/kernel.c               |  2 +-
 kernel/kmalloc.c                   |  5 ++---
 kernel/lib/list.c                  | 11 ++++++-----
 kernel/lib/list.h                  |  1 +
 kernel/sched/scheduler.c           | 23 ++++++++++++++++++++++-
 kernel/sched/scheduler.h           |  4 +++-
 kernel/socket.c                    |  2 +-
 kernel/syscalls/kill.c             | 12 ++++++++++--
 kernel/syscalls/open_process.c     | 26 ++++++++++++++++++++++++++
 userland/libc/Makefile             |  2 +-
 userland/libc/fcntl/open_process.c |  6 ++++++
 userland/libc/include/fcntl.h      |  1 +
 userland/libc/include/signal.h     |  2 +-
 userland/libc/include/syscall.h    |  1 +
 userland/libc/signal/kill.c        |  4 +++-
 userland/minibox/utilities/kill.c  |  5 ++++-
 userland/sh/sh.c                   |  4 +++-
 26 files changed, 135 insertions(+), 42 deletions(-)
 create mode 100644 kernel/syscalls/open_process.c
 create mode 100644 userland/libc/fcntl/open_process.c

diff --git a/kernel/Makefile b/kernel/Makefile
index 0b59509..19853a7 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -1,6 +1,6 @@
 CC="i686-sb-gcc"
 AS="i686-sb-as"
-OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o  read_eip.o libc/exit/assert.o process.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o syscalls/ppoll.o syscalls/ftruncate.o kubsan.o syscalls/mmap.o drivers/serial.o syscalls/accept.o syscalls/bind.o syscalls/socket.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o syscalls/shm.o elf.o ksbrk.o sched/scheduler.o syscalls/stat.o libc/string/copy.o libc/string/strncpy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o syscalls/msleep.o syscalls/uptime.o syscalls/mkdir.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o syscalls/recvfrom.o math.o syscalls/sendto.o signal.o syscalls/kill.o syscalls/sigaction.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o syscalls/chdir.o syscalls/getcwd.o syscalls/isatty.o syscalls/randomfill.o syscalls/open.o syscalls/write.o syscalls/pwrite.o ipc.o syscalls/ipc.o syscalls/port.o syscalls/map_frames.o syscalls/virtual_to_physical.o syscalls/install_irq.o arch/i386/interrupts.o cpu/isr.o lib/stack.o lib/buffered_write.o lib/list.o cpu/arch_inst.o cpu/int_syscall.o queue.o syscalls/queue.o syscalls/munmap.o
+OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o  read_eip.o libc/exit/assert.o process.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o syscalls/ppoll.o syscalls/ftruncate.o kubsan.o syscalls/mmap.o drivers/serial.o syscalls/accept.o syscalls/bind.o syscalls/socket.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o syscalls/shm.o elf.o ksbrk.o sched/scheduler.o syscalls/stat.o libc/string/copy.o libc/string/strncpy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o syscalls/msleep.o syscalls/uptime.o syscalls/mkdir.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o syscalls/recvfrom.o math.o syscalls/sendto.o signal.o syscalls/kill.o syscalls/sigaction.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o syscalls/chdir.o syscalls/getcwd.o syscalls/isatty.o syscalls/randomfill.o syscalls/open.o syscalls/write.o syscalls/pwrite.o ipc.o syscalls/ipc.o syscalls/port.o syscalls/map_frames.o syscalls/virtual_to_physical.o syscalls/install_irq.o arch/i386/interrupts.o cpu/isr.o lib/stack.o lib/buffered_write.o lib/list.o cpu/arch_inst.o cpu/int_syscall.o queue.o syscalls/queue.o syscalls/munmap.o syscalls/open_process.o
 CFLAGS = -std=c99 -Ofast -fsanitize=vla-bound,shift-exponent,pointer-overflow,shift,signed-integer-overflow,bounds -ggdb -ffreestanding -Wall -Werror -mgeneral-regs-only -Wimplicit-fallthrough -I./libc/include/ -I. -Wno-pointer-sign -DKERNEL
 #CFLAGS = -std=c99 -Ofast -flto -ggdb -ffreestanding -Wall -Werror -mgeneral-regs-only -Wimplicit-fallthrough -I./libc/include/ -I. -Wno-pointer-sign -DKERNEL
 #CFLAGS = -std=c99 -O0 -fsanitize=vla-bound,shift-exponent,pointer-overflow,shift,signed-integer-overflow,bounds -ggdb -ffreestanding -Wall -Werror -mgeneral-regs-only -Wimplicit-fallthrough -I./libc/include/ -I. -Wno-pointer-sign -DKERNEL
diff --git a/kernel/cpu/syscall.c b/kernel/cpu/syscall.c
index d47f858..6789628 100644
--- a/kernel/cpu/syscall.c
+++ b/kernel/cpu/syscall.c
@@ -24,19 +24,18 @@ int syscall_exec(SYS_EXEC_PARAMS *args) {
     argc++;
   }
 
-  char **new_argv = kallocarray(argc + 1, sizeof(char *));
+  char *new_argv[argc + 1];
   for (int i = 0; i < argc; i++) {
     new_argv[i] = copy_and_allocate_user_string(args->argv[i]);
   }
 
   new_argv[argc] = NULL;
 
-  exec(filename, new_argv);
+  exec(filename, new_argv, 1, 1);
   kfree((void *)filename);
   for (int i = 0; i < argc; i++) {
     kfree(new_argv[i]);
   }
-  kfree(new_argv);
   return -1;
 }
 
@@ -214,6 +213,7 @@ int (*syscall_functions[])() = {
     (void(*))syscall_queue_add,
     (void(*))syscall_queue_wait,
     (void(*))syscall_munmap,
+    (void(*))syscall_open_process,
 };
 
 void int_syscall(reg_t *r);
diff --git a/kernel/fs/devfs.c b/kernel/fs/devfs.c
index 2705dc8..a3f13db 100644
--- a/kernel/fs/devfs.c
+++ b/kernel/fs/devfs.c
@@ -14,7 +14,7 @@ vfs_inode_t *devfs_add_file(
     u8 has_data, u8 can_write, int type) {
   files[num_files].name = copy_and_allocate_string(path);
 
-  vfs_inode_t *i = kmalloc(sizeof(vfs_inode_t));
+  vfs_inode_t *i = kcalloc(1, sizeof(vfs_inode_t));
   files[num_files].inode = i;
   i->type = type;
   i->read = read;
@@ -24,6 +24,7 @@ vfs_inode_t *devfs_add_file(
   i->has_data = has_data;
   i->is_open = 1;
   i->can_write = can_write;
+  i->ref = 1;
   num_files++;
   return i;
 }
diff --git a/kernel/fs/ext2.c b/kernel/fs/ext2.c
index 9017b82..167c2aa 100644
--- a/kernel/fs/ext2.c
+++ b/kernel/fs/ext2.c
@@ -211,9 +211,12 @@ int ext2_get_inode_in_directory(int dir_inode, char *file,
       if (entry) {
         memcpy(entry, data_p, sizeof(direntry_header_t));
       }
-      return dir->inode;
+      int r = dir->inode;
+      kfree(data);
+      return r;
     }
   }
+  kfree(data);
   return 0;
 }
 
@@ -603,11 +606,12 @@ vfs_inode_t *ext2_open(const char *path) {
     break;
   }
 
-  return vfs_create_inode(
-      inode_num, type, 1 /*has_data*/, 1 /*can_write*/, 1 /*is_open*/,
-      NULL /*internal_object*/, file_size, ext2_open, ext2_create_file,
-      ext2_read, ext2_write, ext2_close, ext2_create_directory,
-      NULL /*get_vm_object*/, ext2_truncate /*truncate*/, ext2_stat);
+  return vfs_create_inode(inode_num, type, 1 /*has_data*/, 1 /*can_write*/,
+                          1 /*is_open*/, NULL /*internal_object*/, file_size,
+                          ext2_open, ext2_create_file, ext2_read, ext2_write,
+                          ext2_close, ext2_create_directory,
+                          NULL /*get_vm_object*/, ext2_truncate /*truncate*/,
+                          ext2_stat, NULL /*send_signal*/);
 }
 
 u64 end_of_last_entry_position(int dir_inode, u64 *entry_offset,
@@ -805,12 +809,12 @@ vfs_inode_t *ext2_mount(void) {
   mount_fd = current_task->file_descriptors[fd];
   current_task->file_descriptors[fd] = NULL;
   parse_superblock();
-  return vfs_create_inode(0 /*inode_num*/, 0 /*type*/, 0 /*has_data*/,
-                          0 /*can_write*/, 0 /*is_open*/,
-                          NULL /*internal_object*/, 0 /*file_size*/, ext2_open,
-                          ext2_create_file, ext2_read, ext2_write, ext2_close,
-                          ext2_create_directory, NULL /*get_vm_object*/,
-                          ext2_truncate /*truncate*/, ext2_stat);
+  return vfs_create_inode(
+      0 /*inode_num*/, 0 /*type*/, 0 /*has_data*/, 0 /*can_write*/,
+      0 /*is_open*/, NULL /*internal_object*/, 0 /*file_size*/, ext2_open,
+      ext2_create_file, ext2_read, ext2_write, ext2_close,
+      ext2_create_directory, NULL /*get_vm_object*/, ext2_truncate /*truncate*/,
+      ext2_stat, NULL /*send_signal*/);
 }
 
 void parse_superblock(void) {
diff --git a/kernel/fs/shm.c b/kernel/fs/shm.c
index 9215b24..7eec825 100644
--- a/kernel/fs/shm.c
+++ b/kernel/fs/shm.c
@@ -83,7 +83,7 @@ int shm_open(const char *name, int oflag, mode_t mode) {
       1 /*is_open*/, internal_object, 0 /*file_size*/, NULL /*open*/,
       NULL /*create_file*/, shm_read, shm_write, NULL /*close*/,
       NULL /*create_directory*/, shm_get_vm_object, shm_ftruncate,
-      NULL /*stat*/);
+      NULL /*stat*/, NULL /*send_signal*/);
 
   vfs_fd_t *fd_ptr;
   int fd = vfs_create_fd(oflag, mode, 0 /*is_tty*/, inode, &fd_ptr);
diff --git a/kernel/fs/tmpfs.c b/kernel/fs/tmpfs.c
index 75de1cd..f8e6712 100644
--- a/kernel/fs/tmpfs.c
+++ b/kernel/fs/tmpfs.c
@@ -49,7 +49,8 @@ void dual_pipe(int fd[2]) {
         0 /*inode_num*/, 0 /*type*/, has_data, can_write, is_open,
         internal_object, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/,
         tmp_read, tmp_write, tmp_close, NULL /*create_directory*/,
-        NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/);
+        NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/,
+        NULL /*send_signal*/);
     assert(inode);
 
     vfs_fd_t *fd_ptr;
@@ -79,7 +80,8 @@ void pipe(int fd[2]) {
         0 /*inode_num*/, 0 /*type*/, has_data, can_write, is_open,
         internal_object, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/,
         tmp_read, tmp_write, tmp_close, NULL /*create_directory*/,
-        NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/);
+        NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/,
+        NULL /*send_signal*/);
     assert(inode);
 
     vfs_fd_t *fd_ptr;
diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c
index 505d6ae..c167e8f 100644
--- a/kernel/fs/vfs.c
+++ b/kernel/fs/vfs.c
@@ -36,7 +36,8 @@ vfs_inode_t *vfs_create_inode(
     int (*create_directory)(const char *path, int mode),
     vfs_vm_object_t *(*get_vm_object)(u64 length, u64 offset, vfs_fd_t *fd),
     int (*truncate)(vfs_fd_t *fd, size_t length),
-    int (*stat)(vfs_fd_t *fd, struct stat *buf)) {
+    int (*stat)(vfs_fd_t *fd, struct stat *buf),
+    int (*send_signal)(vfs_fd_t *fd, int signal)) {
   vfs_inode_t *r = kmalloc(sizeof(inode_t));
   r->inode_num = inode_num;
   r->type = type;
@@ -54,6 +55,8 @@ vfs_inode_t *vfs_create_inode(
   r->get_vm_object = get_vm_object;
   r->truncate = truncate;
   r->stat = stat;
+  r->send_signal = send_signal;
+  r->ref = 1;
   return r;
 }
 
@@ -69,6 +72,7 @@ int vfs_create_fd(int flags, int mode, int is_tty, vfs_inode_t *inode,
   if (p->file_descriptors[i]) {
     return -1;
   }
+  inode->ref++;
   vfs_fd_t *r = kmalloc(sizeof(vfs_fd_t));
   r->flags = flags;
   r->mode = mode;
@@ -307,6 +311,11 @@ int vfs_close_process(process_t *p, int fd) {
       fd_ptr->inode->close(fd_ptr);
     }
 
+    assert(0 < fd_ptr->inode->ref);
+    fd_ptr->inode->ref--;
+    if (0 >= fd_ptr->inode->ref) {
+      kfree(fd_ptr->inode);
+    }
     kfree(fd_ptr);
   }
   return 0;
@@ -333,7 +342,7 @@ int vfs_pmread(int fd, void *buf, u64 count, int blocking, u64 offset) {
     kprintf("EBADF : %x\n", fd);
     return -EBADF;
   }
-  vfs_fd_t *vfs_fd = current_task->file_descriptors[fd];
+  vfs_fd_t *vfs_fd = get_vfs_fd(fd, NULL);
   if (!vfs_fd) {
     return -EBADF;
   }
diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h
index 8e61e11..e75d12e 100644
--- a/kernel/fs/vfs.h
+++ b/kernel/fs/vfs.h
@@ -54,6 +54,7 @@ struct vfs_fd {
 struct vfs_inode {
   int inode_num;
   int type;
+  int ref;
   u8 has_data;
   u8 can_write;
   u8 is_open;
@@ -68,6 +69,7 @@ struct vfs_inode {
   vfs_vm_object_t *(*get_vm_object)(u64 length, u64 offset, vfs_fd_t *fd);
   int (*truncate)(vfs_fd_t *fd, size_t length);
   int (*stat)(vfs_fd_t *fd, struct stat *buf);
+  int (*send_signal)(vfs_fd_t *fd, int signal);
 };
 
 int vfs_close(int fd);
@@ -100,5 +102,6 @@ vfs_inode_t *vfs_create_inode(
     int (*create_directory)(const char *path, int mode),
     vfs_vm_object_t *(*get_vm_object)(u64 length, u64 offset, vfs_fd_t *fd),
     int (*truncate)(vfs_fd_t *fd, size_t length),
-    int (*stat)(vfs_fd_t *fd, struct stat *buf));
+    int (*stat)(vfs_fd_t *fd, struct stat *buf),
+    int (*send_signal)(vfs_fd_t *fd, int signal));
 #endif
diff --git a/kernel/includes/syscalls.h b/kernel/includes/syscalls.h
index cd49a1b..07a73e3 100644
--- a/kernel/includes/syscalls.h
+++ b/kernel/includes/syscalls.h
@@ -11,6 +11,7 @@
 void syscall_outw(u16 port, u16 word);
 u32 syscall_inl(u16 port);
 void syscall_outl(u16 port, u32 l);
+int syscall_open_process(int pid);
 
 int syscall_queue_create(u32 *id);
 int syscall_queue_add(u32 queue_id, struct event *ev, u32 size);
diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c
index 180aaa8..642f4b8 100644
--- a/kernel/init/kernel.c
+++ b/kernel/init/kernel.c
@@ -113,7 +113,7 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr,
   int pid;
   if (0 == (pid = fork())) {
     char *argv[] = {"/init", NULL};
-    if (0 == exec("/init", argv)) {
+    if (0 == exec("/init", argv, 0, 0)) {
       kprintf("exec() failed\n");
     }
   }
diff --git a/kernel/kmalloc.c b/kernel/kmalloc.c
index c88ea8f..7138d61 100644
--- a/kernel/kmalloc.c
+++ b/kernel/kmalloc.c
@@ -231,9 +231,8 @@ void kfree(void *p) {
   // Could this be avoided in a simple way?
   MallocHeader *h = (MallocHeader *)((uintptr_t)p - sizeof(MallocHeader));
   assert(h->magic == 0xdde51ab9410268b1);
-  if (h->flags & IS_FREE) {
-    return;
-  }
+  assert(!(h->flags & IS_FREE));
+
   get_fast_insecure_random((void *)p, h->size);
 
   h->flags |= IS_FREE;
diff --git a/kernel/lib/list.c b/kernel/lib/list.c
index 9cdcd01..d189c86 100644
--- a/kernel/lib/list.c
+++ b/kernel/lib/list.c
@@ -4,7 +4,8 @@
 
 int list_init(struct list *list) {
   // TODO: Make it dynamic
-  list->entries = kmalloc(sizeof(void *) * 100);
+  list->capacity = 5;
+  list->entries = kmalloc(sizeof(void *) * list->capacity);
   if (!list->entries) {
     return 0;
   }
@@ -17,13 +18,13 @@ void list_reset(struct list *list) {
 }
 
 int list_add(struct list *list, void *entry, int *index) {
-  if (list->tail_index > 100 - 1) {
-    kprintf("Error: list has run out of space\n");
-    assert(0);
+  if (list->tail_index + 1 >= list->capacity) {
+    list->capacity += 25;
+    list->entries = krealloc(list->entries, sizeof(void *) * list->capacity);
   }
   list->tail_index++;
   list->entries[list->tail_index] = entry;
-  if(index) {
+  if (index) {
     *index = list->tail_index;
   }
   return 1;
diff --git a/kernel/lib/list.h b/kernel/lib/list.h
index 6ab9e0b..b7085cd 100644
--- a/kernel/lib/list.h
+++ b/kernel/lib/list.h
@@ -2,6 +2,7 @@
 #define LIST_H
 struct list {
   void **entries;
+  int capacity;
   int tail_index;
 };
 
diff --git a/kernel/sched/scheduler.c b/kernel/sched/scheduler.c
index 7afd203..2fa9ad3 100644
--- a/kernel/sched/scheduler.c
+++ b/kernel/sched/scheduler.c
@@ -213,6 +213,10 @@ void free_process(process_t *p) {
   list_free(&p->read_list);
   list_free(&p->write_list);
   list_free(&p->disconnect_list);
+  list_free(&p->tcp_sockets);
+  list_free(&p->tcp_listen);
+  list_free(&p->event_queue);
+  kfree(p->tcb);
 }
 
 void exit_process(process_t *p, int status) {
@@ -291,7 +295,8 @@ u32 setup_stack(u32 stack_pointer, int argc, char **argv) {
   return ptr;
 }
 
-int exec(const char *filename, char **argv) {
+int exec(const char *filename, char **argv, int dealloc_argv,
+         int dealloc_filename) {
   // exec() will "takeover" the process by loading the file specified in
   // filename into memory, change from ring 0 to ring 3 and jump to the
   // files entry point as decided by the ELF header of the file.
@@ -313,6 +318,15 @@ int exec(const char *filename, char **argv) {
 
   u32 ptr = setup_stack(0x90000000, argc, argv);
 
+  if (dealloc_argv) {
+    for (int i = 0; i < argc; i++) {
+      kfree(argv[i]);
+    }
+  }
+  if (dealloc_filename) {
+    kfree((char *)filename);
+  }
+
   jump_usermode((void (*)())(entry), ptr);
   ASSERT_NOT_REACHED;
   return 0;
@@ -475,6 +489,13 @@ void signal_process(process_t *p, int sig) {
   process_push_signal(p, signal);
 }
 
+int process_signal(vfs_fd_t *fd, int sig) {
+  process_t *p = fd->inode->internal_object;
+  assert(p);
+  signal_process(p, sig);
+  return 0;
+}
+
 int kill(pid_t pid, int sig) {
   process_t *p = current_task;
   p = p->next;
diff --git a/kernel/sched/scheduler.h b/kernel/sched/scheduler.h
index fbaed3e..b408f59 100644
--- a/kernel/sched/scheduler.h
+++ b/kernel/sched/scheduler.h
@@ -18,10 +18,12 @@ extern process_t *current_task;
 extern process_t *ready_queue;
 
 int fork(void);
-int exec(const char *filename, char **argv);
+int exec(const char *filename, char **argv, int dealloc_argv,
+         int dealloc_filename);
 void switch_task(void);
 void tasking_init(void);
 void exit(int status);
+int process_signal(vfs_fd_t *fd, int sig);
 
 void *mmap(void *addr, size_t length, int prot, int flags, int fd,
            size_t offset);
diff --git a/kernel/socket.c b/kernel/socket.c
index 39775ce..4017ca1 100644
--- a/kernel/socket.c
+++ b/kernel/socket.c
@@ -341,7 +341,7 @@ int socket(int domain, int type, int protocol) {
       1 /*is_open*/, new_socket /*internal_object*/, 0 /*file_size*/,
       NULL /*open*/, NULL /*create_file*/, socket_read, socket_write,
       socket_close, NULL /*create_directory*/, NULL /*get_vm_object*/,
-      NULL /*truncate*/, NULL /*stat*/);
+      NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/);
 
   vfs_fd_t *fd;
   int n = vfs_create_fd(O_RDWR | O_NONBLOCK, 0, 0 /*is_tty*/, inode, &fd);
diff --git a/kernel/syscalls/kill.c b/kernel/syscalls/kill.c
index 0da229a..affade6 100644
--- a/kernel/syscalls/kill.c
+++ b/kernel/syscalls/kill.c
@@ -1,7 +1,15 @@
+#include <errno.h>
 #include <sched/scheduler.h>
 #include <signal.h>
 #include <syscalls.h>
 
-int syscall_kill(pid_t pid, int sig) {
-  return kill(pid, sig);
+int syscall_kill(int fd, int sig) {
+  vfs_fd_t *fd_ptr = get_vfs_fd(fd, NULL);
+  if (!fd_ptr) {
+    return -EBADF;
+  }
+  if (!fd_ptr->inode->send_signal) {
+    return -EBADF;
+  }
+  return process_signal(fd_ptr, sig);
 }
diff --git a/kernel/syscalls/open_process.c b/kernel/syscalls/open_process.c
new file mode 100644
index 0000000..8e3a35e
--- /dev/null
+++ b/kernel/syscalls/open_process.c
@@ -0,0 +1,26 @@
+#include <assert.h>
+#include <errno.h>
+#include <sched/scheduler.h>
+
+int syscall_open_process(int pid) {
+  // TODO: Permission check
+  process_t *process = (process_t *)ready_queue;
+  for (; process; process = process->next) {
+    if (pid == process->pid) {
+      break;
+    }
+  }
+  if (!process) {
+    return -ESRCH;
+  }
+
+  vfs_inode_t *inode = vfs_create_inode(
+      process->pid, 0 /*type*/, 0 /*has_data*/, 0 /*can_write*/, 1 /*is_open*/,
+      process /*internal_object*/, 0 /*file_size*/, NULL /*open*/,
+      NULL /*create_file*/, NULL /*read*/, NULL /*write*/, NULL /*close*/,
+      NULL /*create_directory*/, NULL /*get_vm_object*/, NULL /*truncate*/,
+      NULL /*stat*/, process_signal);
+  int rc = vfs_create_fd(0, 0, 0, inode, NULL);
+  assert(rc >= 0);
+  return rc;
+}
diff --git a/userland/libc/Makefile b/userland/libc/Makefile
index c818200..b1291fa 100644
--- a/userland/libc/Makefile
+++ b/userland/libc/Makefile
@@ -3,7 +3,7 @@ AR="i686-sb-ar"
 AS="i686-sb-as"
 #CFLAGS = -ggdb -ffreestanding -O2 -Wall -Wextra -pedantic -Wimplicit-fallthrough -I./include/ -static -I../../include/ -Wno-int-conversion -Wno-unused-parameter -Wno-return-type
 CFLAGS = -ggdb -ffreestanding -Wall -Wextra -pedantic -Wimplicit-fallthrough -I./include/ -static -I../../include/ -Wno-int-conversion -Wno-unused-parameter -Wno-return-type
-OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o sys/mman/munmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o unistd/ftruncate.o sys/socket/recvfrom.o sys/socket/sendto.o signal/kill.o signal/sigaction.o unistd/chdir.o unistd/getcwd.o stdio/getdelim.o stdio/getline.o unistd/isatty.o sys/socket/listen.o stdlib/realpath.o systemcall.o sys/random/randomfill.o fcntl/open.o unistd/write.o unistd/pwrite.o
+OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o sys/mman/munmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o unistd/ftruncate.o sys/socket/recvfrom.o sys/socket/sendto.o signal/kill.o signal/sigaction.o unistd/chdir.o unistd/getcwd.o stdio/getdelim.o stdio/getline.o unistd/isatty.o sys/socket/listen.o stdlib/realpath.o systemcall.o sys/random/randomfill.o fcntl/open.o unistd/write.o unistd/pwrite.o fcntl/open_process.o
 all: libc.a
 
 %.o: %.c
diff --git a/userland/libc/fcntl/open_process.c b/userland/libc/fcntl/open_process.c
new file mode 100644
index 0000000..8486728
--- /dev/null
+++ b/userland/libc/fcntl/open_process.c
@@ -0,0 +1,6 @@
+#include <fcntl.h>
+#include <syscall.h>
+
+int open_process(int pid) {
+  RC_ERRNO(syscall(SYS_OPEN_PROCESS, pid, 0, 0, 0, 0));
+}
diff --git a/userland/libc/include/fcntl.h b/userland/libc/include/fcntl.h
index 29134be..57c968a 100644
--- a/userland/libc/include/fcntl.h
+++ b/userland/libc/include/fcntl.h
@@ -11,3 +11,4 @@
 #define O_RDWR (O_WRITE | O_READ)
 
 int open(const char *file, int flags, ...);
+int open_process(int pid);
diff --git a/userland/libc/include/signal.h b/userland/libc/include/signal.h
index 2be081c..a241015 100644
--- a/userland/libc/include/signal.h
+++ b/userland/libc/include/signal.h
@@ -37,7 +37,7 @@ struct siginfo {
 
 typedef struct siginfo siginfo_t;
 
-int kill(pid_t pid, int sig);
+int kill(int fd, int sig);
 
 struct sigaction {
   void (*sa_handler)(int); // Pointer to a signal-catching function or one of
diff --git a/userland/libc/include/syscall.h b/userland/libc/include/syscall.h
index e375079..c5fe3e4 100644
--- a/userland/libc/include/syscall.h
+++ b/userland/libc/include/syscall.h
@@ -61,6 +61,7 @@
 #define SYS_QUEUE_ADD 50
 #define SYS_QUEUE_WAIT 51
 #define SYS_MUNMAP 52
+#define SYS_OPEN_PROCESS 53
 
 int syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx,
             uint32_t esi, uint32_t edi);
diff --git a/userland/libc/signal/kill.c b/userland/libc/signal/kill.c
index 3351baa..c5ed62b 100644
--- a/userland/libc/signal/kill.c
+++ b/userland/libc/signal/kill.c
@@ -1,4 +1,6 @@
 #include <signal.h>
 #include <syscall.h>
 
-int kill(pid_t pid, int sig) { RC_ERRNO(syscall(SYS_KILL, pid, sig, 0, 0, 0)) }
+int kill(int fd, int sig) {
+  RC_ERRNO(syscall(SYS_KILL, fd, sig, 0, 0, 0))
+}
diff --git a/userland/minibox/utilities/kill.c b/userland/minibox/utilities/kill.c
index 2888b3b..8cc6877 100644
--- a/userland/minibox/utilities/kill.c
+++ b/userland/minibox/utilities/kill.c
@@ -1,9 +1,12 @@
 // kill
 #include "include.h"
+#include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 
 int kill_main(int argc, char **argv) {
-  kill(4, SIGTERM);
+  int fd = open_process(4);
+  kill(fd, SIGTERM);
+  close(fd);
   return 0;
 }
diff --git a/userland/sh/sh.c b/userland/sh/sh.c
index e7741aa..e386ef6 100644
--- a/userland/sh/sh.c
+++ b/userland/sh/sh.c
@@ -49,7 +49,9 @@ void remove_child_process(int pid) {
 void slaugther_children(void) {
   struct child_process *child = children;
   for (; child; child = child->next) {
-    kill(child->pid, SIGTERM);
+    int fd = open_process(child->pid);
+    kill(fd, SIGTERM);
+    close(fd);
   }
 }
 
-- 
cgit v1.2.3