Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2994c638 authored by Denis V. Lunev's avatar Denis V. Lunev Committed by David S. Miller
Browse files

[INET]: Small possible memory leak in FIB rules



This patch fixes a small memory leak. Default fib rules can be deleted by
the user if the rule does not carry FIB_RULE_PERMANENT flag, f.e. by
	ip rule flush

Such a rule will not be freed as the ref-counter has 2 on start and becomes
clearly unreachable after removal.

Signed-off-by: default avatarDenis V. Lunev <den@openvz.org>
Acked-by: default avatarAlexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 33d36bb8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -107,4 +107,7 @@ extern int fib_rules_unregister(struct fib_rules_ops *);
extern int			fib_rules_lookup(struct fib_rules_ops *,
						 struct flowi *, int flags,
						 struct fib_lookup_arg *);
extern int			fib_default_rule_add(struct fib_rules_ops *,
						     u32 pref, u32 table,
						     u32 flags);
#endif
+22 −0
Original line number Diff line number Diff line
@@ -18,6 +18,28 @@
static LIST_HEAD(rules_ops);
static DEFINE_SPINLOCK(rules_mod_lock);

int fib_default_rule_add(struct fib_rules_ops *ops,
			 u32 pref, u32 table, u32 flags)
{
	struct fib_rule *r;

	r = kzalloc(ops->rule_size, GFP_KERNEL);
	if (r == NULL)
		return -ENOMEM;

	atomic_set(&r->refcnt, 1);
	r->action = FR_ACT_TO_TBL;
	r->pref = pref;
	r->table = table;
	r->flags = flags;

	/* The lock is not required here, the list in unreacheable
	 * at the moment this function is called */
	list_add_tail(&r->list, &ops->rules_list);
	return 0;
}
EXPORT_SYMBOL(fib_default_rule_add);

static void notify_rule_change(int event, struct fib_rule *rule,
			       struct fib_rules_ops *ops, struct nlmsghdr *nlh,
			       u32 pid);
+2 −11
Original line number Diff line number Diff line
@@ -48,15 +48,6 @@ struct dn_fib_rule
	u8			flags;
};

static struct dn_fib_rule default_rule = {
	.common = {
		.refcnt =		ATOMIC_INIT(2),
		.pref =			0x7fff,
		.table =		RT_TABLE_MAIN,
		.action =		FR_ACT_TO_TBL,
	},
};


int dn_fib_lookup(struct flowi *flp, struct dn_fib_res *res)
{
@@ -262,8 +253,8 @@ static struct fib_rules_ops dn_fib_rules_ops = {

void __init dn_fib_rules_init(void)
{
	list_add_tail(&default_rule.common.list,
			&dn_fib_rules_ops.rules_list);
	BUG_ON(fib_default_rule_add(&dn_fib_rules_ops, 0x7fff,
			            RT_TABLE_MAIN, 0));
	fib_rules_register(&dn_fib_rules_ops);
}

+20 −31
Original line number Diff line number Diff line
@@ -49,33 +49,6 @@ struct fib4_rule
#endif
};

static struct fib4_rule default_rule = {
	.common = {
		.refcnt =	ATOMIC_INIT(2),
		.pref =		0x7FFF,
		.table =	RT_TABLE_DEFAULT,
		.action =	FR_ACT_TO_TBL,
	},
};

static struct fib4_rule main_rule = {
	.common = {
		.refcnt =	ATOMIC_INIT(2),
		.pref =		0x7FFE,
		.table =	RT_TABLE_MAIN,
		.action =	FR_ACT_TO_TBL,
	},
};

static struct fib4_rule local_rule = {
	.common = {
		.refcnt =	ATOMIC_INIT(2),
		.table =	RT_TABLE_LOCAL,
		.action =	FR_ACT_TO_TBL,
		.flags =	FIB_RULE_PERMANENT,
	},
};

#ifdef CONFIG_NET_CLS_ROUTE
u32 fib_rules_tclass(struct fib_result *res)
{
@@ -319,11 +292,27 @@ static struct fib_rules_ops fib4_rules_ops = {
	.owner		= THIS_MODULE,
};

void __init fib4_rules_init(void)
static int __init fib_default_rules_init(void)
{
	list_add_tail(&local_rule.common.list, &fib4_rules_ops.rules_list);
	list_add_tail(&main_rule.common.list, &fib4_rules_ops.rules_list);
	list_add_tail(&default_rule.common.list, &fib4_rules_ops.rules_list);
	int err;

	err = fib_default_rule_add(&fib4_rules_ops, 0,
				   RT_TABLE_LOCAL, FIB_RULE_PERMANENT);
	if (err < 0)
		return err;
	err = fib_default_rule_add(&fib4_rules_ops, 0x7FFE,
				   RT_TABLE_MAIN, 0);
	if (err < 0)
		return err;
	err = fib_default_rule_add(&fib4_rules_ops, 0x7FFF,
				   RT_TABLE_DEFAULT, 0);
	if (err < 0)
		return err;
	return 0;
}

void __init fib4_rules_init(void)
{
	BUG_ON(fib_default_rules_init());
	fib_rules_register(&fib4_rules_ops);
}
+15 −22
Original line number Diff line number Diff line
@@ -31,25 +31,6 @@ struct fib6_rule

static struct fib_rules_ops fib6_rules_ops;

static struct fib6_rule main_rule = {
	.common = {
		.refcnt =	ATOMIC_INIT(2),
		.pref =		0x7FFE,
		.action =	FR_ACT_TO_TBL,
		.table =	RT6_TABLE_MAIN,
	},
};

static struct fib6_rule local_rule = {
	.common = {
		.refcnt =	ATOMIC_INIT(2),
		.pref =		0,
		.action =	FR_ACT_TO_TBL,
		.table =	RT6_TABLE_LOCAL,
		.flags =	FIB_RULE_PERMANENT,
	},
};

struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
				   pol_lookup_t lookup)
{
@@ -270,11 +251,23 @@ static struct fib_rules_ops fib6_rules_ops = {
	.owner			= THIS_MODULE,
};

void __init fib6_rules_init(void)
static int __init fib6_default_rules_init(void)
{
	list_add_tail(&local_rule.common.list, &fib6_rules_ops.rules_list);
	list_add_tail(&main_rule.common.list, &fib6_rules_ops.rules_list);
	int err;

	err = fib_default_rule_add(&fib6_rules_ops, 0,
				   RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
	if (err < 0)
		return err;
	err = fib_default_rule_add(&fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0);
	if (err < 0)
		return err;
	return 0;
}

void __init fib6_rules_init(void)
{
	BUG_ON(fib6_default_rules_init());
	fib_rules_register(&fib6_rules_ops);
}