diff mbox series

[1/1] selinux-testsuite: Update binder test applications

Message ID 20190403122611.6543-1-richard_c_haines@btinternet.com (mailing list archive)
State Accepted
Headers show
Series [1/1] selinux-testsuite: Update binder test applications | expand

Commit Message

Richard Haines April 3, 2019, 12:26 p.m. UTC
Replace binder_test.c with separate manager, client and service provider.
This works in the same way as a service provider/client interacts
with a service manager in the Android world. It passes the service
providers binder file descriptor to the client for the impersonate
permission check.

Also added tests for Dynamically Allocated Binder Devices and passing
the sender SELinux security context on binder transactions.

Note that the tests require a minimum kernel of 4.16, else some tests may
fail. To run successfully the "binder: Add thread->process_todo flag"
patch may be required that is available from:
https://lore.kernel.org/patchwork/patch/851324/
This patch has been backported to some earlier kernels.

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
---
 defconfig                       |   3 +
 policy/test_binder.te           | 176 ++++----
 tests/binder/.gitignore         |   6 +-
 tests/binder/Makefile           |  13 +-
 tests/binder/binder_common.c    | 155 +++++++
 tests/binder/binder_common.h    |  37 ++
 tests/binder/check_binder.c     |  27 +-
 tests/binder/check_binderfs.c   |  53 +++
 tests/binder/client.c           | 450 ++++++++++++++++++++
 tests/binder/manager.c          | 362 ++++++++++++++++
 tests/binder/service_provider.c | 404 ++++++++++++++++++
 tests/binder/test               | 257 ++++++++++--
 tests/binder/test_binder.c      | 705 --------------------------------
 13 files changed, 1785 insertions(+), 863 deletions(-)
 create mode 100644 tests/binder/binder_common.c
 create mode 100644 tests/binder/binder_common.h
 create mode 100644 tests/binder/check_binderfs.c
 create mode 100644 tests/binder/client.c
 create mode 100644 tests/binder/manager.c
 create mode 100644 tests/binder/service_provider.c
 delete mode 100644 tests/binder/test_binder.c

Comments

Paul Moore April 10, 2019, 3:35 p.m. UTC | #1
On Wed, Apr 3, 2019 at 8:43 AM Richard Haines
<richard_c_haines@btinternet.com> wrote:
> Replace binder_test.c with separate manager, client and service provider.
> This works in the same way as a service provider/client interacts
> with a service manager in the Android world. It passes the service
> providers binder file descriptor to the client for the impersonate
> permission check.
>
> Also added tests for Dynamically Allocated Binder Devices and passing
> the sender SELinux security context on binder transactions.
>
> Note that the tests require a minimum kernel of 4.16, else some tests may
> fail. To run successfully the "binder: Add thread->process_todo flag"
> patch may be required that is available from:
> https://lore.kernel.org/patchwork/patch/851324/
> This patch has been backported to some earlier kernels.
>
> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> ---
>  defconfig                       |   3 +
>  policy/test_binder.te           | 176 ++++----
>  tests/binder/.gitignore         |   6 +-
>  tests/binder/Makefile           |  13 +-
>  tests/binder/binder_common.c    | 155 +++++++
>  tests/binder/binder_common.h    |  37 ++
>  tests/binder/check_binder.c     |  27 +-
>  tests/binder/check_binderfs.c   |  53 +++
>  tests/binder/client.c           | 450 ++++++++++++++++++++
>  tests/binder/manager.c          | 362 ++++++++++++++++
>  tests/binder/service_provider.c | 404 ++++++++++++++++++
>  tests/binder/test               | 257 ++++++++++--
>  tests/binder/test_binder.c      | 705 --------------------------------
>  13 files changed, 1785 insertions(+), 863 deletions(-)
>  create mode 100644 tests/binder/binder_common.c
>  create mode 100644 tests/binder/binder_common.h
>  create mode 100644 tests/binder/check_binderfs.c
>  create mode 100644 tests/binder/client.c
>  create mode 100644 tests/binder/manager.c
>  create mode 100644 tests/binder/service_provider.c
>  delete mode 100644 tests/binder/test_binder.c

Hi Richard,

Welcome back :)

I had hoped to spend some time reading up on Binder so I could give
this a proper review, but that hasn't happened so I'm inclined to
merge it, assuming it works on my test system.  However, considering
your comment about this not working on kernel's older than 4.16, I
think we should probably add some checks to only run this test on
systems with the appropriate kernel support.

If you look at tests/Makefile you will see a number of distro specific
test list modifications, and there is even an example of checking the
kernel version (search for "kvercmp" in the Makefile).  I would
suggest a simple check to make sure the kernel is at least v4.16, and
if we find distro specific support (e.g. a particular distro
backported the listed patch) we can always add an exception for that
distro.

How does that sound?
Richard Haines April 10, 2019, 5:04 p.m. UTC | #2
On Wed, 2019-04-10 at 11:35 -0400, Paul Moore wrote:
> On Wed, Apr 3, 2019 at 8:43 AM Richard Haines
> <richard_c_haines@btinternet.com> wrote:
> > Replace binder_test.c with separate manager, client and service
> > provider.
> > This works in the same way as a service provider/client interacts
> > with a service manager in the Android world. It passes the service
> > providers binder file descriptor to the client for the impersonate
> > permission check.
> > 
> > Also added tests for Dynamically Allocated Binder Devices and
> > passing
> > the sender SELinux security context on binder transactions.
> > 
> > Note that the tests require a minimum kernel of 4.16, else some
> > tests may
> > fail. To run successfully the "binder: Add thread->process_todo
> > flag"
> > patch may be required that is available from:
> > https://lore.kernel.org/patchwork/patch/851324/
> > This patch has been backported to some earlier kernels.
> > 
> > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> > ---
> >  defconfig                       |   3 +
> >  policy/test_binder.te           | 176 ++++----
> >  tests/binder/.gitignore         |   6 +-
> >  tests/binder/Makefile           |  13 +-
> >  tests/binder/binder_common.c    | 155 +++++++
> >  tests/binder/binder_common.h    |  37 ++
> >  tests/binder/check_binder.c     |  27 +-
> >  tests/binder/check_binderfs.c   |  53 +++
> >  tests/binder/client.c           | 450 ++++++++++++++++++++
> >  tests/binder/manager.c          | 362 ++++++++++++++++
> >  tests/binder/service_provider.c | 404 ++++++++++++++++++
> >  tests/binder/test               | 257 ++++++++++--
> >  tests/binder/test_binder.c      | 705 ----------------------------
> > ----
> >  13 files changed, 1785 insertions(+), 863 deletions(-)
> >  create mode 100644 tests/binder/binder_common.c
> >  create mode 100644 tests/binder/binder_common.h
> >  create mode 100644 tests/binder/check_binderfs.c
> >  create mode 100644 tests/binder/client.c
> >  create mode 100644 tests/binder/manager.c
> >  create mode 100644 tests/binder/service_provider.c
> >  delete mode 100644 tests/binder/test_binder.c
> 
> Hi Richard,
> 
> Welcome back :)
> 
> I had hoped to spend some time reading up on Binder so I could give
> this a proper review, but that hasn't happened so I'm inclined to
> merge it, assuming it works on my test system.  However, considering
> your comment about this not working on kernel's older than 4.16, I
> think we should probably add some checks to only run this test on
> systems with the appropriate kernel support.
> 
> If you look at tests/Makefile you will see a number of distro
> specific
> test list modifications, and there is even an example of checking the
> kernel version (search for "kvercmp" in the Makefile).  I would
> suggest a simple check to make sure the kernel is at least v4.16, and
> if we find distro specific support (e.g. a particular distro
> backported the listed patch) we can always add an exception for that
> distro.
> 
> How does that sound?

There are tests for the OS in the 'test' script already. I guess you
need to check if these are okay, as I check if < 4.16 and if so print
message saying if fail check for the patch.

I'm not sure this will get to the list as I appear to be black-balled.
I did send a cover letter with this patch + another one regarding
running SCTP on < 4.20.17. I sent email to 
owner-selinux@vger.kernel.org but not heard anything yet.

Cover Letter:
Subject: [PATCH 0/1] selinux-testsuite: Update binder test applications

The Binder tests have been rewritten to support the new Dynamically
Allocated Binder Devices and passing the sender SELinux security
context on binder transactions.

They have been tested on f29 and rawhide with the following kernels
from kernel.org:
mainline: 5.1-rc3
longterm: 4.19.32
longterm: 4.14.109

As noted in the main patch, the tests require a minimum kernel of 4.16,
else some tests may fail (tests 4 & 7). To run successfully the
4.14.109 kernel was patched with: "binder: Add thread->process_todo
flag" available from:
https://lore.kernel.org/patchwork/patch/851324/

I found that on slow systems using 4.14.109, all tests would pass,
however when testing on a faster system they would fail. Once patched,
worked fine.

Any testing feedback gratefully received.

Richard

>
Paul Moore April 10, 2019, 11:43 p.m. UTC | #3
On Wed, Apr 10, 2019 at 1:04 PM Richard Haines
<richard_c_haines@btinternet.com> wrote:
> On Wed, 2019-04-10 at 11:35 -0400, Paul Moore wrote:
> > On Wed, Apr 3, 2019 at 8:43 AM Richard Haines
> > <richard_c_haines@btinternet.com> wrote:
> > > Replace binder_test.c with separate manager, client and service
> > > provider.
> > > This works in the same way as a service provider/client interacts
> > > with a service manager in the Android world. It passes the service
> > > providers binder file descriptor to the client for the impersonate
> > > permission check.
> > >
> > > Also added tests for Dynamically Allocated Binder Devices and
> > > passing
> > > the sender SELinux security context on binder transactions.
> > >
> > > Note that the tests require a minimum kernel of 4.16, else some
> > > tests may
> > > fail. To run successfully the "binder: Add thread->process_todo
> > > flag"
> > > patch may be required that is available from:
> > > https://lore.kernel.org/patchwork/patch/851324/
> > > This patch has been backported to some earlier kernels.
> > >
> > > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> > > ---
> > >  defconfig                       |   3 +
> > >  policy/test_binder.te           | 176 ++++----
> > >  tests/binder/.gitignore         |   6 +-
> > >  tests/binder/Makefile           |  13 +-
> > >  tests/binder/binder_common.c    | 155 +++++++
> > >  tests/binder/binder_common.h    |  37 ++
> > >  tests/binder/check_binder.c     |  27 +-
> > >  tests/binder/check_binderfs.c   |  53 +++
> > >  tests/binder/client.c           | 450 ++++++++++++++++++++
> > >  tests/binder/manager.c          | 362 ++++++++++++++++
> > >  tests/binder/service_provider.c | 404 ++++++++++++++++++
> > >  tests/binder/test               | 257 ++++++++++--
> > >  tests/binder/test_binder.c      | 705 ----------------------------
> > > ----
> > >  13 files changed, 1785 insertions(+), 863 deletions(-)
> > >  create mode 100644 tests/binder/binder_common.c
> > >  create mode 100644 tests/binder/binder_common.h
> > >  create mode 100644 tests/binder/check_binderfs.c
> > >  create mode 100644 tests/binder/client.c
> > >  create mode 100644 tests/binder/manager.c
> > >  create mode 100644 tests/binder/service_provider.c
> > >  delete mode 100644 tests/binder/test_binder.c
> >
> > Hi Richard,
> >
> > Welcome back :)
> >
> > I had hoped to spend some time reading up on Binder so I could give
> > this a proper review, but that hasn't happened so I'm inclined to
> > merge it, assuming it works on my test system.  However, considering
> > your comment about this not working on kernel's older than 4.16, I
> > think we should probably add some checks to only run this test on
> > systems with the appropriate kernel support.
> >
> > If you look at tests/Makefile you will see a number of distro
> > specific
> > test list modifications, and there is even an example of checking the
> > kernel version (search for "kvercmp" in the Makefile).  I would
> > suggest a simple check to make sure the kernel is at least v4.16, and
> > if we find distro specific support (e.g. a particular distro
> > backported the listed patch) we can always add an exception for that
> > distro.
> >
> > How does that sound?
>
> There are tests for the OS in the 'test' script already. I guess you
> need to check if these are okay, as I check if < 4.16 and if so print
> message saying if fail check for the patch.

Ah ha, yes you did, and I missed it.  Sorry about that.  I checked the
Makefiles, didn't see any checks, and wrongly assumed they were not
there.

Looking quickly at the check it seems reasonable, if I notice any
problems when testing I'll let you know.

> I'm not sure this will get to the list as I appear to be black-balled.
> I did send a cover letter with this patch + another one regarding
> running SCTP on < 4.20.17. I sent email to
> owner-selinux@vger.kernel.org but not heard anything yet.

Hmm, that's not good.  FWIW, the original patch obviously made it, but
yes I'm not seeing your response in the list archives.  Did you get
any sort of majordomo hate mail back on your posts, or is is just
silently dropping your messages?

> Cover Letter:
> Subject: [PATCH 0/1] selinux-testsuite: Update binder test applications
>
> The Binder tests have been rewritten to support the new Dynamically
> Allocated Binder Devices and passing the sender SELinux security
> context on binder transactions.
>
> They have been tested on f29 and rawhide with the following kernels
> from kernel.org:
> mainline: 5.1-rc3
> longterm: 4.19.32
> longterm: 4.14.109
>
> As noted in the main patch, the tests require a minimum kernel of 4.16,
> else some tests may fail (tests 4 & 7). To run successfully the
> 4.14.109 kernel was patched with: "binder: Add thread->process_todo
> flag" available from:
> https://lore.kernel.org/patchwork/patch/851324/
>
> I found that on slow systems using 4.14.109, all tests would pass,
> however when testing on a faster system they would fail. Once patched,
> worked fine.
>
> Any testing feedback gratefully received.
>
> Richard
Richard Haines April 11, 2019, 11:48 a.m. UTC | #4
On Wed, 2019-04-10 at 19:43 -0400, Paul Moore wrote:
> On Wed, Apr 10, 2019 at 1:04 PM Richard Haines
> <richard_c_haines@btinternet.com> wrote:
> > On Wed, 2019-04-10 at 11:35 -0400, Paul Moore wrote:
> > > On Wed, Apr 3, 2019 at 8:43 AM Richard Haines
> > > <richard_c_haines@btinternet.com> wrote:
> > > > Replace binder_test.c with separate manager, client and service
> > > > provider.
> > > > This works in the same way as a service provider/client
> > > > interacts
> > > > with a service manager in the Android world. It passes the
> > > > service
> > > > providers binder file descriptor to the client for the
> > > > impersonate
> > > > permission check.
> > > > 
> > > > Also added tests for Dynamically Allocated Binder Devices and
> > > > passing
> > > > the sender SELinux security context on binder transactions.
> > > > 
> > > > Note that the tests require a minimum kernel of 4.16, else some
> > > > tests may
> > > > fail. To run successfully the "binder: Add thread->process_todo
> > > > flag"
> > > > patch may be required that is available from:
> > > > https://lore.kernel.org/patchwork/patch/851324/
> > > > This patch has been backported to some earlier kernels.
> > > > 
> > > > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> > > > ---
> > > >  defconfig                       |   3 +
> > > >  policy/test_binder.te           | 176 ++++----
> > > >  tests/binder/.gitignore         |   6 +-
> > > >  tests/binder/Makefile           |  13 +-
> > > >  tests/binder/binder_common.c    | 155 +++++++
> > > >  tests/binder/binder_common.h    |  37 ++
> > > >  tests/binder/check_binder.c     |  27 +-
> > > >  tests/binder/check_binderfs.c   |  53 +++
> > > >  tests/binder/client.c           | 450 ++++++++++++++++++++
> > > >  tests/binder/manager.c          | 362 ++++++++++++++++
> > > >  tests/binder/service_provider.c | 404 ++++++++++++++++++
> > > >  tests/binder/test               | 257 ++++++++++--
> > > >  tests/binder/test_binder.c      | 705 ------------------------
> > > > ----
> > > > ----
> > > >  13 files changed, 1785 insertions(+), 863 deletions(-)
> > > >  create mode 100644 tests/binder/binder_common.c
> > > >  create mode 100644 tests/binder/binder_common.h
> > > >  create mode 100644 tests/binder/check_binderfs.c
> > > >  create mode 100644 tests/binder/client.c
> > > >  create mode 100644 tests/binder/manager.c
> > > >  create mode 100644 tests/binder/service_provider.c
> > > >  delete mode 100644 tests/binder/test_binder.c
> > > 
> > > Hi Richard,
> > > 
> > > Welcome back :)
> > > 
> > > I had hoped to spend some time reading up on Binder so I could
> > > give
> > > this a proper review, but that hasn't happened so I'm inclined to
> > > merge it, assuming it works on my test system.  However,
> > > considering
> > > your comment about this not working on kernel's older than 4.16,
> > > I
> > > think we should probably add some checks to only run this test on
> > > systems with the appropriate kernel support.
> > > 
> > > If you look at tests/Makefile you will see a number of distro
> > > specific
> > > test list modifications, and there is even an example of checking
> > > the
> > > kernel version (search for "kvercmp" in the Makefile).  I would
> > > suggest a simple check to make sure the kernel is at least v4.16,
> > > and
> > > if we find distro specific support (e.g. a particular distro
> > > backported the listed patch) we can always add an exception for
> > > that
> > > distro.
> > > 
> > > How does that sound?
> > 
> > There are tests for the OS in the 'test' script already. I guess
> > you
> > need to check if these are okay, as I check if < 4.16 and if so
> > print
> > message saying if fail check for the patch.
> 
> Ah ha, yes you did, and I missed it.  Sorry about that.  I checked
> the
> Makefiles, didn't see any checks, and wrongly assumed they were not
> there.
> 
> Looking quickly at the check it seems reasonable, if I notice any
> problems when testing I'll let you know.
> 
> > I'm not sure this will get to the list as I appear to be black-
> > balled.
> > I did send a cover letter with this patch + another one regarding
> > running SCTP on < 4.20.17. I sent email to
> > owner-selinux@vger.kernel.org but not heard anything yet.
> 
> Hmm, that's not good.  FWIW, the original patch obviously made it,
> but
> yes I'm not seeing your response in the list archives.  Did you get
> any sort of majordomo hate mail back on your posts, or is is just
> silently dropping your messages?

Just silently dropping messages. I had thought to remove from list then
add again, however it might smell a rat so left until owner-selinux
returns. I can only repeat what Julius Caesar muttered "Infamy! Infamy!
They've all got it in for me!" (well in Carry On Cleo any way).

