diff mbox series

[v2,4/4] security: binder: Add binder object flags to selinux_binder_transfer_file

Message ID 20230123191728.2928839-5-tjmercier@google.com (mailing list archive)
State Changes Requested
Delegated to: Paul Moore
Headers show
Series Track exported dma-buffers with memcg | expand

Commit Message

T.J. Mercier Jan. 23, 2023, 7:17 p.m. UTC
Any process can cause a memory charge transfer to occur to any other
process when transmitting a file descriptor through binder. This should
only be possible for central allocator processes, so the binder object
flags are added to the security_binder_transfer_file hook so that LSMs
can enforce restrictions on charge transfers.

Signed-off-by: T.J. Mercier <tjmercier@google.com>
---
 drivers/android/binder.c            |  2 +-
 include/linux/lsm_hook_defs.h       |  2 +-
 include/linux/lsm_hooks.h           |  5 ++++-
 include/linux/security.h            |  6 ++++--
 security/security.c                 |  4 ++--
 security/selinux/hooks.c            | 13 ++++++++++++-
 security/selinux/include/classmap.h |  2 +-
 7 files changed, 25 insertions(+), 9 deletions(-)

Comments

Paul Moore Jan. 23, 2023, 9:36 p.m. UTC | #1
On Mon, Jan 23, 2023 at 2:18 PM T.J. Mercier <tjmercier@google.com> wrote:
>
> Any process can cause a memory charge transfer to occur to any other
> process when transmitting a file descriptor through binder. This should
> only be possible for central allocator processes, so the binder object
> flags are added to the security_binder_transfer_file hook so that LSMs
> can enforce restrictions on charge transfers.
>
> Signed-off-by: T.J. Mercier <tjmercier@google.com>
> ---
>  drivers/android/binder.c            |  2 +-
>  include/linux/lsm_hook_defs.h       |  2 +-
>  include/linux/lsm_hooks.h           |  5 ++++-
>  include/linux/security.h            |  6 ++++--
>  security/security.c                 |  4 ++--
>  security/selinux/hooks.c            | 13 ++++++++++++-
>  security/selinux/include/classmap.h |  2 +-
>  7 files changed, 25 insertions(+), 9 deletions(-)

...

> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 3c5be76a9199..d4cfca3c9a3b 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -88,6 +88,7 @@
>  #include <linux/bpf.h>
>  #include <linux/kernfs.h>
>  #include <linux/stringhash.h>  /* for hashlen_string() */
> +#include <uapi/linux/android/binder.h>
>  #include <uapi/linux/mount.h>
>  #include <linux/fsnotify.h>
>  #include <linux/fanotify.h>
> @@ -2029,7 +2030,8 @@ static int selinux_binder_transfer_binder(const struct cred *from,
>
>  static int selinux_binder_transfer_file(const struct cred *from,
>                                         const struct cred *to,
> -                                       struct file *file)
> +                                       struct file *file,
> +                                       u32 binder_object_flags)
>  {
>         u32 sid = cred_sid(to);
>         struct file_security_struct *fsec = selinux_file(file);
> @@ -2038,6 +2040,15 @@ static int selinux_binder_transfer_file(const struct cred *from,
>         struct common_audit_data ad;
>         int rc;
>
> +       if (binder_object_flags & BINDER_FD_FLAG_XFER_CHARGE) {
> +               rc = avc_has_perm(&selinux_state,
> +                           cred_sid(from), sid,
> +                           SECCLASS_BINDER, BINDER__TRANSFER_CHARGE,
> +                           NULL);
> +               if (rc)
> +                       return rc;
> +       }
> +
>         ad.type = LSM_AUDIT_DATA_PATH;
>         ad.u.path = file->f_path;
>
> diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
> index a3c380775d41..2eef180d10d7 100644
> --- a/security/selinux/include/classmap.h
> +++ b/security/selinux/include/classmap.h
> @@ -172,7 +172,7 @@ const struct security_class_mapping secclass_map[] = {
>         { "tun_socket",
>           { COMMON_SOCK_PERMS, "attach_queue", NULL } },
>         { "binder", { "impersonate", "call", "set_context_mgr", "transfer",
> -                     NULL } },
> +                     "transfer_charge", NULL } },
>         { "cap_userns",
>           { COMMON_CAP_PERMS, NULL } },
>         { "cap2_userns",

My first take on reading these changes above is that you've completely
ignored my previous comments about SELinux access controls around
resource management.  You've leveraged the existing LSM/SELinux hook
as we discussed previously, that's good, but can you explain what
changes you've made to address my concerns about one-off resource
management controls?
T.J. Mercier Jan. 24, 2023, 4:47 a.m. UTC | #2
On Mon, Jan 23, 2023 at 2:04 PM T.J. Mercier <tjmercier@google.com> wrote:
>
>
>
> On Mon, Jan 23, 2023 at 1:36 PM Paul Moore <paul@paul-moore.com> wrote:
>>
>> On Mon, Jan 23, 2023 at 2:18 PM T.J. Mercier <tjmercier@google.com> wrote:
>> >
>> > Any process can cause a memory charge transfer to occur to any other
>> > process when transmitting a file descriptor through binder. This should
>> > only be possible for central allocator processes, so the binder object
>> > flags are added to the security_binder_transfer_file hook so that LSMs
>> > can enforce restrictions on charge transfers.
>> >
>> > Signed-off-by: T.J. Mercier <tjmercier@google.com>
>> > ---
>> >  drivers/android/binder.c            |  2 +-
>> >  include/linux/lsm_hook_defs.h       |  2 +-
>> >  include/linux/lsm_hooks.h           |  5 ++++-
>> >  include/linux/security.h            |  6 ++++--
>> >  security/security.c                 |  4 ++--
>> >  security/selinux/hooks.c            | 13 ++++++++++++-
>> >  security/selinux/include/classmap.h |  2 +-
>> >  7 files changed, 25 insertions(+), 9 deletions(-)
>>
>> ...
>>
>> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> > index 3c5be76a9199..d4cfca3c9a3b 100644
>> > --- a/security/selinux/hooks.c
>> > +++ b/security/selinux/hooks.c
>> > @@ -88,6 +88,7 @@
>> >  #include <linux/bpf.h>
>> >  #include <linux/kernfs.h>
>> >  #include <linux/stringhash.h>  /* for hashlen_string() */
>> > +#include <uapi/linux/android/binder.h>
>> >  #include <uapi/linux/mount.h>
>> >  #include <linux/fsnotify.h>
>> >  #include <linux/fanotify.h>
>> > @@ -2029,7 +2030,8 @@ static int selinux_binder_transfer_binder(const struct cred *from,
>> >
>> >  static int selinux_binder_transfer_file(const struct cred *from,
>> >                                         const struct cred *to,
>> > -                                       struct file *file)
>> > +                                       struct file *file,
>> > +                                       u32 binder_object_flags)
>> >  {
>> >         u32 sid = cred_sid(to);
>> >         struct file_security_struct *fsec = selinux_file(file);
>> > @@ -2038,6 +2040,15 @@ static int selinux_binder_transfer_file(const struct cred *from,
>> >         struct common_audit_data ad;
>> >         int rc;
>> >
>> > +       if (binder_object_flags & BINDER_FD_FLAG_XFER_CHARGE) {
>> > +               rc = avc_has_perm(&selinux_state,
>> > +                           cred_sid(from), sid,
>> > +                           SECCLASS_BINDER, BINDER__TRANSFER_CHARGE,
>> > +                           NULL);
>> > +               if (rc)
>> > +                       return rc;
>> > +       }
>> > +
>> >         ad.type = LSM_AUDIT_DATA_PATH;
>> >         ad.u.path = file->f_path;
>> >
>> > diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
>> > index a3c380775d41..2eef180d10d7 100644
>> > --- a/security/selinux/include/classmap.h
>> > +++ b/security/selinux/include/classmap.h
>> > @@ -172,7 +172,7 @@ const struct security_class_mapping secclass_map[] = {
>> >         { "tun_socket",
>> >           { COMMON_SOCK_PERMS, "attach_queue", NULL } },
>> >         { "binder", { "impersonate", "call", "set_context_mgr", "transfer",
>> > -                     NULL } },
>> > +                     "transfer_charge", NULL } },
>> >         { "cap_userns",
>> >           { COMMON_CAP_PERMS, NULL } },
>> >         { "cap2_userns",
>>
>> My first take on reading these changes above is that you've completely
>> ignored my previous comments about SELinux access controls around
>> resource management.  You've leveraged the existing LSM/SELinux hook
>> as we discussed previously, that's good, but can you explain what
>> changes you've made to address my concerns about one-off resource
>> management controls?
>>
> It's been a couple of weeks since v1 so I've sent this update out now to incorporate all the other feedback so far to make sure it's headed in the right direction. I've tried opening up a discussion about this rather unique case, but there's been no activity on that yet.
>
Someone pointed out this didn't make it to the lists. Retrying.

>> --
>> paul-moore.com
diff mbox series

Patch

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 5e707974793f..7b1bb23b6b79 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2270,7 +2270,7 @@  static int binder_translate_fd(u32 fd, binder_size_t fd_offset, __u32 flags,
 		ret = -EBADF;
 		goto err_fget;
 	}
-	ret = security_binder_transfer_file(proc->cred, target_proc->cred, file);
+	ret = security_binder_transfer_file(proc->cred, target_proc->cred, file, flags);
 	if (ret < 0) {
 		ret = -EPERM;
 		goto err_security;
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index ed6cb2ac55fa..84ee61089f7b 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -32,7 +32,7 @@  LSM_HOOK(int, 0, binder_transaction, const struct cred *from,
 LSM_HOOK(int, 0, binder_transfer_binder, const struct cred *from,
 	 const struct cred *to)
 LSM_HOOK(int, 0, binder_transfer_file, const struct cred *from,
-	 const struct cred *to, struct file *file)
+	 const struct cred *to, struct file *file, u32 binder_object_flags)
 LSM_HOOK(int, 0, ptrace_access_check, struct task_struct *child,
 	 unsigned int mode)
 LSM_HOOK(int, 0, ptrace_traceme, struct task_struct *parent)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 0a5ba81f7367..d57977336ae8 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1381,9 +1381,12 @@ 
  *	Return 0 if permission is granted.
  * @binder_transfer_file:
  *	Check whether @from is allowed to transfer @file to @to.
+ *	If @binder_object_flags indicates a memory charge transfer for @file, then
+ *	permission for the charge transfer can be checked as well.
  *	@from contains the struct cred for the sending process.
- *	@file contains the struct file being transferred.
  *	@to contains the struct cred for the receiving process.
+ *	@file contains the struct file being transferred.
+ *	@binder_object_flags contains the flags associated with the binder object.
  *	Return 0 if permission is granted.
  *
  * @ptrace_access_check:
diff --git a/include/linux/security.h b/include/linux/security.h
index 5b67f208f7de..c4b80fc8d104 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -269,7 +269,8 @@  int security_binder_transaction(const struct cred *from,
 int security_binder_transfer_binder(const struct cred *from,
 				    const struct cred *to);
 int security_binder_transfer_file(const struct cred *from,
-				  const struct cred *to, struct file *file);
+				  const struct cred *to, struct file *file,
+				  u32 binder_object_flags);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
@@ -542,7 +543,8 @@  static inline int security_binder_transfer_binder(const struct cred *from,
 
 static inline int security_binder_transfer_file(const struct cred *from,
 						const struct cred *to,
-						struct file *file)
+						struct file *file,
+						u32 binder_object_flags)
 {
 	return 0;
 }
diff --git a/security/security.c b/security/security.c
index d1571900a8c7..12ccaca744c0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -796,9 +796,9 @@  int security_binder_transfer_binder(const struct cred *from,
 }
 
 int security_binder_transfer_file(const struct cred *from,
-				  const struct cred *to, struct file *file)
+				  const struct cred *to, struct file *file, u32 binder_object_flags)
 {
-	return call_int_hook(binder_transfer_file, 0, from, to, file);
+	return call_int_hook(binder_transfer_file, 0, from, to, file, binder_object_flags);
 }
 
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3c5be76a9199..d4cfca3c9a3b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -88,6 +88,7 @@ 
 #include <linux/bpf.h>
 #include <linux/kernfs.h>
 #include <linux/stringhash.h>	/* for hashlen_string() */
+#include <uapi/linux/android/binder.h>
 #include <uapi/linux/mount.h>
 #include <linux/fsnotify.h>
 #include <linux/fanotify.h>
@@ -2029,7 +2030,8 @@  static int selinux_binder_transfer_binder(const struct cred *from,
 
 static int selinux_binder_transfer_file(const struct cred *from,
 					const struct cred *to,
-					struct file *file)
+					struct file *file,
+					u32 binder_object_flags)
 {
 	u32 sid = cred_sid(to);
 	struct file_security_struct *fsec = selinux_file(file);
@@ -2038,6 +2040,15 @@  static int selinux_binder_transfer_file(const struct cred *from,
 	struct common_audit_data ad;
 	int rc;
 
+	if (binder_object_flags & BINDER_FD_FLAG_XFER_CHARGE) {
+		rc = avc_has_perm(&selinux_state,
+			    cred_sid(from), sid,
+			    SECCLASS_BINDER, BINDER__TRANSFER_CHARGE,
+			    NULL);
+		if (rc)
+			return rc;
+	}
+
 	ad.type = LSM_AUDIT_DATA_PATH;
 	ad.u.path = file->f_path;
 
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index a3c380775d41..2eef180d10d7 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -172,7 +172,7 @@  const struct security_class_mapping secclass_map[] = {
 	{ "tun_socket",
 	  { COMMON_SOCK_PERMS, "attach_queue", NULL } },
 	{ "binder", { "impersonate", "call", "set_context_mgr", "transfer",
-		      NULL } },
+		      "transfer_charge", NULL } },
 	{ "cap_userns",
 	  { COMMON_CAP_PERMS, NULL } },
 	{ "cap2_userns",