On Sat, Oct 17, 2020 at 12:57:13AM +0200, Jann Horn wrote: > @@ -374,17 +366,12 @@ static int bprm_mm_init(struct linux_binprm *bprm) > task_unlock(current->group_leader); > > err = __bprm_mm_init(bprm); > - if (err) > - goto err; > - > - return 0; > - > -err: > - if (mm) { > - bprm->mm = NULL; > - mmdrop(mm); > - } > + if (!err) > + return 0; > > + bprm->mm = NULL; > + mmap_write_unlock(mm); > + mmdrop(mm); > return err; nit, but prefer 'success-oriented-flow' eg invert the 'if (!err)' and put the error unwind in the {} > @@ -1545,6 +1532,18 @@ void setup_new_exec(struct linux_binprm * bprm) > me->mm->task_size = TASK_SIZE; > mutex_unlock(&me->signal->exec_update_mutex); > mutex_unlock(&me->signal->cred_guard_mutex); > + > + if (!IS_ENABLED(CONFIG_MMU)) { > + /* > + * On MMU, setup_arg_pages() wants to access bprm->vma after > + * this point, so we can't drop the mmap lock yet. > + * On !MMU, we have neither setup_arg_pages() nor bprm->vma, > + * so we should drop the lock here. > + */ > + mmap_write_unlock(bprm->mm); > + mmput(bprm->mm); > + bprm->mm = NULL; > + } The only thing I dislike about this is how tricky the lock lifetime is, it all looks correct, but expecting the setup_arg_pages() or setup_new_exec() to unlock (depending!) is quite tricky. It feels like it would be clearer to have an explicit function to do this, like 'release_brp_mm()' indicating that current->mm is now the only way to get the mm and it must be locked. Or, more practically, the load_binary functionc can now call vm_mmap(). Anyhow, it took a bit to study all the parts but I think it looks right as is. Jason