diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 98 | ||||
-rw-r--r-- | net/netlink/attr.c | 5 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 66 |
3 files changed, 88 insertions, 81 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c48b0f49f003..42d2fb94eff1 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <linux/types.h> | 56 | #include <linux/types.h> |
57 | #include <linux/audit.h> | 57 | #include <linux/audit.h> |
58 | #include <linux/selinux.h> | 58 | #include <linux/selinux.h> |
59 | #include <linux/mutex.h> | ||
59 | 60 | ||
60 | #include <net/sock.h> | 61 | #include <net/sock.h> |
61 | #include <net/scm.h> | 62 | #include <net/scm.h> |
@@ -76,7 +77,8 @@ struct netlink_sock { | |||
76 | unsigned long state; | 77 | unsigned long state; |
77 | wait_queue_head_t wait; | 78 | wait_queue_head_t wait; |
78 | struct netlink_callback *cb; | 79 | struct netlink_callback *cb; |
79 | spinlock_t cb_lock; | 80 | struct mutex *cb_mutex; |
81 | struct mutex cb_def_mutex; | ||
80 | void (*data_ready)(struct sock *sk, int bytes); | 82 | void (*data_ready)(struct sock *sk, int bytes); |
81 | struct module *module; | 83 | struct module *module; |
82 | }; | 84 | }; |
@@ -108,6 +110,7 @@ struct netlink_table { | |||
108 | unsigned long *listeners; | 110 | unsigned long *listeners; |
109 | unsigned int nl_nonroot; | 111 | unsigned int nl_nonroot; |
110 | unsigned int groups; | 112 | unsigned int groups; |
113 | struct mutex *cb_mutex; | ||
111 | struct module *module; | 114 | struct module *module; |
112 | int registered; | 115 | int registered; |
113 | }; | 116 | }; |
@@ -118,6 +121,7 @@ static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); | |||
118 | 121 | ||
119 | static int netlink_dump(struct sock *sk); | 122 | static int netlink_dump(struct sock *sk); |
120 | static void netlink_destroy_callback(struct netlink_callback *cb); | 123 | static void netlink_destroy_callback(struct netlink_callback *cb); |
124 | static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb); | ||
121 | 125 | ||
122 | static DEFINE_RWLOCK(nl_table_lock); | 126 | static DEFINE_RWLOCK(nl_table_lock); |
123 | static atomic_t nl_table_users = ATOMIC_INIT(0); | 127 | static atomic_t nl_table_users = ATOMIC_INIT(0); |
@@ -370,7 +374,8 @@ static struct proto netlink_proto = { | |||
370 | .obj_size = sizeof(struct netlink_sock), | 374 | .obj_size = sizeof(struct netlink_sock), |
371 | }; | 375 | }; |
372 | 376 | ||
373 | static int __netlink_create(struct socket *sock, int protocol) | 377 | static int __netlink_create(struct socket *sock, struct mutex *cb_mutex, |
378 | int protocol) | ||
374 | { | 379 | { |
375 | struct sock *sk; | 380 | struct sock *sk; |
376 | struct netlink_sock *nlk; | 381 | struct netlink_sock *nlk; |
@@ -384,7 +389,12 @@ static int __netlink_create(struct socket *sock, int protocol) | |||
384 | sock_init_data(sock, sk); | 389 | sock_init_data(sock, sk); |
385 | 390 | ||
386 | nlk = nlk_sk(sk); | 391 | nlk = nlk_sk(sk); |
387 | spin_lock_init(&nlk->cb_lock); | 392 | if (cb_mutex) |
393 | nlk->cb_mutex = cb_mutex; | ||
394 | else { | ||
395 | nlk->cb_mutex = &nlk->cb_def_mutex; | ||
396 | mutex_init(nlk->cb_mutex); | ||
397 | } | ||
388 | init_waitqueue_head(&nlk->wait); | 398 | init_waitqueue_head(&nlk->wait); |
389 | 399 | ||
390 | sk->sk_destruct = netlink_sock_destruct; | 400 | sk->sk_destruct = netlink_sock_destruct; |
@@ -395,8 +405,8 @@ static int __netlink_create(struct socket *sock, int protocol) | |||
395 | static int netlink_create(struct socket *sock, int protocol) | 405 | static int netlink_create(struct socket *sock, int protocol) |
396 | { | 406 | { |
397 | struct module *module = NULL; | 407 | struct module *module = NULL; |
408 | struct mutex *cb_mutex; | ||
398 | struct netlink_sock *nlk; | 409 | struct netlink_sock *nlk; |
399 | unsigned int groups; | ||
400 | int err = 0; | 410 | int err = 0; |
401 | 411 | ||
402 | sock->state = SS_UNCONNECTED; | 412 | sock->state = SS_UNCONNECTED; |
@@ -418,10 +428,10 @@ static int netlink_create(struct socket *sock, int protocol) | |||
418 | if (nl_table[protocol].registered && | 428 | if (nl_table[protocol].registered && |
419 | try_module_get(nl_table[protocol].module)) | 429 | try_module_get(nl_table[protocol].module)) |
420 | module = nl_table[protocol].module; | 430 | module = nl_table[protocol].module; |
421 | groups = nl_table[protocol].groups; | 431 | cb_mutex = nl_table[protocol].cb_mutex; |
422 | netlink_unlock_table(); | 432 | netlink_unlock_table(); |
423 | 433 | ||
424 | if ((err = __netlink_create(sock, protocol)) < 0) | 434 | if ((err = __netlink_create(sock, cb_mutex, protocol)) < 0) |
425 | goto out_module; | 435 | goto out_module; |
426 | 436 | ||
427 | nlk = nlk_sk(sock->sk); | 437 | nlk = nlk_sk(sock->sk); |
@@ -446,14 +456,14 @@ static int netlink_release(struct socket *sock) | |||
446 | sock_orphan(sk); | 456 | sock_orphan(sk); |
447 | nlk = nlk_sk(sk); | 457 | nlk = nlk_sk(sk); |
448 | 458 | ||
449 | spin_lock(&nlk->cb_lock); | 459 | mutex_lock(nlk->cb_mutex); |
450 | if (nlk->cb) { | 460 | if (nlk->cb) { |
451 | if (nlk->cb->done) | 461 | if (nlk->cb->done) |
452 | nlk->cb->done(nlk->cb); | 462 | nlk->cb->done(nlk->cb); |
453 | netlink_destroy_callback(nlk->cb); | 463 | netlink_destroy_callback(nlk->cb); |
454 | nlk->cb = NULL; | 464 | nlk->cb = NULL; |
455 | } | 465 | } |
456 | spin_unlock(&nlk->cb_lock); | 466 | mutex_unlock(nlk->cb_mutex); |
457 | 467 | ||
458 | /* OK. Socket is unlinked, and, therefore, | 468 | /* OK. Socket is unlinked, and, therefore, |
459 | no new packets will arrive */ | 469 | no new packets will arrive */ |
@@ -1215,7 +1225,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1215 | copied = len; | 1225 | copied = len; |
1216 | } | 1226 | } |
1217 | 1227 | ||
1218 | skb->h.raw = skb->data; | 1228 | skb_reset_transport_header(skb); |
1219 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | 1229 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); |
1220 | 1230 | ||
1221 | if (msg->msg_name) { | 1231 | if (msg->msg_name) { |
@@ -1242,6 +1252,9 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1242 | 1252 | ||
1243 | scm_recv(sock, msg, siocb->scm, flags); | 1253 | scm_recv(sock, msg, siocb->scm, flags); |
1244 | 1254 | ||
1255 | if (flags & MSG_TRUNC) | ||
1256 | copied = skb->len; | ||
1257 | |||
1245 | out: | 1258 | out: |
1246 | netlink_rcv_wake(sk); | 1259 | netlink_rcv_wake(sk); |
1247 | return err ? : copied; | 1260 | return err ? : copied; |
@@ -1265,7 +1278,7 @@ static void netlink_data_ready(struct sock *sk, int len) | |||
1265 | struct sock * | 1278 | struct sock * |
1266 | netlink_kernel_create(int unit, unsigned int groups, | 1279 | netlink_kernel_create(int unit, unsigned int groups, |
1267 | void (*input)(struct sock *sk, int len), | 1280 | void (*input)(struct sock *sk, int len), |
1268 | struct module *module) | 1281 | struct mutex *cb_mutex, struct module *module) |
1269 | { | 1282 | { |
1270 | struct socket *sock; | 1283 | struct socket *sock; |
1271 | struct sock *sk; | 1284 | struct sock *sk; |
@@ -1280,7 +1293,7 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1280 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) | 1293 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) |
1281 | return NULL; | 1294 | return NULL; |
1282 | 1295 | ||
1283 | if (__netlink_create(sock, unit) < 0) | 1296 | if (__netlink_create(sock, cb_mutex, unit) < 0) |
1284 | goto out_sock_release; | 1297 | goto out_sock_release; |
1285 | 1298 | ||
1286 | if (groups < 32) | 1299 | if (groups < 32) |
@@ -1304,6 +1317,7 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1304 | netlink_table_grab(); | 1317 | netlink_table_grab(); |
1305 | nl_table[unit].groups = groups; | 1318 | nl_table[unit].groups = groups; |
1306 | nl_table[unit].listeners = listeners; | 1319 | nl_table[unit].listeners = listeners; |
1320 | nl_table[unit].cb_mutex = cb_mutex; | ||
1307 | nl_table[unit].module = module; | 1321 | nl_table[unit].module = module; |
1308 | nl_table[unit].registered = 1; | 1322 | nl_table[unit].registered = 1; |
1309 | netlink_table_ungrab(); | 1323 | netlink_table_ungrab(); |
@@ -1346,7 +1360,7 @@ static int netlink_dump(struct sock *sk) | |||
1346 | if (!skb) | 1360 | if (!skb) |
1347 | goto errout; | 1361 | goto errout; |
1348 | 1362 | ||
1349 | spin_lock(&nlk->cb_lock); | 1363 | mutex_lock(nlk->cb_mutex); |
1350 | 1364 | ||
1351 | cb = nlk->cb; | 1365 | cb = nlk->cb; |
1352 | if (cb == NULL) { | 1366 | if (cb == NULL) { |
@@ -1357,7 +1371,7 @@ static int netlink_dump(struct sock *sk) | |||
1357 | len = cb->dump(skb, cb); | 1371 | len = cb->dump(skb, cb); |
1358 | 1372 | ||
1359 | if (len > 0) { | 1373 | if (len > 0) { |
1360 | spin_unlock(&nlk->cb_lock); | 1374 | mutex_unlock(nlk->cb_mutex); |
1361 | skb_queue_tail(&sk->sk_receive_queue, skb); | 1375 | skb_queue_tail(&sk->sk_receive_queue, skb); |
1362 | sk->sk_data_ready(sk, len); | 1376 | sk->sk_data_ready(sk, len); |
1363 | return 0; | 1377 | return 0; |
@@ -1375,13 +1389,13 @@ static int netlink_dump(struct sock *sk) | |||
1375 | if (cb->done) | 1389 | if (cb->done) |
1376 | cb->done(cb); | 1390 | cb->done(cb); |
1377 | nlk->cb = NULL; | 1391 | nlk->cb = NULL; |
1378 | spin_unlock(&nlk->cb_lock); | 1392 | mutex_unlock(nlk->cb_mutex); |
1379 | 1393 | ||
1380 | netlink_destroy_callback(cb); | 1394 | netlink_destroy_callback(cb); |
1381 | return 0; | 1395 | return 0; |
1382 | 1396 | ||
1383 | errout_skb: | 1397 | errout_skb: |
1384 | spin_unlock(&nlk->cb_lock); | 1398 | mutex_unlock(nlk->cb_mutex); |
1385 | kfree_skb(skb); | 1399 | kfree_skb(skb); |
1386 | errout: | 1400 | errout: |
1387 | return err; | 1401 | return err; |
@@ -1413,19 +1427,24 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
1413 | } | 1427 | } |
1414 | nlk = nlk_sk(sk); | 1428 | nlk = nlk_sk(sk); |
1415 | /* A dump or destruction is in progress... */ | 1429 | /* A dump or destruction is in progress... */ |
1416 | spin_lock(&nlk->cb_lock); | 1430 | mutex_lock(nlk->cb_mutex); |
1417 | if (nlk->cb || sock_flag(sk, SOCK_DEAD)) { | 1431 | if (nlk->cb || sock_flag(sk, SOCK_DEAD)) { |
1418 | spin_unlock(&nlk->cb_lock); | 1432 | mutex_unlock(nlk->cb_mutex); |
1419 | netlink_destroy_callback(cb); | 1433 | netlink_destroy_callback(cb); |
1420 | sock_put(sk); | 1434 | sock_put(sk); |
1421 | return -EBUSY; | 1435 | return -EBUSY; |
1422 | } | 1436 | } |
1423 | nlk->cb = cb; | 1437 | nlk->cb = cb; |
1424 | spin_unlock(&nlk->cb_lock); | 1438 | mutex_unlock(nlk->cb_mutex); |
1425 | 1439 | ||
1426 | netlink_dump(sk); | 1440 | netlink_dump(sk); |
1427 | sock_put(sk); | 1441 | sock_put(sk); |
1428 | return 0; | 1442 | |
1443 | /* We successfully started a dump, by returning -EINTR we | ||
1444 | * signal the queue mangement to interrupt processing of | ||
1445 | * any netlink messages so userspace gets a chance to read | ||
1446 | * the results. */ | ||
1447 | return -EINTR; | ||
1429 | } | 1448 | } |
1430 | 1449 | ||
1431 | void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | 1450 | void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) |
@@ -1462,27 +1481,35 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
1462 | } | 1481 | } |
1463 | 1482 | ||
1464 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | 1483 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, |
1465 | struct nlmsghdr *, int *)) | 1484 | struct nlmsghdr *)) |
1466 | { | 1485 | { |
1467 | struct nlmsghdr *nlh; | 1486 | struct nlmsghdr *nlh; |
1468 | int err; | 1487 | int err; |
1469 | 1488 | ||
1470 | while (skb->len >= nlmsg_total_size(0)) { | 1489 | while (skb->len >= nlmsg_total_size(0)) { |
1471 | nlh = (struct nlmsghdr *) skb->data; | 1490 | nlh = nlmsg_hdr(skb); |
1491 | err = 0; | ||
1472 | 1492 | ||
1473 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) | 1493 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) |
1474 | return 0; | 1494 | return 0; |
1475 | 1495 | ||
1476 | if (cb(skb, nlh, &err) < 0) { | 1496 | /* Only requests are handled by the kernel */ |
1477 | /* Not an error, but we have to interrupt processing | 1497 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) |
1478 | * here. Note: that in this case we do not pull | 1498 | goto skip; |
1479 | * message from skb, it will be processed later. | 1499 | |
1480 | */ | 1500 | /* Skip control messages */ |
1481 | if (err == 0) | 1501 | if (nlh->nlmsg_type < NLMSG_MIN_TYPE) |
1482 | return -1; | 1502 | goto skip; |
1503 | |||
1504 | err = cb(skb, nlh); | ||
1505 | if (err == -EINTR) { | ||
1506 | /* Not an error, but we interrupt processing */ | ||
1507 | netlink_queue_skip(nlh, skb); | ||
1508 | return err; | ||
1509 | } | ||
1510 | skip: | ||
1511 | if (nlh->nlmsg_flags & NLM_F_ACK || err) | ||
1483 | netlink_ack(skb, nlh, err); | 1512 | netlink_ack(skb, nlh, err); |
1484 | } else if (nlh->nlmsg_flags & NLM_F_ACK) | ||
1485 | netlink_ack(skb, nlh, 0); | ||
1486 | 1513 | ||
1487 | netlink_queue_skip(nlh, skb); | 1514 | netlink_queue_skip(nlh, skb); |
1488 | } | 1515 | } |
@@ -1504,9 +1531,14 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | |||
1504 | * | 1531 | * |
1505 | * qlen must be initialized to 0 before the initial entry, afterwards | 1532 | * qlen must be initialized to 0 before the initial entry, afterwards |
1506 | * the function may be called repeatedly until qlen reaches 0. | 1533 | * the function may be called repeatedly until qlen reaches 0. |
1534 | * | ||
1535 | * The callback function may return -EINTR to signal that processing | ||
1536 | * of netlink messages shall be interrupted. In this case the message | ||
1537 | * currently being processed will NOT be requeued onto the receive | ||
1538 | * queue. | ||
1507 | */ | 1539 | */ |
1508 | void netlink_run_queue(struct sock *sk, unsigned int *qlen, | 1540 | void netlink_run_queue(struct sock *sk, unsigned int *qlen, |
1509 | int (*cb)(struct sk_buff *, struct nlmsghdr *, int *)) | 1541 | int (*cb)(struct sk_buff *, struct nlmsghdr *)) |
1510 | { | 1542 | { |
1511 | struct sk_buff *skb; | 1543 | struct sk_buff *skb; |
1512 | 1544 | ||
@@ -1537,7 +1569,7 @@ void netlink_run_queue(struct sock *sk, unsigned int *qlen, | |||
1537 | * Pulls the given netlink message off the socket buffer so the next | 1569 | * Pulls the given netlink message off the socket buffer so the next |
1538 | * call to netlink_queue_run() will not reconsider the message. | 1570 | * call to netlink_queue_run() will not reconsider the message. |
1539 | */ | 1571 | */ |
1540 | void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) | 1572 | static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) |
1541 | { | 1573 | { |
1542 | int msglen = NLMSG_ALIGN(nlh->nlmsg_len); | 1574 | int msglen = NLMSG_ALIGN(nlh->nlmsg_len); |
1543 | 1575 | ||
@@ -1820,12 +1852,10 @@ core_initcall(netlink_proto_init); | |||
1820 | 1852 | ||
1821 | EXPORT_SYMBOL(netlink_ack); | 1853 | EXPORT_SYMBOL(netlink_ack); |
1822 | EXPORT_SYMBOL(netlink_run_queue); | 1854 | EXPORT_SYMBOL(netlink_run_queue); |
1823 | EXPORT_SYMBOL(netlink_queue_skip); | ||
1824 | EXPORT_SYMBOL(netlink_broadcast); | 1855 | EXPORT_SYMBOL(netlink_broadcast); |
1825 | EXPORT_SYMBOL(netlink_dump_start); | 1856 | EXPORT_SYMBOL(netlink_dump_start); |
1826 | EXPORT_SYMBOL(netlink_kernel_create); | 1857 | EXPORT_SYMBOL(netlink_kernel_create); |
1827 | EXPORT_SYMBOL(netlink_register_notifier); | 1858 | EXPORT_SYMBOL(netlink_register_notifier); |
1828 | EXPORT_SYMBOL(netlink_set_err); | ||
1829 | EXPORT_SYMBOL(netlink_set_nonroot); | 1859 | EXPORT_SYMBOL(netlink_set_nonroot); |
1830 | EXPORT_SYMBOL(netlink_unicast); | 1860 | EXPORT_SYMBOL(netlink_unicast); |
1831 | EXPORT_SYMBOL(netlink_unregister_notifier); | 1861 | EXPORT_SYMBOL(netlink_unregister_notifier); |
diff --git a/net/netlink/attr.c b/net/netlink/attr.c index 004139557e09..df5f820a4c32 100644 --- a/net/netlink/attr.c +++ b/net/netlink/attr.c | |||
@@ -67,6 +67,11 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
67 | } | 67 | } |
68 | break; | 68 | break; |
69 | 69 | ||
70 | case NLA_BINARY: | ||
71 | if (pt->len && attrlen > pt->len) | ||
72 | return -ERANGE; | ||
73 | break; | ||
74 | |||
70 | default: | 75 | default: |
71 | if (pt->len) | 76 | if (pt->len) |
72 | minlen = pt->len; | 77 | minlen = pt->len; |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index c2996794eb25..6e31234a4196 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -295,66 +295,46 @@ int genl_unregister_family(struct genl_family *family) | |||
295 | return -ENOENT; | 295 | return -ENOENT; |
296 | } | 296 | } |
297 | 297 | ||
298 | static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | 298 | static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
299 | int *errp) | ||
300 | { | 299 | { |
301 | struct genl_ops *ops; | 300 | struct genl_ops *ops; |
302 | struct genl_family *family; | 301 | struct genl_family *family; |
303 | struct genl_info info; | 302 | struct genl_info info; |
304 | struct genlmsghdr *hdr = nlmsg_data(nlh); | 303 | struct genlmsghdr *hdr = nlmsg_data(nlh); |
305 | int hdrlen, err = -EINVAL; | 304 | int hdrlen, err; |
306 | |||
307 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) | ||
308 | goto ignore; | ||
309 | |||
310 | if (nlh->nlmsg_type < NLMSG_MIN_TYPE) | ||
311 | goto ignore; | ||
312 | 305 | ||
313 | family = genl_family_find_byid(nlh->nlmsg_type); | 306 | family = genl_family_find_byid(nlh->nlmsg_type); |
314 | if (family == NULL) { | 307 | if (family == NULL) |
315 | err = -ENOENT; | 308 | return -ENOENT; |
316 | goto errout; | ||
317 | } | ||
318 | 309 | ||
319 | hdrlen = GENL_HDRLEN + family->hdrsize; | 310 | hdrlen = GENL_HDRLEN + family->hdrsize; |
320 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) | 311 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) |
321 | goto errout; | 312 | return -EINVAL; |
322 | 313 | ||
323 | ops = genl_get_cmd(hdr->cmd, family); | 314 | ops = genl_get_cmd(hdr->cmd, family); |
324 | if (ops == NULL) { | 315 | if (ops == NULL) |
325 | err = -EOPNOTSUPP; | 316 | return -EOPNOTSUPP; |
326 | goto errout; | ||
327 | } | ||
328 | 317 | ||
329 | if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) { | 318 | if ((ops->flags & GENL_ADMIN_PERM) && |
330 | err = -EPERM; | 319 | security_netlink_recv(skb, CAP_NET_ADMIN)) |
331 | goto errout; | 320 | return -EPERM; |
332 | } | ||
333 | 321 | ||
334 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 322 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
335 | if (ops->dumpit == NULL) { | 323 | if (ops->dumpit == NULL) |
336 | err = -EOPNOTSUPP; | 324 | return -EOPNOTSUPP; |
337 | goto errout; | ||
338 | } | ||
339 | 325 | ||
340 | *errp = err = netlink_dump_start(genl_sock, skb, nlh, | 326 | return netlink_dump_start(genl_sock, skb, nlh, |
341 | ops->dumpit, ops->done); | 327 | ops->dumpit, ops->done); |
342 | if (err == 0) | ||
343 | skb_pull(skb, min(NLMSG_ALIGN(nlh->nlmsg_len), | ||
344 | skb->len)); | ||
345 | return -1; | ||
346 | } | 328 | } |
347 | 329 | ||
348 | if (ops->doit == NULL) { | 330 | if (ops->doit == NULL) |
349 | err = -EOPNOTSUPP; | 331 | return -EOPNOTSUPP; |
350 | goto errout; | ||
351 | } | ||
352 | 332 | ||
353 | if (family->attrbuf) { | 333 | if (family->attrbuf) { |
354 | err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr, | 334 | err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr, |
355 | ops->policy); | 335 | ops->policy); |
356 | if (err < 0) | 336 | if (err < 0) |
357 | goto errout; | 337 | return err; |
358 | } | 338 | } |
359 | 339 | ||
360 | info.snd_seq = nlh->nlmsg_seq; | 340 | info.snd_seq = nlh->nlmsg_seq; |
@@ -364,15 +344,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
364 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; | 344 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; |
365 | info.attrs = family->attrbuf; | 345 | info.attrs = family->attrbuf; |
366 | 346 | ||
367 | *errp = err = ops->doit(skb, &info); | 347 | return ops->doit(skb, &info); |
368 | return err; | ||
369 | |||
370 | ignore: | ||
371 | return 0; | ||
372 | |||
373 | errout: | ||
374 | *errp = err; | ||
375 | return -1; | ||
376 | } | 348 | } |
377 | 349 | ||
378 | static void genl_rcv(struct sock *sk, int len) | 350 | static void genl_rcv(struct sock *sk, int len) |
@@ -586,7 +558,7 @@ static int __init genl_init(void) | |||
586 | 558 | ||
587 | netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); | 559 | netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); |
588 | genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID, | 560 | genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID, |
589 | genl_rcv, THIS_MODULE); | 561 | genl_rcv, NULL, THIS_MODULE); |
590 | if (genl_sock == NULL) | 562 | if (genl_sock == NULL) |
591 | panic("GENL: Cannot initialize generic netlink\n"); | 563 | panic("GENL: Cannot initialize generic netlink\n"); |
592 | 564 | ||