All of lore.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: Denis Arefev <arefev@swemel.ru>
Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
	lvc-project@linuxtesting.org, trufanov@swemel.ru, vfh@swemel.ru,
	"Eric W . Biederman" <ebiederm@xmission.com>
Subject: Re: [PATCH v2] namespace: Added pointer check in copy_mnt_ns()
Date: Sat, 19 Nov 2022 07:12:39 +0000	[thread overview]
Message-ID: <Y3iB59LAgL8ORT5N@ZenIV> (raw)
In-Reply-To: <20221118114137.128088-1-arefev@swemel.ru>

On Fri, Nov 18, 2022 at 02:41:37PM +0300, Denis Arefev wrote:
> Return value of a function 'next_mnt' is dereferenced at
> namespace.c:3377 without checking for null,
> but it is usually checked for this function
> 
> Found by Linux Verification Center (linuxtesting.org) with SVACE.

NAK.

I see a bug in there, but it's not going to trigger a NULL pointer
dereference and your patch doesn't fix it at all.

That loop ought to be
		// skipped mntns binding?
                while (p->mnt.mnt_root != q->mnt.mnt_root)
			p = next_mnt(skip_mnt_tree(p), old);

and I suspect that it'll confuse your tool even worse.

What happens here is that new tree is congruent to the old one,
with some subtrees skipped.  Each node N in the new tree is a
clone of some node (Origin(N)) in the old one.  Copying preserves
node order.  We want to have p == Origin(q) on each iteration.

What we really have (due to the real bug) is

	p is no later than Origin(q) in node ordering

Initially it's trivially true (p points to root of the old tree,
and the only way it would *not* be copied would be to somehow get
mntns binding as root; in that case copy_tree() would've failed
and we wouldn't get to that loop at all).

Suppose it is true on some iteration.  What happens on the next
one?  q hadn't been the last node in the new tree, or we would've
found next_mnt(q, new) to be NULL and exited the loop.  But
that means that
	p "<=" Origin(q) "<" Origin(next_mnt(q, new))
("<" and "<=" in the node ordering, that is).  So p couldn't
have been the last node in the old tree and
	next_mnt(p, old) "<=" Origin(next_mnt(q, new))
After the
                p = next_mnt(p, old);
		q = next_mnt(q, new);
		if (!q)
			break;
we have
	p != NULL && p "<=" Origin(q)

Cloning preserves ->mnt_root, so the subsequent loop
                while (p->mnt.mnt_root != q->mnt.mnt_root)
			p = next_mnt(p, old);
could be rewritten as
		while (p->mnt.mnt_root != Origin(q)->mnt.mnt_root)
			p = next_mnt(p, old);
and in that form it's really obvious that p will not advance past
Origin(q), nevermind running out of nodes.

So on the next iteration the property still holds.  There's no way
for your added checks to trigger.

There *IS* a bug in that logics, though - mntns binding can have
a file bound on top of it.  In such case it is possible to have
p behind the Origin(q) for a (short) while.  It's not going to
cause serious problems, but that's certainly a non-obvious
behaviour and a comment needed to explain why it's not problem
is certainly longer than the one-liner change eliminating the
oddity.  Note that running into mnt_root mismatch means that p
is currently pointing to mntns binding we'd skipped when copying.
So let's skip the subtree in the same way copy_tree() did...

The bottom line:
	* your NULL pointer checks could never trigger; if you *do* have
a reproducer, please post it.
	* there's a (pretty harmless) bug in that code, but it is not
fixed by your patch.
	* see if your tool is any happier with the patch below; I would
be rather surprised if it did, but...

diff --git a/fs/namespace.c b/fs/namespace.c
index df137ba19d37..c80f422084eb 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3515,8 +3515,9 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
 		q = next_mnt(q, new);
 		if (!q)
 			break;
+		// an mntns binding we'd skipped?
 		while (p->mnt.mnt_root != q->mnt.mnt_root)
-			p = next_mnt(p, old);
+			p = next_mnt(skip_mnt_tree(p), old);
 	}
 	namespace_unlock();
 

      reply	other threads:[~2022-11-19  7:12 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-18 11:41 [PATCH v2] namespace: Added pointer check in copy_mnt_ns() Denis Arefev
2022-11-19  7:12 ` Al Viro [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Y3iB59LAgL8ORT5N@ZenIV \
    --to=viro@zeniv.linux.org.uk \
    --cc=arefev@swemel.ru \
    --cc=ebiederm@xmission.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lvc-project@linuxtesting.org \
    --cc=trufanov@swemel.ru \
    --cc=vfh@swemel.ru \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.