> 
> > Cover Letter:
> > Subject: [PATCH 0/1] selinux-testsuite: Update binder test
> > applications
> > 
> > The Binder tests have been rewritten to support the new Dynamically
> > Allocated Binder Devices and passing the sender SELinux security
> > context on binder transactions.
> > 
> > They have been tested on f29 and rawhide with the following kernels
> > from kernel.org:
> > mainline: 5.1-rc3
> > longterm: 4.19.32
> > longterm: 4.14.109
> > 
> > As noted in the main patch, the tests require a minimum kernel of
> > 4.16,
> > else some tests may fail (tests 4 & 7). To run successfully the
> > 4.14.109 kernel was patched with: "binder: Add thread->process_todo
> > flag" available from:
> > https://lore.kernel.org/patchwork/patch/851324/
> > 
> > I found that on slow systems using 4.14.109, all tests would pass,
> > however when testing on a faster system they would fail. Once
> > patched,
> > worked fine.
> > 
> > Any testing feedback gratefully received.
> > 
> > Richard
Paul Moore April 11, 2019, 10:07 p.m. UTC | #5
On Thu, Apr 11, 2019 at 7:48 AM Richard Haines
<richard_c_haines@btinternet.com> wrote:
> On Wed, 2019-04-10 at 19:43 -0400, Paul Moore wrote:
> > On Wed, Apr 10, 2019 at 1:04 PM Richard Haines
> > <richard_c_haines@btinternet.com> wrote:
> > > On Wed, 2019-04-10 at 11:35 -0400, Paul Moore wrote:
> > > > On Wed, Apr 3, 2019 at 8:43 AM Richard Haines
> > > > <richard_c_haines@btinternet.com> wrote:
> > > > > Replace binder_test.c with separate manager, client and service
> > > > > provider.
> > > > > This works in the same way as a service provider/client
> > > > > interacts
> > > > > with a service manager in the Android world. It passes the
> > > > > service
> > > > > providers binder file descriptor to the client for the
> > > > > impersonate
> > > > > permission check.
> > > > >
> > > > > Also added tests for Dynamically Allocated Binder Devices and
> > > > > passing
> > > > > the sender SELinux security context on binder transactions.
> > > > >
> > > > > Note that the tests require a minimum kernel of 4.16, else some
> > > > > tests may
> > > > > fail. To run successfully the "binder: Add thread->process_todo
> > > > > flag"
> > > > > patch may be required that is available from:
> > > > > https://lore.kernel.org/patchwork/patch/851324/
> > > > > This patch has been backported to some earlier kernels.
> > > > >
> > > > > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> > > > > ---
> > > > >  defconfig                       |   3 +
> > > > >  policy/test_binder.te           | 176 ++++----
> > > > >  tests/binder/.gitignore         |   6 +-
> > > > >  tests/binder/Makefile           |  13 +-
> > > > >  tests/binder/binder_common.c    | 155 +++++++
> > > > >  tests/binder/binder_common.h    |  37 ++
> > > > >  tests/binder/check_binder.c     |  27 +-
> > > > >  tests/binder/check_binderfs.c   |  53 +++
> > > > >  tests/binder/client.c           | 450 ++++++++++++++++++++
> > > > >  tests/binder/manager.c          | 362 ++++++++++++++++
> > > > >  tests/binder/service_provider.c | 404 ++++++++++++++++++
> > > > >  tests/binder/test               | 257 ++++++++++--
> > > > >  tests/binder/test_binder.c      | 705 ------------------------
> > > > > ----
> > > > > ----
> > > > >  13 files changed, 1785 insertions(+), 863 deletions(-)
> > > > >  create mode 100644 tests/binder/binder_common.c
> > > > >  create mode 100644 tests/binder/binder_common.h
> > > > >  create mode 100644 tests/binder/check_binderfs.c
> > > > >  create mode 100644 tests/binder/client.c
> > > > >  create mode 100644 tests/binder/manager.c
> > > > >  create mode 100644 tests/binder/service_provider.c
> > > > >  delete mode 100644 tests/binder/test_binder.c
> > > >
> > > > Hi Richard,
> > > >
> > > > Welcome back :)
> > > >
> > > > I had hoped to spend some time reading up on Binder so I could
> > > > give
> > > > this a proper review, but that hasn't happened so I'm inclined to
> > > > merge it, assuming it works on my test system.  However,
> > > > considering
> > > > your comment about this not working on kernel's older than 4.16,
> > > > I
> > > > think we should probably add some checks to only run this test on
> > > > systems with the appropriate kernel support.
> > > >
> > > > If you look at tests/Makefile you will see a number of distro
> > > > specific
> > > > test list modifications, and there is even an example of checking
> > > > the
> > > > kernel version (search for "kvercmp" in the Makefile).  I would
> > > > suggest a simple check to make sure the kernel is at least v4.16,
> > > > and
> > > > if we find distro specific support (e.g. a particular distro
> > > > backported the listed patch) we can always add an exception for
> > > > that
> > > > distro.
> > > >
> > > > How does that sound?
> > >
> > > There are tests for the OS in the 'test' script already. I guess
> > > you
> > > need to check if these are okay, as I check if < 4.16 and if so
> > > print
> > > message saying if fail check for the patch.
> >
> > Ah ha, yes you did, and I missed it.  Sorry about that.  I checked
> > the
> > Makefiles, didn't see any checks, and wrongly assumed they were not
> > there.
> >
> > Looking quickly at the check it seems reasonable, if I notice any
> > problems when testing I'll let you know.
> >
> > > I'm not sure this will get to the list as I appear to be black-
> > > balled.
> > > I did send a cover letter with this patch + another one regarding
> > > running SCTP on < 4.20.17. I sent email to
> > > owner-selinux@vger.kernel.org but not heard anything yet.
> >
> > Hmm, that's not good.  FWIW, the original patch obviously made it,
> > but
> > yes I'm not seeing your response in the list archives.  Did you get
> > any sort of majordomo hate mail back on your posts, or is is just
> > silently dropping your messages?
>
> Just silently dropping messages. I had thought to remove from list then
> add again, however it might smell a rat so left until owner-selinux
> returns. I can only repeat what Julius Caesar muttered "Infamy! Infamy!
> They've all got it in for me!" (well in Carry On Cleo any way).

I got the brexit jump label gag, but you lost me on the "Carry on
Cleo"; thankfully good ol' Google came to the rescue on that one ;)

On the plus side, your posts seem to be coming through to the list now.

On the negative side I realized when playing with your test changes
that I wasn't building BINDERFS in my test kernels - oops.  I'm fixing
that now, but I might not get a chance to do another test until
tomorrow; at least I can verify that your BINDERFS testing logic works
:)
Paul Moore April 12, 2019, 2:46 p.m. UTC | #6
On Thu, Apr 11, 2019 at 6:07 PM Paul Moore <paul@paul-moore.com> wrote:
> On the negative side I realized when playing with your test changes
> that I wasn't building BINDERFS in my test kernels - oops.  I'm fixing
> that now, but I might not get a chance to do another test until
> tomorrow; at least I can verify that your BINDERFS testing logic works
> :)

I rebuilt my test kernel (the latest "secnext" builds have it) with
BINDERFS only to realize that Fedora Rawhide doesn't seem to ship
/usr/include/linux/android/binderfs.h so I manually copied the file
from the kernel-devel package only to run into this when building the
new binder tests:

# make
cc -DHAVE_BINDERFS    check_binder.c binder_common.c binder_common.h
-lselinux -lrt -o check_binder
binder_common.c: In function ‘cmd_name’:
binder_common.c:35:7: error: ‘BR_TRANSACTION_SEC_CTX’ undeclared (first use in t
his function); did you mean ‘BC_TRANSACTION_SG’?
  35 |  case BR_TRANSACTION_SEC_CTX:
     |       ^~~~~~~~~~~~~~~~~~~~~~
     |       BC_TRANSACTION_SG
binder_common.c:35:7: note: each undeclared identifier is reported only once for
each function it appears in
binder_common.c: In function ‘print_trans_data’:
binder_common.c:126:23: error: ‘FLAT_BINDER_FLAG_TXN_SECURITY_CTX’ undeclared (f
irst use in this function)
 126 |          obj->flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX ? "YES" : "NO");
     |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make: *** [<builtin>: check_binder] Error 1
