2020-08-20 07:55:55

by Martijn Coenen

[permalink] [raw]
Subject: [PATCH] binder: print warnings when detecting oneway spamming.

The most common cause of the binder transaction buffer filling up is a
client rapidly firing oneway transactions into a process, before it has
a chance to handle them. Yet the root cause of this is often hard to
debug, because either the system or the app will stop, and by that time
binder debug information we dump in bugreports is no longer relevant.

This change warns as soon as a process dips below 80% of its oneway
space (less than 100kB available in the configuration), when any one
process is responsible for either more than 50 transactions, or more
than 50% of the oneway space.

Signed-off-by: Martijn Coenen <[email protected]>
---
drivers/android/binder.c | 2 +-
drivers/android/binder_alloc.c | 49 +++++++++++++++++++++++++++++++---
drivers/android/binder_alloc.h | 5 +++-
3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index f936530a19b0..946332bc871a 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3136,7 +3136,7 @@ static void binder_transaction(struct binder_proc *proc,

t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
- !reply && (t->flags & TF_ONE_WAY));
+ !reply && (t->flags & TF_ONE_WAY), current->tgid);
if (IS_ERR(t->buffer)) {
/*
* -ESRCH indicates VMA cleared. The target is dying.
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 69609696a843..76e8e633dbd4 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -338,12 +338,48 @@ static inline struct vm_area_struct *binder_alloc_get_vma(
return vma;
}

+static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid)
+{
+ /*
+ * Find the amount and size of buffers allocated by the current caller;
+ * The idea is that once we cross the threshold, whoever is responsible
+ * for the low async space is likely to try to send another async txn,
+ * and at some point we'll catch them in the act. This is more efficient
+ * than keeping a map per pid.
+ */
+ struct rb_node *n = alloc->free_buffers.rb_node;
+ struct binder_buffer *buffer;
+ size_t buffer_size;
+ size_t total_alloc_size = 0;
+ size_t num_buffers = 0;
+
+ for (n = rb_first(&alloc->allocated_buffers); n != NULL;
+ n = rb_next(n)) {
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+ if (buffer->pid != pid)
+ continue;
+ if (!buffer->async_transaction)
+ continue;
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+ total_alloc_size += buffer_size;
+ num_buffers++;
+ }
+
+ // Warn if this pid has more than 50% of async space, or more than 50 txns
+ if (num_buffers > 50 || total_alloc_size > alloc->buffer_size / 4) {
+ binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
+ "%d: pid %d spamming oneway? %zd buffers allocated for a total size of %zd\n",
+ alloc->pid, pid, num_buffers, total_alloc_size);
+ }
+}
+
static struct binder_buffer *binder_alloc_new_buf_locked(
struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
- int is_async)
+ int is_async,
+ int pid)
{
struct rb_node *n = alloc->free_buffers.rb_node;
struct binder_buffer *buffer;
@@ -486,11 +522,16 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
buffer->offsets_size = offsets_size;
buffer->async_transaction = is_async;
buffer->extra_buffers_size = extra_buffers_size;
+ buffer->pid = pid;
if (is_async) {
alloc->free_async_space -= size + sizeof(struct binder_buffer);
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
"%d: binder_alloc_buf size %zd async free %zd\n",
alloc->pid, size, alloc->free_async_space);
+ if (alloc->free_async_space < alloc->buffer_size / 10) {
+ // Start detecting spammers once we reach 80% of async space used
+ debug_low_async_space_locked(alloc, pid);
+ }
}
return buffer;

@@ -508,6 +549,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
* @offsets_size: user specified buffer offset
* @extra_buffers_size: size of extra space for meta-data (eg, security context)
* @is_async: buffer for async transaction
+ * @pid: pid to attribute allocation to (used for debugging)
*
* Allocate a new buffer given the requested sizes. Returns
* the kernel version of the buffer pointer. The size allocated
@@ -520,13 +562,14 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
- int is_async)
+ int is_async,
+ int pid)
{
struct binder_buffer *buffer;

mutex_lock(&alloc->mutex);
buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size,
- extra_buffers_size, is_async);
+ extra_buffers_size, is_async, pid);
mutex_unlock(&alloc->mutex);
return buffer;
}
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index db9c1b984695..55d8b4106766 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -32,6 +32,7 @@ struct binder_transaction;
* @offsets_size: size of array of offsets
* @extra_buffers_size: size of space for other objects (like sg lists)
* @user_data: user pointer to base of buffer space
+ * @pid: pid to attribute the buffer to (caller)
*
* Bookkeeping structure for binder transaction buffers
*/
@@ -51,6 +52,7 @@ struct binder_buffer {
size_t offsets_size;
size_t extra_buffers_size;
void __user *user_data;
+ int pid;
};

