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

Configure Feed

Select the types of activity you want to include in your feed.

apparmor: document the buffer hold, add an overflow guard

The buffer hold is a measure of contention, but it is tracked per cpu
where the lock is a globabl resource. On some systems (eg. real time)
there is no guarantee that the code will be on the same cpu pre, and
post spinlock acquisition, nor that the buffer will be put back to
the same percpu cache when we are done with it.

Because of this the hold value can move asynchronous to the buffers on
the cache, meaning it is possible to underflow, and potentially in really
pathelogical cases overflow.

Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>

+26 -2
+26 -2
security/apparmor/lsm.c
··· 2125 2125 return 0; 2126 2126 } 2127 2127 2128 + /* arbitrary cap on how long to hold buffer because contention was 2129 + * encountered before trying to put it back into the global pool 2130 + */ 2131 + #define MAX_HOLD_COUNT 64 2132 + 2133 + /* the hold count is a heuristic for lock contention, and can be 2134 + * incremented async to actual buffer alloc/free. Because buffers 2135 + * may be put back onto a percpu cache different than the ->hold was 2136 + * added to the counts can be out of sync. Guard against underflow 2137 + * and overflow 2138 + */ 2139 + static void cache_hold_inc(unsigned int *hold) 2140 + { 2141 + if (*hold > MAX_HOLD_COUNT) 2142 + (*hold)++; 2143 + } 2144 + 2128 2145 char *aa_get_buffer(bool in_atomic) 2129 2146 { 2130 2147 union aa_buffer *aa_buf; ··· 2160 2143 put_cpu_ptr(&aa_local_buffers); 2161 2144 return &aa_buf->buffer[0]; 2162 2145 } 2146 + /* exit percpu as spinlocks may sleep on realtime kernels */ 2163 2147 put_cpu_ptr(&aa_local_buffers); 2164 2148 2165 2149 if (!spin_trylock(&aa_buffers_lock)) { 2150 + /* had contention on lock so increase hold count. Doesn't 2151 + * really matter if recorded before or after the spin lock 2152 + * as there is no way to guarantee the buffer will be put 2153 + * back on the same percpu cache. Instead rely on holds 2154 + * roughly averaging out over time. 2155 + */ 2166 2156 cache = get_cpu_ptr(&aa_local_buffers); 2167 - cache->hold += 1; 2157 + cache_hold_inc(&cache->hold); 2168 2158 put_cpu_ptr(&aa_local_buffers); 2169 2159 spin_lock(&aa_buffers_lock); 2170 2160 } else { ··· 2237 2213 } 2238 2214 /* contention on global list, fallback to percpu */ 2239 2215 cache = get_cpu_ptr(&aa_local_buffers); 2240 - cache->hold += 1; 2216 + cache_hold_inc(&cache->hold); 2241 2217 } 2242 2218 2243 2219 /* cache in percpu list */