ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / um / kernel / tt / syscall_kern.c
1 /* 
2  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/types.h"
7 #include "linux/utime.h"
8 #include "linux/sys.h"
9 #include "linux/ptrace.h"
10 #include "asm/unistd.h"
11 #include "asm/ptrace.h"
12 #include "asm/uaccess.h"
13 #include "asm/stat.h"
14 #include "sysdep/syscalls.h"
15 #include "kern_util.h"
16
17 static inline int check_area(void *ptr, int size)
18 {
19         return(verify_area(VERIFY_WRITE, ptr, size));
20 }
21
22 static int check_readlink(struct pt_regs *regs)
23 {
24         return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs),
25                           UPT_SYSCALL_ARG2(&regs->regs)));
26 }
27
28 static int check_utime(struct pt_regs *regs)
29 {
30         return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs),
31                           sizeof(struct utimbuf)));
32 }
33
34 static int check_oldstat(struct pt_regs *regs)
35 {
36         return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs), 
37                           sizeof(struct __old_kernel_stat)));
38 }
39
40 static int check_stat(struct pt_regs *regs)
41 {
42         return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs), 
43                           sizeof(struct stat)));
44 }
45
46 static int check_stat64(struct pt_regs *regs)
47 {
48         return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs), 
49                           sizeof(struct stat64)));
50 }
51
52 struct bogus {
53         int kernel_ds;
54         int (*check_params)(struct pt_regs *);
55 };
56
57 struct bogus this_is_bogus[256] = {
58         [ __NR_mknod ] = { 1, NULL },
59         [ __NR_mkdir ] = { 1, NULL },
60         [ __NR_rmdir ] = { 1, NULL },
61         [ __NR_unlink ] = { 1, NULL },
62         [ __NR_symlink ] = { 1, NULL },
63         [ __NR_link ] = { 1, NULL },
64         [ __NR_rename ] = { 1, NULL },
65         [ __NR_umount ] = { 1, NULL },
66         [ __NR_mount ] = { 1, NULL },
67         [ __NR_pivot_root ] = { 1, NULL },
68         [ __NR_chdir ] = { 1, NULL },
69         [ __NR_chroot ] = { 1, NULL },
70         [ __NR_open ] = { 1, NULL },
71         [ __NR_quotactl ] = { 1, NULL },
72         [ __NR_sysfs ] = { 1, NULL },
73         [ __NR_readlink ] = { 1, check_readlink },
74         [ __NR_acct ] = { 1, NULL },
75         [ __NR_execve ] = { 1, NULL },
76         [ __NR_uselib ] = { 1, NULL },
77         [ __NR_statfs ] = { 1, NULL },
78         [ __NR_truncate ] = { 1, NULL },
79         [ __NR_access ] = { 1, NULL },
80         [ __NR_chmod ] = { 1, NULL },
81         [ __NR_chown ] = { 1, NULL },
82         [ __NR_lchown ] = { 1, NULL },
83         [ __NR_utime ] = { 1, check_utime },
84         [ __NR_oldlstat ] = { 1, check_oldstat },
85         [ __NR_oldstat ] = { 1, check_oldstat },
86         [ __NR_stat ] = { 1, check_stat },
87         [ __NR_lstat ] = { 1, check_stat },
88         [ __NR_stat64 ] = { 1, check_stat64 },
89         [ __NR_lstat64 ] = { 1, check_stat64 },
90         [ __NR_chown32 ] = { 1, NULL },
91 };
92
93 /* sys_utimes */
94
95 static int check_bogosity(struct pt_regs *regs)
96 {
97         struct bogus *bogon = &this_is_bogus[UPT_SYSCALL_NR(&regs->regs)];
98
99         if(!bogon->kernel_ds) return(0);
100         if(bogon->check_params && (*bogon->check_params)(regs))
101                 return(-EFAULT);
102         set_fs(KERNEL_DS);
103         return(0);
104 }
105
106 extern syscall_handler_t *sys_call_table[];
107
108 long execute_syscall_tt(void *r)
109 {
110         struct pt_regs *regs = r;
111         long res;
112         int syscall;
113
114         current->thread.nsyscalls++;
115         nsyscalls++;
116         syscall = UPT_SYSCALL_NR(&regs->regs);
117
118         if((syscall >= NR_syscalls) || (syscall < 0))
119                 res = -ENOSYS;
120         else if(honeypot && check_bogosity(regs))
121                 res = -EFAULT;
122         else res = EXECUTE_SYSCALL(syscall, regs);
123
124         set_fs(USER_DS);
125
126         if(current->thread.mode.tt.singlestep_syscall){
127                 current->thread.mode.tt.singlestep_syscall = 0;
128                 current->ptrace &= ~PT_DTRACE;
129                 force_sig(SIGTRAP, current);
130         }
131
132         return(res);
133 }
134
135 /*
136  * Overrides for Emacs so that we follow Linus's tabbing style.
137  * Emacs will notice this stuff at the end of the file and automatically
138  * adjust the settings for this buffer only.  This must remain at the end
139  * of the file.
140  * ---------------------------------------------------------------------------
141  * Local variables:
142  * c-file-style: "linux"
143  * End:
144  */