On 4/7/20 4:01 PM, Waiman Long wrote: > For kvmalloc'ed data object that contains sensitive information like > cryptographic key, we need to make sure that the buffer is always > cleared before freeing it. Using memset() alone for buffer clearing may > not provide certainty as the compiler may compile it away. To be sure, > the special memzero_explicit() has to be used. > > This patch introduces a new kvfree_sensitive() for freeing those > sensitive data objects allocated by kvmalloc(). The relevnat places > where kvfree_sensitive() can be used are modified to use it. > > Fixes: 4f0882491a14 ("KEYS: Avoid false positive ENOMEM error on key read") > Suggested-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> > Signed-off-by: Waiman Long <longman@xxxxxxxxxx> > --- > include/linux/mm.h | 1 + > mm/util.c | 18 ++++++++++++++++++ > security/keys/internal.h | 11 ----------- > security/keys/keyctl.c | 16 +++++----------- > 4 files changed, 24 insertions(+), 22 deletions(-) > > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 7dd5c4ccbf85..9b3130b20f42 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -757,6 +757,7 @@ static inline void *kvcalloc(size_t n, size_t size, gfp_t flags) > } > > extern void kvfree(const void *addr); > +extern void kvfree_sensitive(const void *addr, size_t len); > > static inline int compound_mapcount(struct page *page) > { > diff --git a/mm/util.c b/mm/util.c > index 988d11e6c17c..01e210766f3d 100644 > --- a/mm/util.c > +++ b/mm/util.c > @@ -604,6 +604,24 @@ void kvfree(const void *addr) > } > EXPORT_SYMBOL(kvfree); > > +/** > + * kvfree_sensitive - free a data object containing sensitive information > + * @addr - address of the data object to be freed > + * @len - length of the data object > + * > + * Use the special memzero_explicit() function to clear the content of a > + * kvmalloc'ed object containing sensitive data to make sure that the > + * compiler won't optimize out the data clearing. > + */ > +void kvfree_sensitive(const void *addr, size_t len) > +{ > + if (likely(!ZERO_OR_NULL_PTR(addr))) { > + memzero_explicit((void *)addr, len); > + kvfree(addr); > + } > +} > +EXPORT_SYMBOL(kvfree_sensitive); > + > static inline void *__page_rmapping(struct page *page) > { > unsigned long mapping; > diff --git a/security/keys/internal.h b/security/keys/internal.h > index 6d0ca48ae9a5..153d35c20d3d 100644 > --- a/security/keys/internal.h > +++ b/security/keys/internal.h > @@ -350,15 +350,4 @@ static inline void key_check(const struct key *key) > #define key_check(key) do {} while(0) > > #endif > - > -/* > - * Helper function to clear and free a kvmalloc'ed memory object. > - */ > -static inline void __kvzfree(const void *addr, size_t len) > -{ > - if (addr) { > - memset((void *)addr, 0, len); > - kvfree(addr); > - } > -} > #endif /* _INTERNAL_H */ > diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c > index 5e01192e222a..edde63a63007 100644 > --- a/security/keys/keyctl.c > +++ b/security/keys/keyctl.c > @@ -142,10 +142,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, > > key_ref_put(keyring_ref); > error3: > - if (payload) { > - memzero_explicit(payload, plen); > - kvfree(payload); > - } > + kvfree_sensitive(payload, plen); > error2: > kfree(description); > error: > @@ -360,7 +357,7 @@ long keyctl_update_key(key_serial_t id, > > key_ref_put(key_ref); > error2: > - __kvzfree(payload, plen); > + kvfree_sensitive(payload, plen); > error: > return ret; > } > @@ -914,7 +911,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) > */ > if (ret > key_data_len) { > if (unlikely(key_data)) > - __kvzfree(key_data, key_data_len); > + kvfree_sensitive(key_data, key_data_len); > key_data_len = ret; > continue; /* Allocate buffer */ > } > @@ -923,7 +920,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) > ret = -EFAULT; > break; > } > - __kvzfree(key_data, key_data_len); > + kvfree_sensitive(key_data, key_data_len); > > key_put_out: > key_put(key); > @@ -1225,10 +1222,7 @@ long keyctl_instantiate_key_common(key_serial_t id, > keyctl_change_reqkey_auth(NULL); > > error2: > - if (payload) { > - memzero_explicit(payload, plen); > - kvfree(payload); > - } > + kvfree_sensitive(payload, plen); > error: > return ret; > } Sorry, wrong one. Please ignore it. -Longman