Commit 4b4b699d authored by Mike Kravetz's avatar Mike Kravetz Committed by Linus Torvalds

[PATCH] proc fs task name locking fix

Races have been observed between excec-time overwriting of task->comm and
/proc accesses to the same data.  This causes environment string
information to appear in /proc.

Fix that up by taking task_lock() around updates to and accesses to
task->comm.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9026a8d6
...@@ -786,11 +786,27 @@ static inline void flush_old_files(struct files_struct * files) ...@@ -786,11 +786,27 @@ static inline void flush_old_files(struct files_struct * files)
spin_unlock(&files->file_lock); spin_unlock(&files->file_lock);
} }
void get_task_comm(char *buf, struct task_struct *tsk)
{
/* buf must be at least sizeof(tsk->comm) in size */
task_lock(tsk);
memcpy(buf, tsk->comm, sizeof(tsk->comm));
task_unlock(tsk);
}
void set_task_comm(struct task_struct *tsk, char *buf)
{
task_lock(tsk);
strlcpy(tsk->comm, buf, sizeof(tsk->comm));
task_unlock(tsk);
}
int flush_old_exec(struct linux_binprm * bprm) int flush_old_exec(struct linux_binprm * bprm)
{ {
char * name; char * name;
int i, ch, retval; int i, ch, retval;
struct files_struct *files; struct files_struct *files;
char tcomm[sizeof(current->comm)];
/* /*
* Make sure we have a private signal table and that * Make sure we have a private signal table and that
...@@ -831,10 +847,11 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -831,10 +847,11 @@ int flush_old_exec(struct linux_binprm * bprm)
if (ch == '/') if (ch == '/')
i = 0; i = 0;
else else
if (i < 15) if (i < (sizeof(tcomm) - 1))
current->comm[i++] = ch; tcomm[i++] = ch;
} }
current->comm[i] = '\0'; tcomm[i] = '\0';
set_task_comm(current, tcomm);
flush_thread(); flush_thread();
......
...@@ -88,10 +88,13 @@ static inline char * task_name(struct task_struct *p, char * buf) ...@@ -88,10 +88,13 @@ static inline char * task_name(struct task_struct *p, char * buf)
{ {
int i; int i;
char * name; char * name;
char tcomm[sizeof(p->comm)];
get_task_comm(tcomm, p);
ADDBUF(buf, "Name:\t"); ADDBUF(buf, "Name:\t");
name = p->comm; name = tcomm;
i = sizeof(p->comm); i = sizeof(tcomm);
do { do {
unsigned char c = *name; unsigned char c = *name;
name++; name++;
...@@ -309,6 +312,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer) ...@@ -309,6 +312,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
int num_threads = 0; int num_threads = 0;
struct mm_struct *mm; struct mm_struct *mm;
unsigned long long start_time; unsigned long long start_time;
char tcomm[sizeof(task->comm)];
state = *get_task_state(task); state = *get_task_state(task);
vsize = eip = esp = 0; vsize = eip = esp = 0;
...@@ -325,6 +329,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer) ...@@ -325,6 +329,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
} }
get_task_comm(tcomm, task);
wchan = get_wchan(task); wchan = get_wchan(task);
sigemptyset(&sigign); sigemptyset(&sigign);
...@@ -362,7 +367,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer) ...@@ -362,7 +367,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
%lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n",
task->pid, task->pid,
task->comm, tcomm,
state, state,
ppid, ppid,
pgid, pgid,
......
...@@ -887,6 +887,9 @@ extern int do_execve(char *, char __user * __user *, char __user * __user *, str ...@@ -887,6 +887,9 @@ extern int do_execve(char *, char __user * __user *, char __user * __user *, str
extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *); extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
extern struct task_struct * copy_process(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *); extern struct task_struct * copy_process(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
extern void set_task_comm(struct task_struct *tsk, char *from);
extern void get_task_comm(char *to, struct task_struct *tsk);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
extern void wait_task_inactive(task_t * p); extern void wait_task_inactive(task_t * p);
#else #else
...@@ -941,8 +944,8 @@ static inline int thread_group_empty(task_t *p) ...@@ -941,8 +944,8 @@ static inline int thread_group_empty(task_t *p)
extern void unhash_process(struct task_struct *p); extern void unhash_process(struct task_struct *p);
/* /*
* Protects ->fs, ->files, ->mm, ->ptrace, ->group_info and synchronises with * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm and
* wait4(). * synchronises with wait4().
* *
* Nests both inside and outside of read_lock(&tasklist_lock). * Nests both inside and outside of read_lock(&tasklist_lock).
* It must not be nested with write_lock_irq(&tasklist_lock), * It must not be nested with write_lock_irq(&tasklist_lock),
......
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