[v18,05/23] net: Prepare UDS for security module stacking
diff mbox series

Message ID 20200709001234.9719-6-casey@schaufler-ca.com
State New
Headers show
Series
  • LSM: Module stacking for AppArmor
Related show

Commit Message

Casey Schaufler July 9, 2020, 12:12 a.m. UTC
Change the data used in UDS SO_PEERSEC processing from a
secid to a more general struct lsmblob. Update the
security_socket_getpeersec_dgram() interface to use the
lsmblob. There is a small amount of scaffolding code
that will come out when the security_secid_to_secctx()
code is brought in line with the lsmblob.

The secid field of the unix_skb_parms structure has been
replaced with a pointer to an lsmblob structure, and the
lsmblob is allocated as needed. This is similar to how the
list of passed files is managed. While an lsmblob structure
will fit in the available space today, there is no guarantee
that the addition of other data to the unix_skb_parms or
support for additional security modules wouldn't exceed what
is available.

Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Cc: netdev@vger.kernel.org
---
 include/linux/security.h |  7 +++++--
 include/net/af_unix.h    |  2 +-
 include/net/scm.h        |  8 +++++---
 net/ipv4/ip_sockglue.c   |  8 +++++---
 net/unix/af_unix.c       | 12 +++++++++---
 net/unix/scm.c           |  6 ++++++
 security/security.c      | 18 +++++++++++++++---
 7 files changed, 46 insertions(+), 15 deletions(-)

Comments

Stephen Smalley July 9, 2020, 4:11 p.m. UTC | #1
On Wed, Jul 8, 2020 at 8:23 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Change the data used in UDS SO_PEERSEC processing from a
> secid to a more general struct lsmblob. Update the
> security_socket_getpeersec_dgram() interface to use the
> lsmblob. There is a small amount of scaffolding code
> that will come out when the security_secid_to_secctx()
> code is brought in line with the lsmblob.
>
> The secid field of the unix_skb_parms structure has been
> replaced with a pointer to an lsmblob structure, and the
> lsmblob is allocated as needed. This is similar to how the
> list of passed files is managed. While an lsmblob structure
> will fit in the available space today, there is no guarantee
> that the addition of other data to the unix_skb_parms or
> support for additional security modules wouldn't exceed what
> is available.
>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Cc: netdev@vger.kernel.org
> ---

> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 3385a7a0b231..d246aefcf4da 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -138,17 +138,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)
>  {
> -       UNIXCB(skb).secid = scm->secid;
> +       UNIXCB(skb).lsmdata = kmemdup(&scm->lsmblob, sizeof(scm->lsmblob),
> +                                     GFP_KERNEL);
>  }
>
>  static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
>  {
> -       scm->secid = UNIXCB(skb).secid;
> +       if (likely(UNIXCB(skb).lsmdata))
> +               scm->lsmblob = *(UNIXCB(skb).lsmdata);
> +       else
> +               lsmblob_init(&scm->lsmblob, 0);
>  }
>
>  static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
>  {
> -       return (scm->secid == UNIXCB(skb).secid);
> +       if (likely(UNIXCB(skb).lsmdata))
> +               return lsmblob_equal(&scm->lsmblob, UNIXCB(skb).lsmdata);
> +       return false;
>  }

I don't think that this provides sensible behavior to userspace.  On a
transient memory allocation failure, instead of returning an error to
the sender and letting them handle it, this will just proceed with
sending the message without its associated security information, and
potentially split messages on arbitrary boundaries because it cannot
tell whether the sender had the same security information.  I think
you instead need to change unix_get_secdata() to return an error on
allocation failure and propagate that up to the sender.  Not a fan of
this change in general both due to extra overhead on this code path
and potential for breakage on allocation failures.  I know it was
motivated by paul's observation that we won't be able to fit many more
secids into the cb but not sure we have to go there prematurely,
especially absent its usage by upstream AA (no unix_stream_connect
hook implementation upstream).  Also not sure how the whole bpf local
storage approach to supporting security modules (or at least bpf lsm)
might reduce need for expanding these structures?
John Johansen July 9, 2020, 4:28 p.m. UTC | #2
On 7/9/20 9:11 AM, Stephen Smalley wrote:
> On Wed, Jul 8, 2020 at 8:23 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>
>> Change the data used in UDS SO_PEERSEC processing from a
>> secid to a more general struct lsmblob. Update the
>> security_socket_getpeersec_dgram() interface to use the
>> lsmblob. There is a small amount of scaffolding code
>> that will come out when the security_secid_to_secctx()
>> code is brought in line with the lsmblob.
>>
>> The secid field of the unix_skb_parms structure has been
>> replaced with a pointer to an lsmblob structure, and the
>> lsmblob is allocated as needed. This is similar to how the
>> list of passed files is managed. While an lsmblob structure
>> will fit in the available space today, there is no guarantee
>> that the addition of other data to the unix_skb_parms or
>> support for additional security modules wouldn't exceed what
>> is available.
>>
>> Reviewed-by: Kees Cook <keescook@chromium.org>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> Cc: netdev@vger.kernel.org
>> ---
> 
>> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
>> index 3385a7a0b231..d246aefcf4da 100644
>> --- a/net/unix/af_unix.c
>> +++ b/net/unix/af_unix.c
>> @@ -138,17 +138,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)
>>  {
>> -       UNIXCB(skb).secid = scm->secid;
>> +       UNIXCB(skb).lsmdata = kmemdup(&scm->lsmblob, sizeof(scm->lsmblob),
>> +                                     GFP_KERNEL);
>>  }
>>
>>  static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
>>  {
>> -       scm->secid = UNIXCB(skb).secid;
>> +       if (likely(UNIXCB(skb).lsmdata))
>> +               scm->lsmblob = *(UNIXCB(skb).lsmdata);
>> +       else
>> +               lsmblob_init(&scm->lsmblob, 0);
>>  }
>>
>>  static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
>>  {
>> -       return (scm->secid == UNIXCB(skb).secid);
>> +       if (likely(UNIXCB(skb).lsmdata))
>> +               return lsmblob_equal(&scm->lsmblob, UNIXCB(skb).lsmdata);
>> +       return false;
>>  }
> 
> I don't think that this provides sensible behavior to userspace.  On a
> transient memory allocation failure, instead of returning an error to
> the sender and letting them handle it, this will just proceed with
> sending the message without its associated security information, and
> potentially split messages on arbitrary boundaries because it cannot
> tell whether the sender had the same security information.  I think
> you instead need to change unix_get_secdata() to return an error on
> allocation failure and propagate that up to the sender.  Not a fan of
> this change in general both due to extra overhead on this code path
> and potential for breakage on allocation failures.  I know it was
> motivated by paul's observation that we won't be able to fit many more
> secids into the cb but not sure we have to go there prematurely,
> especially absent its usage by upstream AA (no unix_stream_connect
> hook implementation upstream).  Also not sure how the whole bpf local

I'm not sure how premature it is, I am running late for 5.9 but would
like to land apparmor unix mediation in 5.10

> storage approach to supporting security modules (or at least bpf lsm)
> might reduce need for expanding these structures?
>
Casey Schaufler July 9, 2020, 7:24 p.m. UTC | #3
On 7/9/2020 9:28 AM, John Johansen wrote:
> On 7/9/20 9:11 AM, Stephen Smalley wrote:
>> On Wed, Jul 8, 2020 at 8:23 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>> Change the data used in UDS SO_PEERSEC processing from a
>>> secid to a more general struct lsmblob. Update the
>>> security_socket_getpeersec_dgram() interface to use the
>>> lsmblob. There is a small amount of scaffolding code
>>> that will come out when the security_secid_to_secctx()
>>> code is brought in line with the lsmblob.
>>>
>>> The secid field of the unix_skb_parms structure has been
>>> replaced with a pointer to an lsmblob structure, and the
>>> lsmblob is allocated as needed. This is similar to how the
>>> list of passed files is managed. While an lsmblob structure
>>> will fit in the available space today, there is no guarantee
>>> that the addition of other data to the unix_skb_parms or
>>> support for additional security modules wouldn't exceed what
>>> is available.
>>>
>>> Reviewed-by: Kees Cook <keescook@chromium.org>
>>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>>> Cc: netdev@vger.kernel.org
>>> ---
>>> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
>>> index 3385a7a0b231..d246aefcf4da 100644
>>> --- a/net/unix/af_unix.c
>>> +++ b/net/unix/af_unix.c
>>> @@ -138,17 +138,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)
>>>  {
>>> -       UNIXCB(skb).secid = scm->secid;
>>> +       UNIXCB(skb).lsmdata = kmemdup(&scm->lsmblob, sizeof(scm->lsmblob),
>>> +                                     GFP_KERNEL);
>>>  }
>>>
>>>  static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
>>>  {
>>> -       scm->secid = UNIXCB(skb).secid;
>>> +       if (likely(UNIXCB(skb).lsmdata))
>>> +               scm->lsmblob = *(UNIXCB(skb).lsmdata);
>>> +       else
>>> +               lsmblob_init(&scm->lsmblob, 0);
>>>  }
>>>
>>>  static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
>>>  {
>>> -       return (scm->secid == UNIXCB(skb).secid);
>>> +       if (likely(UNIXCB(skb).lsmdata))
>>> +               return lsmblob_equal(&scm->lsmblob, UNIXCB(skb).lsmdata);
>>> +       return false;
>>>  }
>> I don't think that this provides sensible behavior to userspace.  On a
>> transient memory allocation failure, instead of returning an error to
>> the sender and letting them handle it, this will just proceed with
>> sending the message without its associated security information, and
>> potentially split messages on arbitrary boundaries because it cannot
>> tell whether the sender had the same security information.  I think
>> you instead need to change unix_get_secdata() to return an error on
>> allocation failure and propagate that up to the sender.

Can't say that I think that would go over especially well.
You're right about that being a better, or at least more correct,
change.

>>   Not a fan of
>> this change in general both due to extra overhead on this code path
>> and potential for breakage on allocation failures.  I know it was
>> motivated by paul's observation that we won't be able to fit many more
>> secids into the cb but not sure we have to go there prematurely,

Paul wasn't completely against the original approach. His objection
was that using a struct lsmblob, which was already close to the maximum
size it can be and that can grow over time, might be a hard sell.

>> especially absent its usage by upstream AA (no unix_stream_connect
>> hook implementation upstream).  Also not sure how the whole bpf local
> I'm not sure how premature it is, I am running late for 5.9 but would
> like to land apparmor unix mediation in 5.10

Which means that scaffolding around the UNIXCB.secid wouldn't
suffice for very long.

>
>> storage approach to supporting security modules (or at least bpf lsm)
>> might reduce need for expanding these structures?

I think the allocation failure case would still be an issue,
and it could be much more complicated to deal with using the
local storage model. The fundamental problem comes back to fitting
more that 32 bits of information into 32 bits without having to
perform an operation that might fail.

