diff options
Diffstat (limited to 'net/netlink/genetlink.c')
| -rw-r--r-- | net/netlink/genetlink.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index f329b72578f5..49bc2db7982b 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Thomas Graf <tgraf@suug.ch> | 5 | * Thomas Graf <tgraf@suug.ch> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/config.h> | ||
| 9 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 10 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
| 11 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
| @@ -320,7 +319,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 320 | goto errout; | 319 | goto errout; |
| 321 | } | 320 | } |
| 322 | 321 | ||
| 323 | if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb)) { | 322 | if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) { |
| 324 | err = -EPERM; | 323 | err = -EPERM; |
| 325 | goto errout; | 324 | goto errout; |
| 326 | } | 325 | } |
| @@ -388,7 +387,10 @@ static void genl_rcv(struct sock *sk, int len) | |||
| 388 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | 387 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, |
| 389 | u32 flags, struct sk_buff *skb, u8 cmd) | 388 | u32 flags, struct sk_buff *skb, u8 cmd) |
| 390 | { | 389 | { |
| 390 | struct nlattr *nla_ops; | ||
| 391 | struct genl_ops *ops; | ||
| 391 | void *hdr; | 392 | void *hdr; |
| 393 | int idx = 1; | ||
| 392 | 394 | ||
| 393 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, | 395 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, |
| 394 | family->version); | 396 | family->version); |
| @@ -397,6 +399,37 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | |||
| 397 | 399 | ||
| 398 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); | 400 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); |
| 399 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); | 401 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); |
| 402 | NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version); | ||
| 403 | NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize); | ||
| 404 | NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr); | ||
| 405 | |||
| 406 | nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); | ||
| 407 | if (nla_ops == NULL) | ||
| 408 | goto nla_put_failure; | ||
| 409 | |||
| 410 | list_for_each_entry(ops, &family->ops_list, ops_list) { | ||
| 411 | struct nlattr *nest; | ||
| 412 | |||
| 413 | nest = nla_nest_start(skb, idx++); | ||
| 414 | if (nest == NULL) | ||
| 415 | goto nla_put_failure; | ||
| 416 | |||
| 417 | NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd); | ||
| 418 | NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags); | ||
| 419 | |||
| 420 | if (ops->policy) | ||
| 421 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_POLICY); | ||
| 422 | |||
| 423 | if (ops->doit) | ||
| 424 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DOIT); | ||
| 425 | |||
| 426 | if (ops->dumpit) | ||
| 427 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DUMPIT); | ||
| 428 | |||
| 429 | nla_nest_end(skb, nest); | ||
| 430 | } | ||
| 431 | |||
| 432 | nla_nest_end(skb, nla_ops); | ||
| 400 | 433 | ||
| 401 | return genlmsg_end(skb, hdr); | 434 | return genlmsg_end(skb, hdr); |
| 402 | 435 | ||
| @@ -412,6 +445,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 412 | int chains_to_skip = cb->args[0]; | 445 | int chains_to_skip = cb->args[0]; |
| 413 | int fams_to_skip = cb->args[1]; | 446 | int fams_to_skip = cb->args[1]; |
| 414 | 447 | ||
| 448 | if (chains_to_skip != 0) | ||
| 449 | genl_lock(); | ||
| 450 | |||
| 415 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 451 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { |
| 416 | if (i < chains_to_skip) | 452 | if (i < chains_to_skip) |
| 417 | continue; | 453 | continue; |
| @@ -429,6 +465,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 429 | } | 465 | } |
| 430 | 466 | ||
| 431 | errout: | 467 | errout: |
| 468 | if (chains_to_skip != 0) | ||
| 469 | genl_unlock(); | ||
| 470 | |||
| 432 | cb->args[0] = i; | 471 | cb->args[0] = i; |
| 433 | cb->args[1] = n; | 472 | cb->args[1] = n; |
| 434 | 473 | ||
| @@ -441,7 +480,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, | |||
| 441 | struct sk_buff *skb; | 480 | struct sk_buff *skb; |
| 442 | int err; | 481 | int err; |
| 443 | 482 | ||
| 444 | skb = nlmsg_new(NLMSG_GOODSIZE); | 483 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
| 445 | if (skb == NULL) | 484 | if (skb == NULL) |
| 446 | return ERR_PTR(-ENOBUFS); | 485 | return ERR_PTR(-ENOBUFS); |
| 447 | 486 | ||
| @@ -456,7 +495,8 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, | |||
| 456 | 495 | ||
| 457 | static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = { | 496 | static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = { |
| 458 | [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, | 497 | [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, |
| 459 | [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING }, | 498 | [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING, |
| 499 | .len = GENL_NAMSIZ - 1 }, | ||
| 460 | }; | 500 | }; |
| 461 | 501 | ||
| 462 | static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | 502 | static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) |
| @@ -471,12 +511,9 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | |||
| 471 | } | 511 | } |
| 472 | 512 | ||
| 473 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { | 513 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { |
| 474 | char name[GENL_NAMSIZ]; | 514 | char *name; |
| 475 | |||
| 476 | if (nla_strlcpy(name, info->attrs[CTRL_ATTR_FAMILY_NAME], | ||
| 477 | GENL_NAMSIZ) >= GENL_NAMSIZ) | ||
| 478 | goto errout; | ||
| 479 | 515 | ||
| 516 | name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]); | ||
| 480 | res = genl_family_find_byname(name); | 517 | res = genl_family_find_byname(name); |
| 481 | } | 518 | } |
| 482 | 519 | ||
| @@ -511,7 +548,7 @@ static int genl_ctrl_event(int event, void *data) | |||
| 511 | if (IS_ERR(msg)) | 548 | if (IS_ERR(msg)) |
| 512 | return PTR_ERR(msg); | 549 | return PTR_ERR(msg); |
| 513 | 550 | ||
| 514 | genlmsg_multicast(msg, 0, GENL_ID_CTRL); | 551 | genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); |
| 515 | break; | 552 | break; |
| 516 | } | 553 | } |
| 517 | 554 | ||
