semctl(): move compat to native
[platform/kernel/linux-rpi.git] / ipc / compat.c
1 /*
2  * 32 bit compatibility code for System V IPC
3  *
4  * Copyright (C) 1997,1998      Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5  * Copyright (C) 1997           David S. Miller (davem@caip.rutgers.edu)
6  * Copyright (C) 1999           Arun Sharma <arun.sharma@intel.com>
7  * Copyright (C) 2000           VA Linux Co
8  * Copyright (C) 2000           Don Dugger <n0ano@valinux.com>
9  * Copyright (C) 2000           Hewlett-Packard Co.
10  * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
11  * Copyright (C) 2000           Gerhard Tonn (ton@de.ibm.com)
12  * Copyright (C) 2000-2002      Andi Kleen, SuSE Labs (x86-64 port)
13  * Copyright (C) 2000           Silicon Graphics, Inc.
14  * Copyright (C) 2001           IBM
15  * Copyright (C) 2004           IBM Deutschland Entwicklung GmbH, IBM Corporation
16  * Copyright (C) 2004           Arnd Bergmann (arnd@arndb.de)
17  *
18  * This code is collected from the versions for sparc64, mips64, s390x, ia64,
19  * ppc64 and x86_64, all of which are based on the original sparc64 version
20  * by Jakub Jelinek.
21  *
22  */
23 #include <linux/compat.h>
24 #include <linux/errno.h>
25 #include <linux/highuid.h>
26 #include <linux/init.h>
27 #include <linux/msg.h>
28 #include <linux/shm.h>
29 #include <linux/syscalls.h>
30 #include <linux/ptrace.h>
31
32 #include <linux/mutex.h>
33 #include <linux/uaccess.h>
34
35 #include "util.h"
36
37 struct compat_msgbuf {
38         compat_long_t mtype;
39         char mtext[1];
40 };
41
42 struct compat_ipc_kludge {
43         compat_uptr_t msgp;
44         compat_long_t msgtyp;
45 };
46
47 int get_compat_ipc64_perm(struct ipc64_perm *to,
48                           struct compat_ipc64_perm __user *from)
49 {
50         struct compat_ipc64_perm v;
51         if (copy_from_user(&v, from, sizeof(v)))
52                 return -EFAULT;
53         to->uid = v.uid;
54         to->gid = v.gid;
55         to->mode = v.mode;
56         return 0;
57 }
58
59 int get_compat_ipc_perm(struct ipc64_perm *to,
60                         struct compat_ipc_perm __user *from)
61 {
62         struct compat_ipc_perm v;
63         if (copy_from_user(&v, from, sizeof(v)))
64                 return -EFAULT;
65         to->uid = v.uid;
66         to->gid = v.gid;
67         to->mode = v.mode;
68         return 0;
69 }
70
71 void to_compat_ipc64_perm(struct compat_ipc64_perm *to, struct ipc64_perm *from)
72 {
73         to->key = from->key;
74         to->uid = from->uid;
75         to->gid = from->gid;
76         to->cuid = from->cuid;
77         to->cgid = from->cgid;
78         to->mode = from->mode;
79         to->seq = from->seq;
80 }
81
82 void to_compat_ipc_perm(struct compat_ipc_perm *to, struct ipc64_perm *from)
83 {
84         to->key = from->key;
85         SET_UID(to->uid, from->uid);
86         SET_GID(to->gid, from->gid);
87         SET_UID(to->cuid, from->cuid);
88         SET_GID(to->cgid, from->cgid);
89         to->mode = from->mode;
90         to->seq = from->seq;
91 }
92
93 static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
94 {
95         struct compat_msgbuf __user *msgp = dest;
96         size_t msgsz;
97
98         if (put_user(msg->m_type, &msgp->mtype))
99                 return -EFAULT;
100
101         msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
102         if (store_msg(msgp->mtext, msg, msgsz))
103                 return -EFAULT;
104         return msgsz;
105 }
106
107 #ifndef COMPAT_SHMLBA
108 #define COMPAT_SHMLBA   SHMLBA
109 #endif
110
111 #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
112 COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
113         u32, third, compat_uptr_t, ptr, u32, fifth)
114 {
115         int version;
116         u32 pad;
117
118         version = call >> 16; /* hack for backward compatibility */
119         call &= 0xffff;
120
121         switch (call) {
122         case SEMOP:
123                 /* struct sembuf is the same on 32 and 64bit :)) */
124                 return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
125         case SEMTIMEDOP:
126                 return compat_sys_semtimedop(first, compat_ptr(ptr), second,
127                                                 compat_ptr(fifth));
128         case SEMGET:
129                 return sys_semget(first, second, third);
130         case SEMCTL:
131                 if (!ptr)
132                         return -EINVAL;
133                 if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
134                         return -EFAULT;
135                 return compat_sys_semctl(first, second, third, pad);
136
137         case MSGSND: {
138                 struct compat_msgbuf __user *up = compat_ptr(ptr);
139                 compat_long_t type;
140
141                 if (first < 0 || second < 0)
142                         return -EINVAL;
143
144                 if (get_user(type, &up->mtype))
145                         return -EFAULT;
146
147                 return do_msgsnd(first, type, up->mtext, second, third);
148         }
149         case MSGRCV: {
150                 void __user *uptr = compat_ptr(ptr);
151
152                 if (first < 0 || second < 0)
153                         return -EINVAL;
154
155                 if (!version) {
156                         struct compat_ipc_kludge ipck;
157                         if (!uptr)
158                                 return -EINVAL;
159                         if (copy_from_user(&ipck, uptr, sizeof(ipck)))
160                                 return -EFAULT;
161                         uptr = compat_ptr(ipck.msgp);
162                         fifth = ipck.msgtyp;
163                 }
164                 return do_msgrcv(first, uptr, second, (s32)fifth, third,
165                                  compat_do_msg_fill);
166         }
167         case MSGGET:
168                 return sys_msgget(first, second);
169         case MSGCTL:
170                 return compat_sys_msgctl(first, second, compat_ptr(ptr));
171
172         case SHMAT: {
173                 int err;
174                 unsigned long raddr;
175
176                 if (version == 1)
177                         return -EINVAL;
178                 err = do_shmat(first, compat_ptr(ptr), second, &raddr,
179                                COMPAT_SHMLBA);
180                 if (err < 0)
181                         return err;
182                 return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
183         }
184         case SHMDT:
185                 return sys_shmdt(compat_ptr(ptr));
186         case SHMGET:
187                 return sys_shmget(first, (unsigned)second, third);
188         case SHMCTL:
189                 return compat_sys_shmctl(first, second, compat_ptr(ptr));
190         }
191
192         return -ENOSYS;
193 }
194 #endif
195
196 COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
197                        compat_ssize_t, msgsz, int, msgflg)
198 {
199         struct compat_msgbuf __user *up = compat_ptr(msgp);
200         compat_long_t mtype;
201
202         if (get_user(mtype, &up->mtype))
203                 return -EFAULT;
204         return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
205 }
206
207 COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
208                        compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
209 {
210         return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
211                          msgflg, compat_do_msg_fill);
212 }
213
214 COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
215 {
216         unsigned long ret;
217         long err;
218
219         err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
220         if (err)
221                 return err;
222         force_successful_syscall_return();
223         return (long)ret;
224 }
225
226 COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
227                        unsigned, nsops,
228                        const struct compat_timespec __user *, timeout)
229 {
230         struct timespec __user *ts64;
231         if (compat_convert_timespec(&ts64, timeout))
232                 return -EFAULT;
233         return sys_semtimedop(semid, tsems, nsops, ts64);
234 }