pipe(2) - race-free error recovery
don't mess with sys_close() if copy_to_user() fails; just postpone fd_install() until we know it hasn't. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
a79f41ed97
commit
5b249b1b07
1 changed files with 22 additions and 9 deletions
31
fs/pipe.c
31
fs/pipe.c
|
@ -1064,9 +1064,8 @@ int create_pipe_files(struct file **res, int flags)
|
|||
return err;
|
||||
}
|
||||
|
||||
int do_pipe_flags(int *fd, int flags)
|
||||
static int __do_pipe_flags(int *fd, struct file **files, int flags)
|
||||
{
|
||||
struct file *files[2];
|
||||
int error;
|
||||
int fdw, fdr;
|
||||
|
||||
|
@ -1088,11 +1087,8 @@ int do_pipe_flags(int *fd, int flags)
|
|||
fdw = error;
|
||||
|
||||
audit_fd_pair(fdr, fdw);
|
||||
fd_install(fdr, files[0]);
|
||||
fd_install(fdw, files[1]);
|
||||
fd[0] = fdr;
|
||||
fd[1] = fdw;
|
||||
|
||||
return 0;
|
||||
|
||||
err_fdr:
|
||||
|
@ -1103,21 +1099,38 @@ int do_pipe_flags(int *fd, int flags)
|
|||
return error;
|
||||
}
|
||||
|
||||
int do_pipe_flags(int *fd, int flags)
|
||||
{
|
||||
struct file *files[2];
|
||||
int error = __do_pipe_flags(fd, files, flags);
|
||||
if (!error) {
|
||||
fd_install(fd[0], files[0]);
|
||||
fd_install(fd[1], files[1]);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* sys_pipe() is the normal C calling standard for creating
|
||||
* a pipe. It's not the way Unix traditionally does this, though.
|
||||
*/
|
||||
SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
|
||||
{
|
||||
struct file *files[2];
|
||||
int fd[2];
|
||||
int error;
|
||||
|
||||
error = do_pipe_flags(fd, flags);
|
||||
error = __do_pipe_flags(fd, files, flags);
|
||||
if (!error) {
|
||||
if (copy_to_user(fildes, fd, sizeof(fd))) {
|
||||
sys_close(fd[0]);
|
||||
sys_close(fd[1]);
|
||||
if (unlikely(copy_to_user(fildes, fd, sizeof(fd)))) {
|
||||
fput(files[0]);
|
||||
fput(files[1]);
|
||||
put_unused_fd(fd[0]);
|
||||
put_unused_fd(fd[1]);
|
||||
error = -EFAULT;
|
||||
} else {
|
||||
fd_install(fd[0], files[0]);
|
||||
fd_install(fd[1], files[1]);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
|
|
Loading…
Reference in a new issue