Commit 5b249b1b authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent a79f41ed
...@@ -1064,9 +1064,8 @@ int create_pipe_files(struct file **res, int flags) ...@@ -1064,9 +1064,8 @@ int create_pipe_files(struct file **res, int flags)
return err; 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 error;
int fdw, fdr; int fdw, fdr;
...@@ -1088,11 +1087,8 @@ int do_pipe_flags(int *fd, int flags) ...@@ -1088,11 +1087,8 @@ int do_pipe_flags(int *fd, int flags)
fdw = error; fdw = error;
audit_fd_pair(fdr, fdw); audit_fd_pair(fdr, fdw);
fd_install(fdr, files[0]);
fd_install(fdw, files[1]);
fd[0] = fdr; fd[0] = fdr;
fd[1] = fdw; fd[1] = fdw;
return 0; return 0;
err_fdr: err_fdr:
...@@ -1103,21 +1099,38 @@ int do_pipe_flags(int *fd, int flags) ...@@ -1103,21 +1099,38 @@ int do_pipe_flags(int *fd, int flags)
return error; 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 * sys_pipe() is the normal C calling standard for creating
* a pipe. It's not the way Unix traditionally does this, though. * a pipe. It's not the way Unix traditionally does this, though.
*/ */
SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags) SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
{ {
struct file *files[2];
int fd[2]; int fd[2];
int error; int error;
error = do_pipe_flags(fd, flags); error = __do_pipe_flags(fd, files, flags);
if (!error) { if (!error) {
if (copy_to_user(fildes, fd, sizeof(fd))) { if (unlikely(copy_to_user(fildes, fd, sizeof(fd)))) {
sys_close(fd[0]); fput(files[0]);
sys_close(fd[1]); fput(files[1]);
put_unused_fd(fd[0]);
put_unused_fd(fd[1]);
error = -EFAULT; error = -EFAULT;
} else {
fd_install(fd[0], files[0]);
fd_install(fd[1], files[1]);
} }
} }
return error; return error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment