Re: [PATCH 1/2] apparmor: Use a memory pool instead per-CPU caches
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: 2019-05-02 13:47:37
On 2019-05-02 22:17:35 [+0900], Tetsuo Handa wrote:
There is 'The "too small to fail" memory-allocation rule' ( https://lwn.net/Articles/627419/ ) where GFP_KERNEL allocation for size <= 32768 bytes never fails unless current thread was killed by the OOM killer. This means that kmalloc() in +char *aa_get_buffer(void) +{ + union aa_buffer *aa_buf; + +try_again: + spin_lock(&aa_buffers_lock); + if (!list_empty(&aa_global_buffers)) { + aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer, + list); + list_del(&aa_buf->list); + spin_unlock(&aa_buffers_lock); + return &aa_buf->buffer[0]; + } + spin_unlock(&aa_buffers_lock); + + aa_buf = kmalloc(aa_g_path_max, GFP_KERNEL); + if (WARN_ON_ONCE(!aa_buf)) + goto try_again; + return &aa_buf->buffer[0]; +} can't return NULL unless current thread was killed by the OOM killer if aa_g_path_max <= 32768. On the other hand, if aa_g_path_max > 32768, this allocation can easily fail, and retrying forever is very bad.
as I pointed out in the other email, it shouldn't retry forever because we should have something in the pool which will be returned.
If current thread was killed by the OOM killer, current thread should be able to bail out without retrying. If allocation can never succeed (e.g. aa_g_path_max == 1073741824 was specified), we must bail out.
okay. That is obviously too much and we would loop, indeed.
By the way, did you really test your patch?
I booted Debian on a 112 core which has apparmor enabled and debian ships a few profiles. And then I used the box for a while.
quoted
@@ -1399,6 +1404,7 @@ static int param_set_aauint(const char *val, const struct kernel_param *kp) return -EPERM; error = param_set_uint(val, kp); + aa_g_path_max = min_t(uint32_t, aa_g_path_max, sizeof(union aa_buffer));I think that this will guarantee that aa_g_path_max <= sizeof(struct list_head) which is too small to succeed. :-(
Ach right, this should have been max instead of min. Btw: are there any sane upper/lower limits while at it?
quoted
pr_info("AppArmor: buffer size set to %d bytes\n", aa_g_path_max); return error;
Sebastian