Message ID | 20200410213235.M6eTaELL2%akpm@linux-foundation.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [01/35] hfsplus: fix crash and filesystem corruption when deleting files | expand |
On Fri, Apr 10, 2020 at 2:32 PM Andrew Morton <akpm@linux-foundation.org> wrote: > > In fixup_user_fault(), it is possible that unlocked is NULL, > so we should test unlocked before using it. This seems wrong. > For example, in arch/arc/kernel/process.c, NULL is passed > to fixup_user_fault(). > > ret = fixup_user_fault(current, current->mm, (unsigned long) uaddr, > FAULT_FLAG_WRITE, NULL); Yes, but it doesn't set FAULT_FLAG_ALLOW_RETRY, exactly _because_ 'unlocked' is NULL. Basically, retry is fundamentally tied to that "unlocked" flag. You can't ask for retry without also saying "please tell me if you unlocked the mmap_sem during the retry". So the two go hand in hand there. So I think this is just coverity not understanding the rules. Or maybe I'm the one missing something. Did you actually see a problem? Linus
On Fri, Apr 10, 2020 at 03:24:37PM -0700, Linus Torvalds wrote: > On Fri, Apr 10, 2020 at 2:32 PM Andrew Morton <akpm@linux-foundation.org> wrote: > > > > In fixup_user_fault(), it is possible that unlocked is NULL, > > so we should test unlocked before using it. > > This seems wrong. > > > For example, in arch/arc/kernel/process.c, NULL is passed > > to fixup_user_fault(). > > > > ret = fixup_user_fault(current, current->mm, (unsigned long) uaddr, > > FAULT_FLAG_WRITE, NULL); > > Yes, but it doesn't set FAULT_FLAG_ALLOW_RETRY, exactly _because_ > 'unlocked' is NULL. > > Basically, retry is fundamentally tied to that "unlocked" flag. You > can't ask for retry without also saying "please tell me if you > unlocked the mmap_sem during the retry". So the two go hand in hand > there. > > So I think this is just coverity not understanding the rules. Yeah that's also my understanding - VM_FAULT_RETRY should depend on FAULT_FLAG_ALLOW_RETRY, which further depends on unlocked != NULL. Though I'm not sure how to teach Coverity about the fact. Maybe a "BUG_ON(unlocked == NULL)" (which contains an unreachable() inside) before referencing unlocked? Thanks, > > Or maybe I'm the one missing something. Did you actually see a problem? > > Linus >
On Fri, Apr 10, 2020 at 4:54 PM Peter Xu <peterx@redhat.com> wrote: > > Though I'm not sure how to teach Coverity about the fact. Maybe a > "BUG_ON(unlocked == NULL)" (which contains an unreachable() inside) > before referencing unlocked? Please don't add BUG_ON's. In the "that would be a horrible bug" case, I'd rather see a NULL pointer cause a fault, than see a BUG_ON. Linus
On Fri, 2020-04-10 at 15:24 -0700, Linus Torvalds wrote: > On Fri, Apr 10, 2020 at 2:32 PM Andrew Morton <akpm@linux-foundation.org> wrote: > > > > In fixup_user_fault(), it is possible that unlocked is NULL, > > so we should test unlocked before using it. > > This seems wrong. > > > For example, in arch/arc/kernel/process.c, NULL is passed > > to fixup_user_fault(). > > > > ret = fixup_user_fault(current, current->mm, (unsigned long) uaddr, > > FAULT_FLAG_WRITE, NULL); > > Yes, but it doesn't set FAULT_FLAG_ALLOW_RETRY, exactly _because_ > 'unlocked' is NULL. > > Basically, retry is fundamentally tied to that "unlocked" flag. You > can't ask for retry without also saying "please tell me if you > unlocked the mmap_sem during the retry". So the two go hand in hand > there. > > So I think this is just coverity not understanding the rules. > > Or maybe I'm the one missing something. Did you actually see a problem? Thanks for the explanation, it is just a coverity issue, not a real problem. I worry about the following case: someone passes FAULT_FLAG_ALLOW_RETRY to fixup_user_fault() with unlocked == NULL. e.g., ret = fixup_user_fault(current, current->mm, uaddr, flags | FAULT_FLAG_ALLOW_RETRY, NULL); #define FAULT_FLAG_DEFAULT (FAULT_FLAG_ALLOW_RETRY | \ FAULT_FLAG_KILLABLE | \ FAULT_FLAG_INTERRUPTIBLE) In fixup_user_fault(), it adds FAULT_FLAG_ALLOW_RETRY if unlocked is not NULL, but it does not remove FAULT_FLAG_ALLOW_RETRY if unlocked is NULL. int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm, unsigned long address, unsigned int fault_flags, bool *unlocked) { ... if (unlocked) fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; ... } Things could go wrong in the above case. I checked the source code and there is no such case. I worry too much about it. Miles > > Linus
--- a/mm/gup.c~mm-gup-fix-null-pointer-dereference-detected-by-coverity +++ a/mm/gup.c @@ -1231,7 +1231,8 @@ retry: if (ret & VM_FAULT_RETRY) { down_read(&mm->mmap_sem); if (!(fault_flags & FAULT_FLAG_TRIED)) { - *unlocked = true; + if (unlocked) + *unlocked = true; fault_flags |= FAULT_FLAG_TRIED; goto retry; }