|
@@ -38,6 +38,8 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
|
|
rcu_dereference_protected(table[(id)].subsys, \
|
|
rcu_dereference_protected(table[(id)].subsys, \
|
|
lockdep_nfnl_is_held((id)))
|
|
lockdep_nfnl_is_held((id)))
|
|
|
|
|
|
|
|
+#define NFNL_MAX_ATTR_COUNT 32
|
|
|
|
+
|
|
static struct {
|
|
static struct {
|
|
struct mutex mutex;
|
|
struct mutex mutex;
|
|
const struct nfnetlink_subsystem __rcu *subsys;
|
|
const struct nfnetlink_subsystem __rcu *subsys;
|
|
@@ -77,6 +79,13 @@ EXPORT_SYMBOL_GPL(lockdep_nfnl_is_held);
|
|
|
|
|
|
int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
|
|
int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
|
|
{
|
|
{
|
|
|
|
+ u8 cb_id;
|
|
|
|
+
|
|
|
|
+ /* Sanity-check attr_count size to avoid stack buffer overflow. */
|
|
|
|
+ for (cb_id = 0; cb_id < n->cb_count; cb_id++)
|
|
|
|
+ if (WARN_ON(n->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
nfnl_lock(n->subsys_id);
|
|
nfnl_lock(n->subsys_id);
|
|
if (table[n->subsys_id].subsys) {
|
|
if (table[n->subsys_id].subsys) {
|
|
nfnl_unlock(n->subsys_id);
|
|
nfnl_unlock(n->subsys_id);
|
|
@@ -186,11 +195,17 @@ replay:
|
|
{
|
|
{
|
|
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
|
|
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
|
|
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
|
|
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
|
|
- struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
|
|
|
|
|
|
+ struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
|
|
struct nlattr *attr = (void *)nlh + min_len;
|
|
struct nlattr *attr = (void *)nlh + min_len;
|
|
int attrlen = nlh->nlmsg_len - min_len;
|
|
int attrlen = nlh->nlmsg_len - min_len;
|
|
__u8 subsys_id = NFNL_SUBSYS_ID(type);
|
|
__u8 subsys_id = NFNL_SUBSYS_ID(type);
|
|
|
|
|
|
|
|
+ /* Sanity-check NFNL_MAX_ATTR_COUNT */
|
|
|
|
+ if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
err = nla_parse(cda, ss->cb[cb_id].attr_count, attr, attrlen,
|
|
err = nla_parse(cda, ss->cb[cb_id].attr_count, attr, attrlen,
|
|
ss->cb[cb_id].policy, extack);
|
|
ss->cb[cb_id].policy, extack);
|
|
if (err < 0) {
|
|
if (err < 0) {
|
|
@@ -387,10 +402,16 @@ replay:
|
|
{
|
|
{
|
|
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
|
|
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
|
|
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
|
|
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
|
|
- struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
|
|
|
|
|
|
+ struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
|
|
struct nlattr *attr = (void *)nlh + min_len;
|
|
struct nlattr *attr = (void *)nlh + min_len;
|
|
int attrlen = nlh->nlmsg_len - min_len;
|
|
int attrlen = nlh->nlmsg_len - min_len;
|
|
|
|
|
|
|
|
+ /* Sanity-check NFTA_MAX_ATTR */
|
|
|
|
+ if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
|
|
|
|
+ err = -ENOMEM;
|
|
|
|
+ goto ack;
|
|
|
|
+ }
|
|
|
|
+
|
|
err = nla_parse(cda, ss->cb[cb_id].attr_count, attr,
|
|
err = nla_parse(cda, ss->cb[cb_id].attr_count, attr,
|
|
attrlen, ss->cb[cb_id].policy, NULL);
|
|
attrlen, ss->cb[cb_id].policy, NULL);
|
|
if (err < 0)
|
|
if (err < 0)
|