diff mbox series

[27/59] NET: Store LSM access information in the socket blob for UDS

Message ID 20190409213946.1667-28-casey@schaufler-ca.com (mailing list archive)
State New, archived
Headers show
Series LSM: Module stacking for AppArmor | expand

Commit Message

Casey Schaufler April 9, 2019, 9:39 p.m. UTC
UNIX domain socket connections don't have sufficient
space in the socket buffer (skb) secmark for more than
one Linux security module (LSM) to pass data. Expanding
the secmark has been ruled out as an option. Store the
necessary data in the socket security blob pointed to
by the skb socket.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/security.h | 20 +++++++++++++++++++-
 net/unix/af_unix.c       | 14 ++++++++------
 security/security.c      | 17 ++++++++++++++++-
 3 files changed, 43 insertions(+), 8 deletions(-)

Comments

Stephen Smalley April 10, 2019, 12:28 p.m. UTC | #1
On Tue, Apr 9, 2019 at 5:42 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> UNIX domain socket connections don't have sufficient
> space in the socket buffer (skb) secmark for more than
> one Linux security module (LSM) to pass data. Expanding
> the secmark has been ruled out as an option. Store the
> necessary data in the socket security blob pointed to
> by the skb socket.

I don't believe this is correct.  The secid in the unix_skb_parms is
not the same as the secmark in the sk_buff, and I don't know if we are
necessarily prohibited from expanding it.  Also, I don't think you can
just store it in the socket security blob, especially without any form
of locking, as that can be shared across multiple sk_buffs.

>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  include/linux/security.h | 20 +++++++++++++++++++-
>  net/unix/af_unix.c       | 14 ++++++++------
>  security/security.c      | 17 ++++++++++++++++-
>  3 files changed, 43 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index e76d7a9dbe50..c413dcc1905a 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -71,6 +71,7 @@ struct ctl_table;
>  struct audit_krule;
>  struct user_namespace;
>  struct timezone;
> +struct sk_buff;
>
>  enum lsm_event {
>         LSM_POLICY_CHANGE,
> @@ -100,6 +101,22 @@ static inline bool lsm_export_any(struct lsm_export *l)
>                 ((l->flags & LSM_EXPORT_APPARMOR) && l->apparmor));
>  }
>
> +static inline bool lsm_export_equal(struct lsm_export *l, struct lsm_export *m)
> +{
> +       if (l->flags != m->flags || l->flags == LSM_EXPORT_NONE)
> +               return false;
> +       if (l->flags & LSM_EXPORT_SELINUX &&
> +           (l->selinux != m->selinux || l->selinux == 0))
> +               return false;
> +       if (l->flags & LSM_EXPORT_SMACK &&
> +           (l->smack != m->smack || l->smack == 0))
> +               return false;
> +       if (l->flags & LSM_EXPORT_APPARMOR &&
> +           (l->apparmor != m->apparmor || l->apparmor == 0))
> +               return false;
> +       return true;
> +}
> +
>  /**
>   * lsm_export_secid - pull the useful secid out of a lsm_export
>   * @data: the containing data structure
> @@ -143,6 +160,8 @@ static inline void lsm_export_to_all(struct lsm_export *data, u32 secid)
>                       LSM_EXPORT_APPARMOR;
>  }
>
> +extern struct lsm_export *lsm_export_skb(struct sk_buff *skb);
> +
>  /* These functions are in security/commoncap.c */
>  extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
>                        int cap, unsigned int opts);
> @@ -174,7 +193,6 @@ extern int cap_task_setnice(struct task_struct *p, int nice);
>  extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
>
>  struct msghdr;
> -struct sk_buff;
>  struct sock;
>  struct sockaddr;
>  struct socket;
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 4d4107927ba2..afe9c9f1adeb 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -143,21 +143,23 @@ static struct hlist_head *unix_sockets_unbound(void *addr)
>  #ifdef CONFIG_SECURITY_NETWORK
>  static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
>  {
> -       lsm_export_secid(&scm->le, &(UNIXCB(skb).secid));
> +       struct lsm_export *ble = lsm_export_skb(skb);
> +
> +       *ble = scm->le;
>  }
>
>  static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
>  {
> -       lsm_export_to_all(&scm->le, UNIXCB(skb).secid);
> +       struct lsm_export *ble = lsm_export_skb(skb);
> +
> +       scm->le = *ble;
>  }
>
>  static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
>  {
> -       u32 best_secid;
> -
> -       lsm_export_secid(&scm->le, &best_secid);
> -       return (best_secid == UNIXCB(skb).secid);
> +       return lsm_export_equal(&scm->le, lsm_export_skb(skb));
>  }
> +
>  #else
>  static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
>  { }
> diff --git a/security/security.c b/security/security.c
> index 69983ad68233..015c38c882ba 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -46,7 +46,22 @@ static struct kmem_cache *lsm_file_cache;
>  static struct kmem_cache *lsm_inode_cache;
>
>  char *lsm_names;
> -static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;
> +
> +/* Socket blobs include infrastructure managed data */
> +static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init = {
> +       .lbs_sock = sizeof(struct lsm_export),
> +};
> +
> +/**
> + * lsm_export_skb - pointer to the lsm_export associated with the skb
> + * @skb: the socket buffer
> + *
> + * Returns a pointer to the LSM managed data.
> + */
> +struct lsm_export *lsm_export_skb(struct sk_buff *skb)
> +{
> +       return skb->sk->sk_security;
> +}
>
>  /* Boot-time LSM user choice */
>  static __initdata const char *chosen_lsm_order;
> --
> 2.19.1
>
diff mbox series

Patch

diff --git a/include/linux/security.h b/include/linux/security.h
index e76d7a9dbe50..c413dcc1905a 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -71,6 +71,7 @@  struct ctl_table;
 struct audit_krule;
 struct user_namespace;
 struct timezone;
+struct sk_buff;
 
 enum lsm_event {
 	LSM_POLICY_CHANGE,
@@ -100,6 +101,22 @@  static inline bool lsm_export_any(struct lsm_export *l)
 		((l->flags & LSM_EXPORT_APPARMOR) && l->apparmor));
 }
 
+static inline bool lsm_export_equal(struct lsm_export *l, struct lsm_export *m)
+{
+	if (l->flags != m->flags || l->flags == LSM_EXPORT_NONE)
+		return false;
+	if (l->flags & LSM_EXPORT_SELINUX &&
+	    (l->selinux != m->selinux || l->selinux == 0))
+		return false;
+	if (l->flags & LSM_EXPORT_SMACK &&
+	    (l->smack != m->smack || l->smack == 0))
+		return false;
+	if (l->flags & LSM_EXPORT_APPARMOR &&
+	    (l->apparmor != m->apparmor || l->apparmor == 0))
+		return false;
+	return true;
+}
+
 /**
  * lsm_export_secid - pull the useful secid out of a lsm_export
  * @data: the containing data structure
@@ -143,6 +160,8 @@  static inline void lsm_export_to_all(struct lsm_export *data, u32 secid)
 		      LSM_EXPORT_APPARMOR;
 }
 
+extern struct lsm_export *lsm_export_skb(struct sk_buff *skb);
+
 /* These functions are in security/commoncap.c */
 extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
 		       int cap, unsigned int opts);
@@ -174,7 +193,6 @@  extern int cap_task_setnice(struct task_struct *p, int nice);
 extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
 
 struct msghdr;
-struct sk_buff;
 struct sock;
 struct sockaddr;
 struct socket;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 4d4107927ba2..afe9c9f1adeb 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -143,21 +143,23 @@  static struct hlist_head *unix_sockets_unbound(void *addr)
 #ifdef CONFIG_SECURITY_NETWORK
 static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
 {
-	lsm_export_secid(&scm->le, &(UNIXCB(skb).secid));
+	struct lsm_export *ble = lsm_export_skb(skb);
+
+	*ble = scm->le;
 }
 
 static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
 {
-	lsm_export_to_all(&scm->le, UNIXCB(skb).secid);
+	struct lsm_export *ble = lsm_export_skb(skb);
+
+	scm->le = *ble;
 }
 
 static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
 {
-	u32 best_secid;
-
-	lsm_export_secid(&scm->le, &best_secid);
-	return (best_secid == UNIXCB(skb).secid);
+	return lsm_export_equal(&scm->le, lsm_export_skb(skb));
 }
+
 #else
 static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
 { }
diff --git a/security/security.c b/security/security.c
index 69983ad68233..015c38c882ba 100644
--- a/security/security.c
+++ b/security/security.c
@@ -46,7 +46,22 @@  static struct kmem_cache *lsm_file_cache;
 static struct kmem_cache *lsm_inode_cache;
 
 char *lsm_names;
-static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;
+
+/* Socket blobs include infrastructure managed data */
+static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init = {
+	.lbs_sock = sizeof(struct lsm_export),
+};
+
+/**
+ * lsm_export_skb - pointer to the lsm_export associated with the skb
+ * @skb: the socket buffer
+ *
+ * Returns a pointer to the LSM managed data.
+ */
+struct lsm_export *lsm_export_skb(struct sk_buff *skb)
+{
+	return skb->sk->sk_security;
+}
 
 /* Boot-time LSM user choice */
 static __initdata const char *chosen_lsm_order;