summaryrefslogtreecommitdiffstats
path: root/fs/compat.c
diff options
context:
space:
mode:
authorJames Morris <jmorris@namei.org>2009-05-08 17:56:47 +1000
committerJames Morris <jmorris@namei.org>2009-05-08 17:56:47 +1000
commitd254117099d711f215e62427f55dfb8ebd5ad011 (patch)
tree0848ff8dd74314fec14a86497f8d288c86ba7c65 /fs/compat.c
parent07ff7a0b187f3951788f64ae1f30e8109bc8e9eb (diff)
parent8c9ed899b44c19e81859fbb0e9d659fe2f8630fc (diff)
Merge branch 'master' into next
Diffstat (limited to 'fs/compat.c')
-rw-r--r--fs/compat.c141
1 files changed, 103 insertions, 38 deletions
diff --git a/fs/compat.c b/fs/compat.c
index 55efdfebdf5..681ed81e6be 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -51,6 +51,7 @@
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/eventpoll.h>
+#include <linux/fs_struct.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -180,22 +181,24 @@ asmlinkage long compat_sys_newstat(char __user * filename,
struct compat_stat __user *statbuf)
{
struct kstat stat;
- int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
+ int error;
- if (!error)
- error = cp_compat_stat(&stat, statbuf);
- return error;
+ error = vfs_stat(filename, &stat);
+ if (error)
+ return error;
+ return cp_compat_stat(&stat, statbuf);
}
asmlinkage long compat_sys_newlstat(char __user * filename,
struct compat_stat __user *statbuf)
{
struct kstat stat;
- int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
+ int error;
- if (!error)
- error = cp_compat_stat(&stat, statbuf);
- return error;
+ error = vfs_lstat(filename, &stat);
+ if (error)
+ return error;
+ return cp_compat_stat(&stat, statbuf);
}
#ifndef __ARCH_WANT_STAT64
@@ -203,21 +206,12 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user *filename,
struct compat_stat __user *statbuf, int flag)
{
struct kstat stat;
- int error = -EINVAL;
-
- if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
- goto out;
-
- if (flag & AT_SYMLINK_NOFOLLOW)
- error = vfs_lstat_fd(dfd, filename, &stat);
- else
- error = vfs_stat_fd(dfd, filename, &stat);
-
- if (!error)
- error = cp_compat_stat(&stat, statbuf);
+ int error;
-out:
- return error;
+ error = vfs_fstatat(dfd, filename, &stat, flag);
+ if (error)
+ return error;
+ return cp_compat_stat(&stat, statbuf);
}
#endif
@@ -1195,16 +1189,12 @@ out:
return ret;
}
-asmlinkage ssize_t
-compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
+static size_t compat_readv(struct file *file,
+ const struct compat_iovec __user *vec,
+ unsigned long vlen, loff_t *pos)
{
- struct file *file;
ssize_t ret = -EBADF;
- file = fget(fd);
- if (!file)
- return -EBADF;
-
if (!(file->f_mode & FMODE_READ))
goto out;
@@ -1212,25 +1202,56 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsign
if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
goto out;
- ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
+ ret = compat_do_readv_writev(READ, file, vec, vlen, pos);
out:
if (ret > 0)
add_rchar(current, ret);
inc_syscr(current);
- fput(file);
return ret;
}
asmlinkage ssize_t
-compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
+compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec,
+ unsigned long vlen)
{
struct file *file;
- ssize_t ret = -EBADF;
+ int fput_needed;
+ ssize_t ret;
- file = fget(fd);
+ file = fget_light(fd, &fput_needed);
+ if (!file)
+ return -EBADF;
+ ret = compat_readv(file, vec, vlen, &file->f_pos);
+ fput_light(file, fput_needed);
+ return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
+ unsigned long vlen, u32 pos_low, u32 pos_high)
+{
+ loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+ struct file *file;
+ int fput_needed;
+ ssize_t ret;
+
+ if (pos < 0)
+ return -EINVAL;
+ file = fget_light(fd, &fput_needed);
if (!file)
return -EBADF;
+ ret = compat_readv(file, vec, vlen, &pos);
+ fput_light(file, fput_needed);
+ return ret;
+}
+
+static size_t compat_writev(struct file *file,
+ const struct compat_iovec __user *vec,
+ unsigned long vlen, loff_t *pos)
+{
+ ssize_t ret = -EBADF;
+
if (!(file->f_mode & FMODE_WRITE))
goto out;
@@ -1238,13 +1259,47 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsig
if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
goto out;
- ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
+ ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos);
out:
if (ret > 0)
add_wchar(current, ret);
inc_syscw(current);
- fput(file);
+ return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec,
+ unsigned long vlen)
+{
+ struct file *file;
+ int fput_needed;
+ ssize_t ret;
+
+ file = fget_light(fd, &fput_needed);
+ if (!file)
+ return -EBADF;
+ ret = compat_writev(file, vec, vlen, &file->f_pos);
+ fput_light(file, fput_needed);
+ return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
+ unsigned long vlen, u32 pos_low, u32 pos_high)
+{
+ loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+ struct file *file;
+ int fput_needed;
+ ssize_t ret;
+
+ if (pos < 0)
+ return -EINVAL;
+ file = fget_light(fd, &fput_needed);
+ if (!file)
+ return -EBADF;
+ ret = compat_writev(file, vec, vlen, &pos);
+ fput_light(file, fput_needed);
return ret;
}
@@ -1421,6 +1476,7 @@ int compat_do_execve(char * filename,
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
+ bool clear_in_exec;
int retval;
retval = unshare_files(&displaced);
@@ -1441,12 +1497,16 @@ int compat_do_execve(char * filename,
bprm->cred = prepare_exec_creds();
if (!bprm->cred)
goto out_unlock;
- check_unsafe_exec(bprm);
+
+ retval = check_unsafe_exec(bprm);
+ if (retval < 0)
+ goto out_unlock;
+ clear_in_exec = retval;
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
- goto out_unlock;
+ goto out_unmark;
sched_exec();
@@ -1488,6 +1548,7 @@ int compat_do_execve(char * filename,
goto out;
/* execve succeeded */
+ current->fs->in_exec = 0;
current->in_execve = 0;
mutex_unlock(&current->cred_exec_mutex);
acct_update_integrals(current);
@@ -1506,6 +1567,10 @@ out_file:
fput(bprm->file);
}
+out_unmark:
+ if (clear_in_exec)
+ current->fs->in_exec = 0;
+
out_unlock:
current->in_execve = 0;
mutex_unlock(&current->cred_exec_mutex);