At this point I'm inclined to revert to the original implementation
and see if it doesn't turn out to be acceptable after all. I remain
open to better ideas.
Stephen Smalley July 9, 2020, 7:54 p.m. UTC | #4
On Thu, Jul 9, 2020 at 12:28 PM John Johansen
<john.johansen@canonical.com> wrote:
>
> On 7/9/20 9:11 AM, Stephen Smalley wrote:
> > On Wed, Jul 8, 2020 at 8:23 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >>
> >> Change the data used in UDS SO_PEERSEC processing from a
> >> secid to a more general struct lsmblob. Update the
> >> security_socket_getpeersec_dgram() interface to use the
> >> lsmblob. There is a small amount of scaffolding code
> >> that will come out when the security_secid_to_secctx()
> >> code is brought in line with the lsmblob.
> >>
> >> The secid field of the unix_skb_parms structure has been
> >> replaced with a pointer to an lsmblob structure, and the
> >> lsmblob is allocated as needed. This is similar to how the
> >> list of passed files is managed. While an lsmblob structure
> >> will fit in the available space today, there is no guarantee
> >> that the addition of other data to the unix_skb_parms or
> >> support for additional security modules wouldn't exceed what
> >> is available.
> >>
> >> Reviewed-by: Kees Cook <keescook@chromium.org>
> >> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> >> Cc: netdev@vger.kernel.org
> >> ---
> >
> >> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> >> index 3385a7a0b231..d246aefcf4da 100644
> >> --- a/net/unix/af_unix.c
> >> +++ b/net/unix/af_unix.c
> >> @@ -138,17 +138,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)
> >>  {
> >> -       UNIXCB(skb).secid = scm->secid;
> >> +       UNIXCB(skb).lsmdata = kmemdup(&scm->lsmblob, sizeof(scm->lsmblob),
> >> +                                     GFP_KERNEL);
> >>  }
> >>
> >>  static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
> >>  {
> >> -       scm->secid = UNIXCB(skb).secid;
> >> +       if (likely(UNIXCB(skb).lsmdata))
> >> +               scm->lsmblob = *(UNIXCB(skb).lsmdata);
> >> +       else
> >> +               lsmblob_init(&scm->lsmblob, 0);
> >>  }
> >>
> >>  static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
> >>  {
> >> -       return (scm->secid == UNIXCB(skb).secid);
> >> +       if (likely(UNIXCB(skb).lsmdata))
> >> +               return lsmblob_equal(&scm->lsmblob, UNIXCB(skb).lsmdata);
> >> +       return false;
> >>  }
> >
> > I don't think that this provides sensible behavior to userspace.  On a
> > transient memory allocation failure, instead of returning an error to
> > the sender and letting them handle it, this will just proceed with
> > sending the message without its associated security information, and
> > potentially split messages on arbitrary boundaries because it cannot
> > tell whether the sender had the same security information.  I think
> > you instead need to change unix_get_secdata() to return an error on
> > allocation failure and propagate that up to the sender.  Not a fan of
> > this change in general both due to extra overhead on this code path
> > and potential for breakage on allocation failures.  I know it was
> > motivated by paul's observation that we won't be able to fit many more
> > secids into the cb but not sure we have to go there prematurely,
> > especially absent its usage by upstream AA (no unix_stream_connect
> > hook implementation upstream).  Also not sure how the whole bpf local
>
> I'm not sure how premature it is, I am running late for 5.9 but would
> like to land apparmor unix mediation in 5.10

Sorry I think I mischaracterized the condition under which this
support needs to be stacked. It seems to only be needed if using
SO_PASSSEC and SCM_SECURITY (i.e. datagram labeling), not just for
unix mediation or SO_PEERSEC IIUC.  So not sure if that applies even
for downstream.

Patch
diff mbox series

diff --git a/include/linux/security.h b/include/linux/security.h
index 6d403a522918..d81e8886d799 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1397,7 +1397,8 @@  int security_socket_shutdown(struct socket *sock, int how);
 int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
 int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 				      int __user *optlen, unsigned len);
-int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid);
+int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
+				     struct lsmblob *blob);
 int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
 void security_sk_free(struct sock *sk);
 void security_sk_clone(const struct sock *sk, struct sock *newsk);
@@ -1535,7 +1536,9 @@  static inline int security_socket_getpeersec_stream(struct socket *sock, char __
 	return -ENOPROTOOPT;
 }
 
-static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+static inline int security_socket_getpeersec_dgram(struct socket *sock,
+						   struct sk_buff *skb,
+						   struct lsmblob *blob)
 {
 	return -ENOPROTOOPT;
 }
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index f42fdddecd41..e99c84677e14 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -36,7 +36,7 @@  struct unix_skb_parms {
 	kgid_t			gid;
 	struct scm_fp_list	*fp;		/* Passed files		*/
 #ifdef CONFIG_SECURITY_NETWORK
-	u32			secid;		/* Security ID		*/
+	struct lsmblob		*lsmdata;	/* Security LSM data	*/
 #endif
 	u32			consumed;
 } __randomize_layout;
