Bluetooth: hci_sock: Forward credentials to monitor
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 25 May 2023 23:46:43 +0000 (16:46 -0700)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 11 Aug 2023 18:37:42 +0000 (11:37 -0700)
This stores scm_creds into hci_skb_cb so they can be properly forwarded
to the likes of btmon which is then able to print information about the
process who is originating the traffic:

bluetoothd[35]: @ MGMT Command: Rea.. (0x0001) plen 0  {0x0001}
@ MGMT Event: Command Complete (0x0001) plen 6         {0x0001}
      Read Management Version Information (0x0001) plen 3

bluetoothd[35]: < ACL Data T.. flags 0x00 dlen 41
      ATT: Write Command (0x52) len 36
        Handle: 0x0043 Type: ASE Control Point (0x2bc6)
          Data: 020203000110270000022800020a00409c0001000110270000022800020a00409c00
            Opcode: QoS Configuration (0x02)
            Number of ASE(s): 2
            ASE: #0
            ASE ID: 0x03
            CIG ID: 0x00
            CIS ID: 0x01
            SDU Interval: 10000 usec
            Framing: Unframed (0x00)
            PHY: 0x02
            LE 2M PHY (0x02)
            Max SDU: 40
            RTN: 2
            Max Transport Latency: 10
            Presentation Delay: 40000 us
            ASE: #1
            ASE ID: 0x01
            CIG ID: 0x00
            CIS ID: 0x01
            SDU Interval: 10000 usec
            Framing: Unframed (0x00)
            PHY: 0x02
            LE 2M PHY (0x02)
            Max SDU: 40
            RTN: 2
            Max Transport Latency: 10
            Presentation Delay: 40000 us

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/bluetooth.h
net/bluetooth/hci_sock.c

index 60689a0..34998ae 100644 (file)
@@ -471,6 +471,7 @@ struct bt_skb_cb {
                struct sco_ctrl sco;
                struct hci_ctrl hci;
                struct mgmt_ctrl mgmt;
+               struct scm_creds creds;
        };
 };
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
index 9c45586..5e4f718 100644 (file)
@@ -264,6 +264,53 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
        kfree_skb(skb_copy);
 }
 
+static void hci_sock_copy_creds(struct sock *sk, struct sk_buff *skb)
+{
+       struct scm_creds *creds;
+
+       if (!sk || WARN_ON(!skb))
+               return;
+
+       creds = &bt_cb(skb)->creds;
+
+       /* Check if peer credentials is set */
+       if (!sk->sk_peer_pid) {
+               /* Check if parent peer credentials is set */
+               if (bt_sk(sk)->parent && bt_sk(sk)->parent->sk_peer_pid)
+                       sk = bt_sk(sk)->parent;
+               else
+                       return;
+       }
+
+       /* Check if scm_creds already set */
+       if (creds->pid == pid_vnr(sk->sk_peer_pid))
+               return;
+
+       memset(creds, 0, sizeof(*creds));
+
+       creds->pid = pid_vnr(sk->sk_peer_pid);
+       if (sk->sk_peer_cred) {
+               creds->uid = sk->sk_peer_cred->uid;
+               creds->gid = sk->sk_peer_cred->gid;
+       }
+}
+
+static struct sk_buff *hci_skb_clone(struct sk_buff *skb)
+{
+       struct sk_buff *nskb;
+
+       if (!skb)
+               return NULL;
+
+       nskb = skb_clone(skb, GFP_ATOMIC);
+       if (!nskb)
+               return NULL;
+
+       hci_sock_copy_creds(skb->sk, nskb);
+
+       return nskb;
+}
+
 /* Send frame to sockets with specific channel */
 static void __hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
                                  int flag, struct sock *skip_sk)
@@ -289,7 +336,7 @@ static void __hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
                if (hci_pi(sk)->channel != channel)
                        continue;
 
-               nskb = skb_clone(skb, GFP_ATOMIC);
+               nskb = hci_skb_clone(skb);
                if (!nskb)
                        continue;
 
@@ -356,6 +403,8 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
        if (!skb_copy)
                return;
 
+       hci_sock_copy_creds(skb->sk, skb_copy);
+
        /* Put header before the data */
        hdr = skb_push(skb_copy, HCI_MON_HDR_SIZE);
        hdr->opcode = opcode;
@@ -531,10 +580,12 @@ static struct sk_buff *create_monitor_ctrl_open(struct sock *sk)
                return NULL;
        }
 
-       skb = bt_skb_alloc(14 + TASK_COMM_LEN , GFP_ATOMIC);
+       skb = bt_skb_alloc(14 + TASK_COMM_LEN, GFP_ATOMIC);
        if (!skb)
                return NULL;
 
+       hci_sock_copy_creds(sk, skb);
+
        flags = hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) ? 0x1 : 0x0;
 
        put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
@@ -580,6 +631,8 @@ static struct sk_buff *create_monitor_ctrl_close(struct sock *sk)
        if (!skb)
                return NULL;
 
+       hci_sock_copy_creds(sk, skb);
+
        put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
 
        __net_timestamp(skb);
@@ -606,6 +659,8 @@ static struct sk_buff *create_monitor_ctrl_command(struct sock *sk, u16 index,
        if (!skb)
                return NULL;
 
+       hci_sock_copy_creds(sk, skb);
+
        put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
        put_unaligned_le16(opcode, skb_put(skb, 2));
 
@@ -638,6 +693,8 @@ send_monitor_note(struct sock *sk, const char *fmt, ...)
        if (!skb)
                return;
 
+       hci_sock_copy_creds(sk, skb);
+
        va_start(args, fmt);
        vsprintf(skb_put(skb, len), fmt, args);
        *(u8 *)skb_put(skb, 1) = 0;
@@ -1494,6 +1551,7 @@ static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
 static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg,
                            size_t len, int flags)
 {
+       struct scm_cookie scm;
        struct sock *sk = sock->sk;
        struct sk_buff *skb;
        int copied, err;
@@ -1538,11 +1596,16 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg,
                break;
        }
 
+       memset(&scm, 0, sizeof(scm));
+       scm.creds = bt_cb(skb)->creds;
+
        skb_free_datagram(sk, skb);
 
        if (flags & MSG_TRUNC)
                copied = skblen;
 
+       scm_recv(sock, msg, &scm, flags);
+
        return err ? : copied;
 }