mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
![Anton Blanchard](/assets/img/avatar_default.png)
I chased down a fail on ppc64 on 2.6.34-rc2 where an application that
uses shared memory was getting a SEGV.
Commit baed7fc9b5
("Add generic sys_ipc
wrapper") changed the second argument from an unsigned long to an int.
When we call shmget the system call wrappers for sys_ipc will sign
extend second (ie the size) which truncates it. It took a while to
track down because the call succeeds and strace shows the untruncated
size :)
The patch below changes second from an int to an unsigned long which
fixes shmget on ppc64 (and I assume s390, sparc64 and mips64).
Signed-off-by: Anton Blanchard <anton@samba.org>
--
I assume the function prototypes for the other IPC methods would cause us
to sign or zero extend second where appropriate (avoiding any security
issues). Come to think of it, the syscall wrappers for each method should do
that for us as well.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
99 lines
2.3 KiB
C
99 lines
2.3 KiB
C
/*
|
|
* sys_ipc() is the old de-multiplexer for the SysV IPC calls.
|
|
*
|
|
* This is really horribly ugly, and new architectures should just wire up
|
|
* the individual syscalls instead.
|
|
*/
|
|
#include <linux/unistd.h>
|
|
|
|
#ifdef __ARCH_WANT_SYS_IPC
|
|
#include <linux/errno.h>
|
|
#include <linux/ipc.h>
|
|
#include <linux/shm.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
|
|
unsigned long, third, void __user *, ptr, long, fifth)
|
|
{
|
|
int version, ret;
|
|
|
|
version = call >> 16; /* hack for backward compatibility */
|
|
call &= 0xffff;
|
|
|
|
switch (call) {
|
|
case SEMOP:
|
|
return sys_semtimedop(first, (struct sembuf __user *)ptr,
|
|
second, NULL);
|
|
case SEMTIMEDOP:
|
|
return sys_semtimedop(first, (struct sembuf __user *)ptr,
|
|
second,
|
|
(const struct timespec __user *)fifth);
|
|
|
|
case SEMGET:
|
|
return sys_semget(first, second, third);
|
|
case SEMCTL: {
|
|
union semun fourth;
|
|
if (!ptr)
|
|
return -EINVAL;
|
|
if (get_user(fourth.__pad, (void __user * __user *) ptr))
|
|
return -EFAULT;
|
|
return sys_semctl(first, second, third, fourth);
|
|
}
|
|
|
|
case MSGSND:
|
|
return sys_msgsnd(first, (struct msgbuf __user *) ptr,
|
|
second, third);
|
|
case MSGRCV:
|
|
switch (version) {
|
|
case 0: {
|
|
struct ipc_kludge tmp;
|
|
if (!ptr)
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&tmp,
|
|
(struct ipc_kludge __user *) ptr,
|
|
sizeof(tmp)))
|
|
return -EFAULT;
|
|
return sys_msgrcv(first, tmp.msgp, second,
|
|
tmp.msgtyp, third);
|
|
}
|
|
default:
|
|
return sys_msgrcv(first,
|
|
(struct msgbuf __user *) ptr,
|
|
second, fifth, third);
|
|
}
|
|
case MSGGET:
|
|
return sys_msgget((key_t) first, second);
|
|
case MSGCTL:
|
|
return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);
|
|
|
|
case SHMAT:
|
|
switch (version) {
|
|
default: {
|
|
unsigned long raddr;
|
|
ret = do_shmat(first, (char __user *)ptr,
|
|
second, &raddr);
|
|
if (ret)
|
|
return ret;
|
|
return put_user(raddr, (unsigned long __user *) third);
|
|
}
|
|
case 1:
|
|
/*
|
|
* This was the entry point for kernel-originating calls
|
|
* from iBCS2 in 2.2 days.
|
|
*/
|
|
return -EINVAL;
|
|
}
|
|
case SHMDT:
|
|
return sys_shmdt((char __user *)ptr);
|
|
case SHMGET:
|
|
return sys_shmget(first, second, third);
|
|
case SHMCTL:
|
|
return sys_shmctl(first, second,
|
|
(struct shmid_ds __user *) ptr);
|
|
default:
|
|
return -ENOSYS;
|
|
}
|
|
}
|
|
#endif
|