From: Kirill Tkhai <ktkhai@virtuozzo.com>
To: linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org,
jslaby@suse.com, viro@zeniv.linux.org.uk, keescook@chromium.org,
serge@hallyn.com, james.l.morris@oracle.com, luto@kernel.org,
john.johansen@canonical.com, oleg@redhat.com, mingo@kernel.org,
akpm@linux-foundation.org, mhocko@suse.com, peterz@infradead.org,
ktkhai@virtuozzo.com
Subject: [PATCH 2/4] exec: Assign unshared files after there is no way back
Date: Thu, 11 Jan 2018 18:50:13 +0300 [thread overview]
Message-ID: <151568581368.6090.5877434562731130496.stgit@localhost.localdomain> (raw)
In-Reply-To: <151568564127.6090.3546718160925256054.stgit@localhost.localdomain>
The patch makes unshared files_struct to be assigned
after exec or coredump are known to be successeful.
Since previous patch converted all load_binary methods
to use linux_binprm::new_files instead of current->files,
now we are able to assign unshared_files after load_binary
call.
This change makes task->files more predictable and since
that we may analyse the only thread's files pointer
to determ either the task contains a fd or not, and not
be afraid of race with failing exec. Next patch will
use this feature to skip thread group iteration in __do_SAK(),
and also this predictability may be useful for something else.
Also note, that without the patch we skip failing exec,
when we are doing the iterations in __do_SAK(), and
these tasks remain alive. The patch also fixes this rare issue.
Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
fs/binfmt_misc.c | 2 --
fs/coredump.c | 9 +++++----
fs/exec.c | 15 ++++++++-------
fs/file.c | 2 +-
include/linux/fdtable.h | 4 ++--
kernel/fork.c | 19 +++++++------------
6 files changed, 23 insertions(+), 28 deletions(-)
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 13c1fae45717..7568456895c7 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -242,8 +242,6 @@ static int load_misc_binary(struct linux_binprm *bprm)
dput(fmt->dentry);
return retval;
error:
- if (fd_binary > 0)
- sys_close(fd_binary);
bprm->interp_flags = 0;
bprm->interp_data = 0;
goto ret;
diff --git a/fs/coredump.c b/fs/coredump.c
index 1e2c87acac9b..fe5a4504d975 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -546,7 +546,7 @@ void do_coredump(const siginfo_t *siginfo)
struct cred *cred;
int retval = 0;
int ispipe;
- struct files_struct *displaced;
+ struct files_struct *files;
/* require nonrelative corefile path and be extra careful */
bool need_suid_safe = false;
bool core_dumped = false;
@@ -747,11 +747,12 @@ void do_coredump(const siginfo_t *siginfo)
}
/* get us an unshared descriptor table; almost always a no-op */
- retval = unshare_files(&displaced);
+ files = unshare_files();
+ retval = PTR_ERR_OR_ZERO(files);
if (retval)
goto close_fail;
- if (displaced)
- put_files_struct(displaced);
+ if (files != current->files)
+ assign_files_struct(files);
if (!dump_interrupted()) {
file_start_write(cprm.file);
core_dumped = binfmt->core_dump(&cprm);
diff --git a/fs/exec.c b/fs/exec.c
index 4c3b924ae103..ced4dc09444a 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1699,7 +1699,7 @@ static int do_execveat_common(int fd, struct filename *filename,
char *pathbuf = NULL;
struct linux_binprm *bprm;
struct file *file;
- struct files_struct *displaced;
+ struct files_struct *files;
int retval;
if (IS_ERR(filename))
@@ -1721,7 +1721,8 @@ static int do_execveat_common(int fd, struct filename *filename,
* further execve() calls fail. */
current->flags &= ~PF_NPROC_EXCEEDED;
- retval = unshare_files(&displaced);
+ files = unshare_files();
+ retval = PTR_ERR_OR_ZERO(files);
if (retval)
goto out_ret;
@@ -1729,7 +1730,7 @@ static int do_execveat_common(int fd, struct filename *filename,
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
if (!bprm)
goto out_files;
- bprm->new_files = current->files;
+ bprm->new_files = files;
retval = prepare_bprm_creds(bprm);
if (retval)
@@ -1813,8 +1814,8 @@ static int do_execveat_common(int fd, struct filename *filename,
free_bprm(bprm);
kfree(pathbuf);
putname(filename);
- if (displaced)
- put_files_struct(displaced);
+ if (files != current->files)
+ assign_files_struct(files);
return retval;
out:
@@ -1832,8 +1833,8 @@ static int do_execveat_common(int fd, struct filename *filename,
kfree(pathbuf);
out_files:
- if (displaced)
- reset_files_struct(displaced);
+ if (files != current->files)
+ put_files_struct(files);
out_ret:
putname(filename);
return retval;
diff --git a/fs/file.c b/fs/file.c
index e578e5537c32..7ed519c65d0b 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -427,7 +427,7 @@ void put_files_struct(struct files_struct *files)
}
}
-void reset_files_struct(struct files_struct *files)
+void assign_files_struct(struct files_struct *files)
{
struct task_struct *tsk = current;
struct files_struct *old;
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 1c65817673db..00db7eadf895 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -104,8 +104,8 @@ struct task_struct;
struct files_struct *get_files_struct(struct task_struct *);
void put_files_struct(struct files_struct *fs);
-void reset_files_struct(struct files_struct *);
-int unshare_files(struct files_struct **);
+void assign_files_struct(struct files_struct *);
+struct files_struct *unshare_files(void);
struct files_struct *dup_fd(struct files_struct *, int *) __latent_entropy;
void do_close_on_exec(struct files_struct *);
int iterate_fd(struct files_struct *, unsigned,
diff --git a/kernel/fork.c b/kernel/fork.c
index 2295fc69717f..7690734eb354 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2434,22 +2434,17 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
* the exec layer of the kernel.
*/
-int unshare_files(struct files_struct **displaced)
+struct files_struct *unshare_files(void)
{
struct task_struct *task = current;
- struct files_struct *copy = NULL;
+ struct files_struct *files = task->files;
int error;
- error = unshare_fd(CLONE_FILES, ©);
- if (error || !copy) {
- *displaced = NULL;
- return error;
- }
- *displaced = task->files;
- task_lock(task);
- task->files = copy;
- task_unlock(task);
- return 0;
+ error = unshare_fd(CLONE_FILES, &files);
+ if (error)
+ return ERR_PTR(error);
+
+ return files;
}
int sysctl_max_threads(struct ctl_table *table, int write,
next prev parent reply other threads:[~2018-01-11 15:53 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-11 15:49 [PATCH 0/4] fs, tty: Make __do_SAK() less greedy in regard to tasklist_lock Kirill Tkhai
2018-01-11 15:50 ` [PATCH 1/4] exec: Pass unshared files_struct to load_binary() Kirill Tkhai
2018-01-11 15:50 ` Kirill Tkhai [this message]
2018-01-11 15:50 ` [PATCH 3/4] tty: Iterate only thread group leaders in __do_SAK() Kirill Tkhai
2018-01-11 18:34 ` Oleg Nesterov
2018-01-12 8:42 ` Kirill Tkhai
2018-01-12 10:05 ` Kirill Tkhai
2018-01-12 16:42 ` Oleg Nesterov
2018-01-15 9:32 ` Kirill Tkhai
2018-01-15 20:51 ` Oleg Nesterov
2018-01-16 11:33 ` Kirill Tkhai
2018-01-16 21:13 ` Oleg Nesterov
2018-01-17 12:47 ` Kirill Tkhai
2018-01-11 15:50 ` [PATCH 4/4] tty: Use RCU read lock to iterate tasks " Kirill Tkhai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=151568581368.6090.5877434562731130496.stgit@localhost.localdomain \
--to=ktkhai@virtuozzo.com \
--cc=akpm@linux-foundation.org \
--cc=gregkh@linuxfoundation.org \
--cc=james.l.morris@oracle.com \
--cc=john.johansen@canonical.com \
--cc=jslaby@suse.com \
--cc=keescook@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mhocko@suse.com \
--cc=mingo@kernel.org \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=serge@hallyn.com \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).