[PATCH mptcp-net] mptcp: fix LSM labeling for passive msk
Casey Schaufler
casey at schaufler-ca.com
Thu Dec 8 15:33:01 UTC 2022
On 12/7/2022 6:19 PM, Mat Martineau wrote:
> On Wed, 7 Dec 2022, Paolo Abeni wrote:
>
>> MPTCP sockets created via accept() inherit their LSM label
>> from the initial request socket, which in turn get it from the
>> listener socket's first subflow. The latter is a kernel socket,
>> and get the relevant labeling at creation time.
>>
>> Due to all the above even the accepted MPTCP socket get a kernel
>> label, causing unexpected behaviour and failure on later LSM tests.
>>
>> Address the issue factoring out a socket creation helper that does
>> not include the post-creation LSM checks. Use such helper to create
>> mptcp subflow as in-kernel sockets and doing explicitly LSM validation:
>> vs the current user for the first subflow, as a kernel socket otherwise.
>>
>> Fixes: 0c14846032f2 ("mptcp: fix security context on server socket")
>> Reported-by: Ondrej Mosnacek <omosnace at redhat.com>
>> Signed-off-by: Paolo Abeni <pabeni at redhat.com>
>
> The MPTCP content looks good to me:
>
> Acked-by: Mat Martineau <mathew.j.martineau at linux.intel.com>
>
>
> I didn't see issues with the socket.c changes but I'd like to get some
> security community feedback before upstreaming - Paul or other
> security reviewers, what do you think?
I haven't had the opportunity to work out what impact, if any, this will
have on Smack. I haven't seen a reproducer for the problem, is one available?
Sorry to chime in late.
>
>
> Thanks,
>
> Mat
>
>
>> ---
>> include/linux/net.h | 2 ++
>> net/mptcp/subflow.c | 19 ++++++++++++--
>> net/socket.c | 60 ++++++++++++++++++++++++++++++---------------
>> 3 files changed, 59 insertions(+), 22 deletions(-)
>>
>> diff --git a/include/linux/net.h b/include/linux/net.h
>> index b73ad8e3c212..91713012504d 100644
>> --- a/include/linux/net.h
>> +++ b/include/linux/net.h
>> @@ -251,6 +251,8 @@ int sock_wake_async(struct socket_wq *sk_wq, int
>> how, int band);
>> int sock_register(const struct net_proto_family *fam);
>> void sock_unregister(int family);
>> bool sock_is_registered(int family);
>> +int __sock_create_nosec(struct net *net, int family, int type, int
>> proto,
>> + struct socket **res, int kern);
>> int __sock_create(struct net *net, int family, int type, int proto,
>> struct socket **res, int kern);
>> int sock_create(int family, int type, int proto, struct socket **res);
>> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
>> index d5ff502c88d7..e7e6f17df7ef 100644
>> --- a/net/mptcp/subflow.c
>> +++ b/net/mptcp/subflow.c
>> @@ -1646,11 +1646,26 @@ int mptcp_subflow_create_socket(struct sock
>> *sk, struct socket **new_sock)
>> if (unlikely(!sk->sk_socket))
>> return -EINVAL;
>>
>> - err = sock_create_kern(net, sk->sk_family, SOCK_STREAM,
>> IPPROTO_TCP,
>> - &sf);
>> + /* the subflow is created by the kernel, and we need kernel
>> annotation
>> + * for lockdep's sake...
>> + */
>> + err = __sock_create_nosec(net, sk->sk_family, SOCK_STREAM,
>> IPPROTO_TCP,
>> + &sf, 1);
>> if (err)
>> return err;
>>
>> + /* ... but the MPC subflow will be indirectly exposed to the
>> + * user-space via accept(). Let's attach the current user security
>> + * label to the first subflow, that is when msk->first is not yet
>> + * initialized.
>> + */
>> + err = security_socket_post_create(sf, sk->sk_family, SOCK_STREAM,
>> + IPPROTO_TCP, !!mptcp_sk(sk)->first);
>> + if (err) {
>> + sock_release(sf);
>> + return err;
>> + }
>> +
>> lock_sock(sf->sk);
>>
>> /* the newly created socket has to be in the same cgroup as its
>> parent */
>> diff --git a/net/socket.c b/net/socket.c
>> index 55c5d536e5f6..d5d51e4e26ae 100644
>> --- a/net/socket.c
>> +++ b/net/socket.c
>> @@ -1426,23 +1426,11 @@ int sock_wake_async(struct socket_wq *wq, int
>> how, int band)
>> }
>> EXPORT_SYMBOL(sock_wake_async);
>>
>> -/**
>> - * __sock_create - creates a socket
>> - * @net: net namespace
>> - * @family: protocol family (AF_INET, ...)
>> - * @type: communication type (SOCK_STREAM, ...)
>> - * @protocol: protocol (0, ...)
>> - * @res: new socket
>> - * @kern: boolean for kernel space sockets
>> - *
>> - * Creates a new socket and assigns it to @res, passing through LSM.
>> - * Returns 0 or an error. On failure @res is set to %NULL. @kern
>> must
>> - * be set to true if the socket resides in kernel space.
>> - * This function internally uses GFP_KERNEL.
>> - */
>>
>> -int __sock_create(struct net *net, int family, int type, int protocol,
>> - struct socket **res, int kern)
>> +
>> +/*creates a socket leaving LSM post-creation checks to the caller */
>> +int __sock_create_nosec(struct net *net, int family, int type, int
>> protocol,
>> + struct socket **res, int kern)
>> {
>> int err;
>> struct socket *sock;
>> @@ -1528,11 +1516,8 @@ int __sock_create(struct net *net, int family,
>> int type, int protocol,
>> * module can have its refcnt decremented
>> */
>> module_put(pf->owner);
>> - err = security_socket_post_create(sock, family, type, protocol,
>> kern);
>> - if (err)
>> - goto out_sock_release;
>> - *res = sock;
>>
>> + *res = sock;
>> return 0;
>>
>> out_module_busy:
>> @@ -1548,6 +1533,41 @@ int __sock_create(struct net *net, int family,
>> int type, int protocol,
>> rcu_read_unlock();
>> goto out_sock_release;
>> }
>> +
>> +/**
>> + * __sock_create - creates a socket
>> + * @net: net namespace
>> + * @family: protocol family (AF_INET, ...)
>> + * @type: communication type (SOCK_STREAM, ...)
>> + * @protocol: protocol (0, ...)
>> + * @res: new socket
>> + * @kern: boolean for kernel space sockets
>> + *
>> + * Creates a new socket and assigns it to @res, passing through LSM.
>> + * Returns 0 or an error. On failure @res is set to %NULL. @kern
>> must
>> + * be set to true if the socket resides in kernel space.
>> + * This function internally uses GFP_KERNEL.
>> + */
>> +
>> +int __sock_create(struct net *net, int family, int type, int protocol,
>> + struct socket **res, int kern)
>> +{
>> + struct socket *sock;
>> + int err;
>> +
>> + err = __sock_create_nosec(net, family, type, protocol, &sock,
>> kern);
>> + if (err)
>> + return err;
>> +
>> + err = security_socket_post_create(sock, family, type, protocol,
>> kern);
>> + if (err) {
>> + sock_release(sock);
>> + return err;
>> + }
>> +
>> + *res = sock;
>> + return 0;
>> +}
>> EXPORT_SYMBOL(__sock_create);
>>
>> /**
>> --
>> 2.38.1
>>
>>
>>
>
> --
> Mat Martineau
> Intel
More information about the Linux-security-module-archive
mailing list