aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/binfmt_flat.c3
-rw-r--r--fs/exec.c2
-rw-r--r--fs/proc/base.c75
-rw-r--r--fs/proc/internal.h1
-rw-r--r--fs/proc/task_mmu.c34
-rw-r--r--fs/proc/task_nommu.c34
-rw-r--r--include/linux/mm.h13
-rw-r--r--include/linux/mm_types.h6
-rw-r--r--include/linux/proc_fs.h20
-rw-r--r--kernel/fork.c3
-rw-r--r--mm/mmap.c24
-rw-r--r--mm/nommu.c23
12 files changed, 157 insertions, 81 deletions
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index c12cc362fd3b..3b40d45a3a16 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -531,7 +531,8 @@ static int load_flat_file(struct linux_binprm * bprm,
531 DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); 531 DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
532 532
533 down_write(&current->mm->mmap_sem); 533 down_write(&current->mm->mmap_sem);
534 textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_PRIVATE, 0); 534 textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
535 MAP_PRIVATE|MAP_EXECUTABLE, 0);
535 up_write(&current->mm->mmap_sem); 536 up_write(&current->mm->mmap_sem);
536 if (!textpos || textpos >= (unsigned long) -4096) { 537 if (!textpos || textpos >= (unsigned long) -4096) {
537 if (!textpos) 538 if (!textpos)
diff --git a/fs/exec.c b/fs/exec.c
index 711bc45d789c..a13883903ee9 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -964,6 +964,8 @@ int flush_old_exec(struct linux_binprm * bprm)
964 if (retval) 964 if (retval)
965 goto out; 965 goto out;
966 966
967 set_mm_exe_file(bprm->mm, bprm->file);
968
967 /* 969 /*
968 * Release all of the old mmap stuff 970 * Release all of the old mmap stuff
969 */ 971 */
diff --git a/fs/proc/base.c b/fs/proc/base.c
index c5e412a00b17..b48ddb119945 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1181,6 +1181,81 @@ static const struct file_operations proc_pid_sched_operations = {
1181 1181
1182#endif 1182#endif
1183 1183
1184/*
1185 * We added or removed a vma mapping the executable. The vmas are only mapped
1186 * during exec and are not mapped with the mmap system call.
1187 * Callers must hold down_write() on the mm's mmap_sem for these
1188 */
1189void added_exe_file_vma(struct mm_struct *mm)
1190{
1191 mm->num_exe_file_vmas++;
1192}
1193
1194void removed_exe_file_vma(struct mm_struct *mm)
1195{
1196 mm->num_exe_file_vmas--;
1197 if ((mm->num_exe_file_vmas == 0) && mm->exe_file){
1198 fput(mm->exe_file);
1199 mm->exe_file = NULL;
1200 }
1201
1202}
1203
1204void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
1205{
1206 if (new_exe_file)
1207 get_file(new_exe_file);
1208 if (mm->exe_file)
1209 fput(mm->exe_file);
1210 mm->exe_file = new_exe_file;
1211 mm->num_exe_file_vmas = 0;
1212}
1213
1214struct file *get_mm_exe_file(struct mm_struct *mm)
1215{
1216 struct file *exe_file;
1217
1218 /* We need mmap_sem to protect against races with removal of
1219 * VM_EXECUTABLE vmas */
1220 down_read(&mm->mmap_sem);
1221 exe_file = mm->exe_file;
1222 if (exe_file)
1223 get_file(exe_file);
1224 up_read(&mm->mmap_sem);
1225 return exe_file;
1226}
1227
1228void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
1229{
1230 /* It's safe to write the exe_file pointer without exe_file_lock because
1231 * this is called during fork when the task is not yet in /proc */
1232 newmm->exe_file = get_mm_exe_file(oldmm);
1233}
1234
1235static int proc_exe_link(struct inode *inode, struct path *exe_path)
1236{
1237 struct task_struct *task;
1238 struct mm_struct *mm;
1239 struct file *exe_file;
1240
1241 task = get_proc_task(inode);
1242 if (!task)
1243 return -ENOENT;
1244 mm = get_task_mm(task);
1245 put_task_struct(task);
1246 if (!mm)
1247 return -ENOENT;
1248 exe_file = get_mm_exe_file(mm);
1249 mmput(mm);
1250 if (exe_file) {
1251 *exe_path = exe_file->f_path;
1252 path_get(&exe_file->f_path);
1253 fput(exe_file);
1254 return 0;
1255 } else
1256 return -ENOENT;
1257}
1258
1184static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) 1259static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
1185{ 1260{
1186 struct inode *inode = dentry->d_inode; 1261 struct inode *inode = dentry->d_inode;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index bc72f5c8c47d..45abb9803988 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -48,7 +48,6 @@ extern int maps_protect;
48 48
49extern void create_seq_entry(char *name, mode_t mode, 49extern void create_seq_entry(char *name, mode_t mode,
50 const struct file_operations *f); 50 const struct file_operations *f);
51extern int proc_exe_link(struct inode *, struct path *);
52extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, 51extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
53 struct pid *pid, struct task_struct *task); 52 struct pid *pid, struct task_struct *task);
54extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, 53extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7415eeb7cc3a..e2b8e769f510 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -75,40 +75,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
75 return mm->total_vm; 75 return mm->total_vm;
76} 76}
77 77
78int proc_exe_link(struct inode *inode, struct path *path)
79{
80 struct vm_area_struct * vma;
81 int result = -ENOENT;
82 struct task_struct *task = get_proc_task(inode);
83 struct mm_struct * mm = NULL;
84
85 if (task) {
86 mm = get_task_mm(task);
87 put_task_struct(task);
88 }
89 if (!mm)
90 goto out;
91 down_read(&mm->mmap_sem);
92
93 vma = mm->mmap;
94 while (vma) {
95 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
96 break;
97 vma = vma->vm_next;
98 }
99
100 if (vma) {
101 *path = vma->vm_file->f_path;
102 path_get(&vma->vm_file->f_path);
103 result = 0;
104 }
105
106 up_read(&mm->mmap_sem);
107 mmput(mm);
108out:
109 return result;
110}
111
112static void pad_len_spaces(struct seq_file *m, int len) 78static void pad_len_spaces(struct seq_file *m, int len)
113{ 79{
114 len = 25 + sizeof(void*) * 6 - len; 80 len = 25 + sizeof(void*) * 6 - len;
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 8011528518bd..4b733f108455 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -103,40 +103,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
103 return size; 103 return size;
104} 104}
105 105
106int proc_exe_link(struct inode *inode, struct path *path)
107{
108 struct vm_list_struct *vml;
109 struct vm_area_struct *vma;
110 struct task_struct *task = get_proc_task(inode);
111 struct mm_struct *mm = get_task_mm(task);
112 int result = -ENOENT;
113
114 if (!mm)
115 goto out;
116 down_read(&mm->mmap_sem);
117
118 vml = mm->context.vmlist;
119 vma = NULL;
120 while (vml) {
121 if ((vml->vma->vm_flags & VM_EXECUTABLE) && vml->vma->vm_file) {
122 vma = vml->vma;
123 break;
124 }
125 vml = vml->next;
126 }
127
128 if (vma) {
129 *path = vma->vm_file->f_path;
130 path_get(&vma->vm_file->f_path);
131 result = 0;
132 }
133
134 up_read(&mm->mmap_sem);
135 mmput(mm);
136out:
137 return result;
138}
139
140/* 106/*
141 * display mapping lines for a particular process's /proc/pid/maps 107 * display mapping lines for a particular process's /proc/pid/maps
142 */ 108 */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index fef602d82722..c31a9cd2a30e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1066,6 +1066,19 @@ extern void unlink_file_vma(struct vm_area_struct *);
1066extern struct vm_area_struct *copy_vma(struct vm_area_struct **, 1066extern struct vm_area_struct *copy_vma(struct vm_area_struct **,
1067 unsigned long addr, unsigned long len, pgoff_t pgoff); 1067 unsigned long addr, unsigned long len, pgoff_t pgoff);
1068extern void exit_mmap(struct mm_struct *); 1068extern void exit_mmap(struct mm_struct *);
1069
1070#ifdef CONFIG_PROC_FS
1071/* From fs/proc/base.c. callers must _not_ hold the mm's exe_file_lock */
1072extern void added_exe_file_vma(struct mm_struct *mm);
1073extern void removed_exe_file_vma(struct mm_struct *mm);
1074#else
1075static inline void added_exe_file_vma(struct mm_struct *mm)
1076{}
1077
1078static inline void removed_exe_file_vma(struct mm_struct *mm)
1079{}
1080#endif /* CONFIG_PROC_FS */
1081
1069extern int may_expand_vm(struct mm_struct *mm, unsigned long npages); 1082extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
1070extern int install_special_mapping(struct mm_struct *mm, 1083extern int install_special_mapping(struct mm_struct *mm,
1071 unsigned long addr, unsigned long len, 1084 unsigned long addr, unsigned long len,
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index bc97bd54f606..eb7c16cc9559 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -229,6 +229,12 @@ struct mm_struct {
229 struct task_struct *owner; /* The thread group leader that */ 229 struct task_struct *owner; /* The thread group leader that */
230 /* owns the mm_struct. */ 230 /* owns the mm_struct. */
231#endif 231#endif
232
233#ifdef CONFIG_PROC_FS
234 /* store ref to file /proc/<pid>/exe symlink points to */
235 struct file *exe_file;
236 unsigned long num_exe_file_vmas;
237#endif
232}; 238};
233 239
234#endif /* _LINUX_MM_TYPES_H */ 240#endif /* _LINUX_MM_TYPES_H */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 9b6c935f69cf..65f2299b772b 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -9,7 +9,6 @@
9 9
10struct net; 10struct net;
11struct completion; 11struct completion;
12
13/* 12/*
14 * The proc filesystem constants/structures 13 * The proc filesystem constants/structures
15 */ 14 */
@@ -206,6 +205,12 @@ extern void proc_net_remove(struct net *net, const char *name);
206extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name, 205extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
207 struct proc_dir_entry *parent); 206 struct proc_dir_entry *parent);
208 207
208/* While the {get|set|dup}_mm_exe_file functions are for mm_structs, they are
209 * only needed to implement /proc/<pid>|self/exe so we define them here. */
210extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
211extern struct file *get_mm_exe_file(struct mm_struct *mm);
212extern void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm);
213
209#else 214#else
210 215
211#define proc_root_driver NULL 216#define proc_root_driver NULL
@@ -255,6 +260,19 @@ static inline void pid_ns_release_proc(struct pid_namespace *ns)
255{ 260{
256} 261}
257 262
263static inline void set_mm_exe_file(struct mm_struct *mm,
264 struct file *new_exe_file)
265{}
266
267static inline struct file *get_mm_exe_file(struct mm_struct *mm)
268{
269 return NULL;
270}
271
272static inline void dup_mm_exe_file(struct mm_struct *oldmm,
273 struct mm_struct *newmm)
274{}
275
258#endif /* CONFIG_PROC_FS */ 276#endif /* CONFIG_PROC_FS */
259 277
260#if !defined(CONFIG_PROC_KCORE) 278#if !defined(CONFIG_PROC_KCORE)
diff --git a/kernel/fork.c b/kernel/fork.c
index de5c16c6b6ec..068ffe007529 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -431,6 +431,7 @@ void mmput(struct mm_struct *mm)
431 if (atomic_dec_and_test(&mm->mm_users)) { 431 if (atomic_dec_and_test(&mm->mm_users)) {
432 exit_aio(mm); 432 exit_aio(mm);
433 exit_mmap(mm); 433 exit_mmap(mm);
434 set_mm_exe_file(mm, NULL);
434 if (!list_empty(&mm->mmlist)) { 435 if (!list_empty(&mm->mmlist)) {
435 spin_lock(&mmlist_lock); 436 spin_lock(&mmlist_lock);
436 list_del(&mm->mmlist); 437 list_del(&mm->mmlist);
@@ -543,6 +544,8 @@ struct mm_struct *dup_mm(struct task_struct *tsk)
543 if (init_new_context(tsk, mm)) 544 if (init_new_context(tsk, mm))
544 goto fail_nocontext; 545 goto fail_nocontext;
545 546
547 dup_mm_exe_file(oldmm, mm);
548
546 err = dup_mmap(mm, oldmm); 549 err = dup_mmap(mm, oldmm);
547 if (err) 550 if (err)
548 goto free_pt; 551 goto free_pt;
diff --git a/mm/mmap.c b/mm/mmap.c
index 677d184b0d42..fac66337da2a 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -230,8 +230,11 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
230 might_sleep(); 230 might_sleep();
231 if (vma->vm_ops && vma->vm_ops->close) 231 if (vma->vm_ops && vma->vm_ops->close)
232 vma->vm_ops->close(vma); 232 vma->vm_ops->close(vma);
233 if (vma->vm_file) 233 if (vma->vm_file) {
234 fput(vma->vm_file); 234 fput(vma->vm_file);
235 if (vma->vm_flags & VM_EXECUTABLE)
236 removed_exe_file_vma(vma->vm_mm);
237 }
235 mpol_put(vma_policy(vma)); 238 mpol_put(vma_policy(vma));
236 kmem_cache_free(vm_area_cachep, vma); 239 kmem_cache_free(vm_area_cachep, vma);
237 return next; 240 return next;
@@ -623,8 +626,11 @@ again: remove_next = 1 + (end > next->vm_end);
623 spin_unlock(&mapping->i_mmap_lock); 626 spin_unlock(&mapping->i_mmap_lock);
624 627
625 if (remove_next) { 628 if (remove_next) {
626 if (file) 629 if (file) {
627 fput(file); 630 fput(file);
631 if (next->vm_flags & VM_EXECUTABLE)
632 removed_exe_file_vma(mm);
633 }
628 mm->map_count--; 634 mm->map_count--;
629 mpol_put(vma_policy(next)); 635 mpol_put(vma_policy(next));
630 kmem_cache_free(vm_area_cachep, next); 636 kmem_cache_free(vm_area_cachep, next);
@@ -1154,6 +1160,8 @@ munmap_back:
1154 error = file->f_op->mmap(file, vma); 1160 error = file->f_op->mmap(file, vma);
1155 if (error) 1161 if (error)
1156 goto unmap_and_free_vma; 1162 goto unmap_and_free_vma;
1163 if (vm_flags & VM_EXECUTABLE)
1164 added_exe_file_vma(mm);
1157 } else if (vm_flags & VM_SHARED) { 1165 } else if (vm_flags & VM_SHARED) {
1158 error = shmem_zero_setup(vma); 1166 error = shmem_zero_setup(vma);
1159 if (error) 1167 if (error)
@@ -1185,6 +1193,8 @@ munmap_back:
1185 mpol_put(vma_policy(vma)); 1193 mpol_put(vma_policy(vma));
1186 kmem_cache_free(vm_area_cachep, vma); 1194 kmem_cache_free(vm_area_cachep, vma);
1187 fput(file); 1195 fput(file);
1196 if (vm_flags & VM_EXECUTABLE)
1197 removed_exe_file_vma(mm);
1188 } else { 1198 } else {
1189 vma_link(mm, vma, prev, rb_link, rb_parent); 1199 vma_link(mm, vma, prev, rb_link, rb_parent);
1190 file = vma->vm_file; 1200 file = vma->vm_file;
@@ -1817,8 +1827,11 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
1817 } 1827 }
1818 vma_set_policy(new, pol); 1828 vma_set_policy(new, pol);
1819 1829
1820 if (new->vm_file) 1830 if (new->vm_file) {
1821 get_file(new->vm_file); 1831 get_file(new->vm_file);
1832 if (vma->vm_flags & VM_EXECUTABLE)
1833 added_exe_file_vma(mm);
1834 }
1822 1835
1823 if (new->vm_ops && new->vm_ops->open) 1836 if (new->vm_ops && new->vm_ops->open)
1824 new->vm_ops->open(new); 1837 new->vm_ops->open(new);
@@ -2135,8 +2148,11 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
2135 new_vma->vm_start = addr; 2148 new_vma->vm_start = addr;
2136 new_vma->vm_end = addr + len; 2149 new_vma->vm_end = addr + len;
2137 new_vma->vm_pgoff = pgoff; 2150 new_vma->vm_pgoff = pgoff;
2138 if (new_vma->vm_file) 2151 if (new_vma->vm_file) {
2139 get_file(new_vma->vm_file); 2152 get_file(new_vma->vm_file);
2153 if (vma->vm_flags & VM_EXECUTABLE)
2154 added_exe_file_vma(mm);
2155 }
2140 if (new_vma->vm_ops && new_vma->vm_ops->open) 2156 if (new_vma->vm_ops && new_vma->vm_ops->open)
2141 new_vma->vm_ops->open(new_vma); 2157 new_vma->vm_ops->open(new_vma);
2142 vma_link(mm, new_vma, prev, rb_link, rb_parent); 2158 vma_link(mm, new_vma, prev, rb_link, rb_parent);
diff --git a/mm/nommu.c b/mm/nommu.c
index 1d32fe89d57b..ef8c62cec697 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -966,8 +966,13 @@ unsigned long do_mmap_pgoff(struct file *file,
966 966
967 INIT_LIST_HEAD(&vma->anon_vma_node); 967 INIT_LIST_HEAD(&vma->anon_vma_node);
968 atomic_set(&vma->vm_usage, 1); 968 atomic_set(&vma->vm_usage, 1);
969 if (file) 969 if (file) {
970 get_file(file); 970 get_file(file);
971 if (vm_flags & VM_EXECUTABLE) {
972 added_exe_file_vma(current->mm);
973 vma->vm_mm = current->mm;
974 }
975 }
971 vma->vm_file = file; 976 vma->vm_file = file;
972 vma->vm_flags = vm_flags; 977 vma->vm_flags = vm_flags;
973 vma->vm_start = addr; 978 vma->vm_start = addr;
@@ -1022,8 +1027,11 @@ unsigned long do_mmap_pgoff(struct file *file,
1022 up_write(&nommu_vma_sem); 1027 up_write(&nommu_vma_sem);
1023 kfree(vml); 1028 kfree(vml);
1024 if (vma) { 1029 if (vma) {
1025 if (vma->vm_file) 1030 if (vma->vm_file) {
1026 fput(vma->vm_file); 1031 fput(vma->vm_file);
1032 if (vma->vm_flags & VM_EXECUTABLE)
1033 removed_exe_file_vma(vma->vm_mm);
1034 }
1027 kfree(vma); 1035 kfree(vma);
1028 } 1036 }
1029 return ret; 1037 return ret;
@@ -1053,7 +1061,7 @@ EXPORT_SYMBOL(do_mmap_pgoff);
1053/* 1061/*
1054 * handle mapping disposal for uClinux 1062 * handle mapping disposal for uClinux
1055 */ 1063 */
1056static void put_vma(struct vm_area_struct *vma) 1064static void put_vma(struct mm_struct *mm, struct vm_area_struct *vma)
1057{ 1065{
1058 if (vma) { 1066 if (vma) {
1059 down_write(&nommu_vma_sem); 1067 down_write(&nommu_vma_sem);
@@ -1075,8 +1083,11 @@ static void put_vma(struct vm_area_struct *vma)
1075 realalloc -= kobjsize(vma); 1083 realalloc -= kobjsize(vma);
1076 askedalloc -= sizeof(*vma); 1084 askedalloc -= sizeof(*vma);
1077 1085
1078 if (vma->vm_file) 1086 if (vma->vm_file) {
1079 fput(vma->vm_file); 1087 fput(vma->vm_file);
1088 if (vma->vm_flags & VM_EXECUTABLE)
1089 removed_exe_file_vma(mm);
1090 }
1080 kfree(vma); 1091 kfree(vma);
1081 } 1092 }
1082 1093
@@ -1113,7 +1124,7 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
1113 found: 1124 found:
1114 vml = *parent; 1125 vml = *parent;
1115 1126
1116 put_vma(vml->vma); 1127 put_vma(mm, vml->vma);
1117 1128
1118 *parent = vml->next; 1129 *parent = vml->next;
1119 realalloc -= kobjsize(vml); 1130 realalloc -= kobjsize(vml);
@@ -1158,7 +1169,7 @@ void exit_mmap(struct mm_struct * mm)
1158 1169
1159 while ((tmp = mm->context.vmlist)) { 1170 while ((tmp = mm->context.vmlist)) {
1160 mm->context.vmlist = tmp->next; 1171 mm->context.vmlist = tmp->next;
1161 put_vma(tmp->vma); 1172 put_vma(mm, tmp->vma);
1162 1173
1163 realalloc -= kobjsize(tmp); 1174 realalloc -= kobjsize(tmp);
1164 askedalloc -= sizeof(*tmp); 1175 askedalloc -= sizeof(*tmp);