diff --git a/include/net/scm.h b/include/net/scm.h
index 1ce365f4c256..e2e71c4bf9d0 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -33,7 +33,7 @@  struct scm_cookie {
 	struct scm_fp_list	*fp;		/* Passed files		*/
 	struct scm_creds	creds;		/* Skb credentials	*/
 #ifdef CONFIG_SECURITY_NETWORK
-	u32			secid;		/* Passed security ID 	*/
+	struct lsmblob		lsmblob;	/* Passed LSM data	*/
 #endif
 };
 
@@ -46,7 +46,7 @@  struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
 #ifdef CONFIG_SECURITY_NETWORK
 static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
 {
-	security_socket_getpeersec_dgram(sock, NULL, &scm->secid);
+	security_socket_getpeersec_dgram(sock, NULL, &scm->lsmblob);
 }
 #else
 static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
@@ -97,7 +97,9 @@  static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
 	int err;
 
 	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
-		err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
+		/* Scaffolding - it has to be element 0 for now */
+		err = security_secid_to_secctx(scm->lsmblob.secid[0],
+					       &secdata, &seclen);
 
 		if (!err) {
 			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 84ec3703c909..3ea1103b4c29 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -130,15 +130,17 @@  static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
 
 static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
 {
+	struct lsmblob lb;
 	char *secdata;
-	u32 seclen, secid;
+	u32 seclen;
 	int err;
 
-	err = security_socket_getpeersec_dgram(NULL, skb, &secid);
+	err = security_socket_getpeersec_dgram(NULL, skb, &lb);
 	if (err)
 		return;
 
-	err = security_secid_to_secctx(secid, &secdata, &seclen);
+	/* Scaffolding - it has to be element 0 */
+	err = security_secid_to_secctx(lb.secid[0], &secdata, &seclen);
 	if (err)
 		return;
 
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 3385a7a0b231..d246aefcf4da 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -138,17 +138,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)
 {
-	UNIXCB(skb).secid = scm->secid;
+	UNIXCB(skb).lsmdata = kmemdup(&scm->lsmblob, sizeof(scm->lsmblob),
+				      GFP_KERNEL);
 }
 
 static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
 {
-	scm->secid = UNIXCB(skb).secid;
+	if (likely(UNIXCB(skb).lsmdata))
+		scm->lsmblob = *(UNIXCB(skb).lsmdata);
+	else
+		lsmblob_init(&scm->lsmblob, 0);
 }
 
 static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
 {
-	return (scm->secid == UNIXCB(skb).secid);
+	if (likely(UNIXCB(skb).lsmdata))
+		return lsmblob_equal(&scm->lsmblob, UNIXCB(skb).lsmdata);
+	return false;
 }
 #else
 static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
diff --git a/net/unix/scm.c b/net/unix/scm.c
index 8c40f2b32392..3094323935a4 100644
--- a/net/unix/scm.c
+++ b/net/unix/scm.c
@@ -142,6 +142,12 @@  void unix_destruct_scm(struct sk_buff *skb)
 	scm.pid  = UNIXCB(skb).pid;
 	if (UNIXCB(skb).fp)
 		unix_detach_fds(&scm, skb);
+#ifdef CONFIG_SECURITY_NETWORK
+	if (UNIXCB(skb).lsmdata) {
+		kfree(UNIXCB(skb).lsmdata);
+		UNIXCB(skb).lsmdata = NULL;
+	}
+#endif
 
 	/* Alas, it calls VFS */
 	/* So fscking what? fput() had been SMP-safe since the last Summer */
diff --git a/security/security.c b/security/security.c
index f54c6dfd9b89..2122ed9df058 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2204,10 +2204,22 @@  int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 				optval, optlen, len);
 }
 
-int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
+				     struct lsmblob *blob)
 {
-	return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock,
-			     skb, secid);
+	struct security_hook_list *hp;
+	int rc = -ENOPROTOOPT;
+
+	hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram,
+			     list) {
+		if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+			continue;
+		rc = hp->hook.socket_getpeersec_dgram(sock, skb,
+						&blob->secid[hp->lsmid->slot]);
+		if (rc != 0)
+			break;
+	}
+	return rc;
 }
 EXPORT_SYMBOL(security_socket_getpeersec_dgram);