Thread (22 messages) 22 messages, 4 authors, 2020-03-17

Re: [PATCH v3 3/3] KEYS: Use kvmalloc() to better handle large buffer allocation

From: Waiman Long <longman@redhat.com>
Date: 2020-03-13 17:50:07
Also in: keyrings, linux-integrity, lkml

On 3/13/20 12:43 PM, Eric Biggers wrote:
On Fri, Mar 13, 2020 at 11:21:02AM -0400, Waiman Long wrote:
quoted
For large multi-page temporary buffer allocation, the security/keys
subsystem don't need contiguous physical pages. It will work perfectly
fine with virtually mapped pages.

Replace the kmalloc() call by kvmalloc() and provide a __kvzfree()
helper function to clear and free the kvmalloc'ed buffer. This will
reduce the chance of memory allocation failure just because of highly
fragmented pages.

Suggested-by: David Howells <dhowells@redhat.com>
Signed-off-by: Waiman Long <longman@redhat.com>
---
 security/keys/internal.h | 14 ++++++++++++++
 security/keys/keyctl.c   | 10 +++++-----
 2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/security/keys/internal.h b/security/keys/internal.h
index ba3e2da14cef..855b11eb73ee 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -16,6 +16,8 @@
 #include <linux/keyctl.h>
 #include <linux/refcount.h>
 #include <linux/compat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
 
 struct iovec;
 
@@ -349,4 +351,16 @@ static inline void key_check(const struct key *key)
 
 #endif
 
+/*
+ * Helper function to clear and free a kvmalloc'ed memory object.
+ */
+static inline void __kvzfree(const void *addr, size_t len)
+{
+	if (is_vmalloc_addr(addr)) {
+		memset((void *)addr, 0, len);
+		vfree(addr);
+	} else {
+		kzfree(addr);
+	}
+}
Since this takes the length as a parameter, it can be simplified to:

static inline void __kvzfree(const void *addr, size_t len)
{
	if (addr) {
		memset((void *)addr, 0, len);
		kvfree(addr);
	}
}
Yes, that will work too.
quoted
 			if (!tmpbuf || unlikely(ret > tmpbuflen)) {
 				if (unlikely(tmpbuf))
-					kzfree(tmpbuf);
+					__kvzfree(tmpbuf, tmpbuflen);
Both kzfree() and __kvzfree() handle a NULL pointer, so there's no need for the
NULL check first.
I would like to keep this one because of the unlikely annotation.

quoted
@@ -920,7 +920,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 				ret = -EFAULT;
 		}
 		if (tmpbuf)
-			kzfree(tmpbuf);
+			__kvzfree(tmpbuf, tmpbuflen);
Likewise here.  No need for the NULL check.
Yes, that tmpbuf check is not really necessary, but it doesn't harm either.

My plan is to send out a mm patch to officially add the kvzfree()
function to mm/util.c. I will remove the tmpbuf check at that time if
you don't mind.

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