@@ -1285,6 +1285,13 @@ int begin_new_exec(struct linux_binprm * bprm)
if (retval)
goto out;
+ /*
+ * In case we're in an interpreted scenario (like binfmt_misc,
+ * for example), flag it on mm_struct in order to expose such
+ * interpreter as the symlink /proc/self/interpreter.
+ */
+ bprm->mm->has_interpreter = bprm->has_interpreter;
+
/* If the binary is not readable then enforce mm->dumpable=0 */
would_dump(bprm, bprm->file);
if (bprm->have_execfd)
@@ -1796,6 +1803,7 @@ static int exec_binprm(struct linux_binprm *bprm)
exec = bprm->file;
bprm->file = bprm->interpreter;
+ bprm->has_interpreter = true;
bprm->interpreter = NULL;
allow_write_access(exec);
@@ -1719,25 +1719,39 @@ 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 struct file *proc_get_task_exe_file(struct task_struct *task)
{
- struct task_struct *task;
- struct file *exe_file;
-
- task = get_proc_task(d_inode(dentry));
- if (!task)
- return -ENOENT;
- exe_file = get_task_exe_file(task, true);
- put_task_struct(task);
- if (exe_file) {
- *exe_path = exe_file->f_path;
- path_get(&exe_file->f_path);
- fput(exe_file);
- return 0;
- } else
- return -ENOENT;
+ return get_task_exe_file(task, true);
}
+static struct file *proc_get_task_interpreter_file(struct task_struct *task)
+{
+ return get_task_interpreter_file(task);
+}
+
+/* Definition of proc_exe_link and proc_interpreter_link. */
+#define PROC_GET_LINK_FUNC(type) \
+static int proc_##type##_link(struct dentry *dentry, struct path *path) \
+{ \
+ struct task_struct *task; \
+ struct file *file; \
+ \
+ task = get_proc_task(d_inode(dentry)); \
+ if (!task) \
+ return -ENOENT; \
+ file = proc_get_task_##type##_file(task); \
+ put_task_struct(task); \
+ if (file) { \
+ *path = file->f_path; \
+ path_get(&file->f_path); \
+ fput(file); \
+ return 0; \
+ } else \
+ return -ENOENT; \
+}
+PROC_GET_LINK_FUNC(exe);
+PROC_GET_LINK_FUNC(interpreter);
+
static const char *proc_pid_get_link(struct dentry *dentry,
struct inode *inode,
struct delayed_call *done)
@@ -3276,6 +3290,7 @@ static const struct pid_entry tgid_base_stuff[] = {
LNK("cwd", proc_cwd_link),
LNK("root", proc_root_link),
LNK("exe", proc_exe_link),
+ LNK("interpreter", proc_interpreter_link),
REG("mounts", S_IRUGO, proc_mounts_operations),
REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
REG("mountstats", S_IRUSR, proc_mountstats_operations),
@@ -3626,6 +3641,7 @@ static const struct pid_entry tid_base_stuff[] = {
LNK("cwd", proc_cwd_link),
LNK("root", proc_root_link),
LNK("exe", proc_exe_link),
+ LNK("interpreter", proc_interpreter_link),
REG("mounts", S_IRUGO, proc_mounts_operations),
REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
#ifdef CONFIG_PROC_PAGE_MONITOR
@@ -46,6 +46,7 @@ struct linux_binprm {
struct file *executable; /* Executable to pass to the interpreter */
struct file *interpreter;
struct file *interpreted_file; /* only for binfmt_misc with flag I */
+ bool has_interpreter; /* In order to expose /proc/self/interpreter */
struct file *file;
struct cred *cred; /* new credentials */
int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
@@ -3261,6 +3261,7 @@ extern int replace_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
extern struct file *get_mm_exe_file(struct mm_struct *mm);
extern struct file *get_task_exe_file(struct task_struct *task,
bool prefer_interpreted);
+extern struct file *get_task_interpreter_file(struct task_struct *task);
extern bool may_expand_vm(struct mm_struct *, vm_flags_t, unsigned long npages);
extern void vm_stat_account(struct mm_struct *, vm_flags_t, long npages);
@@ -843,6 +843,7 @@ struct mm_struct {
/* store ref to file /proc/<pid>/exe symlink points to */
struct file __rcu *exe_file;
struct file __rcu *interpreted_file; /* see binfmt_misc flag I */
+ bool has_interpreter; /* exposes (or not) /proc/self/interpreter */
#ifdef CONFIG_MMU_NOTIFIER
struct mmu_notifier_subscriptions *notifier_subscriptions;
#endif
@@ -1568,6 +1568,32 @@ struct file *get_task_exe_file(struct task_struct *task,
return exe_file;
}
+/**
+ * get_task_interpreter_file - acquire a reference to the task's *interpreter*
+ * executable (which is in fact the exe_file on mm_struct!). This is used in
+ * order to expose /proc/self/interpreter, if we're under an interpreted
+ * scenario (like binfmt_misc).
+ *
+ * Returns %NULL if exe_file is not an interpreter (i.e., it is the truly
+ * running binary indeed).
+ */
+struct file *get_task_interpreter_file(struct task_struct *task)
+{
+ struct file *interpreter_file = NULL;
+ struct mm_struct *mm;
+
+ task_lock(task);
+
+ mm = task->mm;
+ if (mm && mm->has_interpreter) {
+ if (!(task->flags & PF_KTHREAD))
+ interpreter_file = get_mm_exe_file(mm);
+ }
+
+ task_unlock(task);
+ return interpreter_file;
+}
+
/**
* get_task_mm - acquire a reference to the task's mm
*