* [PATCH 1/1] turn mm->exe_file into mm->exe_path
2012-03-05 15:28 [PATCH 0/1] turn mm->exe_file into mm->exe_path Oleg Nesterov
@ 2012-03-05 15:28 ` Oleg Nesterov
2012-03-05 17:05 ` [PATCH 0/1] " Cyrill Gorcunov
2012-03-05 21:14 ` Matt Helsley
2 siblings, 0 replies; 9+ messages in thread
From: Oleg Nesterov @ 2012-03-05 15:28 UTC (permalink / raw
To: Andrew Morton, Matt Helsley
Cc: Alexey Dobriyan, Cyrill Gorcunov, Eric W. Biederman, Kees Cook,
KOSAKI Motohiro, Pavel Emelyanov, Tejun Heo, linux-kernel
Turn mm->exe_file into mm->exe_path and fix the compilation errors.
We only need this member to get the path, additional reference to
bprm->file makes no sense.
The patch doesn't rename added_exe_file_vma/removed_exe_file_vma
and mm->num_exe_file_vmas, and perhaps we can remove them later.
Also remove the stale comment in include/linux/mm.h.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
fs/exec.c | 20 ++++++++++----------
fs/proc/base.c | 17 ++++++++---------
include/linux/mm.h | 5 ++---
include/linux/mm_types.h | 2 +-
kernel/fork.c | 41 +++++++++++++++++++++--------------------
5 files changed, 42 insertions(+), 43 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 92ce83a..cf16922 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1098,7 +1098,7 @@ int flush_old_exec(struct linux_binprm * bprm)
if (retval)
goto out;
- set_mm_exe_file(bprm->mm, bprm->file);
+ set_mm_exe_path(bprm->mm, &bprm->file->f_path);
filename_to_taskname(bprm->tcomm, bprm->filename, sizeof(bprm->tcomm));
/*
@@ -1671,14 +1671,14 @@ static void cn_escape(char *str)
*str = '!';
}
-static int cn_print_exe_file(struct core_name *cn)
+static int cn_print_exe_path(struct core_name *cn)
{
- struct file *exe_file;
+ struct path *exe_path;
char *pathbuf, *path;
int ret;
- exe_file = get_mm_exe_file(current->mm);
- if (!exe_file) {
+ exe_path = get_mm_exe_path(current->mm);
+ if (!exe_path) {
char *commstart = cn->corename + cn->used;
ret = cn_printf(cn, "%s (path unknown)", current->comm);
cn_escape(commstart);
@@ -1688,10 +1688,10 @@ static int cn_print_exe_file(struct core_name *cn)
pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY);
if (!pathbuf) {
ret = -ENOMEM;
- goto put_exe_file;
+ goto put_exe_path;
}
- path = d_path(&exe_file->f_path, pathbuf, PATH_MAX);
+ path = d_path(exe_path, pathbuf, PATH_MAX);
if (IS_ERR(path)) {
ret = PTR_ERR(path);
goto free_buf;
@@ -1703,8 +1703,8 @@ static int cn_print_exe_file(struct core_name *cn)
free_buf:
kfree(pathbuf);
-put_exe_file:
- fput(exe_file);
+put_exe_path:
+ path_put(exe_path);
return ret;
}
@@ -1786,7 +1786,7 @@ static int format_corename(struct core_name *cn, long signr)
break;
}
case 'E':
- err = cn_print_exe_file(cn);
+ err = cn_print_exe_path(cn);
break;
/* core limit size */
case 'c':
diff --git a/fs/proc/base.c b/fs/proc/base.c
index d4548dd..0d7dbd6 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1401,11 +1401,11 @@ static const struct file_operations proc_pid_set_comm_operations = {
.release = single_release,
};
-static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
+static int proc_exe_link(struct dentry *dentry, struct path *path)
{
struct task_struct *task;
struct mm_struct *mm;
- struct file *exe_file;
+ struct path *exe_path;
task = get_proc_task(dentry->d_inode);
if (!task)
@@ -1414,15 +1414,14 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
put_task_struct(task);
if (!mm)
return -ENOENT;
- exe_file = get_mm_exe_file(mm);
+ exe_path = get_mm_exe_path(mm);
mmput(mm);
- if (exe_file) {
- *exe_path = exe_file->f_path;
- path_get(&exe_file->f_path);
- fput(exe_file);
- return 0;
- } else
+
+ if (!exe_path)
return -ENOENT;
+
+ *path = *exe_path;
+ return 0;
}
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 17b27cd..d18fe93 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1375,11 +1375,10 @@ extern void exit_mmap(struct mm_struct *);
extern int mm_take_all_locks(struct mm_struct *mm);
extern void mm_drop_all_locks(struct mm_struct *mm);
-/* From fs/proc/base.c. callers must _not_ hold the mm's exe_file_lock */
extern void added_exe_file_vma(struct mm_struct *mm);
extern void removed_exe_file_vma(struct mm_struct *mm);
-extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
-extern struct file *get_mm_exe_file(struct mm_struct *mm);
+extern void set_mm_exe_path(struct mm_struct *mm, struct path *exe_path);
+extern struct path *get_mm_exe_path(struct mm_struct *mm);
extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
extern int install_special_mapping(struct mm_struct *mm,
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 3cc3062..e734984 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -377,7 +377,7 @@ struct mm_struct {
#endif
/* store ref to file /proc/<pid>/exe symlink points to */
- struct file *exe_file;
+ struct path *exe_path;
unsigned long num_exe_file_vmas;
#ifdef CONFIG_MMU_NOTIFIER
struct mmu_notifier_mm *mmu_notifier_mm;
diff --git a/kernel/fork.c b/kernel/fork.c
index b77fd55..5e3aa50 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -556,7 +556,7 @@ void mmput(struct mm_struct *mm)
ksm_exit(mm);
khugepaged_exit(mm); /* must run before exit_mmap */
exit_mmap(mm);
- set_mm_exe_file(mm, NULL);
+ set_mm_exe_path(mm, NULL);
if (!list_empty(&mm->mmlist)) {
spin_lock(&mmlist_lock);
list_del(&mm->mmlist);
@@ -583,42 +583,43 @@ void added_exe_file_vma(struct mm_struct *mm)
void removed_exe_file_vma(struct mm_struct *mm)
{
mm->num_exe_file_vmas--;
- if ((mm->num_exe_file_vmas == 0) && mm->exe_file) {
- fput(mm->exe_file);
- mm->exe_file = NULL;
+ if ((mm->num_exe_file_vmas == 0) && mm->exe_path) {
+ path_put(mm->exe_path);
+ mm->exe_path = NULL;
}
}
-void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
+void set_mm_exe_path(struct mm_struct *mm, struct path *exe_path)
{
- if (new_exe_file)
- get_file(new_exe_file);
- if (mm->exe_file)
- fput(mm->exe_file);
- mm->exe_file = new_exe_file;
+ if (mm->exe_path)
+ path_put(mm->exe_path);
+ mm->exe_path = exe_path;
+ if (mm->exe_path)
+ path_get(mm->exe_path);
mm->num_exe_file_vmas = 0;
}
-struct file *get_mm_exe_file(struct mm_struct *mm)
+struct path *get_mm_exe_path(struct mm_struct *mm)
{
- struct file *exe_file;
+ struct path *exe_path;
/* We need mmap_sem to protect against races with removal of
* VM_EXECUTABLE vmas */
down_read(&mm->mmap_sem);
- exe_file = mm->exe_file;
- if (exe_file)
- get_file(exe_file);
+ exe_path = mm->exe_path;
+ if (exe_path)
+ path_get(exe_path);
up_read(&mm->mmap_sem);
- return exe_file;
+
+ return exe_path;
}
-static void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
+static void dup_mm_exe_path(struct mm_struct *oldmm, struct mm_struct *newmm)
{
- /* It's safe to write the exe_file pointer without exe_file_lock because
+ /* It's safe to write the exe_path pointer without mmap_sem because
* this is called during fork when the task is not yet in /proc */
- newmm->exe_file = get_mm_exe_file(oldmm);
+ newmm->exe_path = get_mm_exe_path(oldmm);
}
/**
@@ -763,7 +764,7 @@ struct mm_struct *dup_mm(struct task_struct *tsk)
if (init_new_context(tsk, mm))
goto fail_nocontext;
- dup_mm_exe_file(oldmm, mm);
+ dup_mm_exe_path(oldmm, mm);
err = dup_mmap(mm, oldmm);
if (err)
--
1.5.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/1] turn mm->exe_file into mm->exe_path
2012-03-05 15:28 [PATCH 0/1] turn mm->exe_file into mm->exe_path Oleg Nesterov
2012-03-05 15:28 ` [PATCH 1/1] " Oleg Nesterov
@ 2012-03-05 17:05 ` Cyrill Gorcunov
2012-03-05 17:33 ` Oleg Nesterov
2012-03-05 21:14 ` Matt Helsley
2 siblings, 1 reply; 9+ messages in thread
From: Cyrill Gorcunov @ 2012-03-05 17:05 UTC (permalink / raw
To: Oleg Nesterov
Cc: Andrew Morton, Matt Helsley, Alexey Dobriyan, Eric W. Biederman,
Kees Cook, KOSAKI Motohiro, Pavel Emelyanov, Tejun Heo,
linux-kernel
On Mon, Mar 05, 2012 at 04:28:26PM +0100, Oleg Nesterov wrote:
> I think the patch is simple and self-explanatory, it simply
> does s/mm->exe_file/mm->exe_path/.
>
> Why do we need mm->exe_file? IIUC, there are 2 reasons:
>
> 1. we do not want O(n) proc/pid/exe looking for the 1st
> VM_EXECUTABLE vma.
>
> 2. we do not want to rely on vma->vm_file->f_path,
> bprm->file->f_op->mmap can change ->vm_file.
>
> Unless there was another subtle reason, "struct path *exe_path"
> can equally work but it looks more clear.
>
> And can't we also remove added_exe_file_vma/removed_exe_file_vma?
> Why do we need mm->num_exe_file_vmas? Afaics it is only needed to
> "free" mm->exe_file if the application unmaps all these vmas. Say,
> to allow to unmount fs.
>
> Can't we simply add PR_CLEAR_MM_EXE_PATH instead? Of course it is
> not enough if ->vm_file still has a reference. But c/r people want
> PR_SET_MM_EXE_FILE anyway, see http://marc.info/?t=133052865500016
> So perhaps we can add PR_SET_MM_EXE_PATH which accepts NULL as well
> and kill this counter?
>
So, if I understand you correctly, if there is exe_path, I would
simply put() it and get() and assign new one. Looks cool for me.
Not sure where we may use PR_SET_MM_EXE_PATH with NULL to kill
num_exe_file_vmas from user space though (or to kill this exe_path
in case if num_exe_file_vmas is removed from code).
Cyrill
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/1] turn mm->exe_file into mm->exe_path
2012-03-05 15:28 [PATCH 0/1] turn mm->exe_file into mm->exe_path Oleg Nesterov
2012-03-05 15:28 ` [PATCH 1/1] " Oleg Nesterov
2012-03-05 17:05 ` [PATCH 0/1] " Cyrill Gorcunov
@ 2012-03-05 21:14 ` Matt Helsley
2012-03-06 16:28 ` Oleg Nesterov
2 siblings, 1 reply; 9+ messages in thread
From: Matt Helsley @ 2012-03-05 21:14 UTC (permalink / raw
To: Oleg Nesterov
Cc: Andrew Morton, Matt Helsley, Alexey Dobriyan, Cyrill Gorcunov,
Eric W. Biederman, Kees Cook, KOSAKI Motohiro, Pavel Emelyanov,
Tejun Heo, linux-kernel
On Mon, Mar 05, 2012 at 04:28:26PM +0100, Oleg Nesterov wrote:
> I think the patch is simple and self-explanatory, it simply
> does s/mm->exe_file/mm->exe_path/.
>
> Why do we need mm->exe_file? IIUC, there are 2 reasons:
>
> 1. we do not want O(n) proc/pid/exe looking for the 1st
> VM_EXECUTABLE vma.
(Frankly this always seemed like a bit of a hack to me. If someone got
creative with text layout then it could break this hack...)
>
> 2. we do not want to rely on vma->vm_file->f_path,
> bprm->file->f_op->mmap can change ->vm_file.
>
> Unless there was another subtle reason, "struct path *exe_path"
> can equally work but it looks more clear.
PATCH 1/1 looks fine. I think Alexey Dobriyan was working on a similar
patch years ago.
> And can't we also remove added_exe_file_vma/removed_exe_file_vma?
> Why do we need mm->num_exe_file_vmas? Afaics it is only needed to
> "free" mm->exe_file if the application unmaps all these vmas. Say,
> to allow to unmount fs.
Yup. I know it's not pretty to have to track the exe file refs this way
but I couldn't see any other way to keep a reference to the file (or
path) and avoid pinning the mounted filesystem the exectuable is on.
> Can't we simply add PR_CLEAR_MM_EXE_PATH instead? Of course it is
> not enough if ->vm_file still has a reference. But c/r people want
Relying solely on this prctl would break existing programs. I believe Al
Viro's example was a program that copies its text to a new executable
area, unmaps the original, performs a pivot_root(), and finally umounts
the old root. Removing the counter would cause the mount to be pinned
for these programs and the umount would fail.
> PR_SET_MM_EXE_FILE anyway, see http://marc.info/?t=133052865500016
> So perhaps we can add PR_SET_MM_EXE_PATH which accepts NULL as well
> and kill this counter?
>
> Oleg.
Cheers,
-Matt Helsley
^ permalink raw reply [flat|nested] 9+ messages in thread