Commit 6a1a1239 authored by Ernie Petrides's avatar Ernie Petrides Committed by David Mosberger

[PATCH] ia64: fixes for semtimedop() ia32-compat handling

Here are two fixes for the ia32-compatibility mode handling
for the new semtimedop() system call for the ia64 architecture.

The first problem was that treatment of user-mode calls to semtimedop()
with a NULL 4th (struct timespec *) parameter was inconsistent with the
behavior of the same executable on i386 and also with a natively compiled
ia64 binary.  A NULL 4th arg to semtimedop() should result in no timeout
being used (like a straight semop() call) rather than in an EFAULT error.

The second problem was that a legitimate semtimedop() with a timeout was
also resulting in an EFAULT because the fetch of the internal timespec
strucure by sys_semtimedop() from semtimedop32()'s kernel stack was
treated as an invalid user-data reference.  This requires temporarily
switching the addressing limit with set_fs(), further requiring that
appropriate parameter checking by performed prior to the switch.

The const qualifier was removed from the (struct compat_timespec *) arg
to semtimedop32() so that the call to get_compat_timespec() wouldn't
generate a compilation warning.
parent 7c19bf64
...@@ -1576,19 +1576,35 @@ shmctl32 (int first, int second, void *uptr) ...@@ -1576,19 +1576,35 @@ shmctl32 (int first, int second, void *uptr)
return err; return err;
} }
extern int sem_ctls[];
#define sc_semopm (sem_ctls[2])
static long static long
semtimedop32(int semid, struct sembuf *tsems, int nsems, semtimedop32(int semid, struct sembuf *tsops, int nsops,
const struct compat_timespec *timeout32) struct compat_timespec *timeout32)
{ {
struct timespec t; struct timespec t;
if (get_user (t.tv_sec, &timeout32->tv_sec) || mm_segment_t oldfs;
get_user (t.tv_nsec, &timeout32->tv_nsec)) long ret;
/* parameter checking precedence should mirror sys_semtimedop() */
if (nsops < 1 || semid < 0)
return -EINVAL;
if (nsops > sc_semopm)
return -E2BIG;
if (!access_ok(VERIFY_READ, tsops, nsops * sizeof(struct sembuf)) ||
get_compat_timespec(&t, timeout32))
return -EFAULT; return -EFAULT;
return sys_semtimedop(semid, tsems, nsems, &t);
oldfs = get_fs();
set_fs(KERNEL_DS);
ret = sys_semtimedop(semid, tsops, nsops, &t);
set_fs(oldfs);
return ret;
} }
asmlinkage long asmlinkage long
sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth)
{ {
int version; int version;
...@@ -1596,12 +1612,15 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) ...@@ -1596,12 +1612,15 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
call &= 0xffff; call &= 0xffff;
switch (call) { switch (call) {
case SEMTIMEDOP:
if (fifth)
return semtimedop32(first, (struct sembuf *)AA(ptr),
second, (struct compat_timespec *)AA(fifth));
/* else fall through for normal semop() */
case SEMOP: case SEMOP:
/* struct sembuf is the same on 32 and 64bit :)) */ /* struct sembuf is the same on 32 and 64bit :)) */
return sys_semtimedop(first, (struct sembuf *)AA(ptr), second, NULL); return sys_semtimedop(first, (struct sembuf *)AA(ptr), second,
case SEMTIMEDOP: NULL);
return semtimedop32(first, (struct sembuf *)AA(ptr), second,
(const struct compat_timespec *)AA(fifth));
case SEMGET: case SEMGET:
return sys_semget(first, second, third); return sys_semget(first, second, third);
case SEMCTL: case SEMCTL:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment