Fork me on GitHub

root/kernel/syscalls.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. verify_address
  2. free_name
  3. malloc_name
  4. check_user_permission
  5. check_group
  6. check_user_area
  7. check_permission
  8. do_bad_syscall
  9. do_syscall

   1 /*
   2  * fiwix/kernel/syscalls.c
   3  *
   4  * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/types.h>
   9 #include <fiwix/syscalls.h>
  10 #include <fiwix/mm.h>
  11 #include <fiwix/stat.h>
  12 #include <fiwix/errno.h>
  13 #include <fiwix/string.h>
  14 
  15 #ifdef __DEBUG__
  16 #include <fiwix/stdio.h>
  17 #endif /*__DEBUG__ */
  18 
  19 static int verify_address(int type, const void *addr, unsigned int size)
  20 {
  21 #ifdef CONFIG_LAZY_USER_ADDR_CHECK
  22         if(!addr) {
  23                 return -EFAULT;
  24         }
  25 #else
  26         struct vma *vma;
  27         unsigned int start;
  28 
  29         /*
  30          * Verifies if the 'vma' array of that process is not empty. It can
  31          * only be empty during the initialization of INIT, when it calls to
  32          * sys_execve and sys_open without having yet a proper setup.
  33          */
  34         if(current->vma[0].s_type != 0) {
  35                 start = (unsigned int)addr;
  36                 if(!(vma = find_vma_region(start))) {
  37                         return -EFAULT;
  38                 }
  39 
  40                 for(;;) {
  41                         if(type == VERIFY_WRITE) {
  42                                 if(!(vma->prot & PROT_WRITE)) {
  43                                         return -EFAULT;
  44                                 }
  45                         } else {
  46                                 if(!(vma->prot & PROT_READ)) {
  47                                         return -EFAULT;
  48                                 }
  49                         }
  50                         if(start + size < vma->end) {
  51                                 break;
  52                         }
  53                         if(!(vma = find_vma_region(vma->end))) {
  54                                 return -EFAULT;
  55                         }
  56                 }
  57         }
  58 #endif /* CONFIG_LAZY_USER_ADDR_CHECK */
  59 
  60         return 0;
  61 }
  62 
  63 void free_name(const char *name)
  64 {
  65         kfree((unsigned int)name);
  66 }
  67 
  68 /*
  69  * This function has two objectives:
  70  *
  71  * 1. verifies the memory address validity of the char pointer supplied by the
  72  *    user and, at the same time, limits its length to PAGE_SIZE (4096) bytes.
  73  * 2. creates a copy of 'filename' in the kernel data space before using it.
  74  */
  75 int malloc_name(const char *filename, char **name)
  76 {
  77         short int n, len;
  78         char *b;
  79         int errno;
  80 
  81         /* verifies only the pointer address */
  82         if((errno = verify_address(PROT_READ, filename, 0))) {
  83                 return errno;
  84         }
  85 
  86         len = MIN(strlen(filename), PAGE_SIZE);
  87         if(!(b = (char *)kmalloc())) {
  88                 return -ENOMEM;
  89         }
  90         *name = b;
  91         for(n = 0; n < (len + 1); n++) {
  92                 if(!(*b = *filename)) {
  93                         return 0;
  94                 }
  95                 b++;
  96                 filename++;
  97         }
  98 
  99         free_name(*name);
 100         return -ENAMETOOLONG;
 101 }
 102 
 103 int check_user_permission(struct inode *i)
 104 {
 105         if(!IS_SUPERUSER) {
 106                 if(current->euid != i->i_uid) {
 107                         return 1;
 108                 }
 109         }
 110         return 0;
 111 }
 112 
 113 int check_group(struct inode *i)
 114 {
 115         int n;
 116         __gid_t gid;
 117 
 118         if(current->flags & PF_USEREAL) {
 119                 gid = current->gid;
 120         } else {
 121                 gid = current->egid;
 122         }
 123 
 124         if(i->i_gid == gid) {
 125                 return 0;
 126         }
 127 
 128         for(n = 0; n < NGROUPS_MAX; n++) {
 129                 if(current->groups[n] == -1) {
 130                         break;
 131                 }
 132                 if(current->groups[n] == i->i_gid) {
 133                         return 0;
 134                 }
 135         }
 136         return 1;
 137 }
 138 
 139 int check_user_area(int type, const void *addr, unsigned int size)
 140 {
 141         return verify_address(type, addr, size);
 142 }
 143 
 144 int check_permission(int mask, struct inode *i)
 145 {
 146         __uid_t uid;
 147 
 148         if(current->flags & PF_USEREAL) {
 149                 uid = current->uid;
 150         } else {
 151                 uid = current->euid;
 152         }
 153 
 154         if(mask & TO_EXEC) {
 155                 if(!(i->i_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
 156                         return -EACCES;
 157                 }
 158         }
 159         if(uid == 0) {
 160                 return 0;
 161         }
 162         if(i->i_uid == uid) {
 163                 if((((i->i_mode >> 6) & 7) & mask) == mask) {
 164                         return 0;
 165                 }
 166         }
 167         if(!check_group(i)) {
 168                 if((((i->i_mode >> 3) & 7) & mask) == mask) {
 169                         return 0;
 170                 }
 171         }
 172         if(((i->i_mode & 7) & mask) == mask) {
 173                 return 0;
 174         }
 175 
 176         return -EACCES;
 177 }
 178 
 179 
 180 /* Linux 2.0 ABI system call (plus some from Linux 2.2) */
 181 void *syscall_table[] = {
 182         NULL,                           /* 0 */ /* sys_setup (-ENOSYS) */
 183         sys_exit,
 184         sys_fork,
 185         sys_read,
 186         sys_write,
 187         sys_open,                       /* 5 */
 188         sys_close,
 189         sys_waitpid,
 190         sys_creat,
 191         sys_link,
 192         sys_unlink,                     /* 10 */
 193         sys_execve,
 194         sys_chdir,
 195         sys_time,
 196         sys_mknod,
 197         sys_chmod,                      /* 15 */
 198         sys_chown,
 199         NULL,                                   /* sys_break (-ENOSYS) */
 200         sys_stat,
 201         sys_lseek,
 202         sys_getpid,                     /* 20 */
 203         sys_mount,
 204         sys_umount,
 205         sys_setuid,
 206         sys_getuid,
 207         sys_stime,                      /* 25 */
 208         NULL,   /* sys_ptrace */
 209         sys_alarm,
 210         sys_fstat,
 211         sys_pause,
 212         sys_utime,                      /* 30 */
 213         NULL,                                   /* sys_stty (-ENOSYS) */
 214         NULL,                                   /* sys_gtty (-ENOSYS) */
 215         sys_access,
 216         NULL,   /* sys_nice */
 217         sys_ftime,                      /* 35 */
 218         sys_sync,
 219         sys_kill,
 220         sys_rename,
 221         sys_mkdir,
 222         sys_rmdir,                      /* 40 */
 223         sys_dup,
 224         sys_pipe,
 225         sys_times,
 226         NULL,   /* sys_prof */
 227         sys_brk,                        /* 45 */
 228         sys_setgid,
 229         sys_getgid,
 230         sys_signal,
 231         sys_geteuid,
 232         sys_getegid,                    /* 50 */
 233         NULL,   /* sys_acct */
 234         sys_umount2,
 235         NULL,                                   /* sys_lock (-ENOSYS) */
 236         sys_ioctl,
 237         sys_fcntl,                      /* 55 */
 238         NULL,                                   /* sys_mpx (-ENOSYS) */
 239         sys_setpgid,
 240         NULL,                                   /* sys_ulimit (-ENOSYS) */
 241         sys_olduname,
 242         sys_umask,                      /* 60 */
 243         sys_chroot,
 244         sys_ustat,
 245         sys_dup2,
 246         sys_getppid,
 247         sys_getpgrp,                    /* 65 */
 248         sys_setsid,
 249         sys_sigaction,
 250         sys_sgetmask,
 251         sys_ssetmask,
 252         sys_setreuid,                   /* 70 */
 253         sys_setregid,
 254         sys_sigsuspend,
 255         sys_sigpending,
 256         sys_sethostname,
 257         sys_setrlimit,                  /* 75 */
 258         sys_getrlimit,
 259         sys_getrusage,
 260         sys_gettimeofday,
 261         sys_settimeofday,
 262         sys_getgroups,                  /* 80 */
 263         sys_setgroups,
 264         old_select,
 265         sys_symlink,
 266         sys_lstat,
 267         sys_readlink,                   /* 85 */
 268         NULL,   /* sys_uselib */
 269         NULL,   /* sys_swapon */
 270         sys_reboot,
 271         NULL,   /* old_readdir */
 272         old_mmap,                       /* 90 */
 273         sys_munmap,
 274         sys_truncate,
 275         sys_ftruncate,
 276         sys_fchmod,
 277         sys_fchown,                     /* 95 */
 278         NULL,   /* sys_getpriority */
 279         NULL,   /* sys_setpriority */
 280         NULL,                                   /* sys_profil (-ENOSYS) */
 281         sys_statfs,
 282         sys_fstatfs,                    /* 100 */
 283         sys_ioperm,
 284         sys_socketcall, /* sys_socketcall XXX */
 285         NULL,   /* sys_syslog */
 286         sys_setitimer,
 287         sys_getitimer,                  /* 105 */
 288         sys_newstat,
 289         sys_newlstat,
 290         sys_newfstat,
 291         sys_uname,
 292         sys_iopl,                       /* 110 */
 293         NULL,   /* sys_vhangup */
 294         NULL,                                   /* sys_idle (-ENOSYS) */
 295         NULL,   /* sys_vm86old */
 296         sys_wait4,
 297         NULL,   /* sys_swapoff */       /* 115 */
 298         sys_sysinfo,
 299 #ifdef CONFIG_SYSVIPC
 300         sys_ipc,
 301 #else
 302         NULL,   /* sys_ipc */
 303 #endif /* CONFIG_SYSVIPC */
 304         sys_fsync,
 305         sys_sigreturn,
 306         NULL,   /* sys_clone */         /* 120 */
 307         sys_setdomainname,
 308         sys_newuname,
 309         NULL,   /* sys_modify_ldt */
 310         NULL,   /* sys_adjtimex */
 311         sys_mprotect,                   /* 125 */
 312         sys_sigprocmask,
 313         NULL,   /* sys_create_module */
 314         NULL,   /* sys_init_module */
 315         NULL,   /* sys_delete_module */
 316         NULL,   /* sys_get_kernel_syms */       /* 130 */
 317         NULL,   /* sys_quotactl */
 318         sys_getpgid,
 319         sys_fchdir,
 320         NULL,   /* sys_bdflush */
 321         NULL,   /* sys_sysfs */         /* 135 */
 322         sys_personality,
 323         NULL,                                   /* afs_syscall (-ENOSYS) */
 324         sys_setfsuid,
 325         sys_setfsgid,
 326         sys_llseek,                     /* 140 */
 327         sys_getdents,
 328         sys_select,
 329         sys_flock,
 330         NULL,   /* sys_msync */
 331         NULL,   /* sys_readv */         /* 145 */
 332         NULL,   /* sys_writev */
 333         sys_getsid,
 334         sys_fdatasync,
 335         NULL,   /* sys_sysctl */
 336         NULL,   /* sys_mlock */         /* 150 */
 337         NULL,   /* sys_munlock */
 338         NULL,   /* sys_mlockall */
 339         NULL,   /* sys_munlockall */
 340         NULL,   /* sys_sched_setparam */
 341         NULL,   /* sys_sched_getparam */        /* 155 */
 342         NULL,   /* sys_sched_setscheduler */
 343         NULL,   /* sys_sched_getscheduler */
 344         NULL,   /* sys_sched_yield */
 345         NULL,   /* sys_sched_get_priority_max */
 346         NULL,   /* sys_sched_get_priority_min */        /* 160 */
 347         NULL,   /* sys_sched_rr_get_interval */
 348         sys_nanosleep,
 349         NULL,   /* sys_mremap */
 350         NULL,
 351         NULL,                           /* 165 */
 352         NULL,
 353         NULL,
 354         NULL,
 355         NULL,
 356         NULL,                           /* 170 */
 357         NULL,
 358         NULL,
 359         NULL,
 360         NULL,
 361         NULL,                           /* 175 */
 362         NULL,
 363         NULL,
 364         NULL,
 365         NULL,
 366         NULL,                           /* 180 */
 367         NULL,
 368         sys_chown,
 369         sys_getcwd,
 370         NULL,
 371         NULL,                           /* 185 */
 372         NULL,
 373         NULL,
 374         NULL,
 375         NULL,
 376         sys_fork,                       /* 190 (sys_vfork) */
 377 };
 378 
 379 static void do_bad_syscall(unsigned int num)
 380 {
 381 #ifdef __DEBUG__
 382         printk("***** (pid %d) system call %d not supported yet *****\n", current->pid, num);
 383 #endif /*__DEBUG__ */
 384 }
 385 
 386 /*
 387  * The argument 'struct sigcontext' is needed because there are some system
 388  * calls (such as sys_iopl and sys_fork) that need to get information from
 389  * certain registers (EFLAGS and ESP). The rest of system calls will ignore
 390  * such extra argument.
 391  */
 392 #ifdef CONFIG_SYSCALL_6TH_ARG
 393 int do_syscall(unsigned int num, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, struct sigcontext sc)
 394 #else
 395 int do_syscall(unsigned int num, int arg1, int arg2, int arg3, int arg4, int arg5, struct sigcontext sc)
 396 #endif /* CONFIG_SYSCALL_6TH_ARG */
 397 {
 398         int (*sys_func)(int, ...);
 399 
 400         if(num > NR_SYSCALLS) {
 401                 do_bad_syscall(num);
 402                 return -ENOSYS;
 403         }
 404         sys_func = syscall_table[num];
 405         if(!sys_func) {
 406                 do_bad_syscall(num);
 407                 return -ENOSYS;
 408         }
 409         current->sp = (unsigned int)&sc;
 410 #ifdef CONFIG_SYSCALL_6TH_ARG
 411         return sys_func(arg1, arg2, arg3, arg4, arg5, arg6, &sc);
 412 #else
 413         return sys_func(arg1, arg2, arg3, arg4, arg5, &sc);
 414 #endif /* CONFIG_SYSCALL_6TH_ARG */
 415 }

/* [previous][next][first][last][top][bottom][index][help] */