Skip to content

Commit

Permalink
[CVE-2009-0029] System call wrapper special cases
Browse files Browse the repository at this point in the history
System calls with an unsigned long long argument can't be converted with
the standard wrappers since that would include a cast to long, which in
turn means that we would lose the upper 32 bit on 32 bit architectures.
Also semctl can't use the standard wrapper since it has a 'union'
parameter.

So we handle them as special case and add some extra wrappers instead.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
  • Loading branch information
heicarst committed Jan 14, 2009
1 parent ed6bb61 commit 6673e0c
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 17 deletions.
10 changes: 8 additions & 2 deletions fs/dcookies.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ int get_dcookie(struct path *path, unsigned long *cookie)
/* And here is where the userspace process can look up the cookie value
* to retrieve the path.
*/
asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len)
SYSCALL_DEFINE(lookup_dcookie)(u64 cookie64, char __user * buf, size_t len)
{
unsigned long cookie = (unsigned long)cookie64;
int err = -EINVAL;
Expand Down Expand Up @@ -198,7 +198,13 @@ asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len)
mutex_unlock(&dcookie_mutex);
return err;
}

#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_lookup_dcookie(u64 cookie64, long buf, long len)
{
return SYSC_lookup_dcookie(cookie64, (char __user *) buf, (size_t) len);
}
SYSCALL_ALIAS(sys_lookup_dcookie, SyS_lookup_dcookie);
#endif

static int dcookie_init(void)
{
Expand Down
27 changes: 24 additions & 3 deletions fs/open.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,21 +351,35 @@ asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)

