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

Commit 2671e9fc authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ipv4-ipv6-refcount_t'



Elena Reshetova says:

====================
v2 ipv4/ipv6 refcount conversions

Changes in v2:
 * rebase on top of net-next
 * currently by default refcount_t = atomic_t (*) and uses all
   atomic standard operations unless CONFIG_REFCOUNT_FULL is enabled.
   This is a compromise for the systems that are critical on
   performance (such as net) and cannot accept even slight delay
   on the refcounter operations.

This series, for ipv4/ipv6 network components, replaces atomic_t reference
counters with the new refcount_t type and API (see include/linux/refcount.h).
By doing this we prevent intentional or accidental
underflows or overflows that can led to use-after-free vulnerabilities.

The patches are fully independent and can be cherry-picked separately.
In order to try with refcount functionality enabled in run-time,
CONFIG_REFCOUNT_FULL must be enabled.

NOTE: automatic kernel builder for some reason doesn't like all my
network branches and regularly times out the builds on these branches.
Suggestion for "waiting a day for a good coverage" doesn't work, as
we have seen with generic network conversions. So please wait for the
full report from kernel test rebot before merging further up.
This has been compile-tested in 116 configs, but 71 timed out (including
all s390-related configs again). I am trying to see if they can fix
build coverage for me in meanwhile.

* The respective change is currently merged into -next as
  "locking/refcount: Create unchecked atomic_t implementation".
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 25f4535a 0029c0de
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -316,7 +316,7 @@ static inline struct inet6_dev *in6_dev_get(const struct net_device *dev)
	rcu_read_lock();
	idev = rcu_dereference(dev->ip6_ptr);
	if (idev)
		atomic_inc(&idev->refcnt);
		refcount_inc(&idev->refcnt);
	rcu_read_unlock();
	return idev;
}
@@ -332,36 +332,36 @@ void in6_dev_finish_destroy(struct inet6_dev *idev);

static inline void in6_dev_put(struct inet6_dev *idev)
{
	if (atomic_dec_and_test(&idev->refcnt))
	if (refcount_dec_and_test(&idev->refcnt))
		in6_dev_finish_destroy(idev);
}

static inline void __in6_dev_put(struct inet6_dev *idev)
{
	atomic_dec(&idev->refcnt);
	refcount_dec(&idev->refcnt);
}

static inline void in6_dev_hold(struct inet6_dev *idev)
{
	atomic_inc(&idev->refcnt);
	refcount_inc(&idev->refcnt);
}

void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp);

static inline void in6_ifa_put(struct inet6_ifaddr *ifp)
{
	if (atomic_dec_and_test(&ifp->refcnt))
	if (refcount_dec_and_test(&ifp->refcnt))
		inet6_ifa_finish_destroy(ifp);
}

static inline void __in6_ifa_put(struct inet6_ifaddr *ifp)
{
	atomic_dec(&ifp->refcnt);
	refcount_dec(&ifp->refcnt);
}

static inline void in6_ifa_hold(struct inet6_ifaddr *ifp)
{
	atomic_inc(&ifp->refcnt);
	refcount_inc(&ifp->refcnt);
}


+2 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include <net/netlabel.h>
#include <net/request_sock.h>
#include <linux/atomic.h>
#include <linux/refcount.h>
#include <asm/unaligned.h>

/* known doi values */
@@ -85,7 +86,7 @@ struct cipso_v4_doi {
	} map;
	u8 tags[CIPSO_V4_TAG_MAXCNT];

	atomic_t refcount;
	refcount_t refcount;
	struct list_head list;
	struct rcu_head rcu;
};
+5 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

#include <net/snmp.h>
#include <linux/ipv6.h>
#include <linux/refcount.h>

/* inet6_dev.if_flags */

@@ -45,7 +46,7 @@ struct inet6_ifaddr {
	/* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
	__u32			valid_lft;
	__u32			prefered_lft;
	atomic_t		refcnt;
	refcount_t		refcnt;
	spinlock_t		lock;

	int			state;
@@ -126,7 +127,7 @@ struct ifmcaddr6 {
	struct timer_list	mca_timer;
	unsigned int		mca_flags;
	int			mca_users;
	atomic_t		mca_refcnt;
	refcount_t		mca_refcnt;
	spinlock_t		mca_lock;
	unsigned long		mca_cstamp;
	unsigned long		mca_tstamp;
@@ -146,7 +147,7 @@ struct ifacaddr6 {
	struct rt6_info		*aca_rt;
	struct ifacaddr6	*aca_next;
	int			aca_users;
	atomic_t		aca_refcnt;
	refcount_t		aca_refcnt;
	unsigned long		aca_cstamp;
	unsigned long		aca_tstamp;
};
@@ -187,7 +188,7 @@ struct inet6_dev {

	struct ifacaddr6	*ac_list;
	rwlock_t		lock;
	atomic_t		refcnt;
	refcount_t		refcnt;
	__u32			if_flags;
	int			dead;

+4 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <net/inetpeer.h>
#include <linux/percpu.h>
#include <linux/notifier.h>
#include <linux/refcount.h>

struct fib_config {
	u8			fc_dst_len;
@@ -105,7 +106,7 @@ struct fib_info {
	struct hlist_node	fib_lhash;
	struct net		*fib_net;
	int			fib_treeref;
	atomic_t		fib_clntref;
	refcount_t		fib_clntref;
	unsigned int		fib_flags;
	unsigned char		fib_dead;
	unsigned char		fib_protocol;
@@ -430,12 +431,12 @@ void free_fib_info(struct fib_info *fi);

static inline void fib_info_hold(struct fib_info *fi)
{
	atomic_inc(&fi->fib_clntref);
	refcount_inc(&fi->fib_clntref);
}

static inline void fib_info_put(struct fib_info *fi)
{
	if (atomic_dec_and_test(&fi->fib_clntref))
	if (refcount_dec_and_test(&fi->fib_clntref))
		free_fib_info(fi);
}

+4 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/ipv6.h>
#include <linux/hardirq.h>
#include <linux/jhash.h>
#include <linux/refcount.h>
#include <net/if_inet6.h>
#include <net/ndisc.h>
#include <net/flow.h>
@@ -203,7 +204,7 @@ extern rwlock_t ip6_ra_lock;
 */

struct ipv6_txoptions {
	atomic_t		refcnt;
	refcount_t		refcnt;
	/* Length of this structure */
	int			tot_len;

@@ -265,7 +266,7 @@ static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
	rcu_read_lock();
	opt = rcu_dereference(np->opt);
	if (opt) {
		if (!atomic_inc_not_zero(&opt->refcnt))
		if (!refcount_inc_not_zero(&opt->refcnt))
			opt = NULL;
		else
			opt = rcu_pointer_handoff(opt);
@@ -276,7 +277,7 @@ static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)

static inline void txopt_put(struct ipv6_txoptions *opt)
{
	if (opt && atomic_dec_and_test(&opt->refcnt))
	if (opt && refcount_dec_and_test(&opt->refcnt))
		kfree_rcu(opt, rcu);
}

Loading