unserialized task->files changing
Subsystems (2)
PATCH 1/1 unserialized task->files changing
Fixed race on put_files_struct on exec with proc. Restoring files on current on error path may lead to proc having a pointer to already kfree-d files_struct.
Found during OpenVZ stress testing.
fs/binfmt_elf.c renamed from fs/binfmt_elf.c.fsfix +6 -1
@@ -1027,8 +1027,13 @@ out_free_file:sys_close (elf_exec_fileno); out_free_fh:if (files) { -put_files_struct (current->files); +struct files_struct *old; + + old = current->files; +task_lock (current); current->files = files; +task_unlock (current); +put_files_struct (old); } out_free_ph:kfree (elf_phdata);
fs/binfmt_misc.c renamed from fs/binfmt_misc.c.fsfix +6 -1
@@ -216,8 +216,13 @@ _error: bprm->interp_data =0 ; _unshare:if (files) { -put_files_struct (current->files); +struct files_struct *old; + + old = current->files; +task_lock (current); current->files = files; +task_unlock (current); +put_files_struct (old); } goto _ret; }
fs/exec.c renamed from fs/exec.c.fsfix +5 -2
@@ -865,7 +865,7 @@ int flush_old_exec(struct linux_binprm * {char * name;int i, ch, retval; -struct files_struct *files; +struct files_struct *files, *old;char tcomm[sizeof (current->comm)];/*
@@ -946,8 +946,11 @@ int flush_old_exec(struct linux_binprm *return 0 ; mmap_failed: -put_files_struct (current->files); + old = current->files; +task_lock (current); current->files = files; +task_unlock (current); +put_files_struct (old); out:return retval; }
Quoted 3 lines · Kirill Korotaev
Fixed race on
put_files_structon exec with proc. Restoring files on current on error path may lead to proc having a pointer to already kfree-dfiles_struct.
This is three times the exact same code sequence, it should probably go into a helper:
void reset_current_files(struct files_struct *files)
{
struct files_struct *old = current->files;
task_lock(current);
current->files = files;
task_unlock(current);
put_files_struct(old);
}Quoted 9 lines · Christoph Hellwig
Quoted 3 lines · Kirill Korotaev
Fixed race on
put_files_structon exec with proc. Restoring files on current on error path may lead to proc having a pointer to already kfree-dfiles_struct.This is three times the exact same code sequence, it should probably go into a helper:
void
reset_current_files(struct files_struct *files)
Quoted 8 lines
{
struct files_struct *old = current->files;
task_lock(current);
current->files = files;
task_unlock(current);
put_files_struct(old);
}More over I think you want to task_lock() before reading current->files into 'old'
task_lock(current);
old = current->files;current->files = files;task_unlock(current);put_files_struct(old);
or maybe a xchg() ?
Quoted 25 lines · Eric Dumazet
Quoted 10 lines · Christoph Hellwig
Quoted 3 lines · Kirill Korotaev
Fixed race on
put_files_structon exec with proc. Restoring files on current on error path may lead to proc having a pointer to already kfree-dfiles_struct.This is three times the exact same code sequence, it should probably go into a helper:
void
reset_current_files(struct files_struct *files)Quoted 8 lines
{ struct files_struct *old = current->files; task_lock(current); current->files = files; task_unlock(current); put_files_struct(old); }More over I think you want to
task_lock()before readingcurrent->filesinto 'old'
Quoted 7 lines
task_lock(current);
old =current->files;current->files= files;task_unlock(current);put_files_struct(old);or maybe a
xchg()?
yeah, never do assignments in declarations :)
BTW, not sure about kthread_exit_files() yet, but looks like it suffers too.
unshare_files() changes current->files w/o locking as well. but I can't see where it puts the old files... hmm...
Kirill