Hi Jon,

I have one idea about how to block the vulnerability described below from 
happening. Although it's not so elegant, it's quite simple:

As you mentioned below, TIPC_TOP_SRV service is only published in 
tipc_topsrv_create_listener () from kernel space. So probably we can change the 
code as below:

tipc_bind()
{
...
        if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) {
                res = -EACCES;
                goto exit;
        }
        __tipc_bind();
...
}

Int __tipc_bind()
{
        If (addr->scope >= 0)                
        tipc_sk_publish(tsk, addr->scope, &addr->addr.nameseq) :
         else
                tipc_sk_withdraw(tsk, -addr->scope, &addr->addr.nameseq);
}

tipc_topsrv_create_listener()
{
...
- rc = kernel_bind(lsock, (struct sockaddr *)&saddr, sizeof(saddr));
+ rc = __tipc_bind(lsock, (struct sockaddr *)&saddr, sizeof(saddr));
...
}

Thanks,
Ying

-----Original Message-----
From: jma...@redhat.com <jma...@redhat.com> 
Sent: Sunday, October 25, 2020 3:16 AM
To: tipc-discussion@lists.sourceforge.net
Cc: tung.q.ngu...@dektech.com.au; hoang.h...@dektech.com.au; 
tuong.t.l...@dektech.com.au; jma...@redhat.com; ma...@donjonn.com; 
x...@redhat.com; Xue, Ying <ying....@windriver.com>; 
parthasarathy.bhuvara...@gmail.com
Subject: [net v2] tipc: add stricter control of reserved service types

From: Jon Maloy <jma...@redhat.com>

TIPC reserves 64 service types for current and future internal use.
Therefore, the bind() function is meant to block regular user sockets from 
being bound to these values, while it should let through such bindings from 
internal users.

However, since we at the design moment saw no way to distinguish between 
regular and internal users the filter function ended up with allowing all 
bindings of the reserved types which were really in use ([0,1]), and block all 
the rest ([2,63]).

This is risky, since a regular user may bind to the service type representing 
the topology server (TIPC_TOP_SRV == 1) or the one used for indicating 
neigboring node status (TIPC_CFG_SRV == 0), and wreak havoc for users of those 
services, i.e., practically all users.

The reality is however that TIPC_CFG_SRV never is bound through the
bind() function, since it doesn't represent a regular socket, and TIPC_TOP_SRV 
can easily be singled out, since it is published from kernel mode and is the 
very first binding performed when the system is starting.

We now introduce a 'privileged' mode for sockets, marking which of those are 
entitled to bind to reserved service type values. The only such socket we have 
so far is the topology server's listener socket, which is identified the way 
described above. All other bindings to reserved service types are rejected.

It should be noted that, although this is a change of the API semantics, there 
is no risk we will break any currently working applications by doing this. Any 
application trying to bind to the values in question would be badly broken from 
the outset, so there is no chance we would find any such applications in 
real-world production systems.

Signed-off-by: Jon Maloy <jma...@redhat.com>
---
 net/tipc/socket.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 
e795a8a2955b..a0a144ff84fd 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1,7 +1,8 @@
 /*
  * net/tipc/socket.c: TIPC socket API
  *
- * Copyright (c) 2001-2007, 2012-2017, Ericsson AB
+ * Copyright (c) 2020, Red Hat Inc
+ * Copyright (c) 2001-2007, 2012-2019, Ericsson AB
  * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -127,6 +128,8 @@ struct tipc_sock {
        bool expect_ack;
        bool nodelay;
        bool group_is_open;
+       bool privileged;
+       bool kernel;
 };
 
 static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb); @@ 
-479,6 +482,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        tsk->max_pkt = MAX_PKT_DEFAULT;
        tsk->maxnagle = 0;
        tsk->nagle_start = NAGLE_START_INIT;
+       tsk->kernel = !!kern;
        INIT_LIST_HEAD(&tsk->publications);
        INIT_LIST_HEAD(&tsk->cong_links);
        msg = &tsk->phdr;
@@ -665,6 +669,7 @@ static int tipc_bind(struct socket *sock, struct sockaddr 
*uaddr,
        struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
        struct tipc_sock *tsk = tipc_sk(sk);
        int res = -EINVAL;
+       u32 stype, dnode;
 
        lock_sock(sk);
        if (unlikely(!uaddr_len)) {
@@ -691,13 +696,15 @@ static int tipc_bind(struct socket *sock, struct sockaddr 
*uaddr,
                goto exit;
        }
 
-       if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) &&
-           (addr->addr.nameseq.type != TIPC_TOP_SRV) &&
-           (addr->addr.nameseq.type != TIPC_CFG_SRV)) {
+       stype = addr->addr.nameseq.type;
+       if (stype == TIPC_TOP_SRV && tsk->kernel &&
+           !tipc_nametbl_translate(sock_net(sk), stype, stype, &dnode))
+               tsk->privileged = true;
+
+       if (stype < TIPC_RESERVED_TYPES && !tsk->privileged) {
                res = -EACCES;
                goto exit;
        }
-
        res = (addr->scope >= 0) ?
                tipc_sk_publish(tsk, addr->scope, &addr->addr.nameseq) :
                tipc_sk_withdraw(tsk, -addr->scope, &addr->addr.nameseq);
--
2.25.4



_______________________________________________
tipc-discussion mailing list
tipc-discussion@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tipc-discussion

Reply via email to