/**
@@ -117,7 +119,8 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
- int is_async);
+ int is_async,
+ int pid);
extern void binder_alloc_init(struct binder_alloc *alloc);
extern int binder_alloc_shrinker_init(void);
extern void binder_alloc_vma_close(struct binder_alloc *alloc);
--
2.28.0.220.ged08abb693-goog


2020-08-20 10:44:09

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] binder: print warnings when detecting oneway spamming.

Hi Martijn,

I love your patch! Yet something to improve:

[auto build test ERROR on staging/staging-testing]
[also build test ERROR on v5.9-rc1 next-20200820]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Martijn-Coenen/binder-print-warnings-when-detecting-oneway-spamming/20200820-155358
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git bc752d2f345bf55d71b3422a6a24890ea03168dc
config: s390-randconfig-r002-20200818 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 4deda57106f7c9b982a49cb907c33e3966c8de7f)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install s390 cross compiling tool for clang build
# apt-get install binutils-s390x-linux-gnu
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=s390

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

>> drivers/android/binder_alloc_selftest.c:122:61: error: too few arguments to function call, expected 6, have 5
buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
~~~~~~~~~~~~~~~~~~~~ ^
drivers/android/binder_alloc.h:118:30: note: 'binder_alloc_new_buf' declared here
extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
^
1 error generated.

# https://github.com/0day-ci/linux/commit/9d0b269f4468d6793f6fd76a410fdde39dbf6ac2
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Martijn-Coenen/binder-print-warnings-when-detecting-oneway-spamming/20200820-155358
git checkout 9d0b269f4468d6793f6fd76a410fdde39dbf6ac2
vim +122 drivers/android/binder_alloc_selftest.c

4175e2b46fd4b9 Sherry Yang 2017-08-23 114
4175e2b46fd4b9 Sherry Yang 2017-08-23 115 static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
4175e2b46fd4b9 Sherry Yang 2017-08-23 116 struct binder_buffer *buffers[],
4175e2b46fd4b9 Sherry Yang 2017-08-23 117 size_t *sizes, int *seq)
4175e2b46fd4b9 Sherry Yang 2017-08-23 118 {
4175e2b46fd4b9 Sherry Yang 2017-08-23 119 int i;
4175e2b46fd4b9 Sherry Yang 2017-08-23 120
4175e2b46fd4b9 Sherry Yang 2017-08-23 121 for (i = 0; i < BUFFER_NUM; i++) {
4175e2b46fd4b9 Sherry Yang 2017-08-23 @122 buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
4175e2b46fd4b9 Sherry Yang 2017-08-23 123 if (IS_ERR(buffers[i]) ||
4175e2b46fd4b9 Sherry Yang 2017-08-23 124 !check_buffer_pages_allocated(alloc, buffers[i],
4175e2b46fd4b9 Sherry Yang 2017-08-23 125 sizes[i])) {
4175e2b46fd4b9 Sherry Yang 2017-08-23 126 pr_err_size_seq(sizes, seq);
4175e2b46fd4b9 Sherry Yang 2017-08-23 127 binder_selftest_failures++;
4175e2b46fd4b9 Sherry Yang 2017-08-23 128 }
4175e2b46fd4b9 Sherry Yang 2017-08-23 129 }
4175e2b46fd4b9 Sherry Yang 2017-08-23 130 }
4175e2b46fd4b9 Sherry Yang 2017-08-23 131

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (3.51 kB)
.config.gz (19.50 kB)
Download all attachments

2020-08-20 11:50:06

by Martijn Coenen

[permalink] [raw]
Subject: Re: [PATCH] binder: print warnings when detecting oneway spamming.

On Thu, Aug 20, 2020 at 12:41 PM kernel test robot <[email protected]> wrote:
>
> Hi Martijn,
>
> I love your patch! Yet something to improve:
>
> [auto build test ERROR on staging/staging-testing]
> [also build test ERROR on v5.9-rc1 next-20200820]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
>
> url: https://github.com/0day-ci/linux/commits/Martijn-Coenen/binder-print-warnings-when-detecting-oneway-spamming/20200820-155358
> base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git bc752d2f345bf55d71b3422a6a24890ea03168dc
> config: s390-randconfig-r002-20200818 (attached as .config)
> compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 4deda57106f7c9b982a49cb907c33e3966c8de7f)
> reproduce (this is a W=1 build):
> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # install s390 cross compiling tool for clang build
> # apt-get install binutils-s390x-linux-gnu
> # save the attached .config to linux build tree
> COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=s390
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <[email protected]>
>
> All errors (new ones prefixed by >>):
>
> >> drivers/android/binder_alloc_selftest.c:122:61: error: too few arguments to function call, expected 6, have 5
> buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);

missed this call-site, will send v2.

Martijn
> ~~~~~~~~~~~~~~~~~~~~ ^
> drivers/android/binder_alloc.h:118:30: note: 'binder_alloc_new_buf' declared here
> extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
> ^
> 1 error generated.
>
> # https://github.com/0day-ci/linux/commit/9d0b269f4468d6793f6fd76a410fdde39dbf6ac2
> git remote add linux-review https://github.com/0day-ci/linux
> git fetch --no-tags linux-review Martijn-Coenen/binder-print-warnings-when-detecting-oneway-spamming/20200820-155358
> git checkout 9d0b269f4468d6793f6fd76a410fdde39dbf6ac2
> vim +122 drivers/android/binder_alloc_selftest.c
>
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 114
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 115 static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 116 struct binder_buffer *buffers[],
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 117 size_t *sizes, int *seq)
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 118 {
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 119 int i;
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 120
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 121 for (i = 0; i < BUFFER_NUM; i++) {
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 @122 buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 123 if (IS_ERR(buffers[i]) ||
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 124 !check_buffer_pages_allocated(alloc, buffers[i],
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 125 sizes[i])) {
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 126 pr_err_size_seq(sizes, seq);
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 127 binder_selftest_failures++;
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 128 }
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 129 }
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 130 }
> 4175e2b46fd4b9 Sherry Yang 2017-08-23 131
>
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/[email protected]