![Jeff Layton](/assets/img/avatar_default.png)
getname() is intended to copy pathname strings from userspace into a kernel buffer. The result is just a string in kernel space. It would however be quite helpful to be able to attach some ancillary info to the string. For instance, we could attach some audit-related info to reduce the amount of audit-related processing needed. When auditing is enabled, we could also call getname() on the string more than once and not need to recopy it from userspace. This patchset converts the getname()/putname() interfaces to return a struct instead of a string. For now, the struct just tracks the string in kernel space and the original userland pointer for it. Later, we'll add other information to the struct as it becomes convenient. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
239 lines
5.6 KiB
C
239 lines
5.6 KiB
C
/*
|
|
* sys_parisc32.c: Conversion between 32bit and 64bit native syscalls.
|
|
*
|
|
* Copyright (C) 2000-2001 Hewlett Packard Company
|
|
* Copyright (C) 2000 John Marvin
|
|
* Copyright (C) 2001 Matthew Wilcox
|
|
*
|
|
* These routines maintain argument size conversion between 32bit and 64bit
|
|
* environment. Based heavily on sys_ia32.c and sys_sparc32.c.
|
|
*/
|
|
|
|
#include <linux/compat.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/file.h>
|
|
#include <linux/signal.h>
|
|
#include <linux/resource.h>
|
|
#include <linux/times.h>
|
|
#include <linux/time.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/sem.h>
|
|
#include <linux/msg.h>
|
|
#include <linux/shm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/uio.h>
|
|
#include <linux/ncp_fs.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/personality.h>
|
|
#include <linux/stat.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/highuid.h>
|
|
#include <linux/mman.h>
|
|
#include <linux/binfmts.h>
|
|
#include <linux/namei.h>
|
|
#include <linux/vfs.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/swap.h>
|
|
#include <linux/syscalls.h>
|
|
|
|
#include <asm/types.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/mmu_context.h>
|
|
|
|
#include "sys32.h"
|
|
|
|
#undef DEBUG
|
|
|
|
#ifdef DEBUG
|
|
#define DBG(x) printk x
|
|
#else
|
|
#define DBG(x)
|
|
#endif
|
|
|
|
/*
|
|
* sys32_execve() executes a new program.
|
|
*/
|
|
|
|
asmlinkage int sys32_execve(struct pt_regs *regs)
|
|
{
|
|
int error;
|
|
struct filename *filename;
|
|
|
|
DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
|
|
filename = getname((const char __user *) regs->gr[26]);
|
|
error = PTR_ERR(filename);
|
|
if (IS_ERR(filename))
|
|
goto out;
|
|
error = compat_do_execve(filename->name, compat_ptr(regs->gr[25]),
|
|
compat_ptr(regs->gr[24]), regs);
|
|
putname(filename);
|
|
out:
|
|
|
|
return error;
|
|
}
|
|
|
|
asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
|
|
int r22, int r21, int r20)
|
|
{
|
|
printk(KERN_ERR "%s(%d): Unimplemented 32 on 64 syscall #%d!\n",
|
|
current->comm, current->pid, r20);
|
|
return -ENOSYS;
|
|
}
|
|
|
|
asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
|
|
struct compat_timespec __user *interval)
|
|
{
|
|
struct timespec t;
|
|
int ret;
|
|
|
|
KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, (struct timespec __user *)&t);
|
|
if (put_compat_timespec(&t, interval))
|
|
return -EFAULT;
|
|
return ret;
|
|
}
|
|
|
|
struct msgbuf32 {
|
|
int mtype;
|
|
char mtext[1];
|
|
};
|
|
|
|
asmlinkage long sys32_msgsnd(int msqid,
|
|
struct msgbuf32 __user *umsgp32,
|
|
size_t msgsz, int msgflg)
|
|
{
|
|
struct msgbuf *mb;
|
|
struct msgbuf32 mb32;
|
|
int err;
|
|
|
|
if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
|
|
return -ENOMEM;
|
|
|
|
err = get_user(mb32.mtype, &umsgp32->mtype);
|
|
mb->mtype = mb32.mtype;
|
|
err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz);
|
|
|
|
if (err)
|
|
err = -EFAULT;
|
|
else
|
|
KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg);
|
|
|
|
kfree(mb);
|
|
return err;
|
|
}
|
|
|
|
asmlinkage long sys32_msgrcv(int msqid,
|
|
struct msgbuf32 __user *umsgp32,
|
|
size_t msgsz, long msgtyp, int msgflg)
|
|
{
|
|
struct msgbuf *mb;
|
|
struct msgbuf32 mb32;
|
|
int err, len;
|
|
|
|
if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
|
|
return -ENOMEM;
|
|
|
|
KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg);
|
|
|
|
if (err >= 0) {
|
|
len = err;
|
|
mb32.mtype = mb->mtype;
|
|
err = put_user(mb32.mtype, &umsgp32->mtype);
|
|
err |= copy_to_user(&umsgp32->mtext, mb->mtext, len);
|
|
if (err)
|
|
err = -EFAULT;
|
|
else
|
|
err = len;
|
|
}
|
|
|
|
kfree(mb);
|
|
return err;
|
|
}
|
|
|
|
asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
|
|
{
|
|
mm_segment_t old_fs = get_fs();
|
|
int ret;
|
|
off_t of;
|
|
|
|
if (offset && get_user(of, offset))
|
|
return -EFAULT;
|
|
|
|
set_fs(KERNEL_DS);
|
|
ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
|
|
set_fs(old_fs);
|
|
|
|
if (offset && put_user(of, offset))
|
|
return -EFAULT;
|
|
|
|
return ret;
|
|
}
|
|
|
|
asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count)
|
|
{
|
|
mm_segment_t old_fs = get_fs();
|
|
int ret;
|
|
loff_t lof;
|
|
|
|
if (offset && get_user(lof, offset))
|
|
return -EFAULT;
|
|
|
|
set_fs(KERNEL_DS);
|
|
ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count);
|
|
set_fs(old_fs);
|
|
|
|
if (offset && put_user(lof, offset))
|
|
return -EFAULT;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* lseek() needs a wrapper because 'offset' can be negative, but the top
|
|
* half of the argument has been zeroed by syscall.S.
|
|
*/
|
|
|
|
asmlinkage int sys32_lseek(unsigned int fd, int offset, unsigned int origin)
|
|
{
|
|
return sys_lseek(fd, offset, origin);
|
|
}
|
|
|
|
asmlinkage long sys32_semctl(int semid, int semnum, int cmd, union semun arg)
|
|
{
|
|
union semun u;
|
|
|
|
if (cmd == SETVAL) {
|
|
/* Ugh. arg is a union of int,ptr,ptr,ptr, so is 8 bytes.
|
|
* The int should be in the first 4, but our argument
|
|
* frobbing has left it in the last 4.
|
|
*/
|
|
u.val = *((int *)&arg + 1);
|
|
return sys_semctl (semid, semnum, cmd, u);
|
|
}
|
|
return sys_semctl (semid, semnum, cmd, arg);
|
|
}
|
|
|
|
long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
|
|
size_t len)
|
|
{
|
|
return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
|
|
buf, len);
|
|
}
|
|
|
|
asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
|
|
u32 lenhi, u32 lenlo)
|
|
{
|
|
return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
|
|
((loff_t)lenhi << 32) | lenlo);
|
|
}
|
|
|
|
asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi,
|
|
u32 mask_lo, int fd,
|
|
const char __user *pathname)
|
|
{
|
|
return sys_fanotify_mark(fan_fd, flags, ((u64)mask_hi << 32) | mask_lo,
|
|
fd, pathname);
|
|
}
|