Chris Wright wrote:
Great, thanks. This is technically racy. It's possible (albeit small
window) that something could be delivered before this is set.
Yes, hard trigger but that can happen and doesn't tell too much in
favour of me.
Using a callback struct during registration would fix this.
I agree, maybe something like the example patch attached. Hope that helps.
--
Pablo
===== net/netlink/af_netlink.c 1.69 vs edited =====
--- 1.69/net/netlink/af_netlink.c 2005-01-21 21:25:32 +01:00
+++ edited/net/netlink/af_netlink.c 2005-02-15 23:10:47 +01:00
@@ -71,6 +71,7 @@
struct netlink_callback *cb;
spinlock_t cb_lock;
void (*data_ready)(struct sock *sk, int bytes);
+ int (*check_sender)(struct sk_buff *skb);
};
#define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->sk_protinfo)
@@ -636,9 +637,16 @@
int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol)
{
struct netlink_opt *nlk;
- int len = skb->len;
+ int err, len = skb->len;
+
+ nlk = nlk_sk(sk);
+
+ if (nlk->check_sender)
+ if ((err = nlk->check_sender(skb))) {
+ netlink_detachskb(sk, skb);
+ return err;
+ }
- nlk = nlk_sk(sk);
#ifdef NL_EMULATE_DEV
if (nlk->handler) {
skb_orphan(skb);
@@ -1033,7 +1041,7 @@
*/
struct sock *
-netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len))
+netlink_kernel_create(int unit, struct netlink_ops *nlops)
{
struct socket *sock;
struct sock *sk;
@@ -1053,8 +1061,12 @@
}
sk = sock->sk;
sk->sk_data_ready = netlink_data_ready;
- if (input)
- nlk_sk(sk)->data_ready = input;
+ if (nlops != NULL) {
+ if (nlops->input)
+ nlk_sk(sk)->data_ready = nlops->input;
+ if (nlops->check_sender)
+ nlk_sk(sk)->check_sender = nlops->check_sender;
+ }
if (netlink_insert(sk, 0)) {
sock_release(sock);
===== include/linux/netlink.h 1.23 vs edited =====
--- 1.23/include/linux/netlink.h 2005-02-07 06:59:39 +01:00
+++ edited/include/linux/netlink.h 2005-02-15 22:53:01 +01:00
@@ -115,8 +115,13 @@
#define NETLINK_CB(skb) (*(struct
netlink_skb_parms*)&((skb)->cb))
#define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds)
+struct netlink_ops
+{
+ void (*input)(struct sock *sk, int len);
+ int (*check_sender)(struct sk_buff *skb);
+};
-extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock
*sk, int len));
+extern struct sock *netlink_kernel_create(int unit, struct netlink_ops *nlops);
extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
int nonblock);
extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
===== net/core/rtnetlink.c 1.33 vs edited =====
--- 1.33/net/core/rtnetlink.c 2005-01-10 22:42:22 +01:00
+++ edited/net/core/rtnetlink.c 2005-02-15 23:08:05 +01:00
@@ -462,8 +462,32 @@
static struct rtattr **rta_buf;
static int rtattr_max;
-/* Process one rtnetlink message. */
+static int rtnetlink_check_sender(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+ int kind;
+ int type;
+
+ if (skb->len < NLMSG_LENGTH(0))
+ return -EINVAL;
+
+ nlh = (struct nlmsghdr *)skb->data;
+ type = nlh->nlmsg_type;
+
+ /* Unknown message: reply with EINVAL */
+ if (type > RTM_MAX)
+ return -EINVAL;
+
+ type -= RTM_BASE;
+ kind = type&3;
+ if (kind != 2 && !capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ return 0;
+}
+
+/* Process one rtnetlink message. */
static __inline__ int
rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
{
@@ -485,10 +509,6 @@
if (type < RTM_BASE)
return 0;
- /* Unknown message: reply with EINVAL */
- if (type > RTM_MAX)
- goto err_inval;
-
type -= RTM_BASE;
/* All the messages must have at least 1 byte length */
@@ -509,11 +529,6 @@
sz_idx = type>>2;
kind = type&3;
- if (kind != 2 && security_netlink_recv(skb)) {
- *errp = -EPERM;
- return -1;
- }
-
if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
u32 rlen;
@@ -681,6 +696,10 @@
void __init rtnetlink_init(void)
{
int i;
+ struct netlink_ops rtnl_ops = {
+ .input = rtnetlink_rcv,
+ .check_sender = rtnetlink_check_sender
+ };
rtattr_max = 0;
for (i = 0; i < ARRAY_SIZE(rta_max); i++)
@@ -690,7 +709,7 @@
if (!rta_buf)
panic("rtnetlink_init: cannot allocate rta_buf\n");
- rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv);
+ rtnl = netlink_kernel_create(NETLINK_ROUTE, &rtnl_ops);
if (rtnl == NULL)
panic("rtnetlink_init: cannot initialize rtnetlink\n");
netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
|