/* LFS versions of truncate are only needed on 32 bit machines */
#if BITS_PER_LONG == 32
asmlinkage long sys_truncate64(const char __user * path, loff_t length)
SYSCALL_DEFINE(truncate64)(const char __user * path, loff_t length)
{
return do_sys_truncate(path, length);
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_truncate64(long path, loff_t length)
{
return SYSC_truncate64((const char __user *) path, length);
}
SYSCALL_ALIAS(sys_truncate64, SyS_truncate64);
#endif

asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
SYSCALL_DEFINE(ftruncate64)(unsigned int fd, loff_t length)
{
long ret = do_sys_ftruncate(fd, length, 0);
/* avoid REGPARM breakage on x86: */
asmlinkage_protect(2, ret, fd, length);
return ret;
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_ftruncate64(long fd, loff_t length)
{
return SYSC_ftruncate64((unsigned int) fd, length);
}
SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64);
#endif
#endif /* BITS_PER_LONG == 32 */

asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
{
struct file *file;
struct inode *inode;
Expand Down Expand Up @@ -422,6 +436,13 @@ asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
out:
return ret;
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len)
{
return SYSC_fallocate((int)fd, (int)mode, offset, len);
}
SYSCALL_ALIAS(sys_fallocate, SyS_fallocate);
#endif

/*
* access() needs to use the real uid/gid, not the effective uid/gid.
Expand Down
24 changes: 20 additions & 4 deletions fs/read_write.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,8 @@ asmlinkage long sys_write(unsigned int fd, const char __user * buf, size_t count
return ret;
}

asmlinkage long sys_pread64(unsigned int fd, char __user *buf,
size_t count, loff_t pos)
SYSCALL_DEFINE(pread64)(unsigned int fd, char __user *buf,
size_t count, loff_t pos)
{
struct file *file;
ssize_t ret = -EBADF;
Expand All @@ -423,9 +423,17 @@ asmlinkage long sys_pread64(unsigned int fd, char __user *buf,

return ret;
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_pread64(long fd, long buf, long count, loff_t pos)
{
return SYSC_pread64((unsigned int) fd, (char __user *) buf,
(size_t) count, pos);
}
SYSCALL_ALIAS(sys_pread64, SyS_pread64);
#endif

asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf,
size_t count, loff_t pos)
SYSCALL_DEFINE(pwrite64)(unsigned int fd, const char __user *buf,
size_t count, loff_t pos)
{
struct file *file;
ssize_t ret = -EBADF;
Expand All @@ -444,6 +452,14 @@ asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf,

return ret;
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_pwrite64(long fd, long buf, long count, loff_t pos)
{
return SYSC_pwrite64((unsigned int) fd, (const char __user *) buf,
(size_t) count, pos);
}
SYSCALL_ALIAS(sys_pwrite64, SyS_pwrite64);
#endif

/*
* Reduce an iovec's length in-place. Return the resulting number of segments
Expand Down
26 changes: 22 additions & 4 deletions fs/sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ asmlinkage long sys_fdatasync(unsigned int fd)
* already-instantiated disk blocks, there are no guarantees here that the data
* will be available after a crash.
*/
asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
unsigned int flags)
SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
unsigned int flags)
{
int ret;
struct file *file;
Expand Down Expand Up @@ -262,14 +262,32 @@ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
out:
return ret;
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_sync_file_range(long fd, loff_t offset, loff_t nbytes,
long flags)
{
return SYSC_sync_file_range((int) fd, offset, nbytes,
(unsigned int) flags);
}
SYSCALL_ALIAS(sys_sync_file_range, SyS_sync_file_range);
#endif

/* It would be nice if people remember that not all the world's an i386
when they introduce new system calls */
asmlinkage long sys_sync_file_range2(int fd, unsigned int flags,
loff_t offset, loff_t nbytes)
SYSCALL_DEFINE(sync_file_range2)(int fd, unsigned int flags,
loff_t offset, loff_t nbytes)
{
return sys_sync_file_range(fd, offset, nbytes, flags);
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_sync_file_range2(long fd, long flags,
loff_t offset, loff_t nbytes)
{
return SYSC_sync_file_range2((int) fd, (unsigned int) flags,
offset, nbytes);
}
SYSCALL_ALIAS(sys_sync_file_range2, SyS_sync_file_range2);
#endif

/*
* `endbyte' is inclusive
Expand Down
9 changes: 8 additions & 1 deletion ipc/sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
return err;
}

asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg)
{
int err = -EINVAL;
int version;
Expand Down Expand Up @@ -923,6 +923,13 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
return -EINVAL;
}
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg)
{
return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg);
}
SYSCALL_ALIAS(sys_semctl, SyS_semctl);
#endif

/* If the task doesn't already have a undo_list, then allocate one
* here. We guarantee there is only one thread using this undo list,
Expand Down
18 changes: 16 additions & 2 deletions mm/fadvise.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could
* deactivate the pages and clear PG_Referenced.
*/
asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)
{
struct file *file = fget(fd);
struct address_space *mapping;
Expand Down Expand Up @@ -126,12 +126,26 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
fput(file);
return ret;
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_fadvise64_64(long fd, loff_t offset, loff_t len, long advice)
{
return SYSC_fadvise64_64((int) fd, offset, len, (int) advice);
}
SYSCALL_ALIAS(sys_fadvise64_64, SyS_fadvise64_64);
#endif

#ifdef __ARCH_WANT_SYS_FADVISE64

asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice)
SYSCALL_DEFINE(fadvise64)(int fd, loff_t offset, size_t len, int advice)
{
return sys_fadvise64_64(fd, offset, len, advice);
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_fadvise64(long fd, loff_t offset, long len, long advice)
{
return SYSC_fadvise64((int) fd, offset, (size_t)len, (int)advice);
}
SYSCALL_ALIAS(sys_fadvise64, SyS_fadvise64);
#endif

#endif
9 changes: 8 additions & 1 deletion mm/filemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1374,7 +1374,7 @@ do_readahead(struct address_space *mapping, struct file *filp,
return 0;
}

asmlinkage long sys_readahead(int fd, loff_t offset, size_t count)
SYSCALL_DEFINE(readahead)(int fd, loff_t offset, size_t count)
{
ssize_t ret;
struct file *file;
Expand All @@ -1393,6 +1393,13 @@ asmlinkage long sys_readahead(int fd, loff_t offset, size_t count)
}
return ret;
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_readahead(long fd, loff_t offset, long count)
{
return SYSC_readahead((int) fd, offset, (size_t) count);
}
SYSCALL_ALIAS(sys_readahead, SyS_readahead);
#endif

#ifdef CONFIG_MMU
/**
Expand Down

0 comments on commit 6673e0c

Please sign in to comment.