2023-05-26 00:05:59

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH 3/3] Bluetooth: hci_sock: Forward credentials to monitor

From: Luiz Augusto von Dentz <[email protected]>

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

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/bluetooth.h | 1 +
net/bluetooth/hci_sock.c | 60 +++++++++++++++++++++++++++++--
2 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index b518e5379045..310231e47b3d 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -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))
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 9c45586f5818..2cb996e88caf 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -264,6 +264,45 @@ 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 scm_creds *creds)
+{
+ if (!sk || !creds)
+ return;
+
+ /* 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;
+ }
+
+ 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, &bt_cb(nskb)->creds);
+
+ 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 +328,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 +395,8 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
if (!skb_copy)
return;

+ hci_sock_copy_creds(skb->sk, &bt_cb(skb_copy)->creds);
+
/* Put header before the data */
hdr = skb_push(skb_copy, HCI_MON_HDR_SIZE);
hdr->opcode = opcode;
@@ -531,10 +572,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, &bt_cb(skb)->creds);
+
flags = hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) ? 0x1 : 0x0;

put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
@@ -580,6 +623,8 @@ static struct sk_buff *create_monitor_ctrl_close(struct sock *sk)
if (!skb)
return NULL;

+ hci_sock_copy_creds(sk, &bt_cb(skb)->creds);
+
put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));

__net_timestamp(skb);
@@ -606,6 +651,8 @@ static struct sk_buff *create_monitor_ctrl_command(struct sock *sk, u16 index,
if (!skb)
return NULL;

+ hci_sock_copy_creds(sk, &bt_cb(skb)->creds);
+
put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
put_unaligned_le16(opcode, skb_put(skb, 2));

@@ -638,6 +685,8 @@ send_monitor_note(struct sock *sk, const char *fmt, ...)
if (!skb)
return;

+ hci_sock_copy_creds(sk, &bt_cb(skb)->creds);
+
va_start(args, fmt);
vsprintf(skb_put(skb, len), fmt, args);
*(u8 *)skb_put(skb, 1) = 0;
@@ -1494,6 +1543,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 +1588,17 @@ 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;

+ if (scm.creds.pid)
+ scm_recv(sock, msg, &scm, flags);
+
return err ? : copied;
}

--
2.40.1