Thread (11 messages) 11 messages, 4 authors, 2021-09-15

Re: [bug report] nfsd: Protect session creation and client confirm using client_lock

From: Chuck Lever III <chuck.lever@oracle.com>
Date: 2021-09-09 14:31:43

On Sep 9, 2021, at 6:19 AM, Jeff Layton [off-list ref] wrote:

On Wed, 2021-09-08 at 21:32 +0000, Chuck Lever III wrote:
quoted
quoted
On Sep 8, 2021, at 5:26 PM, Bruce Fields [off-list ref] wrote:

On Tue, Sep 07, 2021 at 03:00:23PM +0000, Chuck Lever III wrote:
quoted
We have IPV6_SCOPE_ID_LEN as a maximum size of the scope ID,
and it's not a big value. As long as boundary checking is made
to be sufficient, then a stack residency for the device name
should be safe.
Something like this?  (Or are you making a patch?
I thought Jeff was going to handle it? More below.
No, sorry... I was just suggesting a potential fix. I'd probably rather
you guys fix it since you're better positioned to test this at the
moment.
quoted
quoted
I'm not even sure how to test.)
are
--b.
diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c
index 6e4dbd577a39..d435bffc6199 100644
--- a/net/sunrpc/addr.c
+++ b/net/sunrpc/addr.c
@@ -162,8 +162,10 @@ static int rpc_parse_scope_id(struct net *net, const char *buf,
			      const size_t buflen, const char *delim,
			      struct sockaddr_in6 *sin6)
{
-	char *p;
+	char p[IPV6_SCOPE_ID_LEN + 1];
	size_t len;
+	u32 scope_id = 0;
+	struct net_device *dev;

	if ((buf + buflen) == delim)
		return 1;
@@ -175,29 +177,23 @@ static int rpc_parse_scope_id(struct net *net, const char *buf,
		return 0;

	len = (buf + buflen) - delim - 1;
-	p = kmemdup_nul(delim + 1, len, GFP_KERNEL);
-	if (p) {
-		u32 scope_id = 0;
-		struct net_device *dev;
-
-		dev = dev_get_by_name(net, p);
-		if (dev != NULL) {
-			scope_id = dev->ifindex;
-			dev_put(dev);
-		} else {
-			if (kstrtou32(p, 10, &scope_id) != 0) {
-				kfree(p);
-				return 0;
-			}
-		}
-
-		kfree(p);
-
-		sin6->sin6_scope_id = scope_id;
-		return 1;
+	if (len > IPV6_SCOPE_ID_LEN)
+		return 0;
+
+	memcpy(p, delim + 1, len);
+	p[len] = 0;
If I recall correctly, Linus prefers us to use the str*()
functions instead of raw memcpy() in cases like this.
I hadn't heard that.
I'm paraphrasing these:

https://lore.kernel.org/lkml/CAHk-=wj5Pp5J-CAPck22RSQ13k3cEOVnJHUA-WocAZqCJK1BZw@mail.gmail.com/ (local)

https://lore.kernel.org/lkml/CAHk-=wjWosrcv2=6m-=YgXRKev=5cnCg-1EhqDpbRXT5z6eQmg@mail.gmail.com/ (local)

If you already know the length to be copied, then
strcpy and the like tend to be less efficient since they continually
have to check for null terminators as they walk the source string.
I'm sure there's one str helper that comes close to what we need.
Here efficiency doesn't really matter, and the size of the device
string is always going to be in the single digits.

The priority is correctness.

quoted
quoted
+
+	dev = dev_get_by_name(net, p);
+	if (dev != NULL) {
+		scope_id = dev->ifindex;
+		dev_put(dev);
+	} else {
+		if (kstrtou32(p, 10, &scope_id) != 0)
+			return 0;
	}

-	return 0;
+	sin6->sin6_scope_id = scope_id;
+	return 1;
}

static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen,
--
Chuck Lever

-- 
Jeff Layton [off-list ref]
--
Chuck Lever


Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help