# grep "BR_TRANSACTION_SEC_CTX" *
binder_common.c:        case BR_TRANSACTION_SEC_CTX:
binder_common.c:                return "BR_TRANSACTION_SEC_CTX";
service_provider.c:             case BR_TRANSACTION_SEC_CTX: {
# grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binderfs.h
# grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binder.h

... and that's when I stopped playing with this.  If it helps, I
pulled my binderfs.h file from a current Rawhide kernel.  What are you
using to run these tests?

At the very least, I'm thinking we'll also want to include some notes
in the README.md file under the "Optional Prerequisites" section about
how to get this running with BINDERFS.

--
paul moore
www.paul-moore.com
Richard Haines April 12, 2019, 4:37 p.m. UTC | #7
On Fri, 2019-04-12 at 10:46 -0400, Paul Moore wrote:
> On Thu, Apr 11, 2019 at 6:07 PM Paul Moore <paul@paul-moore.com>
> wrote:
> > On the negative side I realized when playing with your test changes
> > that I wasn't building BINDERFS in my test kernels - oops.  I'm
> > fixing
> > that now, but I might not get a chance to do another test until
> > tomorrow; at least I can verify that your BINDERFS testing logic
> > works
> > :)
> 
> I rebuilt my test kernel (the latest "secnext" builds have it) with
> BINDERFS only to realize that Fedora Rawhide doesn't seem to ship
> /usr/include/linux/android/binderfs.h so I manually copied the file
> from the kernel-devel package only to run into this when building the
> new binder tests:
> 
> # make
> cc -DHAVE_BINDERFS    check_binder.c binder_common.c binder_common.h
> -lselinux -lrt -o check_binder
> binder_common.c: In function ‘cmd_name’:
> binder_common.c:35:7: error: ‘BR_TRANSACTION_SEC_CTX’ undeclared
> (first use in t
> his function); did you mean ‘BC_TRANSACTION_SG’?
>   35 |  case BR_TRANSACTION_SEC_CTX:
>      |       ^~~~~~~~~~~~~~~~~~~~~~
>      |       BC_TRANSACTION_SG
> binder_common.c:35:7: note: each undeclared identifier is reported
> only once for
> each function it appears in
> binder_common.c: In function ‘print_trans_data’:
> binder_common.c:126:23: error: ‘FLAT_BINDER_FLAG_TXN_SECURITY_CTX’
> undeclared (f
> irst use in this function)
>  126 |          obj->flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX ?
> "YES" : "NO");
>      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> make: *** [<builtin>: check_binder] Error 1
> # grep "BR_TRANSACTION_SEC_CTX" *
> binder_common.c:        case BR_TRANSACTION_SEC_CTX:
> binder_common.c:                return "BR_TRANSACTION_SEC_CTX";
> service_provider.c:             case BR_TRANSACTION_SEC_CTX: {
> # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binderfs.h
> # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binder.h
> 
> ... and that's when I stopped playing with this.  If it helps, I
> pulled my binderfs.h file from a current Rawhide kernel.  What are
> you
> using to run these tests?
> 
> At the very least, I'm thinking we'll also want to include some notes
> in the README.md file under the "Optional Prerequisites" section
> about
> how to get this running with BINDERFS.

The BR_TRANSACTION_SEC_CTX is defined in an updated binder.h file, so
you need both binder.h and binderfs.h from devel.

I guess I must have copied them over by hand as I tested on rawhide.
I'll add a note in the README.md file.

Thanks
Richard
> 
> --
> paul moore
> www.paul-moore.com
Paul Moore April 12, 2019, 7:20 p.m. UTC | #8
On Fri, Apr 12, 2019 at 12:37 PM Richard Haines
<richard_c_haines@btinternet.com> wrote:
> On Fri, 2019-04-12 at 10:46 -0400, Paul Moore wrote:
> > On Thu, Apr 11, 2019 at 6:07 PM Paul Moore <paul@paul-moore.com>
> > wrote:
> > > On the negative side I realized when playing with your test changes
> > > that I wasn't building BINDERFS in my test kernels - oops.  I'm
> > > fixing
> > > that now, but I might not get a chance to do another test until
> > > tomorrow; at least I can verify that your BINDERFS testing logic
> > > works
> > > :)
> >
> > I rebuilt my test kernel (the latest "secnext" builds have it) with
> > BINDERFS only to realize that Fedora Rawhide doesn't seem to ship
> > /usr/include/linux/android/binderfs.h so I manually copied the file
> > from the kernel-devel package only to run into this when building the
> > new binder tests:
> >
> > # make
> > cc -DHAVE_BINDERFS    check_binder.c binder_common.c binder_common.h
> > -lselinux -lrt -o check_binder
> > binder_common.c: In function ‘cmd_name’:
> > binder_common.c:35:7: error: ‘BR_TRANSACTION_SEC_CTX’ undeclared
> > (first use in t
> > his function); did you mean ‘BC_TRANSACTION_SG’?
> >   35 |  case BR_TRANSACTION_SEC_CTX:
> >      |       ^~~~~~~~~~~~~~~~~~~~~~
> >      |       BC_TRANSACTION_SG
> > binder_common.c:35:7: note: each undeclared identifier is reported
> > only once for
> > each function it appears in
> > binder_common.c: In function ‘print_trans_data’:
> > binder_common.c:126:23: error: ‘FLAT_BINDER_FLAG_TXN_SECURITY_CTX’
> > undeclared (f
> > irst use in this function)
> >  126 |          obj->flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX ?
> > "YES" : "NO");
> >      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > make: *** [<builtin>: check_binder] Error 1
> > # grep "BR_TRANSACTION_SEC_CTX" *
> > binder_common.c:        case BR_TRANSACTION_SEC_CTX:
> > binder_common.c:                return "BR_TRANSACTION_SEC_CTX";
> > service_provider.c:             case BR_TRANSACTION_SEC_CTX: {
> > # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binderfs.h
> > # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binder.h
> >
> > ... and that's when I stopped playing with this.  If it helps, I
> > pulled my binderfs.h file from a current Rawhide kernel.  What are
> > you
> > using to run these tests?
> >
> > At the very least, I'm thinking we'll also want to include some notes
> > in the README.md file under the "Optional Prerequisites" section
> > about
> > how to get this running with BINDERFS.
>
> The BR_TRANSACTION_SEC_CTX is defined in an updated binder.h file, so
> you need both binder.h and binderfs.h from devel.
>
> I guess I must have copied them over by hand as I tested on rawhide.
> I'll add a note in the README.md file.

Okay, that solved the problem, thanks.

I just noticed that the kernel-headers package on my Rawhide systems
are *really* old.  I suspect this may be due to the fact that I'm not
running Fedora Rawhide kernels and thus my currently installed kernel
packages don't match what is present in the main Rawhide repos; this
problem might be limited to just me (and anyone exclusively running
the secnext kernels on their system).

Can anyone with a Rawhide system confirm if they have the
/usr/include/linux/android/binderfs.h header file?
Stephen Smalley April 12, 2019, 7:28 p.m. UTC | #9
On 4/12/19 3:20 PM, Paul Moore wrote:
> On Fri, Apr 12, 2019 at 12:37 PM Richard Haines
> <richard_c_haines@btinternet.com> wrote:
>> On Fri, 2019-04-12 at 10:46 -0400, Paul Moore wrote:
>>> On Thu, Apr 11, 2019 at 6:07 PM Paul Moore <paul@paul-moore.com>
>>> wrote:
>>>> On the negative side I realized when playing with your test changes
>>>> that I wasn't building BINDERFS in my test kernels - oops.  I'm
>>>> fixing
>>>> that now, but I might not get a chance to do another test until
>>>> tomorrow; at least I can verify that your BINDERFS testing logic
>>>> works
>>>> :)
>>>
>>> I rebuilt my test kernel (the latest "secnext" builds have it) with
>>> BINDERFS only to realize that Fedora Rawhide doesn't seem to ship
>>> /usr/include/linux/android/binderfs.h so I manually copied the file
>>> from the kernel-devel package only to run into this when building the
>>> new binder tests:
>>>
>>> # make
>>> cc -DHAVE_BINDERFS    check_binder.c binder_common.c binder_common.h
>>> -lselinux -lrt -o check_binder
>>> binder_common.c: In function ‘cmd_name’:
>>> binder_common.c:35:7: error: ‘BR_TRANSACTION_SEC_CTX’ undeclared
>>> (first use in t
>>> his function); did you mean ‘BC_TRANSACTION_SG’?
>>>    35 |  case BR_TRANSACTION_SEC_CTX:
>>>       |       ^~~~~~~~~~~~~~~~~~~~~~
>>>       |       BC_TRANSACTION_SG
>>> binder_common.c:35:7: note: each undeclared identifier is reported
>>> only once for
>>> each function it appears in
>>> binder_common.c: In function ‘print_trans_data’:
>>> binder_common.c:126:23: error: ‘FLAT_BINDER_FLAG_TXN_SECURITY_CTX’
>>> undeclared (f
>>> irst use in this function)
>>>   126 |          obj->flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX ?
>>> "YES" : "NO");
>>>       |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> make: *** [<builtin>: check_binder] Error 1
>>> # grep "BR_TRANSACTION_SEC_CTX" *
>>> binder_common.c:        case BR_TRANSACTION_SEC_CTX:
>>> binder_common.c:                return "BR_TRANSACTION_SEC_CTX";
>>> service_provider.c:             case BR_TRANSACTION_SEC_CTX: {
>>> # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binderfs.h
>>> # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binder.h
>>>
>>> ... and that's when I stopped playing with this.  If it helps, I
>>> pulled my binderfs.h file from a current Rawhide kernel.  What are
>>> you
>>> using to run these tests?
>>>
>>> At the very least, I'm thinking we'll also want to include some notes
>>> in the README.md file under the "Optional Prerequisites" section
>>> about
>>> how to get this running with BINDERFS.
>>
>> The BR_TRANSACTION_SEC_CTX is defined in an updated binder.h file, so
>> you need both binder.h and binderfs.h from devel.
>>
>> I guess I must have copied them over by hand as I tested on rawhide.
>> I'll add a note in the README.md file.
> 
> Okay, that solved the problem, thanks.
> 
> I just noticed that the kernel-headers package on my Rawhide systems
> are *really* old.  I suspect this may be due to the fact that I'm not
> running Fedora Rawhide kernels and thus my currently installed kernel
> packages don't match what is present in the main Rawhide repos; this
> problem might be limited to just me (and anyone exclusively running
> the secnext kernels on their system).
> 
> Can anyone with a Rawhide system confirm if they have the
> /usr/include/linux/android/binderfs.h header file?

Don't have rawhide handy, but Fedora 29 has it,
$ rpm -q -f /usr/include/linux/android/binderfs.h
kernel-headers-5.0.6-200.fc29.x86_64
Dac Override April 12, 2019, 7:31 p.m. UTC | #10
Paul Moore <paul@paul-moore.com> writes:

> On Fri, Apr 12, 2019 at 12:37 PM Richard Haines
> <richard_c_haines@btinternet.com> wrote:
>> On Fri, 2019-04-12 at 10:46 -0400, Paul Moore wrote:
>> > On Thu, Apr 11, 2019 at 6:07 PM Paul Moore <paul@paul-moore.com>
>> > wrote:
>> > > On the negative side I realized when playing with your test changes
>> > > that I wasn't building BINDERFS in my test kernels - oops.  I'm
>> > > fixing
>> > > that now, but I might not get a chance to do another test until
>> > > tomorrow; at least I can verify that your BINDERFS testing logic
>> > > works
>> > > :)
>> >
>> > I rebuilt my test kernel (the latest "secnext" builds have it) with
>> > BINDERFS only to realize that Fedora Rawhide doesn't seem to ship
>> > /usr/include/linux/android/binderfs.h so I manually copied the file
>> > from the kernel-devel package only to run into this when building the
>> > new binder tests:
>> >
>> > # make
>> > cc -DHAVE_BINDERFS    check_binder.c binder_common.c binder_common.h
>> > -lselinux -lrt -o check_binder
>> > binder_common.c: In function ‘cmd_name’:
>> > binder_common.c:35:7: error: ‘BR_TRANSACTION_SEC_CTX’ undeclared
>> > (first use in t
>> > his function); did you mean ‘BC_TRANSACTION_SG’?
>> >   35 |  case BR_TRANSACTION_SEC_CTX:
>> >      |       ^~~~~~~~~~~~~~~~~~~~~~
>> >      |       BC_TRANSACTION_SG
>> > binder_common.c:35:7: note: each undeclared identifier is reported
>> > only once for
>> > each function it appears in
>> > binder_common.c: In function ‘print_trans_data’:
>> > binder_common.c:126:23: error: ‘FLAT_BINDER_FLAG_TXN_SECURITY_CTX’
>> > undeclared (f
>> > irst use in this function)
>> >  126 |          obj->flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX ?
>> > "YES" : "NO");
>> >      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> > make: *** [<builtin>: check_binder] Error 1
>> > # grep "BR_TRANSACTION_SEC_CTX" *
>> > binder_common.c:        case BR_TRANSACTION_SEC_CTX:
>> > binder_common.c:                return "BR_TRANSACTION_SEC_CTX";
>> > service_provider.c:             case BR_TRANSACTION_SEC_CTX: {
>> > # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binderfs.h
>> > # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binder.h
>> >
>> > ... and that's when I stopped playing with this.  If it helps, I
>> > pulled my binderfs.h file from a current Rawhide kernel.  What are
>> > you
>> > using to run these tests?
>> >
>> > At the very least, I'm thinking we'll also want to include some notes
>> > in the README.md file under the "Optional Prerequisites" section
>> > about
>> > how to get this running with BINDERFS.
>>
>> The BR_TRANSACTION_SEC_CTX is defined in an updated binder.h file, so
>> you need both binder.h and binderfs.h from devel.
>>
>> I guess I must have copied them over by hand as I tested on rawhide.
>> I'll add a note in the README.md file.
>
> Okay, that solved the problem, thanks.
>
> I just noticed that the kernel-headers package on my Rawhide systems
> are *really* old.  I suspect this may be due to the fact that I'm not
> running Fedora Rawhide kernels and thus my currently installed kernel
> packages don't match what is present in the main Rawhide repos; this
> problem might be limited to just me (and anyone exclusively running
> the secnext kernels on their system).
>
> Can anyone with a Rawhide system confirm if they have the
> /usr/include/linux/android/binderfs.h header file?

[root@brutus ~]# rpm -qf /usr/include/linux/android/binderfs.h
kernel-headers-5.1.0-0.rc2.git1.1.fc31.x86_64
Paul Moore April 12, 2019, 10:02 p.m. UTC | #11
On Fri, Apr 12, 2019 at 3:31 PM Dominick Grift <dac.override@gmail.com> wrote:
> Paul Moore <paul@paul-moore.com> writes:
>
> > On Fri, Apr 12, 2019 at 12:37 PM Richard Haines
> > <richard_c_haines@btinternet.com> wrote:
> >> On Fri, 2019-04-12 at 10:46 -0400, Paul Moore wrote:
> >> > On Thu, Apr 11, 2019 at 6:07 PM Paul Moore <paul@paul-moore.com>
> >> > wrote:
> >> > > On the negative side I realized when playing with your test changes
> >> > > that I wasn't building BINDERFS in my test kernels - oops.  I'm
> >> > > fixing
> >> > > that now, but I might not get a chance to do another test until
> >> > > tomorrow; at least I can verify that your BINDERFS testing logic
> >> > > works
> >> > > :)
> >> >
> >> > I rebuilt my test kernel (the latest "secnext" builds have it) with
> >> > BINDERFS only to realize that Fedora Rawhide doesn't seem to ship
> >> > /usr/include/linux/android/binderfs.h so I manually copied the file
> >> > from the kernel-devel package only to run into this when building the
> >> > new binder tests:
> >> >
> >> > # make
> >> > cc -DHAVE_BINDERFS    check_binder.c binder_common.c binder_common.h
> >> > -lselinux -lrt -o check_binder
> >> > binder_common.c: In function ‘cmd_name’:
> >> > binder_common.c:35:7: error: ‘BR_TRANSACTION_SEC_CTX’ undeclared
> >> > (first use in t
> >> > his function); did you mean ‘BC_TRANSACTION_SG’?
> >> >   35 |  case BR_TRANSACTION_SEC_CTX:
> >> >      |       ^~~~~~~~~~~~~~~~~~~~~~
> >> >      |       BC_TRANSACTION_SG
> >> > binder_common.c:35:7: note: each undeclared identifier is reported
> >> > only once for
> >> > each function it appears in
> >> > binder_common.c: In function ‘print_trans_data’:
> >> > binder_common.c:126:23: error: ‘FLAT_BINDER_FLAG_TXN_SECURITY_CTX’
> >> > undeclared (f
> >> > irst use in this function)
> >> >  126 |          obj->flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX ?
> >> > "YES" : "NO");
> >> >      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >> > make: *** [<builtin>: check_binder] Error 1
> >> > # grep "BR_TRANSACTION_SEC_CTX" *
> >> > binder_common.c:        case BR_TRANSACTION_SEC_CTX:
> >> > binder_common.c:                return "BR_TRANSACTION_SEC_CTX";
> >> > service_provider.c:             case BR_TRANSACTION_SEC_CTX: {
> >> > # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binderfs.h
> >> > # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binder.h
> >> >
> >> > ... and that's when I stopped playing with this.  If it helps, I
> >> > pulled my binderfs.h file from a current Rawhide kernel.  What are
> >> > you
> >> > using to run these tests?
> >> >
> >> > At the very least, I'm thinking we'll also want to include some notes
> >> > in the README.md file under the "Optional Prerequisites" section
> >> > about
> >> > how to get this running with BINDERFS.
> >>
> >> The BR_TRANSACTION_SEC_CTX is defined in an updated binder.h file, so
> >> you need both binder.h and binderfs.h from devel.
> >>
> >> I guess I must have copied them over by hand as I tested on rawhide.
> >> I'll add a note in the README.md file.
> >
> > Okay, that solved the problem, thanks.
> >
> > I just noticed that the kernel-headers package on my Rawhide systems
> > are *really* old.  I suspect this may be due to the fact that I'm not
> > running Fedora Rawhide kernels and thus my currently installed kernel
> > packages don't match what is present in the main Rawhide repos; this
> > problem might be limited to just me (and anyone exclusively running
> > the secnext kernels on their system).
> >
> > Can anyone with a Rawhide system confirm if they have the
> > /usr/include/linux/android/binderfs.h header file?
>
> [root@brutus ~]# rpm -qf /usr/include/linux/android/binderfs.h
> kernel-headers-5.1.0-0.rc2.git1.1.fc31.x86_64

Thanks.

I realized today that last summer Fedora changed how they package the
kernel headers and thus I need to update how I build my test kernels.
As an aside, I don't get why the change was made, this new process for
building the kernel-headers package is *really* convoluted ... and
broken if you are using a custom %buildid (which I do for "secnext"
builds), but that's a different issue.
Paul Moore April 17, 2019, 3:27 p.m. UTC | #12
On Fri, Apr 12, 2019 at 6:02 PM Paul Moore <paul@paul-moore.com> wrote:
> On Fri, Apr 12, 2019 at 3:31 PM Dominick Grift <dac.override@gmail.com> wrote:
> > Paul Moore <paul@paul-moore.com> writes:
> >
> > > On Fri, Apr 12, 2019 at 12:37 PM Richard Haines
> > > <richard_c_haines@btinternet.com> wrote:
> > >> On Fri, 2019-04-12 at 10:46 -0400, Paul Moore wrote:
> > >> > On Thu, Apr 11, 2019 at 6:07 PM Paul Moore <paul@paul-moore.com>
> > >> > wrote:
> > >> > > On the negative side I realized when playing with your test changes
> > >> > > that I wasn't building BINDERFS in my test kernels - oops.  I'm
> > >> > > fixing
> > >> > > that now, but I might not get a chance to do another test until
> > >> > > tomorrow; at least I can verify that your BINDERFS testing logic
> > >> > > works
> > >> > > :)
> > >> >
> > >> > I rebuilt my test kernel (the latest "secnext" builds have it) with
> > >> > BINDERFS only to realize that Fedora Rawhide doesn't seem to ship
> > >> > /usr/include/linux/android/binderfs.h so I manually copied the file
> > >> > from the kernel-devel package only to run into this when building the
> > >> > new binder tests:
> > >> >
> > >> > # make
> > >> > cc -DHAVE_BINDERFS    check_binder.c binder_common.c binder_common.h
> > >> > -lselinux -lrt -o check_binder
> > >> > binder_common.c: In function ‘cmd_name’:
> > >> > binder_common.c:35:7: error: ‘BR_TRANSACTION_SEC_CTX’ undeclared
> > >> > (first use in t
> > >> > his function); did you mean ‘BC_TRANSACTION_SG’?
> > >> >   35 |  case BR_TRANSACTION_SEC_CTX:
> > >> >      |       ^~~~~~~~~~~~~~~~~~~~~~
> > >> >      |       BC_TRANSACTION_SG
> > >> > binder_common.c:35:7: note: each undeclared identifier is reported
> > >> > only once for
> > >> > each function it appears in
> > >> > binder_common.c: In function ‘print_trans_data’:
> > >> > binder_common.c:126:23: error: ‘FLAT_BINDER_FLAG_TXN_SECURITY_CTX’
> > >> > undeclared (f
> > >> > irst use in this function)
> > >> >  126 |          obj->flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX ?
> > >> > "YES" : "NO");
> > >> >      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > >> > make: *** [<builtin>: check_binder] Error 1
> > >> > # grep "BR_TRANSACTION_SEC_CTX" *
> > >> > binder_common.c:        case BR_TRANSACTION_SEC_CTX:
> > >> > binder_common.c:                return "BR_TRANSACTION_SEC_CTX";
> > >> > service_provider.c:             case BR_TRANSACTION_SEC_CTX: {
> > >> > # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binderfs.h
> > >> > # grep "BR_TRANSACTION_SEC_CTX" /usr/include/linux/android/binder.h
> > >> >
> > >> > ... and that's when I stopped playing with this.  If it helps, I
> > >> > pulled my binderfs.h file from a current Rawhide kernel.  What are
> > >> > you
> > >> > using to run these tests?
> > >> >
> > >> > At the very least, I'm thinking we'll also want to include some notes
> > >> > in the README.md file under the "Optional Prerequisites" section
> > >> > about
> > >> > how to get this running with BINDERFS.
> > >>
> > >> The BR_TRANSACTION_SEC_CTX is defined in an updated binder.h file, so
> > >> you need both binder.h and binderfs.h from devel.
> > >>
> > >> I guess I must have copied them over by hand as I tested on rawhide.
> > >> I'll add a note in the README.md file.
> > >
> > > Okay, that solved the problem, thanks.
> > >
> > > I just noticed that the kernel-headers package on my Rawhide systems
> > > are *really* old.  I suspect this may be due to the fact that I'm not
> > > running Fedora Rawhide kernels and thus my currently installed kernel
> > > packages don't match what is present in the main Rawhide repos; this
> > > problem might be limited to just me (and anyone exclusively running
> > > the secnext kernels on their system).
> > >
> > > Can anyone with a Rawhide system confirm if they have the
> > > /usr/include/linux/android/binderfs.h header file?
> >
> > [root@brutus ~]# rpm -qf /usr/include/linux/android/binderfs.h
> > kernel-headers-5.1.0-0.rc2.git1.1.fc31.x86_64
>
> Thanks.
>
> I realized today that last summer Fedora changed how they package the
> kernel headers and thus I need to update how I build my test kernels.
> As an aside, I don't get why the change was made, this new process for
> building the kernel-headers package is *really* convoluted ... and
> broken if you are using a custom %buildid (which I do for "secnext"
> builds), but that's a different issue.

With the header issue sorted out, the tests is now running clean for
me so I just merged it into the selinux-testsuite master branch.
Thanks for your patience on this.
diff mbox series

Patch

diff --git a/defconfig b/defconfig
index ff0704f..d7f0ea5 100644
--- a/defconfig
+++ b/defconfig
@@ -59,3 +59,6 @@  CONFIG_OVERLAY_FS=m
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_DEVICES="binder"
 CONFIG_ANDROID_BINDER_IPC=y
+# This will configure the Dynamically Allocated Binder Devices added
+# to 5.0+ kernels:
+CONFIG_ANDROID_BINDERFS=y
diff --git a/policy/test_binder.te b/policy/test_binder.te
index 47992b2..c160ec0 100644
--- a/policy/test_binder.te
+++ b/policy/test_binder.te
@@ -1,126 +1,118 @@ 
-
 attribute binderdomain;
 
 #
-################################## Manager ###################################
+################################## Manager ##################################
 #
 type test_binder_mgr_t;
 domain_type(test_binder_mgr_t)
 unconfined_runs_test(test_binder_mgr_t)
 typeattribute test_binder_mgr_t testdomain;
 typeattribute test_binder_mgr_t binderdomain;
-allow test_binder_mgr_t self:binder { set_context_mgr call };
-allow test_binder_mgr_t test_binder_provider_t:binder call;
+allow test_binder_mgr_t test_binder_client_t:binder { transfer };
 allow test_binder_mgr_t device_t:chr_file { ioctl open read write };
 allow_map(test_binder_mgr_t, device_t, chr_file)
-allow test_binder_mgr_t self:capability { sys_nice };
-allow test_binder_provider_t test_binder_mgr_t:fd use;
-fs_getattr_tmpfs(test_binder_mgr_t)
-allow test_binder_mgr_t tmpfs_t:file { read write open };
-allow_map(test_binder_mgr_t, tmpfs_t, file)
-fs_manage_tmpfs_dirs(test_binder_mgr_t)
-fs_manage_tmpfs_files(test_binder_mgr_t)
-
+allow test_binder_mgr_t self:binder { set_context_mgr };
 # For writing to flag file:
 allow test_binder_mgr_t test_file_t:fifo_file rw_file_perms;
 
 #
-########################## Manager no fd {use} ###############################
-#
-type test_binder_mgr_no_fd_t;
-domain_type(test_binder_mgr_no_fd_t)
-unconfined_runs_test(test_binder_mgr_no_fd_t)
-typeattribute test_binder_mgr_no_fd_t testdomain;
-typeattribute test_binder_mgr_no_fd_t binderdomain;
-allow test_binder_mgr_no_fd_t self:binder { set_context_mgr call };
-allow test_binder_mgr_no_fd_t test_binder_provider_t:binder { call };
-allow test_binder_mgr_no_fd_t device_t:chr_file { ioctl open read write };
-allow_map(test_binder_mgr_no_fd_t, device_t, chr_file)
-allow test_binder_provider_t test_binder_mgr_no_fd_t:binder { call transfer impersonate };
-fs_getattr_tmpfs(test_binder_mgr_no_fd_t)
-allow test_binder_mgr_no_fd_t tmpfs_t:file { read write open };
-allow_map(test_binder_mgr_no_fd_t, tmpfs_t, file)
-fs_manage_tmpfs_dirs(test_binder_mgr_no_fd_t)
-fs_manage_tmpfs_files(test_binder_mgr_no_fd_t)
-
-# For writing to flag file:
-allow test_binder_mgr_no_fd_t test_file_t:fifo_file rw_file_perms;
-
-#
-########################## Service Provider ################################
+########################### Service Provider ################################
 #
 type test_binder_provider_t;
 domain_type(test_binder_provider_t)
 unconfined_runs_test(test_binder_provider_t)
 typeattribute test_binder_provider_t testdomain;
 typeattribute test_binder_provider_t binderdomain;
-allow test_binder_provider_t self:binder { call };
-allow test_binder_provider_t test_binder_mgr_t:binder { call transfer impersonate };
+allow test_binder_provider_t test_binder_mgr_t:binder { call transfer };
 allow test_binder_provider_t device_t:chr_file { ioctl open read write };
 allow_map(test_binder_provider_t, device_t, chr_file)
-# For fstat:
-allow test_binder_provider_t device_t:chr_file getattr;
-fs_getattr_tmpfs(test_binder_provider_t)
-allow test_binder_provider_t tmpfs_t:file { read write open };
-allow_map(test_binder_provider_t, tmpfs_t, file)
-fs_manage_tmpfs_dirs(test_binder_provider_t)
-fs_manage_tmpfs_files(test_binder_provider_t)
+# For writing to flag file:
+allow test_binder_provider_t test_file_t:fifo_file rw_file_perms;
 
 #
-#################### Service Provider no call ################################
-#
-type test_binder_provider_no_call_t;
-domain_type(test_binder_provider_no_call_t)
-unconfined_runs_test(test_binder_provider_no_call_t)
-typeattribute test_binder_provider_no_call_t testdomain;
-typeattribute test_binder_provider_no_call_t binderdomain;
-allow test_binder_provider_no_call_t device_t:chr_file { ioctl open read write };
-allow_map(test_binder_provider_no_call_t, device_t, chr_file)
-fs_getattr_tmpfs(test_binder_provider_no_call_t)
-allow test_binder_provider_no_call_t tmpfs_t:file { read write open };
-allow_map(test_binder_provider_no_call_t, tmpfs_t, file)
-fs_manage_tmpfs_dirs(test_binder_provider_no_call_t)
-fs_manage_tmpfs_files(test_binder_provider_no_call_t)
+#################### Service Provider no fd {use} ###########################
+# test 7
+type test_binder_provider_no_fd_t;
+domain_type(test_binder_provider_no_fd_t)
+unconfined_runs_test(test_binder_provider_no_fd_t)
+typeattribute test_binder_provider_no_fd_t testdomain;
+typeattribute test_binder_provider_no_fd_t binderdomain;
+allow test_binder_provider_no_fd_t test_binder_mgr_t:binder { call transfer };
+allow test_binder_client_t test_binder_provider_no_fd_t:binder { call impersonate };
+allow test_binder_provider_no_fd_t device_t:chr_file { ioctl open read write };
+allow_map(test_binder_provider_no_fd_t, device_t, chr_file)
+# For writing to flag file:
+allow test_binder_provider_no_fd_t test_file_t:fifo_file rw_file_perms;
 
 #
-#################### Service Provider no transfer #############################
-#
-type test_binder_provider_no_transfer_t;
-domain_type(test_binder_provider_no_transfer_t)
-unconfined_runs_test(test_binder_provider_no_transfer_t)
-typeattribute test_binder_provider_no_transfer_t testdomain;
-typeattribute test_binder_provider_no_transfer_t binderdomain;
-allow test_binder_provider_no_transfer_t test_binder_mgr_t:binder { call };
-allow test_binder_provider_no_transfer_t device_t:chr_file { ioctl open read write };
-allow_map(test_binder_provider_no_transfer_t, device_t, chr_file)
-fs_getattr_tmpfs(test_binder_provider_no_transfer_t)
-allow test_binder_provider_no_transfer_t tmpfs_t:file { read write open };
-allow_map(test_binder_provider_no_transfer_t, tmpfs_t, file)
-fs_manage_tmpfs_dirs(test_binder_provider_no_transfer_t)
-fs_manage_tmpfs_files(test_binder_provider_no_transfer_t)
+################################# Client ####################################
+#
+type test_binder_client_t;
+domain_type(test_binder_client_t)
+unconfined_runs_test(test_binder_client_t)
+typeattribute test_binder_client_t testdomain;
+typeattribute test_binder_client_t binderdomain;
+allow test_binder_client_t test_binder_provider_t:binder { call impersonate };
+allow test_binder_client_t test_binder_mgr_t:binder { call };
+allow test_binder_client_t test_binder_provider_t:fd { use };
+allow test_binder_client_t device_t:chr_file { getattr ioctl open read write };
+allow_map(test_binder_client_t, device_t, chr_file)
 
 #
-#################### Service Provider no impersonate ##########################
-#
-type test_binder_provider_no_im_t;
-domain_type(test_binder_provider_no_im_t)
-unconfined_runs_test(test_binder_provider_no_im_t)
-typeattribute test_binder_provider_no_im_t testdomain;
-typeattribute test_binder_provider_no_im_t binderdomain;
-allow test_binder_provider_no_im_t self:binder { call };
-allow test_binder_provider_no_im_t test_binder_mgr_t:binder { call transfer };
-allow test_binder_provider_no_im_t device_t:chr_file { ioctl open read write };
-allow_map(test_binder_provider_no_im_t, device_t, chr_file)
-allow test_binder_provider_no_im_t test_binder_mgr_t:fd use;
-allow test_binder_provider_no_im_t device_t:chr_file getattr;
-fs_getattr_tmpfs(test_binder_provider_no_im_t)
-allow test_binder_provider_no_im_t tmpfs_t:file { read write open };
-allow_map(test_binder_provider_no_im_t, tmpfs_t, file)
-fs_manage_tmpfs_dirs(test_binder_provider_no_im_t)
-fs_manage_tmpfs_files(test_binder_provider_no_im_t)
+######################## Client No call Manager #############################
+#
+type test_binder_client_no_call_mgr_t;
+domain_type(test_binder_client_no_call_mgr_t)
+unconfined_runs_test(test_binder_client_no_call_mgr_t)
+typeattribute test_binder_client_no_call_mgr_t testdomain;
+typeattribute test_binder_client_no_call_mgr_t binderdomain;
+allow test_binder_client_no_call_mgr_t test_binder_provider_t:binder { call impersonate };
+allow test_binder_client_no_call_mgr_t device_t:chr_file { getattr ioctl open read write };
+allow_map(test_binder_client_no_call_mgr_t, device_t, chr_file)
+
+#
+################## Client No call Service Provider ##########################
+#
+type test_binder_client_no_call_sp_t;
+domain_type(test_binder_client_no_call_sp_t)
+unconfined_runs_test(test_binder_client_no_call_sp_t)
+typeattribute test_binder_client_no_call_sp_t testdomain;
+typeattribute test_binder_client_no_call_sp_t binderdomain;
+allow test_binder_mgr_t test_binder_client_no_call_sp_t:binder { transfer };
+allow test_binder_client_no_call_sp_t test_binder_mgr_t:binder { call };
+allow test_binder_client_no_call_sp_t device_t:chr_file { getattr ioctl open read write };
+allow_map(test_binder_client_no_call_sp_t, device_t, chr_file)
+
+#
+######################## Client No impersonate ##############################
+#
+type test_binder_client_no_im_t;
+domain_type(test_binder_client_no_im_t)
+unconfined_runs_test(test_binder_client_no_im_t)
+typeattribute test_binder_client_no_im_t testdomain;
+typeattribute test_binder_client_no_im_t binderdomain;
+allow test_binder_mgr_t test_binder_client_no_im_t:binder { transfer };
+allow test_binder_client_no_im_t test_binder_provider_t:binder { call };
+allow test_binder_client_no_im_t test_binder_mgr_t:binder { call };
+allow test_binder_client_no_im_t test_binder_provider_t:fd { use };
+allow test_binder_client_no_im_t device_t:chr_file { getattr ioctl open read write };
+allow_map(test_binder_client_no_im_t, device_t, chr_file)
+
+#
+########################## Client No transfer ###############################
+#
+type test_binder_client_no_transfer_t;
+domain_type(test_binder_client_no_transfer_t)
+unconfined_runs_test(test_binder_client_no_transfer_t)
+typeattribute test_binder_client_no_transfer_t testdomain;
+typeattribute test_binder_client_no_transfer_t binderdomain;
+allow test_binder_client_no_transfer_t test_binder_mgr_t:binder { call };
+allow test_binder_client_no_transfer_t test_binder_provider_t:binder { call impersonate };
+allow test_binder_client_no_transfer_t device_t:chr_file { getattr ioctl open read write };
+allow_map(test_binder_client_no_transfer_t, device_t, chr_file)
 
 #
-############ Allow these domains to be entered from sysadm domain ############
+########### Allow these domains to be entered from sysadm domain ############
 #
 miscfiles_domain_entry_test_files(binderdomain)
 userdom_sysadm_entry_spec_domtrans_to(binderdomain)
diff --git a/tests/binder/.gitignore b/tests/binder/.gitignore
index 37a2dd7..dc6ce20 100644
--- a/tests/binder/.gitignore
+++ b/tests/binder/.gitignore
@@ -1,3 +1,5 @@ 
 check_binder
-test_binder
-thread
+check_binderfs
+manager
+service_provider
+client
diff --git a/tests/binder/Makefile b/tests/binder/Makefile
index 0d76723..32f9a83 100644
--- a/tests/binder/Makefile
+++ b/tests/binder/Makefile
@@ -1,7 +1,18 @@ 
-TARGETS = check_binder test_binder
+# Required for local building
+INCLUDEDIR ?= /usr/include
 
+TARGETS = check_binder client manager service_provider
 LDLIBS += -lselinux -lrt
+DEPS = binder_common.c binder_common.h
+
+ifeq ($(shell test -e $(INCLUDEDIR)/linux/android/binderfs.h && echo true),true)
+CFLAGS += -DHAVE_BINDERFS
+TARGETS += check_binderfs
+endif
 
 all: $(TARGETS)
+
 clean:
 	rm -f $(TARGETS)
+
+$(TARGETS): $(DEPS)
diff --git a/tests/binder/binder_common.c b/tests/binder/binder_common.c
new file mode 100644
index 0000000..a240453
--- /dev/null
+++ b/tests/binder/binder_common.c
@@ -0,0 +1,155 @@ 
+/*
+ * This is a simple binder Service Manager/Service Provider that only uses
+ * the raw ioctl commands to test the SELinux binder permissions:
+ *     set_context_mgr, call, transfer, impersonate.
+ *
+ * Using binder test policy the following will be validated:
+ *    security_binder_set_context_mgr() binder { set_context_mgr }
+ *    security_binder_transaction()     binder { call impersonate }
+ *    security_binder_transfer_binder() binder { transfer }
+ *    security_binder_transfer_file()   fd { use }
+ *
+ * TODO security_binder_transfer_file() uses BPF if configured in kernel.
+ */
+
+#include "binder_common.h"
+
+const char *cmd_name(uint32_t cmd)
+{
+	switch (cmd) {
+	case BR_NOOP:
+		return "BR_NOOP";
+	case BR_TRANSACTION_COMPLETE:
+		return "BR_TRANSACTION_COMPLETE";
+	case BR_INCREFS:
+		return "BR_INCREFS";
+	case BR_ACQUIRE:
+		return "BR_ACQUIRE";
+	case BR_RELEASE:
+		return "BR_RELEASE";
+	case BR_DECREFS:
+		return "BR_DECREFS";
+	case BR_TRANSACTION:
+		return "BR_TRANSACTION";
+#if HAVE_BINDERFS
+	case BR_TRANSACTION_SEC_CTX:
+		return "BR_TRANSACTION_SEC_CTX";
+#endif
+	case BR_REPLY:
+		return "BR_REPLY";
+	case BR_FAILED_REPLY:
+		return "BR_FAILED_REPLY";
+	case BR_DEAD_REPLY:
+		return "BR_DEAD_REPLY";
+	case BR_DEAD_BINDER:
+		return "BR_DEAD_BINDER";
+	case BR_ERROR:
+		return "BR_ERROR";
+	/* fallthrough */
+	default:
+		return "Unknown Binder return code";
+	}
+}
+
+void print_trans_data(const struct binder_transaction_data *txn_in)
+{
+	const struct flat_binder_object *obj;
+	binder_size_t *offs = (binder_size_t *)
+			      (binder_uintptr_t)txn_in->data.ptr.offsets;
+	size_t count = txn_in->offsets_size / sizeof(binder_size_t);
+
+	printf("\thandle: %d\n", (uint32_t)txn_in->target.handle);
+	printf("\tcookie: %lld\n", txn_in->cookie);
+	switch (txn_in->code) {
+	case TEST_SERVICE_ADD:
+		printf("\tcode: TEST_SERVICE_ADD\n");
+		break;
+	case TEST_SERVICE_GET:
+		printf("\tcode: TEST_SERVICE_GET\n");
+		break;
+	case TEST_SERVICE_SEND_CLIENT_SP_FD:
+		printf("\tcode: TEST_SERVICE_SEND_CLIENT_SP_FD\n");
+		break;
+	default:
+		printf("Unknown binder_transaction_data->code: %x\n",
+		       txn_in->code);
+		return;
+	}
+
+	switch (txn_in->flags) {
+	case TF_ONE_WAY:
+		printf("\tflag: TF_ONE_WAY\n");
+		break;
+	case TF_ROOT_OBJECT:
+		printf("\tflag: TF_ROOT_OBJECT\n");
+		break;
+	case TF_STATUS_CODE:
+		printf("\tflag: TF_STATUS_CODE\n");
+		break;
+	case TF_ACCEPT_FDS:
+		printf("\tflag: TF_ACCEPT_FDS\n");
+		break;
+	default:
+		printf("Unknown flag: %x\n", txn_in->flags);
+		return;
+	}
+	printf("\tsender pid: %u\n", txn_in->sender_pid);
+	printf("\tsender euid: %u\n", txn_in->sender_euid);
+	printf("\tdata_size: %llu\n", txn_in->data_size);
+	printf("\toffsets_size: %llu\n", txn_in->offsets_size);
+
+	while (count--) {
+		obj = (const struct flat_binder_object *)
+		      (((char *)(binder_uintptr_t)txn_in->data.ptr.buffer) + *offs++);
+
+		switch (obj->hdr.type) {
+		case BINDER_TYPE_BINDER:
+			printf("\thdr: BINDER_TYPE_BINDER\n");
+			printf("\tbinder: %llx\n", obj->binder);
+			break;
+		case BINDER_TYPE_HANDLE:
+			printf("\thdr: BINDER_TYPE_HANDLE\n");
+			printf("\thandle: %x\n", obj->handle);
+			break;
+		case BINDER_TYPE_FD:
+			printf("\thdr: BINDER_TYPE_FD\n");
+			printf("\tfd: %x\n", obj->handle);
+			break;
+		default:
+			printf("Unknown header: %u\n", obj->hdr.type);
+			return;
+		}
+#if HAVE_BINDERFS
+		printf("\tflags: priority: 0x%x accept FDS: %s request security CTX: %s\n",
+		       obj->flags & FLAT_BINDER_FLAG_PRIORITY_MASK,
+		       obj->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS ? "YES" : "NO",
+		       obj->flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX ? "YES" : "NO");
+#else
+		printf("\tflags: priority: 0x%x accept FDS: %s\n",
+		       obj->flags & FLAT_BINDER_FLAG_PRIORITY_MASK,
+		       obj->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS ? "YES" : "NO");
+#endif
+		printf("\tcookie: %llx\n", obj->cookie);
+	}
+	fflush(stdout);
+}
+
+int binder_write(int fd, void *data, size_t len)
+{
+	struct binder_write_read bwr;
+	int result;
+
+	bwr.write_size = len;
+	bwr.write_consumed = 0;
+	bwr.write_buffer = (binder_uintptr_t)data;
+	bwr.read_size = 0;
+	bwr.read_consumed = 0;
+	bwr.read_buffer = 0;
+
+	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr, "binder_write ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+	}
+	return result;
+}
diff --git a/tests/binder/binder_common.h b/tests/binder/binder_common.h
new file mode 100644
index 0000000..bcf9e0c
--- /dev/null
+++ b/tests/binder/binder_common.h
@@ -0,0 +1,37 @@ 
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <selinux/selinux.h>
+#include <linux/android/binder.h>
+#if HAVE_BINDERFS
+#include <linux/android/binderfs.h>
+#endif
+
+#define BINDER_DEV "/dev/binder"
+#define BINDERFS_DEV "/dev/binderfs"
+#define BINDERFS_NAME "binder-test"
+#define BINDERFS_CONTROL "/dev/binderfs/binder-control"
+#define BINDER_MMAP_SIZE 1024
+
+#define TEST_SERVICE_MANAGER_HANDLE 0
+/* These are the Binder txn->code values used by the Service Provider, Client
+ * and Manager to request/retrieve a binder handle or file descriptor.
+ */
+#define TEST_SERVICE_ADD		240616 /* Sent by Service Provider */
+#define TEST_SERVICE_GET		290317 /* Sent by Client */
+#define TEST_SERVICE_SEND_CLIENT_SP_FD	120419 /* Sent by Client */
+
+bool verbose;
+
+const char *cmd_name(uint32_t cmd);
+void print_trans_data(const struct binder_transaction_data *txn_in);
+int binder_write(int fd, void *data, size_t len);
diff --git a/tests/binder/check_binder.c b/tests/binder/check_binder.c
index 7b81a3d..2fc8d77 100644
--- a/tests/binder/check_binder.c
+++ b/tests/binder/check_binder.c
@@ -1,13 +1,4 @@ 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-#include <linux/android/binder.h>
+#include "binder_common.h"
 
 static void usage(char *progname)
 {
@@ -21,10 +12,8 @@  static void usage(char *progname)
 int main(int argc, char **argv)
 {
 	int opt, result, fd;
-	char *driver = "/dev/binder";
-	bool verbose;
 	void *mapped;
-	size_t mapsize = 1024;
+	size_t mapsize = BINDER_MMAP_SIZE;
 	struct binder_version vers;
 
 	while ((opt = getopt(argc, argv, "v")) != -1) {
@@ -37,14 +26,15 @@  int main(int argc, char **argv)
 		}
 	}
 
-	fd = open(driver, O_RDWR | O_CLOEXEC);
+	fd = open(BINDER_DEV, O_RDWR | O_CLOEXEC);
 	if (fd < 0) {
 		fprintf(stderr, "Cannot open: %s error: %s\n",
-			driver, strerror(errno));
-		exit(1);
+			BINDER_DEV, strerror(errno));
+		result = 1;
+		return result;
 	}
 
-	/* Need this or no VMA error from kernel */
+	/* Need this or 'no VMA error' from kernel */
 	mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
 	if (mapped == MAP_FAILED) {
 		fprintf(stderr, "mmap error: %s\n", strerror(errno));
@@ -69,8 +59,7 @@  int main(int argc, char **argv)
 	}
 
 	if (verbose)
-		fprintf(stderr, "Binder kernel version: %d\n",
-			vers.protocol_version);
+		printf("Binder kernel version: %d\n", vers.protocol_version);
 
 brexit:
 	munmap(mapped, mapsize);
diff --git a/tests/binder/check_binderfs.c b/tests/binder/check_binderfs.c
new file mode 100644
index 0000000..b016755
--- /dev/null
+++ b/tests/binder/check_binderfs.c
@@ -0,0 +1,53 @@ 
+#include "binder_common.h"
+
+static void usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v]\n"
+		"Where:\n\t"
+		"-v Print new device information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, fd, result;
+	size_t len;
+	struct binderfs_device device = { 0 };
+
+	while ((opt = getopt(argc, argv, "v")) != -1) {
+		switch (opt) {
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	len = strlen(BINDERFS_NAME);
+	memcpy(device.name, BINDERFS_NAME, len);
+
+	fd = open(BINDERFS_CONTROL, O_RDONLY | O_CLOEXEC);
+	if (fd < 0) {
+		fprintf(stderr, "Failed to open binder-control device: %s\n",
+			strerror(errno));
+		return 1;
+	}
+
+	result = ioctl(fd, BINDER_CTL_ADD, &device);
+	if (result < 0) {
+		fprintf(stderr, "Failed to allocate new binder device: %s\n",
+			strerror(errno));
+		result = 2;
+		goto brexit;
+	}
+
+	if (verbose)
+		printf("Allocated new binder device: major %d minor %d"
+		       " with name \"%s\"\n", device.major, device.minor,
+		       device.name);
+brexit:
+	close(fd);
+	return result;
+}
diff --git a/tests/binder/client.c b/tests/binder/client.c
new file mode 100644
index 0000000..e4e2a61
--- /dev/null
+++ b/tests/binder/client.c
@@ -0,0 +1,450 @@ 
+#include "binder_common.h"
+
+static int binder_parse(int fd, binder_uintptr_t ptr, binder_size_t size);
+static int transactions_complete;
+
+static void usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-c] [-n] [-r replies] [-v]\n"
+		"Where:\n\t"
+		"-c  Use the number of replies for the BR_TRANSACTION_COMPLETE"
+		" count.\n\t"
+		"-n  Use the /dev/binderfs name service.\n\t"
+		"-r  Number of replies expected that depends on the test.\n\t"
+		"    It can be the number of BR_TRANSACTION_COMPLETE if\n\t"
+		"    the -c option is set or number of times to issue the\n\t"
+		"    ioctl - BINDER_WRITE_READ command if -c not set.\n\t"
+		"-v  Print context and command information.\n\t"
+		"\nNote: Ensure this boolean command is run when "
+		"testing after a reboot:\n\t"
+		"setsebool allow_domain_fd_use=0\n", progname);
+	exit(-1);
+}
+
+static void client_alarm(int sig)
+{
+	fprintf(stderr, "Client timer expired waiting for Binder reply\n");
+	exit(-1);
+}
+
+/* This retrieves the Service Providers file descriptor, then using this
+ * sends a simple transaction to trigger the impersonate permission.
+ */
+static void extract_fd_and_respond(const struct binder_transaction_data *txn_in)
+{
+	int result;
+	uint32_t cmd;
+	struct stat sb;
+	struct binder_write_read bwr;
+	const struct binder_fd_object *obj;
+	struct {
+		uint32_t cmd;
+		struct binder_transaction_data txn;
+	} __attribute__((packed)) writebuf;
+	unsigned int readbuf[32];
+
+	binder_size_t *offs = (binder_size_t *)
+			      (binder_uintptr_t)txn_in->data.ptr.offsets;
+
+	/* Get the binder_fd_object that contains the Service Providers
+	 * binder file descriptor.
+	 */
+	obj = (const struct binder_fd_object *)
+	      (((char *)(binder_uintptr_t)txn_in->data.ptr.buffer) + *offs);
+
+	if (obj->hdr.type != BINDER_TYPE_FD) {
+		fprintf(stderr, "Header not BINDER_TYPE_FD: %d\n",
+			obj->hdr.type);
+		exit(130);
+	}
+
+	/* fstat this just to see if a valid fd */
+	result = fstat(obj->fd, &sb);
+	if (result < 0) {
+		fprintf(stderr, "Not a valid fd: %s\n", strerror(errno));
+		exit(131);
+	}
+
+	if (verbose)
+		printf("Client retrieved Service Providers fd: %d st_dev: %ld\n",
+		       obj->fd, sb.st_dev);
+
+	memset(&writebuf, 0, sizeof(writebuf));
+	memset(readbuf, 0, sizeof(readbuf));
+	memset(&bwr, 0, sizeof(bwr));
+
+	/* Send response using Service Providers fd to trigger
+	 * impersonate check.
+	 */
+	writebuf.cmd = BC_TRANSACTION;
+	writebuf.txn.target.handle = txn_in->target.handle;
+	writebuf.txn.cookie = txn_in->cookie;
+	writebuf.txn.code = txn_in->code;
+	writebuf.txn.flags = TF_ONE_WAY;
+
+	writebuf.txn.data_size = 0;
+	writebuf.txn.data.ptr.buffer = (binder_uintptr_t)NULL;
+	writebuf.txn.data.ptr.offsets = (binder_uintptr_t)NULL;
+	writebuf.txn.offsets_size = 0;
+
+	bwr.write_size = sizeof(writebuf);
+	bwr.write_consumed = 0;
+	bwr.write_buffer = (binder_uintptr_t)&writebuf;
+	bwr.read_size = sizeof(readbuf);
+	bwr.read_consumed = 0;
+	bwr.read_buffer = (binder_uintptr_t)readbuf;
+
+	result = ioctl(obj->fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr,
+			"Client ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+		exit(132);
+	}
+
+	if (verbose)
+		printf("Client read_consumed: %lld\n",
+		       bwr.read_consumed);
+
+	cmd = binder_parse(obj->fd, (binder_uintptr_t)readbuf,
+			   bwr.read_consumed);
+
+	if (cmd == BR_FAILED_REPLY ||
+	    cmd == BR_DEAD_REPLY ||
+	    cmd == BR_DEAD_BINDER) {
+		fprintf(stderr, "Client %s() failing command %s, exiting.\n",
+			__func__, cmd_name(cmd));
+		exit(133);
+	}
+
+	if (verbose)
+		printf("Client sent transaction using Service Providers FD: %d\n",
+		       obj->fd);
+}
+
+static void request_service_provider_fd(int fd, uint32_t handle)
+{
+	int result;
+	uint32_t cmd;
+	struct binder_write_read bwr;
+	struct {
+		uint32_t cmd;
+		struct binder_transaction_data txn;
+	} __attribute__((packed)) writebuf;
+	unsigned int readbuf[32];
+
+	memset(&writebuf, 0, sizeof(writebuf));
+	memset(readbuf, 0, sizeof(readbuf));
+	memset(&bwr, 0, sizeof(bwr));
+
+	writebuf.cmd = BC_TRANSACTION;
+	writebuf.txn.target.handle = handle;
+	writebuf.txn.cookie = 0;
+	writebuf.txn.code = TEST_SERVICE_SEND_CLIENT_SP_FD;
+	writebuf.txn.flags = TF_ACCEPT_FDS;
+
+	writebuf.txn.data_size = 0;
+	writebuf.txn.data.ptr.buffer = (binder_uintptr_t)NULL;
+	writebuf.txn.data.ptr.offsets = (binder_uintptr_t)NULL;
+	writebuf.txn.offsets_size = 0;
+
+	bwr.write_size = sizeof(writebuf);
+	bwr.write_consumed = 0;
+	bwr.write_buffer = (binder_uintptr_t)&writebuf;
+	bwr.read_size = sizeof(readbuf);
+	bwr.read_consumed = 0;
+	bwr.read_buffer = (binder_uintptr_t)readbuf;
+
+	if (verbose)
+		printf("Client sending transaction SEND_CLIENT_YOUR_BINDER_FD to handle: %d\n",
+		       handle);
+
+	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr, "Client ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+		exit(140);
+	}
+
+	cmd = binder_parse(fd, (binder_uintptr_t)readbuf, bwr.read_consumed);
+	if (cmd == BR_FAILED_REPLY ||
+	    cmd == BR_DEAD_REPLY ||
+	    cmd == BR_DEAD_BINDER) {
+		fprintf(stderr, "Client %s() failing command %s, exiting.\n",
+			__func__, cmd_name(cmd));
+		exit(141);
+	}
+}
+
+static void extract_handle_and_acquire(int fd,
+				       struct binder_transaction_data *txn_in)
+{
+	int result;
+	uint32_t acmd[2];
+	struct binder_write_read bwr;
+	const struct flat_binder_object *obj;
+	binder_size_t *offs = (binder_size_t *)
+			      (binder_uintptr_t)txn_in->data.ptr.offsets;
+
+	/* Get the fbo that contains the Service Provider's Handle. */
+	obj = (const struct flat_binder_object *)
+	      (((char *)(binder_uintptr_t)txn_in->data.ptr.buffer) + *offs);
+
+	if (obj->hdr.type != BINDER_TYPE_HANDLE) {
+		fprintf(stderr, "Client - Header not BINDER_TYPE_HANDLE: %d\n",
+			obj->hdr.type);
+		exit(150);
+	}
+
+	acmd[0] = BC_ACQUIRE;
+	acmd[1] = obj->handle;
+
+	memset(&bwr, 0, sizeof(bwr));
+	bwr.write_buffer = (binder_uintptr_t)&acmd;
+	bwr.write_size = sizeof(acmd);
+
+	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr,
+			"Client ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+		exit(151);
+	}
+
+	if (verbose)
+		printf("Client acquired binder handle: %d for Service Provider\n",
+		       obj->handle);
+
+	/* Now get their fd */
+	request_service_provider_fd(fd, obj->handle);
+
+}
+
+/* Parse response, reply as required and then return last CMD */
+static int binder_parse(int fd, binder_uintptr_t ptr, binder_size_t size)
+{
+	binder_uintptr_t end = ptr + size;
+	uint32_t cmd;
+
+	while (ptr < end) {
+		cmd = *(uint32_t *)ptr;
+		ptr += sizeof(uint32_t);
+
+		if (verbose)
+			printf("Client command: %s\n", cmd_name(cmd));
+
+		switch (cmd) {
+		case BR_NOOP:
+			break;
+		case BR_TRANSACTION_COMPLETE:
+			transactions_complete++;
+			break;
+		case BR_INCREFS:
+		case BR_ACQUIRE:
+		case BR_RELEASE:
+		case BR_DECREFS:
+			ptr += sizeof(const struct binder_ptr_cookie);
+			break;
+		case BR_TRANSACTION: {
+			struct binder_transaction_data *txn =
+				(struct binder_transaction_data *)ptr;
+
+			if (verbose) {
+				printf("Client BR_TRANSACTION data:\n");
+				print_trans_data(txn);
+			}
+
+			ptr += sizeof(*txn);
+			break;
+		}
+		case BR_REPLY: {
+			struct binder_transaction_data *txn =
+				(struct binder_transaction_data *)ptr;
+
+			if (verbose) {
+				printf("Client BR_REPLY data:\n");
+				print_trans_data(txn);
+			}
+
+			if (txn->code == TEST_SERVICE_GET)
+				extract_handle_and_acquire(fd, txn);
+
+			if (txn->code == TEST_SERVICE_SEND_CLIENT_SP_FD)
+				extract_fd_and_respond(txn);
+
+			ptr += sizeof(*txn);
+			break;
+		}
+		case BR_DEAD_BINDER:
+		case BR_FAILED_REPLY:
+		case BR_DEAD_REPLY:
+			break;
+		case BR_ERROR:
+			ptr += sizeof(uint32_t);
+			break;
+		default:
+			if (verbose)
+				printf("Client parsed unknown command: %d\n",
+				       cmd);
+			exit(160);
+		}
+	}
+	fflush(stdout);
+	return cmd;
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, fd, client_replies = 0, ioctl_wr = 0;
+	bool name = false;
+	bool use_transactions_complete = false;
+	uint32_t cmd;
+	pid_t pid;
+	char *context;
+	char dev_str[128];
+	void *map_base;
+	size_t map_size = BINDER_MMAP_SIZE;
+	struct binder_write_read bwr;
+	struct {
+		uint32_t cmd;
+		struct binder_transaction_data txn;
+	} __attribute__((packed)) writebuf;
+	unsigned int readbuf[32];
+
+	transactions_complete = 0;
+
+	while ((opt = getopt(argc, argv, "cnr:v")) != -1) {
+		switch (opt) {
+		case 'c':
+			use_transactions_complete = true;
+			break;
+		case 'n':
+			name = true;
+			break;
+		case 'r':
+			client_replies = atoi(optarg);
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	/* Get our context and pid */
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Client failed to obtain SELinux context\n");
+		exit(120);
+	}
+	pid = getpid();
+
+	if (verbose) {
+		printf("Client PID: %d Process context:\n\t%s\n",
+		       pid, context);
+	}
+	free(context);
+
+	if (name)
+		result = sprintf(dev_str, "%s/%s", BINDERFS_DEV, BINDERFS_NAME);
+	else
+		result = sprintf(dev_str, "%s", BINDER_DEV);
+
+	if (result < 0) {
+		fprintf(stderr, "Manager failed to obtain Binder dev name\n");
+		exit(121);
+	}
+
+	fd = open(dev_str, O_RDWR | O_CLOEXEC);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot open %s error: %s\n", dev_str,
+			strerror(errno));
+		exit(122);
+	}
+
+	map_base = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (map_base == MAP_FAILED) {
+		fprintf(stderr, "mmap error: %s\n", strerror(errno));
+		close(fd);
+		exit(123);
+	}
+
+	memset(&bwr, 0, sizeof(bwr));
+	memset(&writebuf, 0, sizeof(writebuf));
+	memset(readbuf, 0, sizeof(readbuf));
+
+	writebuf.cmd = BC_TRANSACTION;
+	writebuf.txn.target.handle = TEST_SERVICE_MANAGER_HANDLE;
+	writebuf.txn.cookie = 0;
+	writebuf.txn.code = TEST_SERVICE_GET;
+	writebuf.txn.flags = TF_ACCEPT_FDS;
+
+	writebuf.txn.data_size = 0;
+	writebuf.txn.offsets_size = 0;
+
+	writebuf.txn.data.ptr.buffer = (binder_uintptr_t)NULL;
+	writebuf.txn.data.ptr.offsets = (binder_uintptr_t)NULL;
+
+	bwr.write_buffer = (binder_uintptr_t)&writebuf;
+	bwr.write_size = sizeof(writebuf);
+	bwr.write_consumed = 0;
+
+	if (verbose)
+		printf("Client sending transaction to Manager - TEST_SERVICE_GET\n");
+
+	/* Set an alarm just in case Binder does not reply when sitting
+	 * on the ioctl BINDER_WRITE_READ
+	 */
+	signal(SIGALRM, client_alarm);
+	alarm(10);
+
+	/* Each Client test expects a different number of replies */
+	while (true) {
+		memset(readbuf, 0, sizeof(readbuf));
+		bwr.read_size = sizeof(readbuf);
+		bwr.read_consumed = 0;
+		bwr.read_buffer = (binder_uintptr_t)readbuf;
+
+		result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+		if (result < 0) {
+			fprintf(stderr,
+				"Client ioctl BINDER_WRITE_READ error: %s\n",
+				strerror(errno));
+			result = 124;
+			goto brexit;
+		}
+		ioctl_wr++;
+
+		if (verbose)
+			printf("Client read_consumed: %lld\n",
+			       bwr.read_consumed);
+
+		cmd = binder_parse(fd, (binder_uintptr_t)readbuf,
+				   bwr.read_consumed);
+
+		if (cmd == BR_FAILED_REPLY ||
+		    cmd == BR_DEAD_REPLY ||
+		    cmd == BR_DEAD_BINDER) {
+			fprintf(stderr, "Client %s() failing command %s, exiting.\n",
+				__func__, cmd_name(cmd));
+			result = 125;
+			goto brexit;
+		}
+
+		result = 0;
+		if (use_transactions_complete &&
+		    transactions_complete == client_replies)
+			break;
+		else if (!use_transactions_complete &&
+			 ioctl_wr == client_replies)
+			break;
+	}
+
+brexit:
+	munmap(map_base, map_size);
+	close(fd);
+
+	return result;
+}
diff --git a/tests/binder/manager.c b/tests/binder/manager.c
new file mode 100644
index 0000000..9922183
--- /dev/null
+++ b/tests/binder/manager.c
@@ -0,0 +1,362 @@ 
+#include "binder_common.h"
+
+/* Store the only service provider handle here. */
+uint32_t sp_handle;
+
+static int binder_parse(int fd, binder_uintptr_t ptr, binder_size_t size);
+static void reply_with_handle(int fd, struct binder_transaction_data *txn_in);
+
+static void usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-f file] [-n] [-v]\n"
+		"Where:\n\t"
+		"-f  Write a line to the file when listening starts.\n\t"
+		"-n  Use the /dev/binderfs name service.\n\t"
+		"-v  Print context and command information.\n\t"
+		"\nNote: Ensure this boolean command is run when "
+		"testing after a reboot:\n\t"
+		"setsebool allow_domain_fd_use=0\n", progname);
+	exit(-1);
+}
+
+static void do_service_manager(int fd, struct binder_transaction_data *txn_in)
+{
+	int result;
+	const struct flat_binder_object *obj;
+	struct binder_write_read bwr;
+	uint32_t acmd[2];
+	binder_size_t *offs;
+
+	struct {
+		uint32_t cmd_reply;
+		struct binder_transaction_data txn;
+	} __attribute__((packed)) reply;
+
+	switch (txn_in->code) {
+	case TEST_SERVICE_ADD:
+		offs = (binder_size_t *)(binder_uintptr_t)txn_in->data.ptr.offsets;
+
+		/* Get fbo that contains the Service Providers handle. */
+		obj = (const struct flat_binder_object *)
+		      (((char *)(binder_uintptr_t)txn_in->data.ptr.buffer) + *offs);
+
+		if (obj->hdr.type == BINDER_TYPE_HANDLE) {
+			sp_handle = obj->handle;
+
+			if (verbose)
+				printf("Manager has TEST_SERVICE_ADD obj->handle: %d\n",
+				       sp_handle);
+		} else {
+			fprintf(stderr, "Manager failed to obtain a handle\n");
+			exit(20);
+		}
+
+		acmd[0] = BC_ACQUIRE;
+		acmd[1] = obj->handle;
+
+		memset(&bwr, 0, sizeof(bwr));
+		bwr.write_buffer = (binder_uintptr_t)&acmd;
+		bwr.write_size = sizeof(acmd);
+
+		result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+		if (result < 0) {
+			fprintf(stderr,
+				"Manager ioctl BINDER_WRITE_READ error: %s\n",
+				strerror(errno));
+			exit(21);
+		}
+
+		if (verbose)
+			printf("Manager acquired binder handle: %d for Service Provider\n",
+			       sp_handle);
+
+		/* Inform the Service Provider of outcome. */
+		reply.cmd_reply = BC_REPLY;
+		reply.txn.target.ptr = 0;
+		reply.txn.cookie = txn_in->cookie;
+		reply.txn.code = txn_in->code;
+		reply.txn.flags = TF_STATUS_CODE;
+		reply.txn.data_size = sizeof(int);
+		reply.txn.offsets_size = 0;
+		reply.txn.data.ptr.buffer = (binder_uintptr_t)&result;
+		reply.txn.data.ptr.offsets = 0;
+		binder_write(fd, &reply, sizeof(reply));
+		break;
+	case TEST_SERVICE_GET:
+		if (verbose)
+			printf("Manager has TEST_SERVICE_GET handle: %d\n",
+			       sp_handle);
+
+		reply_with_handle(fd, txn_in);
+
+		break;
+	case TEST_SERVICE_SEND_CLIENT_SP_FD:
+		if (verbose)
+			printf("Manager Rx'ed SEND_CLIENT_YOUR_BINDER_FD for handle: %d\n",
+			       txn_in->target.handle);
+		break;
+	default:
+		fprintf(stderr, "Manager unknown txn->code: %d for handle: %d\n",
+			txn_in->code, txn_in->target.handle);
+		exit(22);
+	}
+}
+
+static void reply_with_handle(int fd, struct binder_transaction_data *txn_in)
+{
+	int result;
+	unsigned int writebuf[1024];
+	binder_size_t offset = 0;
+	struct flat_binder_object obj;
+	struct binder_write_read bwr;
+	struct binder_transaction_data *txn;
+
+	if (verbose)
+		printf("Manager sending BC_REPLY to Client with handle\n");
+
+	memset(&writebuf, 0, sizeof(writebuf));
+	memset(&obj, 0, sizeof(obj));
+	memset(&bwr, 0, sizeof(bwr));
+
+	writebuf[0] = BC_REPLY;
+	txn = (struct binder_transaction_data *)(&writebuf[1]);
+	memset(txn, 0, sizeof(*txn));
+	txn->target.handle = txn_in->target.handle;
+	txn->cookie = txn_in->cookie;
+	txn->code = txn_in->code;
+	txn->flags = TF_ACCEPT_FDS;
+
+	obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+	obj.hdr.type = BINDER_TYPE_HANDLE;
+	obj.handle = sp_handle;
+	obj.cookie = 0;
+
+	txn->data_size = sizeof(obj);
+	txn->data.ptr.buffer = (binder_uintptr_t)&obj;
+	txn->data.ptr.offsets = (binder_uintptr_t)&offset;
+	txn->offsets_size = sizeof(offset);
+
+	bwr.write_buffer = (binder_uintptr_t)writebuf;
+	bwr.write_size = sizeof(writebuf[0]) + sizeof(*txn);
+
+	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr, "Manager ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+		exit(30);
+	}
+
+	if (verbose)
+		printf("Manager sent Service Provider handle: %d to Client\n",
+		       sp_handle);
+}
+
+/* Parse response, reply as required and then return last CMD */
+static int binder_parse(int fd, binder_uintptr_t ptr, binder_size_t size)
+{
+	binder_uintptr_t end = ptr + size;
+	uint32_t cmd;
+
+	while (ptr < end) {
+		cmd = *(uint32_t *)ptr;
+		ptr += sizeof(uint32_t);
+
+		if (verbose)
+			printf("Manager command: %s\n", cmd_name(cmd));
+
+		switch (cmd) {
+		case BR_NOOP:
+			break;
+		case BR_TRANSACTION_COMPLETE:
+			break;
+		case BR_INCREFS:
+		case BR_ACQUIRE:
+		case BR_RELEASE:
+		case BR_DECREFS:
+			ptr += sizeof(const struct binder_ptr_cookie);
+			break;
+		case BR_TRANSACTION: {
+			struct binder_transaction_data *txn =
+				(struct binder_transaction_data *)ptr;
+
+			if (verbose) {
+				printf("Manager BR_TRANSACTION data:\n");
+				print_trans_data(txn);
+			}
+
+			do_service_manager(fd, txn);
+			ptr += sizeof(*txn);
+			break;
+		}
+		case BR_REPLY: {
+			struct binder_transaction_data *txn =
+				(struct binder_transaction_data *)ptr;
+
+			if (verbose) {
+				printf("Manager BR_REPLY data:\n");
+				print_trans_data(txn);
+			}
+
+			ptr += sizeof(*txn);
+			break;
+		}
+		case BR_DEAD_BINDER:
+		case BR_FAILED_REPLY:
+		case BR_DEAD_REPLY:
+			break;
+		case BR_ERROR:
+			ptr += sizeof(uint32_t);
+			break;
+		default:
+			if (verbose)
+				printf("Manager parsed unknown command: %d\n",
+				       cmd);
+			exit(40);
+		}
+	}
+	fflush(stdout);
+	return cmd;
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, fd;
+	bool name = false;
+	pid_t pid;
+	char *context;
+	char *flag_file = NULL;
+	char dev_str[128];
+	FILE *flag_fd;
+	void *map_base;
+	size_t map_size = BINDER_MMAP_SIZE;
+	struct binder_write_read bwr;
+	unsigned int readbuf[32];
+
+	while ((opt = getopt(argc, argv, "f:nv")) != -1) {
+		switch (opt) {
+		case 'f':
+			flag_file = optarg;
+			break;
+		case 'n':
+			name = true;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	/* Get our context and pid */
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Manager failed to obtain SELinux context\n");
+		exit(10);
+	}
+	pid = getpid();
+
+	if (verbose) {
+		printf("Manager PID: %d Process context:\n\t%s\n",
+		       pid, context);
+	}
+	free(context);
+
+	if (name)
+		result = sprintf(dev_str, "%s/%s", BINDERFS_DEV, BINDERFS_NAME);
+	else
+		result = sprintf(dev_str, "%s", BINDER_DEV);
+
+	if (result < 0) {
+		fprintf(stderr, "Manager failed to obtain Binder dev name\n");
+		exit(11);
+	}
+
+	fd = open(dev_str, O_RDWR | O_CLOEXEC);
+	if (fd < 0) {
+		fprintf(stderr, "Manager cannot open %s error: %s\n",
+			dev_str, strerror(errno));
+		exit(12);
+	}
+
+	map_base = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (map_base == MAP_FAILED) {
+		fprintf(stderr, "Manager mmap error: %s\n", strerror(errno));
+		close(fd);
+		exit(13);
+	}
+
+	result = ioctl(fd, BINDER_SET_CONTEXT_MGR, 0);
+	if (result < 0) {
+		fprintf(stderr,
+			"Manager failed to become context manager: %s\n",
+			strerror(errno));
+		result = 14;
+		goto brexit;
+	}
+
+	if (flag_file) {
+		flag_fd = fopen(flag_file, "w");
+		if (!flag_fd) {
+			fprintf(stderr,
+				"Manager failed to open %s: %s\n",
+				flag_file, strerror(errno));
+			result = 15;
+			goto brexit;
+		}
+		fprintf(flag_fd, "listening\n");
+		fclose(flag_fd);
+	}
+
+	memset(readbuf, 0, sizeof(readbuf));
+	memset(&bwr, 0, sizeof(bwr));
+
+	readbuf[0] = BC_ENTER_LOOPER;
+	bwr.write_size = sizeof(readbuf[0]);
+	bwr.write_consumed = 0;
+	bwr.write_buffer = (binder_uintptr_t)readbuf;
+	bwr.read_size = 0;
+	bwr.read_consumed = 0;
+	bwr.read_buffer = 0;
+
+	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr,
+			"Manager ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+		result = 16;
+		goto brexit;
+	}
+
+	while (true) {
+		memset(readbuf, 0, sizeof(readbuf));
+		bwr.read_size = sizeof(readbuf);
+		bwr.read_consumed = 0;
+		bwr.read_buffer = (binder_uintptr_t)readbuf;
+
+		result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+		if (result < 0) {
+			fprintf(stderr,
+				"Manager ioctl BINDER_WRITE_READ error: %s\n",
+				strerror(errno));
+			result = 17;
+			goto brexit;
+		}
+
+		if (bwr.read_consumed == 0)
+			continue;
+
+		if (verbose)
+			printf("Manager read_consumed: %lld\n",
+			       bwr.read_consumed);
+
+		binder_parse(fd, (binder_uintptr_t)readbuf, bwr.read_consumed);
+	}
+
+brexit:
+	munmap(map_base, map_size);
+	close(fd);
+
+	return result;
+}
diff --git a/tests/binder/service_provider.c b/tests/binder/service_provider.c
new file mode 100644
index 0000000..2873af8
--- /dev/null
+++ b/tests/binder/service_provider.c
@@ -0,0 +1,404 @@ 
+#include "binder_common.h"
+
+static char *expected_ctx;
+static int binder_parse(int fd, binder_uintptr_t ptr, binder_size_t size);
+
+static void usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-e expected_ctx] [-f file] [-n] [-v]\n"
+		"Where:\n\t"
+		"-e  Expected security context.\n\t"
+		"-f  Write a line to the file when listening starts.\n\t"
+		"-n  Use the /dev/binderfs name service.\n\t"
+		"-v  Print context and command information.\n\t"
+		"\nNote: Ensure this boolean command is run when "
+		"testing after a reboot:\n\t"
+		"setsebool allow_domain_fd_use=0\n", progname);
+	exit(-1);
+}
+
+static void request_service_provider_fd(int fd,
+					struct binder_transaction_data *txn_in)
+{
+	int result;
+	unsigned int writebuf[1024];
+	struct binder_fd_object obj;
+	binder_size_t offset = 0;
+	struct binder_write_read bwr;
+	struct binder_transaction_data *txn;
+
+	if (txn_in->flags == TF_ONE_WAY && verbose) {
+		printf("Service Provider no reply to BC_TRANSACTION as flags = TF_ONE_WAY\n");
+		return;
+	}
+
+	if (verbose)
+		printf("Service Provider sending BC_REPLY with its FD\n");
+
+	memset(writebuf, 0, sizeof(writebuf));
+	memset(&bwr, 0, sizeof(bwr));
+	memset(&obj, 0, sizeof(obj));
+
+	writebuf[0] = BC_REPLY;
+	txn = (struct binder_transaction_data *)(&writebuf[1]);
+	memset(txn, 0, sizeof(*txn));
+	txn->target.handle = txn_in->target.handle;
+	txn->cookie = txn_in->cookie;
+	txn->code = txn_in->code;
+	txn->flags = TF_ACCEPT_FDS;
+
+	obj.hdr.type = BINDER_TYPE_FD;
+#if HAVE_BINDERFS
+	obj.pad_flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS |
+			FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
+#else
+	obj.pad_flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+#endif
+	obj.cookie = txn->cookie;
+	/* The Service Providers binder fd is used for testing as it allows
+	 * policy to set whether the Service Provider and Client can be
+	 * allowed access (fd use) or not.
+	 * This also allows a check for the impersonate permission later as
+	 * the Client will use the Service Provider fd to send a transaction.
+	 */
+	obj.fd = fd;
+
+	if (verbose)
+		printf("Service Provider handle: %d and its FD: %d\n",
+		       txn->target.handle, fd);
+
+	txn->data_size = sizeof(obj);
+	txn->data.ptr.buffer = (binder_uintptr_t)&obj;
+	txn->data.ptr.offsets = (binder_uintptr_t)&offset;
+	txn->offsets_size = sizeof(offset);
+
+	bwr.write_buffer = (binder_uintptr_t)writebuf;
+	bwr.write_size = sizeof(writebuf[0]) + sizeof(*txn);
+
+	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr,
+			"Service Provider ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+		exit(70);
+	}
+}
+
+/* Parse response, reply as required and then return last CMD */
+static int binder_parse(int fd, binder_uintptr_t ptr, binder_size_t size)
+{
+	binder_uintptr_t end = ptr + size;
+	uint32_t cmd;
+
+	while (ptr < end) {
+		cmd = *(uint32_t *)ptr;
+		ptr += sizeof(uint32_t);
+
+		if (verbose)
+			printf("Service Provider command: %s\n",
+			       cmd_name(cmd));
+
+		switch (cmd) {
+		case BR_NOOP:
+			break;
+		case BR_TRANSACTION_COMPLETE:
+			break;
+		case BR_INCREFS:
+		case BR_ACQUIRE:
+		case BR_RELEASE:
+		case BR_DECREFS:
+			ptr += sizeof(const struct binder_ptr_cookie);
+			break;
+		case BR_TRANSACTION: {
+			struct binder_transaction_data *txn =
+				(struct binder_transaction_data *)ptr;
+
+			if (verbose) {
+				printf("Service Provider BR_TRANSACTION data:\n");
+				print_trans_data(txn);
+			}
+
+			if (txn->code == TEST_SERVICE_SEND_CLIENT_SP_FD)
+				request_service_provider_fd(fd, txn);
+
+			ptr += sizeof(*txn);
+			break;
+		}
+#if HAVE_BINDERFS
+		case BR_TRANSACTION_SEC_CTX: {
+			struct binder_transaction_data_secctx *txn_ctx =
+				(struct binder_transaction_data_secctx *)ptr;
+
+			if (verbose) {
+				printf("\tclient context:\n\t\t%s\n",
+				       (char *)txn_ctx->secctx);
+				print_trans_data(&txn_ctx->transaction_data);
+			}
+
+			if (expected_ctx) {
+				int result = strcmp(expected_ctx,
+						    (char *)txn_ctx->secctx);
+				if (result) {
+					fprintf(stderr, "Service Provider received incorrect context:\n");
+					fprintf(stderr, "Expected: %s\nReceived: %s\n",
+						expected_ctx,
+						(char *)txn_ctx->secctx);
+					exit(80);
+				}
+			}
+
+			if (txn_ctx->transaction_data.code ==
+			    TEST_SERVICE_SEND_CLIENT_SP_FD)
+				request_service_provider_fd(fd,
+							    &txn_ctx->transaction_data);
+
+			ptr += sizeof(*txn_ctx);
+			break;
+		}
+#endif
+		case BR_REPLY: {
+			struct binder_transaction_data *txn =
+				(struct binder_transaction_data *)ptr;
+
+			if (verbose) {
+				printf("Service Provider BR_REPLY data:\n");
+				print_trans_data(txn);
+			}
+
+			ptr += sizeof(*txn);
+			break;
+		}
+		case BR_DEAD_BINDER:
+		case BR_FAILED_REPLY:
+		case BR_DEAD_REPLY:
+			break;
+		case BR_ERROR:
+			ptr += sizeof(uint32_t);
+			break;
+		default:
+			if (verbose)
+				printf("Service Provider parsed unknown command: %d\n",
+				       cmd);
+			exit(81);
+		}
+	}
+	fflush(stdout);
+	return cmd;
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, fd;
+	bool name = false;
+	uint32_t cmd;
+	pid_t pid;
+	char *context;
+	char *flag_file = NULL;
+	char dev_str[128];
+	FILE *flag_fd;
+	void *map_base;
+	size_t map_size = BINDER_MMAP_SIZE;
+	binder_size_t offset = 0;
+	struct binder_write_read bwr;
+	struct flat_binder_object obj;
+	struct {
+		uint32_t cmd;
+		struct binder_transaction_data txn;
+	} __attribute__((packed)) writebuf;
+	unsigned int readbuf[32];
+
+	expected_ctx = NULL;
+
+	while ((opt = getopt(argc, argv, "e:f:nv")) != -1) {
+		switch (opt) {
+		case 'e':
+			expected_ctx = optarg;
+			break;
+		case 'f':
+			flag_file = optarg;
+			break;
+		case 'n':
+			name = true;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	/* Get our context and pid */
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Service Provider failed to obtain SELinux context\n");
+		exit(60);
+	}
+	pid = getpid();
+
+	if (verbose) {
+		printf("Service Provider PID: %d Process context:\n\t%s\n",
+		       pid, context);
+	}
+	free(context);
+
+	if (name)
+		result = sprintf(dev_str, "%s/%s", BINDERFS_DEV, BINDERFS_NAME);
+	else
+		result = sprintf(dev_str, "%s", BINDER_DEV);
+
+	if (result < 0) {
+		fprintf(stderr, "Manager failed to obtain Binder dev name\n");
+		exit(61);
+	}
+
+	fd = open(dev_str, O_RDWR | O_CLOEXEC);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot open %s error: %s\n", dev_str,
+			strerror(errno));
+		exit(62);
+	}
+
+	map_base = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (map_base == MAP_FAILED) {
+		fprintf(stderr, "mmap error: %s\n", strerror(errno));
+		close(fd);
+		exit(63);
+	}
+
+	if (flag_file) {
+		flag_fd = fopen(flag_file, "w");
+		if (!flag_fd) {
+			fprintf(stderr,
+				"Service Provider failed to open %s: %s\n",
+				flag_file, strerror(errno));
+			result = 64;
+			goto brexit;
+		}
+		fprintf(flag_fd, "listening\n");
+		fclose(flag_fd);
+	}
+
+	memset(&writebuf, 0, sizeof(writebuf));
+	memset(&obj, 0, sizeof(obj));
+	memset(readbuf, 0, sizeof(readbuf));
+
+	writebuf.cmd = BC_TRANSACTION;
+	writebuf.txn.target.handle = TEST_SERVICE_MANAGER_HANDLE;
+	writebuf.txn.cookie = 0;
+	writebuf.txn.code = TEST_SERVICE_ADD;
+	writebuf.txn.flags = TF_ROOT_OBJECT;
+
+	obj.hdr.type = BINDER_TYPE_BINDER;
+#if HAVE_BINDERFS
+	obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS |
+		    FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
+#else
+	obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+#endif
+	obj.binder = (binder_uintptr_t)NULL;
+	obj.cookie = 0;
+
+	writebuf.txn.data_size = sizeof(obj);
+	writebuf.txn.offsets_size = sizeof(offset);
+
+	writebuf.txn.data.ptr.buffer = (binder_uintptr_t)&obj;
+	writebuf.txn.data.ptr.offsets = (binder_uintptr_t)&offset;
+
+	bwr.write_buffer = (binder_uintptr_t)&writebuf;
+	bwr.write_size = sizeof(writebuf);
+	bwr.write_consumed = 0;
+
+	if (verbose)
+		printf("Service Provider sending transaction to Manager - TEST_SERVICE_ADD\n");
+
+	bwr.read_size = sizeof(readbuf);
+	bwr.read_consumed = 0;
+	bwr.read_buffer = (binder_uintptr_t)readbuf;
+
+	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr,
+			"Service Provider ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+		result = 65;
+		goto brexit;
+	}
+
+	if (verbose)
+		printf("Service Provider read_consumed: %lld\n",
+		       bwr.read_consumed);
+
+	cmd = binder_parse(fd, (binder_uintptr_t)readbuf,
+			   bwr.read_consumed);
+
+	if (cmd == BR_FAILED_REPLY ||
+	    cmd == BR_DEAD_REPLY ||
+	    cmd == BR_DEAD_BINDER) {
+		fprintf(stderr, "Service Provider %s() failing command %s, exiting.\n",
+			__func__, cmd_name(cmd));
+		result = 66;
+		goto brexit;
+	}
+
+	/* Service Provider loops on commands */
+	memset(readbuf, 0, sizeof(readbuf));
+	readbuf[0] = BC_ENTER_LOOPER;
+	bwr.write_size = sizeof(readbuf[0]);
+	bwr.write_consumed = 0;
+	bwr.write_buffer = (binder_uintptr_t)readbuf;
+
+	bwr.read_size = 0;
+	bwr.read_consumed = 0;
+	bwr.read_buffer = 0;
+
+	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+	if (result < 0) {
+		fprintf(stderr,
+			"Service Provider ioctl BINDER_WRITE_READ error: %s\n",
+			strerror(errno));
+		result = 67;
+		goto brexit;
+	}
+
+	while (true) {
+		memset(readbuf, 0, sizeof(readbuf));
+		bwr.read_size = sizeof(readbuf);
+		bwr.read_consumed = 0;
+		bwr.read_buffer = (binder_uintptr_t)readbuf;
+
+		result = ioctl(fd, BINDER_WRITE_READ, &bwr);
+		if (result < 0) {
+			fprintf(stderr,
+				"Service Provider ioctl BINDER_WRITE_READ error: %s\n",
+				strerror(errno));
+			result = 68;
+			goto brexit;
+		}
+
+		if (bwr.read_consumed == 0)
+			continue;
+
+		if (verbose)
+			printf("Service Provider read_consumed: %lld\n",
+			       bwr.read_consumed);
+
+		cmd = binder_parse(fd, (binder_uintptr_t)readbuf, bwr.read_consumed);
+
+		if (cmd == BR_FAILED_REPLY ||
+		    cmd == BR_DEAD_REPLY ||
+		    cmd == BR_DEAD_BINDER) {
+			fprintf(stderr, "Service Provider %s() failing command %s, exiting.\n",
+				__func__, cmd_name(cmd));
+			result = 69;
+			goto brexit;
+		}
+	}
+
+brexit:
+	munmap(map_base, map_size);
+	close(fd);
+
+	return result;
+}
diff --git a/tests/binder/test b/tests/binder/test
index e8aaec4..2ccaa23 100755
--- a/tests/binder/test
+++ b/tests/binder/test
@@ -5,7 +5,11 @@  BEGIN {
     $basedir = $0;
     $basedir =~ s|(.*)/[^/]*|$1|;
 
-    # allow binder info to be shown
+    $test_count      = 0;
+    $test_binderfs   = 0;
+    $test_binder_ctx = 0;
+
+    # Allow binder info to be shown.
     $v = $ARGV[0];
     if ($v) {
         if ( $v ne "-v" ) {
@@ -17,10 +21,10 @@  BEGIN {
     }
 
     # check if binder driver available and kernel/userspace versions.
-    $result = system("$basedir/check_binder 2> /dev/null");
+    $result = system("$basedir/check_binder $v 2>/dev/null");
 
     if ( $result >> 8 eq 0 ) {
-        plan tests => 6;
+        $test_count += 7;
     }
     elsif ( $result >> 8 eq 1 ) {
         plan skip_all => "Binder not supported by kernel";
@@ -31,73 +35,238 @@  BEGIN {
     else {
         plan skip_all => "Error checking Binder driver";
     }
+
+    # Check if kernel may have "binder: Add thread->process_todo flag" patch.
+    # This has been backported to some earlier kernels.
+    # Patch available from: https://lore.kernel.org/patchwork/patch/851324/
+    $kvercur = `uname -r`;
+    chomp($kvercur);
+    $kverminstream = "4.16";
+    $result        = `$basedir/../kvercmp $kvercur $kverminstream`;
+    if ( $result < 0 ) {
+        print "This $kvercur kernel may fail some tests, if so may require\n";
+        print
+          "\"binder: Add thread->process_todo flag\" patch available from:\n";
+        print "https://lore.kernel.org/patchwork/patch/851324/\n";
+    }
+
+    # Check if kernel supports binderfs and return of security context.
+    $kverminstream = "5.0";
+    $result        = `$basedir/../kvercmp $kvercur $kverminstream`;
+
+    if ( $result > 0 ) {
+        $test_binder_ctx = 1;
+        $test_count += 1;
+        system("mkdir /dev/binderfs 2>/dev/null");
+        system(
+"mount -t binder binder /dev/binderfs -o context=system_u:object_r:device_t:s0 2>/dev/null"
+        );
+        $result = system("$basedir/check_binderfs $v 2>/dev/null");
+        if ( $result == 0 ) {
+            $test_binderfs = 1;
+            $test_count += 8;
+        }
+        elsif ( $result >> 8 eq 1 or $result >> 8 eq 2 ) {
+            print
+"Error BINDERFS: May require kernel \"CONFIG_ANDROID_BINDERFS=y\" or test rebuild.\n";
+            system("umount binder 2>/dev/null");
+            system("rmdir /dev/binderfs 2>/dev/null");
+        }
+    }
+
+    plan tests => $test_count;
 }
 
-sub manager_start {
-    my ( $runcon_args, $args ) = @_;
+sub service_start {
+    my ( $service, $runcon_args, $args ) = @_;
     my $pid;
+    my $flag = $service . "_flag";
 
-    system("mkfifo $basedir/flag");
+    system("mkfifo $basedir/$flag");
 
     if ( ( $pid = fork() ) == 0 ) {
-        exec "runcon $runcon_args $basedir/test_binder -f $basedir/flag $args";
+        exec "runcon $runcon_args $basedir/$service -f $basedir/$flag $args";
     }
 
     # Wait for it to initialize.
-    system("cat $basedir/flag >/dev/null");
+    system("cat $basedir/$flag >/dev/null");
     return $pid;
 }
 
-sub manager_end {
-    my ($pid) = @_;
+sub service_end {
+    my ( $service, $pid ) = @_;
+    my $flag = $service . "_flag";
 
     kill KILL, $pid;
-    system("rm -f $basedir/flag");
+    system("rm -f $basedir/$flag");
 }
 
-$pid = manager_start( "-t test_binder_mgr_t", "$v manager" );
+$sm_pid = service_start( "manager", "-t test_binder_mgr_t", "$v" );
+$sp_pid =
+  service_start( "service_provider", "-t test_binder_provider_t", "$v" );
 
-# 1 Verify that authorized provider can transact with the manager.
-$result =
-  system
-  "runcon -t test_binder_provider_t $basedir/test_binder $v -r 1 provider";
+# 1 Verify that authorized client and service provider can communicate with the binder service manager.
+$result = system "runcon -t test_binder_client_t $basedir/client $v -c -r 3";
 ok( $result eq 0 );
 
-# 2 Verify that provider cannot call manager (no call perm).
-$result = system
-"runcon -t test_binder_provider_no_call_t $basedir/test_binder $v -r 2 provider 2>&1";
-ok( $result >> 8 eq 8 );
-
-# 3 Verify that provider cannot communicate with manager (no impersonate perm).
-$result = system
-"runcon -t test_binder_provider_no_im_t $basedir/test_binder $v -r 2 provider 2>&1";
-ok( $result >> 8 eq 103 );
-
-# 4 Verify that provider cannot communicate with manager (no transfer perm).
-$result = system
-"runcon -t test_binder_provider_no_transfer_t $basedir/test_binder $v -r 1 provider 2>&1";
-ok( $result >> 8 eq 8 );
-
-# Kill the manager.
-manager_end($pid);
+# 2 Verify that client cannot call manager (no call perm).
+$result =
+  system
+  "runcon -t test_binder_client_no_call_mgr_t $basedir/client $v -r 1 2>&1";
+ok( $result >> 8 eq 125 );
 
-# 5 Verify that provider cannot become a manager (no set_context_mgr perm).
+# 3 Verify that client cannot call service provider (no call perm).
 $result =
   system
-  "runcon -t test_binder_provider_t $basedir/test_binder $v manager 2>&1";
-ok( $result >> 8 eq 4 );
+  "runcon -t test_binder_client_no_call_sp_t $basedir/client $v -r 2 2>&1";
+ok( $result >> 8 eq 141 );
 
-# Start manager to test that selinux_binder_transfer_file() fails when fd { use } is denied by policy.
-$pid = manager_start( "-t test_binder_mgr_no_fd_t", "$v manager" );
+# 4 Verify that client cannot communicate with service provider (no impersonate perm).
+$result =
+  system "runcon -t test_binder_client_no_im_t $basedir/client $v -r 2 2>&1";
+ok( $result >> 8 eq 133 );
 
-# 6 Verify that authorized provider can communicate with the server, however the fd passed will not be valid for manager
-# domain and binder will return BR_FAILED_REPLY.
+# 5 Verify that client cannot communicate with service provider (no transfer perm).
 $result =
   system
-  "runcon -t test_binder_provider_t $basedir/test_binder $v provider -r 2 2>&1";
-ok( $result >> 8 eq 8 );
+  "runcon -t test_binder_client_no_transfer_t $basedir/client $v -r 2 2>&1";
+ok( $result >> 8 eq 125 );
+
+# Kill the service provider & manager before next tests:
+service_end( "service_provider", $sp_pid );
+service_end( "manager",          $sm_pid );
+
+# 6 Verify that provider domain cannot become a manager (no set_context_mgr perm).
+$result = system "runcon -t test_binder_provider_t $basedir/manager $v 2>&1";
+ok( $result >> 8 eq 14 );
+
+# 7 Test that selinux_binder_transfer_file() fails when fd { use } is denied by policy.
+#   Note that this test requires the Reference Policy boolean "allow_domain_fd_use" set to FALSE.
+#   (setsebool allow_domain_fd_use=0)
+# 7a Start Manager
+$sm_pid = service_start( "manager", "-t test_binder_mgr_t", "$v" );
+
+# 7b Start Service Provider
+$sp_pid =
+  service_start( "service_provider", "-t test_binder_provider_no_fd_t", "$v" );
+
+# 7c Verify that authorized client can communicate with the service provider, however the sp's binder fd passed
+#    to the client will not be valid for service provider domain and binder will return BR_FAILED_REPLY.
+$result = system "runcon -t test_binder_client_t $basedir/client $v -r2 2>&1";
+ok( $result >> 8 eq 141 );
 
-# Kill the manager
-manager_end($pid);
+# Kill the service provider & manager
+service_end( "service_provider", $sp_pid );
+service_end( "manager",          $sm_pid );
+
+if ($test_binder_ctx) {
+    #### Binder return security context test ######################
+    #
+    $sm_pid = service_start( "manager", "-t test_binder_mgr_t", "$v" );
+    $sp_pid = service_start(
+        "service_provider",
+        "-t test_binder_provider_t",
+        "$v -e unconfined_u:unconfined_r:test_binder_client_t:s0-s0:c0.c1023"
+    );
+
+# 8 Verify that authorized client and service provider can communicate with the binder service manager.
+#   Also check that the service provider can receive the Clients security context.
+    $result =
+      system "runcon -t test_binder_client_t $basedir/client $v -c -r 3";
+    ok( $result eq 0 );
+
+    # Kill the service provider & manager.
+    service_end( "service_provider", $sp_pid );
+    service_end( "manager",          $sm_pid );
+}
+
+if ($test_binderfs) {
+    #### Linux 5.0+ Test binder 'Dynamically Allocated Binder Devices'.
+    $sm_pid = service_start( "manager", "-t test_binder_mgr_t", "$v -n" );
+    $sp_pid =
+      service_start( "service_provider", "-t test_binder_provider_t", "$v -n" );
+
+# 9 Verify that authorized client and service provider can communicate with the binder service manager.
+    $result =
+      system "runcon -t test_binder_client_t $basedir/client $v -n -c -r 3";
+    ok( $result eq 0 );
+
+    # 10 Verify that client cannot call manager (no call perm).
+    $result =
+      system
+"runcon -t test_binder_client_no_call_mgr_t $basedir/client $v -n -r 1 2>&1";
+    ok( $result >> 8 eq 125 );
+
+    # 11 Verify that client cannot call service provider (no call perm).
+    $result =
+      system
+"runcon -t test_binder_client_no_call_sp_t $basedir/client $v -n -r 2 2>&1";
+    ok( $result >> 8 eq 141 );
+
+# 12 Verify that client cannot communicate with service provider (no impersonate perm).
+    $result =
+      system
+      "runcon -t test_binder_client_no_im_t $basedir/client $v -n -r 2 2>&1";
+    ok( $result >> 8 eq 133 );
+
+# 13 Verify that client cannot communicate with service provider (no transfer perm).
+    $result =
+      system
+"runcon -t test_binder_client_no_transfer_t $basedir/client $v -n -r 2 2>&1";
+    ok( $result >> 8 eq 125 );
+
+    # Kill the service provider & manager before next tests:
+    service_end( "service_provider", $sp_pid );
+    service_end( "manager",          $sm_pid );
+
+# 14 Verify that provider domain cannot become a manager (no set_context_mgr perm).
+    $result =
+      system "runcon -t test_binder_provider_t $basedir/manager $v -n 2>&1";
+    ok( $result >> 8 eq 14 );
+
+# 15 Test that selinux_binder_transfer_file() fails when fd { use } is denied by policy.
+#    Note that this test requires the Reference Policy boolean "allow_domain_fd_use" set to FALSE.
+#    (setsebool allow_domain_fd_use=0)
+# 15a Start Manager
+    $sm_pid = service_start( "manager", "-t test_binder_mgr_t", "$v -n" );
+
+    # 15b Start Service Provider
+    $sp_pid =
+      service_start( "service_provider", "-t test_binder_provider_no_fd_t",
+        "$v -n" );
+
+# 15c Verify that authorized client can communicate with the service provider, however the sp's binder fd passed
+#    to the client will not be valid for service provider domain and binder will return BR_FAILED_REPLY.
+    $result =
+      system "runcon -t test_binder_client_t $basedir/client $v -n -r2 2>&1";
+    ok( $result >> 8 eq 141 );
+
+    # Kill the service provider & manager
+    service_end( "service_provider", $sp_pid );
+    service_end( "manager",          $sm_pid );
+
+    #### Binder return security context test #########################
+    #
+    $sm_pid = service_start( "manager", "-t test_binder_mgr_t", "$v -n" );
+    $sp_pid = service_start(
+        "service_provider",
+        "-t test_binder_provider_t",
+        "$v -n -e unconfined_u:unconfined_r:test_binder_client_t:s0-s0:c0.c1023"
+    );
+
+# 16 Verify that authorized client and service provider can communicate with the binder service manager.
+#    Also check that the service provider can receive the Clients security context.
+    $result =
+      system "runcon -t test_binder_client_t $basedir/client $v -n -c -r 3";
+    ok( $result eq 0 );
+
+    # Kill the service provider & manager.
+    service_end( "service_provider", $sp_pid );
+    service_end( "manager",          $sm_pid );
+
+    # Cleanup binderfs stuff.
+    system("umount binder 2>/dev/null");
+    system("rmdir /dev/binderfs 2>/dev/null");
+}
 
 exit;
diff --git a/tests/binder/test_binder.c b/tests/binder/test_binder.c
deleted file mode 100644
index 62194bf..0000000
--- a/tests/binder/test_binder.c
+++ /dev/null
@@ -1,705 +0,0 @@ 
-/*
- * This is a simple binder Service Manager/Service Provider that only uses
- * the raw ioctl commands to test the SELinux binder permissions:
- *     set_context_mgr, call, transfer, impersonate.
- *
- * Using binder test policy the following will be validated:
- *    security_binder_set_context_mgr() binder { set_context_mgr }
- *    security_binder_transaction()     binder { call impersonate }
- *    security_binder_transfer_binder() binder { transfer }
- *    security_binder_transfer_file()   fd { use }
- *
- * TODO security_binder_transfer_file() uses BPF if configured in kernel.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <stdbool.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-#include <selinux/selinux.h>
-#include <linux/android/binder.h>
-
-/* These are the Binder txn->code values used by the Service Provider and
- * Manager to request/retrieve a binder handle.
- */
-#define ADD_TEST_SERVICE 100 /* Sent by Service Provider */
-#define GET_TEST_SERVICE 101 /* Sent by Client */
-
-#define TEST_SERVICE_MANAGER_HANDLE 0
-
-static int binder_parse(int fd, uintptr_t ptr, size_t size, bool manager);
-
-static bool verbose;
-uint32_t sp_handle;
-static unsigned char *shm_base;
-static int shm_fd;
-static int shm_size = 32;
-
-static void usage(char *progname)
-{
-	fprintf(stderr,
-		"usage:  %s [-f file] [-r replies] [-v] manager | provider\n"
-		"Where:\n\t"
-		"-f       Write a line to the file when listening starts.\n\t"
-		"-r       Number of replies to expect from test - default 0.\n\t"
-		"-v       Print context and command information.\n\t"
-		"manager  Act as Service Manager.\n\t"
-		"service  Act as Service Provider.\n"
-		"\nNote: Ensure this boolean command is run when "
-		"testing after a reboot:\n\t"
-		"setsebool allow_domain_fd_use=0\n", progname);
-	exit(-1);
-}
-
-/* Create a small piece of shared memory between the Manager and Service
- * Provider to share a handle as explained in the do_service_manager()
- * function.
- */
-static void create_shm(bool manager)
-{
-	char *name =  "sp_handle";
-
-	if (manager)
-		shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
-	else
-		shm_fd = shm_open(name, O_RDONLY, 0666);
-	if (shm_fd < 0) {
-		fprintf(stderr, "%s shm_open: %s\n", __func__, strerror(errno));
-		exit(-1);
-	}
-
-	ftruncate(shm_fd, shm_size);
-
-	if (manager)
-		shm_base = mmap(0, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED,
-				shm_fd, 0);
-	else
-		shm_base = mmap(0, shm_size, PROT_READ, MAP_SHARED, shm_fd, 0);
-	if (shm_base == MAP_FAILED) {
-		fprintf(stderr, "%s mmap: %s\n", __func__, strerror(errno));
-		close(shm_fd);
-		exit(-1);
-	}
-}
-
-static const char *cmd_name(uint32_t cmd)
-{
-	switch (cmd) {
-	case BR_NOOP:
-		return "BR_NOOP";
-	case BR_TRANSACTION_COMPLETE:
-		return "BR_TRANSACTION_COMPLETE";
-	case BR_INCREFS:
-		return "BR_INCREFS";
-	case BR_ACQUIRE:
-		return "BR_ACQUIRE";
-	case BR_RELEASE:
-		return "BR_RELEASE";
-	case BR_DECREFS:
-		return "BR_DECREFS";
-	case BR_TRANSACTION:
-		return "BR_TRANSACTION";
-	case BR_REPLY:
-		return "BR_REPLY";
-	case BR_FAILED_REPLY:
-		return "BR_FAILED_REPLY";
-	case BR_DEAD_REPLY:
-		return "BR_DEAD_REPLY";
-	case BR_DEAD_BINDER:
-		return "BR_DEAD_BINDER";
-	case BR_ERROR:
-		return "BR_ERROR";
-	/* fallthrough */
-	default:
-		return "Unknown command";
-	}
-}
-
-static void print_trans_data(struct binder_transaction_data *txn_in)
-{
-	struct flat_binder_object *obj;
-	binder_size_t *offs = (binder_size_t *)
-			      (uintptr_t)txn_in->data.ptr.offsets;
-	size_t count = txn_in->offsets_size / sizeof(binder_size_t);
-
-	printf("\thandle: %ld\n", (unsigned long)txn_in->target.handle);
-	printf("\tcookie: %lld\n", txn_in->cookie);
-	printf("\tcode: %d\n", txn_in->code);
-	switch (txn_in->flags) {
-	case TF_ONE_WAY:
-		printf("\tflag: TF_ONE_WAY\n");
-		break;
-	case TF_ROOT_OBJECT:
-		printf("\tflag: TF_ROOT_OBJECT\n");
-		break;
-	case TF_STATUS_CODE:
-		printf("\tflag: TF_STATUS_CODE\n");
-		break;
-	case TF_ACCEPT_FDS:
-		printf("\tflag: TF_ACCEPT_FDS\n");
-		break;
-	default:
-		printf("Unknown flag: %x\n", txn_in->flags);
-		return;
-	}
-	printf("\tsender pid: %u\n", txn_in->sender_pid);
-	printf("\tsender euid: %u\n", txn_in->sender_euid);
-	printf("\tdata_size: %llu\n", txn_in->data_size);
-	printf("\toffsets_size: %llu\n", txn_in->offsets_size);
-
-	while (count--) {
-		obj = (struct flat_binder_object *)
-		      (((char *)(uintptr_t)txn_in->data.ptr.buffer) + *offs++);
-
-		switch (obj->hdr.type) {
-		case BINDER_TYPE_BINDER:
-			printf("\thdr: BINDER_TYPE_BINDER\n");
-			printf("\tbinder: %llx\n", obj->binder);
-			break;
-		case BINDER_TYPE_HANDLE:
-			printf("\thdr: BINDER_TYPE_HANDLE\n");
-			printf("\thandle: %x\n", obj->handle);
-			break;
-		case BINDER_TYPE_FD:
-			printf("\thdr: BINDER_TYPE_FD\n");
-			printf("\tfd: %x\n", obj->handle);
-			break;
-		default:
-			printf("Unknown header: %u\n", obj->hdr.type);
-			return;
-		}
-		printf("\tflags: priority: 0x%x accept FDS: %s\n",
-		       obj->flags & FLAT_BINDER_FLAG_PRIORITY_MASK,
-		       obj->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS ? "YES" : "NO");
-		printf("\tcookie: %llx\n", obj->cookie);
-	}
-}
-
-/* If add a service provider, then obtain a handle for it and store in
- * shared memory. The handle will then be used by the service provider
- * process to contact the Manager for its file descriptor, thus triggering
- * the 'impersonate' permission (as current_sid() != task_sid(from))
- * It is done this way as being a cheapskate it saved adding code to the
- * GET_TEST_SERVICE process plus running a Client as well. This achieves
- * the same objective.
- */
-static void do_service_manager(int fd, struct binder_transaction_data *txn_in)
-{
-	int result;
-	struct flat_binder_object *obj;
-	struct binder_write_read bwr;
-	uint32_t acmd[2];
-	binder_size_t *offs;
-
-	switch (txn_in->code) {
-	case ADD_TEST_SERVICE:
-		offs = (binder_size_t *)(uintptr_t)txn_in->data.ptr.offsets;
-
-		/* Get fbo that contains the Managers binder file descriptor. */
-		obj = (struct flat_binder_object *)
-		      (((char *)(uintptr_t)txn_in->data.ptr.buffer) + *offs);
-
-		if (obj->hdr.type == BINDER_TYPE_HANDLE) {
-			sp_handle = obj->handle;
-			memcpy(shm_base, &sp_handle, sizeof(sp_handle));
-			if (verbose)
-				printf("Manager has BINDER_TYPE_HANDLE obj->handle: %d\n",
-				       sp_handle);
-		} else {
-			fprintf(stderr, "Failed to obtain a handle\n");
-			exit(-1);
-		}
-
-		acmd[0] = BC_ACQUIRE;
-		acmd[1] = obj->handle;
-
-		memset(&bwr, 0, sizeof(bwr));
-		bwr.write_buffer = (uintptr_t)&acmd;
-		bwr.write_size = sizeof(acmd);
-
-		result = ioctl(fd, BINDER_WRITE_READ, &bwr);
-		if (result < 0) {
-			fprintf(stderr,
-				"ServiceProvider ioctl BINDER_WRITE_READ: %s\n",
-				strerror(errno));
-			exit(-1);
-		}
-
-		if (verbose)
-			printf("Manager acquired handle: %d for Service Provider\n",
-			       sp_handle);
-		break;
-
-	case GET_TEST_SERVICE:
-		if (verbose)
-			printf("GET_TEST_SERVICE not supported\n");
-		break;
-	default:
-		fprintf(stderr, "Unknown txn->code: %d\n", txn_in->code);
-		exit(-1);
-	}
-}
-
-static void request_manager_fd(int fd, struct binder_transaction_data *txn_in)
-{
-	int result;
-	unsigned int writebuf[1024];
-	struct binder_fd_object obj;
-	binder_size_t offset = 0;
-	struct binder_write_read bwr;
-	struct binder_transaction_data *txn;
-
-	if (txn_in->flags == TF_ONE_WAY) {
-		if (verbose)
-			printf("Manager no reply to BC_TRANSACTION as flags = TF_ONE_WAY\n");
-		return;
-	}
-
-	if (verbose)
-		printf("Manager sending BC_REPLY to obtain its FD\n");
-
-	writebuf[0] = BC_REPLY;
-	txn = (struct binder_transaction_data *)(&writebuf[1]);
-
-	memset(txn, 0, sizeof(*txn));
-	txn->target.handle = txn_in->target.handle;
-	txn->cookie = txn_in->cookie;
-	txn->code = txn_in->code;
-	txn->flags = TF_ACCEPT_FDS;
-	memset(&obj, 0, sizeof(obj));
-	obj.hdr.type = BINDER_TYPE_FD;
-	obj.pad_flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
-	obj.cookie = txn->cookie;
-	/* The binder fd is used for testing as it allows policy to set
-	 * whether the Service and Manager can be allowed access (fd use)
-	 * or not. For example test_binder_mgr_t has:
-	 *        allow test_binder_service_t test_binder_mgr_t:fd use;
-	 * whereas test_binder_mgr_no_fd_t does not allow this fd use.
-	 *
-	 * This also allows a check for the impersonate permission later
-	 * as the Service Provider will use this (the Managers fd) to
-	 * send a transaction.
-	 */
-	obj.fd = fd;
-
-	if (verbose)
-		printf("Manager handle: %d and its FD: %d\n",
-		       txn->target.handle, fd);
-
-	txn->data_size = sizeof(obj);
-	txn->offsets_size = sizeof(offset);
-	txn->data.ptr.buffer = (uintptr_t)&obj;
-	txn->data.ptr.offsets = (uintptr_t)&offset;
-
-	memset(&bwr, 0, sizeof(bwr));
-	bwr.write_buffer = (uintptr_t)writebuf;
-	bwr.write_size = sizeof(writebuf[0]) + sizeof(*txn);
-
-	result = ioctl(fd, BINDER_WRITE_READ, &bwr);
-	if (result < 0) {
-		fprintf(stderr, "%s ioctl BINDER_WRITE_READ: %s\n",
-			__func__, strerror(errno));
-		exit(-1);
-	}
-}
-
-/* This retrieves the requested Managers file descriptor, then using this
- * sends a simple transaction to trigger the impersonate permission.
- */
-static void extract_fd_and_respond(struct binder_transaction_data *txn_in,
-				   bool manager)
-{
-	int result;
-	uint32_t cmd;
-	struct stat sb;
-	struct binder_write_read bwr;
-	struct binder_fd_object *obj;
-	struct {
-		uint32_t cmd;
-		struct binder_transaction_data txn;
-	} __attribute__((packed)) writebuf;
-	unsigned int readbuf[32];
-
-	memset(readbuf, 0, sizeof readbuf);
-
-	binder_size_t *offs = (binder_size_t *)
-			      (uintptr_t)txn_in->data.ptr.offsets;
-
-	/* Get the bfdo that contains the Managers binder file descriptor. */
-	obj = (struct binder_fd_object *)
-	      (((char *)(uintptr_t)txn_in->data.ptr.buffer) + *offs);
-
-	if (obj->hdr.type != BINDER_TYPE_FD) {
-		fprintf(stderr, "Header not BINDER_TYPE_FD: %d\n",
-			obj->hdr.type);
-		exit(100);
-	}
-
-	/* fstat this just to see if a valid fd */
-	result = fstat(obj->fd, &sb);
-	if (result < 0) {
-		fprintf(stderr, "Not a valid fd: %s\n", strerror(errno));
-		exit(101);
-	}
-
-	if (verbose)
-		printf("Service Provider retrieved Managers fd: %d st_dev: %ld\n",
-		       obj->fd, sb.st_dev);
-
-	/* Send response using Managers fd to trigger impersonate check. */
-	writebuf.cmd = BC_TRANSACTION;
-	memcpy(&writebuf.txn.target.handle, shm_base, sizeof(uint32_t));
-
-	writebuf.txn.cookie = 0;
-	writebuf.txn.code = 0;
-	writebuf.txn.flags = TF_ONE_WAY;
-
-	writebuf.txn.data_size = 0;
-	writebuf.txn.data.ptr.buffer = (uintptr_t)NULL;
-	writebuf.txn.data.ptr.offsets = (uintptr_t)NULL;
-	writebuf.txn.offsets_size = 0;
-
-	memset(&bwr, 0, sizeof(bwr));
-	bwr.write_size = sizeof(writebuf);
-	bwr.write_consumed = 0;
-	bwr.write_buffer = (uintptr_t)&writebuf;
-	bwr.read_size = sizeof(readbuf);
-	bwr.read_consumed = 0;
-	bwr.read_buffer = (uintptr_t)readbuf;
-
-	result = ioctl(obj->fd, BINDER_WRITE_READ, &bwr);
-	if (result < 0) {
-		fprintf(stderr,
-			"Service Provider ioctl BINDER_WRITE_READ: %s\n",
-			strerror(errno));
-		exit(102);
-	}
-
-	if (verbose)
-		printf("Service Provider read_consumed: %lld\n",
-		       bwr.read_consumed);
-
-	cmd = binder_parse(obj->fd, (uintptr_t)readbuf,
-			   bwr.read_consumed, manager);
-
-	if (verbose)
-		printf("Service Provider using Managers FD\n");
-
-	if (cmd == BR_FAILED_REPLY ||
-	    cmd == BR_DEAD_REPLY ||
-	    cmd == BR_DEAD_BINDER) {
-		fprintf(stderr,
-			"Failed response from Service Provider using Managers FD\n");
-		exit(103);
-	}
-}
-
-/* Parse response, reply as required and then return last CMD */
-static int binder_parse(int fd, uintptr_t ptr, size_t size, bool manager)
-{
-	uintptr_t end = ptr + (uintptr_t)size;
-	uint32_t cmd;
-
-	while (ptr < end) {
-		cmd = *(uint32_t *)ptr;
-		ptr += sizeof(uint32_t);
-
-		if (verbose)
-			printf("%s command: %s\n",
-			       manager ? "Manager" : "Service Provider",
-			       cmd_name(cmd));
-
-		switch (cmd) {
-		case BR_NOOP:
-			break;
-		case BR_TRANSACTION_COMPLETE:
-			break;
-		case BR_INCREFS:
-		case BR_ACQUIRE:
-		case BR_RELEASE:
-		case BR_DECREFS:
-			ptr += sizeof(struct binder_ptr_cookie);
-			break;
-		case BR_TRANSACTION: {
-			struct binder_transaction_data *txn =
-				(struct binder_transaction_data *)ptr;
-
-			if (verbose) {
-				printf("%s BR_TRANSACTION data:\n",
-				       manager ? "Manager" : "Service Provider");
-				print_trans_data(txn);
-			}
-
-			if (manager) {
-				do_service_manager(fd, txn);
-				request_manager_fd(fd, txn);
-			}
-
-			ptr += sizeof(*txn);
-			break;
-		}
-		case BR_REPLY: {
-			struct binder_transaction_data *txn =
-				(struct binder_transaction_data *)ptr;
-
-			if (verbose) {
-				printf("%s BR_REPLY data:\n",
-				       manager ? "Manager" : "Service Provider");
-				print_trans_data(txn);
-			}
-
-			/* Service Provider extracts the Manager fd, and responds */
-			if (!manager)
-				extract_fd_and_respond(txn, manager);
-
-			ptr += sizeof(*txn);
-			break;
-		}
-		case BR_DEAD_BINDER:
-			break;
-		case BR_FAILED_REPLY:
-			break;
-		case BR_DEAD_REPLY:
-			break;
-		case BR_ERROR:
-			ptr += sizeof(uint32_t);
-			break;
-		default:
-			if (verbose)
-				printf("%s Parsed unknown command: %d\n",
-				       manager ? "Manager" : "Service Provider",
-				       cmd);
-			exit(-1);
-		}
-	}
-
-	return cmd;
-}
-
-int main(int argc, char **argv)
-{
-	int opt, result, binder_fd, provider_replies = 0;
-	uint32_t cmd;
-	bool manager;
-	pid_t pid;
-	char *driver = "/dev/binder";
-	char *context;
-	char *flag_file = NULL;
-	void *map_base;
-	size_t map_size = 1024 * 8;
-	struct binder_write_read bwr;
-	struct flat_binder_object obj;
-	binder_size_t offset = 0;
-	struct {
-		uint32_t cmd;
-		struct binder_transaction_data txn;
-	} __attribute__((packed)) writebuf;
-	unsigned int readbuf[32];
-
-	verbose = false;
-
-	while ((opt = getopt(argc, argv, "f:vr:")) != -1) {
-		switch (opt) {
-		case 'f':
-			flag_file = optarg;
-			break;
-		case 'v':
-			verbose = true;
-			break;
-		case 'r':
-			provider_replies = atoi(optarg);
-			break;
-		default:
-			usage(argv[0]);
-		}
-	}
-
-	if ((argc - optind) != 1)
-		usage(argv[0]);
-
-	if (!strcmp(argv[optind], "manager"))
-		manager = true;
-	else if (!strcmp(argv[optind], "provider"))
-		manager = false;
-	else
-		usage(argv[0]);
-
-	binder_fd = open(driver, O_RDWR | O_CLOEXEC);
-	if (binder_fd < 0) {
-		fprintf(stderr, "Cannot open %s error: %s\n", driver,
-			strerror(errno));
-		exit(1);
-	}
-
-	map_base = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, binder_fd, 0);
-	if (map_base == MAP_FAILED) {
-		fprintf(stderr, "mmap error: %s\n", strerror(errno));
-		close(binder_fd);
-		exit(2);
-	}
-
-	/* Create the appropriate shared memory for passing the Service
-	 * Providers handle from the Manager to the Service Provider for
-	 * use in the impersonate tests. This saves adding a Client to
-	 * do this job.
-	 */
-	create_shm(manager);
-
-	/* Get our context and pid */
-	result = getcon(&context);
-	if (result < 0) {
-		fprintf(stderr, "Failed to obtain SELinux context\n");
-		result = 3;
-		goto brexit;
-	}
-	pid = getpid();
-
-	if (manager) { /* Service Manager */
-		if (verbose) {
-			printf("Manager PID: %d Process context:\n\t%s\n",
-			       pid, context);
-		}
-
-		result = ioctl(binder_fd, BINDER_SET_CONTEXT_MGR, 0);
-		if (result < 0) {
-			fprintf(stderr,
-				"Failed to become context manager: %s\n",
-				strerror(errno));
-			result = 4;
-			goto brexit;
-		}
-
-		writebuf.cmd = BC_ENTER_LOOPER;
-		bwr.write_size = sizeof(writebuf.cmd);
-		bwr.write_consumed = 0;
-		bwr.write_buffer = (uintptr_t)&writebuf;
-
-		bwr.read_size = 0;
-		bwr.read_consumed = 0;
-		bwr.read_buffer = 0;
-
-		result = ioctl(binder_fd, BINDER_WRITE_READ, &bwr);
-		if (result < 0) {
-			fprintf(stderr,
-				"Manager ioctl BINDER_WRITE_READ: %s\n",
-				strerror(errno));
-			result = 5;
-			goto brexit;
-		}
-
-		if (flag_file) {
-			FILE *f = fopen(flag_file, "w");
-			if (!f) {
-				perror("Flag file open");
-				result = 9;
-				goto brexit;
-			}
-			fprintf(f, "listening\n");
-			fclose(f);
-		}
-
-		while (true) {
-			memset(readbuf, 0, sizeof readbuf);
-			bwr.read_size = sizeof(readbuf);
-			bwr.read_consumed = 0;
-			bwr.read_buffer = (uintptr_t)readbuf;
-
-			result = ioctl(binder_fd, BINDER_WRITE_READ, &bwr);
-			if (result < 0) {
-				fprintf(stderr,
-					"Manager ioctl BINDER_WRITE_READ: %s\n",
-					strerror(errno));
-				result = 6;
-				goto brexit;
-			}
-
-			if (bwr.read_consumed == 0)
-				continue;
-
-			if (verbose)
-				printf("Manager read_consumed: %lld\n",
-				       bwr.read_consumed);
-
-			cmd = binder_parse(binder_fd, (uintptr_t)readbuf,
-					   bwr.read_consumed, manager);
-		}
-	} else { /* Service Provider */
-		if (verbose) {
-			printf("Service Provider PID: %d Process context:\n\t%s\n",
-			       pid, context);
-		}
-
-		writebuf.cmd = BC_TRANSACTION;
-		writebuf.txn.target.handle = TEST_SERVICE_MANAGER_HANDLE;
-		writebuf.txn.cookie = 0;
-		writebuf.txn.code = ADD_TEST_SERVICE;
-		writebuf.txn.flags = TF_ACCEPT_FDS;
-
-		memset(&obj, 0, sizeof(obj));
-		obj.hdr.type = BINDER_TYPE_BINDER;
-		obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
-		obj.binder = (uintptr_t)NULL;
-		obj.cookie = 0;
-
-		writebuf.txn.data_size = sizeof(obj);
-		writebuf.txn.offsets_size = sizeof(offset);
-
-		writebuf.txn.data.ptr.buffer = (uintptr_t)&obj;
-		writebuf.txn.data.ptr.offsets = (uintptr_t)&offset;
-
-		bwr.write_buffer = (uintptr_t)&writebuf;
-		bwr.write_size = sizeof(writebuf);
-		bwr.write_consumed = 0;
-
-		if (verbose)
-			printf("Service Provider sending transaction to Manager - ADD_TEST_SERVICE\n");
-
-		/* Each test will expect a different number of replies */
-		while (provider_replies) {
-			memset(readbuf, 0, sizeof readbuf);
-			bwr.read_size = sizeof(readbuf);
-			bwr.read_consumed = 0;
-			bwr.read_buffer = (uintptr_t)readbuf;
-
-			result = ioctl(binder_fd, BINDER_WRITE_READ, &bwr);
-			if (result < 0) {
-				fprintf(stderr,
-					"xxService Provider ioctl BINDER_WRITE_READ: %s\n",
-					strerror(errno));
-				result = 7;
-				goto brexit;
-			}
-
-			if (verbose)
-				printf("Service Provider read_consumed: %lld\n",
-				       bwr.read_consumed);
-
-			cmd = binder_parse(binder_fd, (uintptr_t)readbuf,
-					   bwr.read_consumed, manager);
-
-			if (cmd == BR_FAILED_REPLY ||
-			    cmd == BR_DEAD_REPLY ||
-			    cmd == BR_DEAD_BINDER) {
-				result = 8;
-				goto brexit;
-			}
-			provider_replies--;
-		}
-	}
-
-brexit:
-	free(context);
-	munmap(shm_base, shm_size);
-	close(shm_fd);
-	munmap(map_base, map_size);
-	close(binder_fd);
-
-	return result;
-}