Re: [PATCH 1/7] binder: create userspace-to-binder-buffer copy function

2019-01-29 Thread Dan Carpenter
On Tue, Jan 29, 2019 at 04:32:09PM -0800, Todd Kjos wrote:
> On Tue, Jan 29, 2019 at 12:12 AM Dan Carpenter  
> wrote:
> >
> > On Mon, Jan 28, 2019 at 04:49:28PM -0800, Todd Kjos wrote:
> > > +/**
> > > + * binder_alloc_copy_user_to_buffer() - copy src user to tgt user
> > > + * @alloc: binder_alloc for this proc
> > > + * @buffer: binder buffer to be accessed
> > > + * @buffer_offset: offset into @buffer data
> > > + * @from: userspace pointer to source buffer
> > > + * @bytes: bytes to copy
> > > + *
> > > + * Copy bytes from source userspace to target buffer.
> > > + *
> > > + * Return: bytes remaining to be copied
> > > + */
> > > +unsigned long
> > > +binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
> > > +  struct binder_buffer *buffer,
> > > +  binder_size_t buffer_offset,
> > > +  const void __user *from,
> > > +  size_t bytes)
> > > +{
> > > + if (!check_buffer(alloc, buffer, buffer_offset, bytes))
> > > + return bytes;
> > > +
> > > + while (bytes) {
> > > + unsigned long size;
> > > + unsigned long ret;
> > > + struct page *page;
> > > + pgoff_t pgoff;
> > > + void *kptr;
> > > +
> > > + page = binder_alloc_get_page(alloc, buffer,
> > > +  buffer_offset, );
> > > + size = min(bytes, (size_t)(PAGE_SIZE - pgoff));
> >
> > This code has so much more casting than necessary.  To me casting says
> > that we haven't got the types correct or something.  I've just pulled
> > this function out as an example really, but none of the casts here are
> > required...  This could just be:
> >
> > size = min(bytes, PAGE_SIZE - pgoff);
> 
> Dan,
> 
> Thanks for the feedback.
> 
> The one above: "size = min(bytes, PAGE_SIZE - pgoff);", results in
> 32-bit compile warnings:
> 
> ./include/linux/kernel.h:846:29: warning: comparison of distinct
> pointer types lacks a cast
>(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
> [...]
> drivers/android/binder_alloc.c:1157:10: note: in expansion of macro ‘min’
>size = min(bytes, PAGE_SIZE - pgoff);
> 
> so, I took your suggestion:
> 
>   size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
> 
> >
> > Btw, if you really need to do a cast inside a min() (you don't in this
> > cast) then use min_t().
> >
> > > + kptr = (void *)((uintptr_t)kmap(page) + pgoff);
> >
> > This would be a lot cleaner as:
> >
> > kptr = kmap(page) + pgoff;
> 
> It definitely is cleaner, but the clean version is doing arithmetic on
> a void pointer which is generally not considered good practice (but is
> supported by gcc). Is this acceptable in the kernel? I don't see any
> statement on it in Documentation/process/coding-style.rst.

Yeah, it's a GCCism but to me it seems so nice.  We do it all the time.

We'd like to get Clang to compile the kernel, but we've done very little
work to make that happen.  Removing variable length arrays was really
done for other reasons...

regards,
dan carpenter

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH 1/7] binder: create userspace-to-binder-buffer copy function

2019-01-29 Thread Todd Kjos
On Tue, Jan 29, 2019 at 12:12 AM Dan Carpenter  wrote:
>
> On Mon, Jan 28, 2019 at 04:49:28PM -0800, Todd Kjos wrote:
> > +/**
> > + * binder_alloc_copy_user_to_buffer() - copy src user to tgt user
> > + * @alloc: binder_alloc for this proc
> > + * @buffer: binder buffer to be accessed
> > + * @buffer_offset: offset into @buffer data
> > + * @from: userspace pointer to source buffer
> > + * @bytes: bytes to copy
> > + *
> > + * Copy bytes from source userspace to target buffer.
> > + *
> > + * Return: bytes remaining to be copied
> > + */
> > +unsigned long
> > +binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
> > +  struct binder_buffer *buffer,
> > +  binder_size_t buffer_offset,
> > +  const void __user *from,
> > +  size_t bytes)
> > +{
> > + if (!check_buffer(alloc, buffer, buffer_offset, bytes))
> > + return bytes;
> > +
> > + while (bytes) {
> > + unsigned long size;
> > + unsigned long ret;
> > + struct page *page;
> > + pgoff_t pgoff;
> > + void *kptr;
> > +
> > + page = binder_alloc_get_page(alloc, buffer,
> > +  buffer_offset, );
> > + size = min(bytes, (size_t)(PAGE_SIZE - pgoff));
>
> This code has so much more casting than necessary.  To me casting says
> that we haven't got the types correct or something.  I've just pulled
> this function out as an example really, but none of the casts here are
> required...  This could just be:
>
> size = min(bytes, PAGE_SIZE - pgoff);

Dan,

Thanks for the feedback.

The one above: "size = min(bytes, PAGE_SIZE - pgoff);", results in
32-bit compile warnings:

./include/linux/kernel.h:846:29: warning: comparison of distinct
pointer types lacks a cast
   (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
[...]
drivers/android/binder_alloc.c:1157:10: note: in expansion of macro ‘min’
   size = min(bytes, PAGE_SIZE - pgoff);

so, I took your suggestion:

  size = min_t(size_t, bytes, PAGE_SIZE - pgoff);

>
> Btw, if you really need to do a cast inside a min() (you don't in this
> cast) then use min_t().
>
> > + kptr = (void *)((uintptr_t)kmap(page) + pgoff);
>
> This would be a lot cleaner as:
>
> kptr = kmap(page) + pgoff;

It definitely is cleaner, but the clean version is doing arithmetic on
a void pointer which is generally not considered good practice (but is
supported by gcc). Is this acceptable in the kernel? I don't see any
statement on it in Documentation/process/coding-style.rst.

If so, I agree a bunch of these casts can go as you suggest.

-Todd

[...]

>
> regards,
> dan carpenter
>
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH 1/7] binder: create userspace-to-binder-buffer copy function

2019-01-29 Thread Dan Carpenter
On Mon, Jan 28, 2019 at 04:49:28PM -0800, Todd Kjos wrote:
> +/**
> + * binder_alloc_copy_user_to_buffer() - copy src user to tgt user
> + * @alloc: binder_alloc for this proc
> + * @buffer: binder buffer to be accessed
> + * @buffer_offset: offset into @buffer data
> + * @from: userspace pointer to source buffer
> + * @bytes: bytes to copy
> + *
> + * Copy bytes from source userspace to target buffer.
> + *
> + * Return: bytes remaining to be copied
> + */
> +unsigned long
> +binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
> +  struct binder_buffer *buffer,
> +  binder_size_t buffer_offset,
> +  const void __user *from,
> +  size_t bytes)
> +{
> + if (!check_buffer(alloc, buffer, buffer_offset, bytes))
> + return bytes;
> +
> + while (bytes) {
> + unsigned long size;
> + unsigned long ret;
> + struct page *page;
> + pgoff_t pgoff;
> + void *kptr;
> +
> + page = binder_alloc_get_page(alloc, buffer,
> +  buffer_offset, );
> + size = min(bytes, (size_t)(PAGE_SIZE - pgoff));

This code has so much more casting than necessary.  To me casting says
that we haven't got the types correct or something.  I've just pulled
this function out as an example really, but none of the casts here are
required...  This could just be:

size = min(bytes, PAGE_SIZE - pgoff);

Btw, if you really need to do a cast inside a min() (you don't in this
cast) then use min_t().

> + kptr = (void *)((uintptr_t)kmap(page) + pgoff);

This would be a lot cleaner as:

kptr = kmap(page) + pgoff;

> + ret = copy_from_user(kptr, (const void __user *)(uintptr_t)from,
> +  size);

Remove the cast:

ret = copy_from_user(kptr, from, size);


> + kunmap(page);
> + if (ret)
> + return bytes - size + ret;
> + bytes -= size;
> + from = (void __user *)(uintptr_t)from + size;

Remove the cast:

from += size;

> + buffer_offset += size;
> + }
> + return 0;
> +}

regards,
dan carpenter

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 1/7] binder: create userspace-to-binder-buffer copy function

2019-01-28 Thread Todd Kjos
The binder driver uses a vm_area to map the per-process
binder buffer space. For 32-bit android devices, this is
now taking too much vmalloc space. This patch removes
the use of vm_area when copying the transaction data
from the sender to the buffer space. Instead of using
copy_from_user() for multi-page copies, it now uses
binder_alloc_copy_user_to_buffer() which uses kmap()
and kunmap() to map each page, and uses copy_from_user()
for copying to that page.

Signed-off-by: Todd Kjos 
---
 drivers/android/binder.c   |  29 +++--
 drivers/android/binder_alloc.c | 114 +
 drivers/android/binder_alloc.h |   8 +++
 3 files changed, 144 insertions(+), 7 deletions(-)

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 5f6ef5e63b91e..ab0b3eec363bc 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3078,8 +3078,12 @@ static void binder_transaction(struct binder_proc *proc,
  ALIGN(tr->data_size, sizeof(void *)));
offp = off_start;
 
-   if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
-  tr->data.ptr.buffer, tr->data_size)) {
+   if (binder_alloc_copy_user_to_buffer(
+   _proc->alloc,
+   t->buffer, 0,
+   (const void __user *)
+   (uintptr_t)tr->data.ptr.buffer,
+   tr->data_size)) {
binder_user_error("%d:%d got transaction with invalid data 
ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
@@ -3087,8 +3091,13 @@ static void binder_transaction(struct binder_proc *proc,
return_error_line = __LINE__;
goto err_copy_data_failed;
}
-   if (copy_from_user(offp, (const void __user *)(uintptr_t)
-  tr->data.ptr.offsets, tr->offsets_size)) {
+   if (binder_alloc_copy_user_to_buffer(
+   _proc->alloc,
+   t->buffer,
+   ALIGN(tr->data_size, sizeof(void *)),
+   (const void __user *)
+   (uintptr_t)tr->data.ptr.offsets,
+   tr->offsets_size)) {
binder_user_error("%d:%d got transaction with invalid offsets 
ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
@@ -3217,6 +3226,8 @@ static void binder_transaction(struct binder_proc *proc,
struct binder_buffer_object *bp =
to_binder_buffer_object(hdr);
size_t buf_left = sg_buf_end - sg_bufp;
+   binder_size_t sg_buf_offset = (uintptr_t)sg_bufp -
+   (uintptr_t)t->buffer->data;
 
if (bp->length > buf_left) {
binder_user_error("%d:%d got transaction with 
too large buffer\n",
@@ -3226,9 +3237,13 @@ static void binder_transaction(struct binder_proc *proc,
return_error_line = __LINE__;
goto err_bad_offset;
}
-   if (copy_from_user(sg_bufp,
-  (const void __user *)(uintptr_t)
-  bp->buffer, bp->length)) {
+   if (binder_alloc_copy_user_to_buffer(
+   _proc->alloc,
+   t->buffer,
+   sg_buf_offset,
+   (const void __user *)
+   (uintptr_t)bp->buffer,
+   bp->length)) {
binder_user_error("%d:%d got transaction with 
invalid offsets ptr\n",
  proc->pid, thread->pid);
return_error_param = -EFAULT;
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 022cd80e80cc3..255fa71911e5e 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -29,6 +29,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include "binder_alloc.h"
 #include "binder_trace.h"
 
@@ -1053,3 +1055,115 @@ int binder_alloc_shrinker_init(void)
}
return ret;
 }
+
+/**
+ * check_buffer() - verify that buffer/offset is safe to access
+ * @alloc: binder_alloc for this proc
+ * @buffer: binder buffer to be accessed
+ * @offset: offset into @buffer data
+ * @bytes: bytes to access from offset
+ *
+ * Check that the @offset/@bytes are within the size of the given
+ *