d7627467b7
Make do_execve() take a const filename pointer so that kernel_execve() compiles correctly on ARM: arch/arm/kernel/sys_arm.c:88: warning: passing argument 1 of 'do_execve' discards qualifiers from pointer target type This also requires the argv and envp arguments to be consted twice, once for the pointer array and once for the strings the array points to. This is because do_execve() passes a pointer to the filename (now const) to copy_strings_kernel(). A simpler alternative would be to cast the filename pointer in do_execve() when it's passed to copy_strings_kernel(). do_execve() may not change any of the strings it is passed as part of the argv or envp lists as they are some of them in .rodata, so marking these strings as const should be fine. Further kernel_execve() and sys_execve() need to be changed to match. This has been test built on x86_64, frv, arm and mips. Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Ralf Baechle <ralf@linux-mips.org> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
138 lines
3.6 KiB
C
138 lines
3.6 KiB
C
/*
|
|
* arch/score/kernel/syscall.c
|
|
*
|
|
* Score Processor version.
|
|
*
|
|
* Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
|
|
* Chen Liqin <liqin.chen@sunplusct.com>
|
|
* Lennox Wu <lennox.wu@sunplusct.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see the file COPYING, or write
|
|
* to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <linux/file.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/mman.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/unistd.h>
|
|
#include <linux/syscalls.h>
|
|
#include <asm/syscalls.h>
|
|
|
|
asmlinkage long
|
|
sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
|
|
unsigned long flags, unsigned long fd, unsigned long pgoff)
|
|
{
|
|
return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
|
|
}
|
|
|
|
asmlinkage long
|
|
sys_mmap(unsigned long addr, unsigned long len, unsigned long prot,
|
|
unsigned long flags, unsigned long fd, off_t offset)
|
|
{
|
|
if (unlikely(offset & ~PAGE_MASK))
|
|
return -EINVAL;
|
|
return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
|
|
}
|
|
|
|
asmlinkage long
|
|
score_fork(struct pt_regs *regs)
|
|
{
|
|
return do_fork(SIGCHLD, regs->regs[0], regs, 0, NULL, NULL);
|
|
}
|
|
|
|
/*
|
|
* Clone a task - this clones the calling program thread.
|
|
* This is called indirectly via a small wrapper
|
|
*/
|
|
asmlinkage long
|
|
score_clone(struct pt_regs *regs)
|
|
{
|
|
unsigned long clone_flags;
|
|
unsigned long newsp;
|
|
int __user *parent_tidptr, *child_tidptr;
|
|
|
|
clone_flags = regs->regs[4];
|
|
newsp = regs->regs[5];
|
|
if (!newsp)
|
|
newsp = regs->regs[0];
|
|
parent_tidptr = (int __user *)regs->regs[6];
|
|
child_tidptr = (int __user *)regs->regs[8];
|
|
|
|
return do_fork(clone_flags, newsp, regs, 0,
|
|
parent_tidptr, child_tidptr);
|
|
}
|
|
|
|
asmlinkage long
|
|
score_vfork(struct pt_regs *regs)
|
|
{
|
|
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
|
|
regs->regs[0], regs, 0, NULL, NULL);
|
|
}
|
|
|
|
/*
|
|
* sys_execve() executes a new program.
|
|
* This is called indirectly via a small wrapper
|
|
*/
|
|
asmlinkage long
|
|
score_execve(struct pt_regs *regs)
|
|
{
|
|
int error;
|
|
char *filename;
|
|
|
|
filename = getname((char __user*)regs->regs[4]);
|
|
error = PTR_ERR(filename);
|
|
if (IS_ERR(filename))
|
|
return error;
|
|
|
|
error = do_execve(filename,
|
|
(const char __user *const __user *)regs->regs[5],
|
|
(const char __user *const __user *)regs->regs[6],
|
|
regs);
|
|
|
|
putname(filename);
|
|
return error;
|
|
}
|
|
|
|
/*
|
|
* Do a system call from kernel instead of calling sys_execve so we
|
|
* end up with proper pt_regs.
|
|
*/
|
|
int kernel_execve(const char *filename,
|
|
const char *const argv[],
|
|
const char *const envp[])
|
|
{
|
|
register unsigned long __r4 asm("r4") = (unsigned long) filename;
|
|
register unsigned long __r5 asm("r5") = (unsigned long) argv;
|
|
register unsigned long __r6 asm("r6") = (unsigned long) envp;
|
|
register unsigned long __r7 asm("r7");
|
|
|
|
__asm__ __volatile__ (" \n"
|
|
"ldi r27, %5 \n"
|
|
"syscall \n"
|
|
"mv %0, r4 \n"
|
|
"mv %1, r7 \n"
|
|
: "=&r" (__r4), "=r" (__r7)
|
|
: "r" (__r4), "r" (__r5), "r" (__r6), "i" (__NR_execve)
|
|
: "r8", "r9", "r10", "r11", "r22", "r23", "r24", "r25",
|
|
"r26", "r27", "memory");
|
|
|
|
if (__r7 == 0)
|
|
return __r4;
|
|
|
|
return -__r4;
|
|
}
|