Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: attribute count is an attribute of message type, not subsytem

Prior to this patch, every nfnetlink subsystem had to specify it's
attribute count. However, in reality the attribute count depends on
the message type within the subsystem, not the subsystem itself. This
patch moves 'attr_count' from 'struct nfnetlink_subsys' into
nfnl_callback to fix this.

Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Harald Welte and committed by
David S. Miller
927ccbcc bd9a26b7

+31 -11
+2 -2
include/linux/netfilter/nfnetlink.h
··· 85 85 86 86 struct nfnl_callback 87 87 { 88 - kernel_cap_t cap_required; /* capabilities required for this msg */ 89 88 int (*call)(struct sock *nl, struct sk_buff *skb, 90 89 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp); 90 + kernel_cap_t cap_required; /* capabilities required for this msg */ 91 + u_int16_t attr_count; /* number of nfattr's */ 91 92 }; 92 93 93 94 struct nfnetlink_subsystem ··· 96 95 const char *name; 97 96 __u8 subsys_id; /* nfnetlink subsystem ID */ 98 97 __u8 cb_count; /* number of callbacks */ 99 - u_int32_t attr_count; /* number of nfattr's */ 100 98 struct nfnl_callback *cb; /* callback for individual types */ 101 99 }; 102 100
+7 -2
net/ipv4/netfilter/ip_conntrack_netlink.c
··· 1484 1484 1485 1485 static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { 1486 1486 [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, 1487 + .attr_count = CTA_MAX, 1487 1488 .cap_required = CAP_NET_ADMIN }, 1488 1489 [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, 1490 + .attr_count = CTA_MAX, 1489 1491 .cap_required = CAP_NET_ADMIN }, 1490 1492 [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, 1493 + .attr_count = CTA_MAX, 1491 1494 .cap_required = CAP_NET_ADMIN }, 1492 1495 [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, 1496 + .attr_count = CTA_MAX, 1493 1497 .cap_required = CAP_NET_ADMIN }, 1494 1498 }; 1495 1499 1496 1500 static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_MAX] = { 1497 1501 [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, 1502 + .attr_count = CTA_EXPECT_MAX, 1498 1503 .cap_required = CAP_NET_ADMIN }, 1499 1504 [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, 1505 + .attr_count = CTA_EXPECT_MAX, 1500 1506 .cap_required = CAP_NET_ADMIN }, 1501 1507 [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, 1508 + .attr_count = CTA_EXPECT_MAX, 1502 1509 .cap_required = CAP_NET_ADMIN }, 1503 1510 }; 1504 1511 ··· 1513 1506 .name = "conntrack", 1514 1507 .subsys_id = NFNL_SUBSYS_CTNETLINK, 1515 1508 .cb_count = IPCTNL_MSG_MAX, 1516 - .attr_count = CTA_MAX, 1517 1509 .cb = ctnl_cb, 1518 1510 }; 1519 1511 ··· 1520 1514 .name = "conntrack_expect", 1521 1515 .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, 1522 1516 .cb_count = IPCTNL_MSG_EXP_MAX, 1523 - .attr_count = CTA_MAX, 1524 1517 .cb = ctnl_exp_cb, 1525 1518 }; 1526 1519
+16 -4
net/netfilter/nfnetlink.c
··· 155 155 struct nlmsghdr *nlh, struct nfattr *cda[]) 156 156 { 157 157 int min_len; 158 + u_int16_t attr_count; 159 + u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); 158 160 159 - memset(cda, 0, sizeof(struct nfattr *) * subsys->attr_count); 161 + if (unlikely(cb_id >= subsys->cb_count)) { 162 + DEBUGP("msgtype %u >= %u, returning\n", 163 + cb_id, subsys->cb_count); 164 + return -EINVAL; 165 + } 166 + 167 + attr_count = subsys->cb[cb_id].attr_count; 168 + 169 + memset(cda, 0, sizeof(struct nfattr *) * attr_count); 160 170 161 171 /* check attribute lengths. */ 162 172 min_len = NLMSG_ALIGN(sizeof(struct nfgenmsg)); ··· 180 170 while (NFA_OK(attr, attrlen)) { 181 171 unsigned flavor = attr->nfa_type; 182 172 if (flavor) { 183 - if (flavor > subsys->attr_count) 173 + if (flavor > attr_count) 184 174 return -EINVAL; 185 175 cda[flavor - 1] = attr; 186 176 } ··· 266 256 } 267 257 268 258 { 269 - struct nfattr *cda[ss->attr_count]; 259 + u_int16_t attr_count = 260 + ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count; 261 + struct nfattr *cda[attr_count]; 270 262 271 - memset(cda, 0, ss->attr_count*sizeof(struct nfattr *)); 263 + memset(cda, 0, sizeof(struct nfattr *) * attr_count); 272 264 273 265 err = nfnetlink_check_attributes(ss, nlh, cda); 274 266 if (err < 0)