Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm, slub: make remaining slub_debug related attributes read-only

SLUB_DEBUG creates several files under /sys/kernel/slab/<cache>/ that can
be read to check if the respective debugging options are enabled for given
cache. Some options, namely sanity_checks, trace, and failslab can be
also enabled and disabled at runtime by writing into the files.

The runtime toggling is racy. Some options disable __CMPXCHG_DOUBLE when
enabled, which means that in case of concurrent allocations, some can
still use __CMPXCHG_DOUBLE and some not, leading to potential corruption.
The s->flags field is also not updated or checked atomically. The
simplest solution is to remove the runtime toggling. The extended
slub_debug boot parameter syntax introduced by earlier patch should allow
to fine-tune the debugging configuration during boot with same
granularity.

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Acked-by: Roman Gushchin <guro@fb.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Jann Horn <jannh@google.com>
Cc: Vijayanand Jitta <vjitta@codeaurora.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Pekka Enberg <penberg@kernel.org>
Link: http://lkml.kernel.org/r/20200610163135.17364-5-vbabka@suse.cz
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Vlastimil Babka and committed by
Linus Torvalds
060807f8 32a6f409

+5 -64
+2 -5
Documentation/vm/slub.rst
··· 116 116 T trace 117 117 A failslab 118 118 119 - The sanity_checks, trace and failslab files are writable, so writing 1 or 0 120 - will enable or disable the option at runtime. The writes to trace and failslab 121 - may return -EINVAL if the cache is subject to slab merging. Careful with 122 - tracing: It may spew out lots of information and never stop if used on the 123 - wrong slab. 119 + Careful with tracing: It may spew out lots of information and never stop if 120 + used on the wrong slab. 124 121 125 122 Slab merging 126 123 ============
+3 -59
mm/slub.c
··· 5040 5040 return x + sprintf(buf + x, "\n"); 5041 5041 } 5042 5042 5043 - #ifdef CONFIG_SLUB_DEBUG 5044 - static int any_slab_objects(struct kmem_cache *s) 5045 - { 5046 - int node; 5047 - struct kmem_cache_node *n; 5048 - 5049 - for_each_kmem_cache_node(s, node, n) 5050 - if (atomic_long_read(&n->total_objects)) 5051 - return 1; 5052 - 5053 - return 0; 5054 - } 5055 - #endif 5056 - 5057 5043 #define to_slab_attr(n) container_of(n, struct slab_attribute, attr) 5058 5044 #define to_slab(n) container_of(n, struct kmem_cache, kobj) 5059 5045 ··· 5261 5275 { 5262 5276 return sprintf(buf, "%d\n", !!(s->flags & SLAB_CONSISTENCY_CHECKS)); 5263 5277 } 5264 - 5265 - static ssize_t sanity_checks_store(struct kmem_cache *s, 5266 - const char *buf, size_t length) 5267 - { 5268 - s->flags &= ~SLAB_CONSISTENCY_CHECKS; 5269 - if (buf[0] == '1') { 5270 - s->flags &= ~__CMPXCHG_DOUBLE; 5271 - s->flags |= SLAB_CONSISTENCY_CHECKS; 5272 - } 5273 - return length; 5274 - } 5275 - SLAB_ATTR(sanity_checks); 5278 + SLAB_ATTR_RO(sanity_checks); 5276 5279 5277 5280 static ssize_t trace_show(struct kmem_cache *s, char *buf) 5278 5281 { 5279 5282 return sprintf(buf, "%d\n", !!(s->flags & SLAB_TRACE)); 5280 5283 } 5281 - 5282 - static ssize_t trace_store(struct kmem_cache *s, const char *buf, 5283 - size_t length) 5284 - { 5285 - /* 5286 - * Tracing a merged cache is going to give confusing results 5287 - * as well as cause other issues like converting a mergeable 5288 - * cache into an umergeable one. 5289 - */ 5290 - if (s->refcount > 1) 5291 - return -EINVAL; 5292 - 5293 - s->flags &= ~SLAB_TRACE; 5294 - if (buf[0] == '1') { 5295 - s->flags &= ~__CMPXCHG_DOUBLE; 5296 - s->flags |= SLAB_TRACE; 5297 - } 5298 - return length; 5299 - } 5300 - SLAB_ATTR(trace); 5284 + SLAB_ATTR_RO(trace); 5301 5285 5302 5286 static ssize_t red_zone_show(struct kmem_cache *s, char *buf) 5303 5287 { ··· 5331 5375 { 5332 5376 return sprintf(buf, "%d\n", !!(s->flags & SLAB_FAILSLAB)); 5333 5377 } 5334 - 5335 - static ssize_t failslab_store(struct kmem_cache *s, const char *buf, 5336 - size_t length) 5337 - { 5338 - if (s->refcount > 1) 5339 - return -EINVAL; 5340 - 5341 - s->flags &= ~SLAB_FAILSLAB; 5342 - if (buf[0] == '1') 5343 - s->flags |= SLAB_FAILSLAB; 5344 - return length; 5345 - } 5346 - SLAB_ATTR(failslab); 5378 + SLAB_ATTR_RO(failslab); 5347 5379 #endif 5348 5380 5349 5381 static ssize_t shrink_show(struct kmem_cache *s, char *buf)