mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	bpf: don't rely on the verifier lock for metadata_dst allocation
bpf_skb_set_tunnel_*() functions require allocation of per-cpu metadata_dst. The allocation happens upon verification of the first program using those helpers. In preparation for removing the verifier lock, use cmpxchg() to make sure we only allocate the metadata_dsts once. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Simon Horman <simon.horman@netronome.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									c9c35995bc
								
							
						
					
					
						commit
						d66f2b91f9
					
				
					 3 changed files with 26 additions and 7 deletions
				
			
		| 
						 | 
					@ -87,6 +87,7 @@ static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
 | 
				
			||||||
void metadata_dst_free(struct metadata_dst *);
 | 
					void metadata_dst_free(struct metadata_dst *);
 | 
				
			||||||
struct metadata_dst *metadata_dst_alloc(u8 optslen, enum metadata_type type,
 | 
					struct metadata_dst *metadata_dst_alloc(u8 optslen, enum metadata_type type,
 | 
				
			||||||
					gfp_t flags);
 | 
										gfp_t flags);
 | 
				
			||||||
 | 
					void metadata_dst_free_percpu(struct metadata_dst __percpu *md_dst);
 | 
				
			||||||
struct metadata_dst __percpu *
 | 
					struct metadata_dst __percpu *
 | 
				
			||||||
metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags);
 | 
					metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -322,3 +322,19 @@ metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags)
 | 
				
			||||||
	return md_dst;
 | 
						return md_dst;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(metadata_dst_alloc_percpu);
 | 
					EXPORT_SYMBOL_GPL(metadata_dst_alloc_percpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void metadata_dst_free_percpu(struct metadata_dst __percpu *md_dst)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_DST_CACHE
 | 
				
			||||||
 | 
						for_each_possible_cpu(cpu) {
 | 
				
			||||||
 | 
							struct metadata_dst *one_md_dst = per_cpu_ptr(md_dst, cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (one_md_dst->type == METADATA_IP_TUNNEL)
 | 
				
			||||||
 | 
								dst_cache_destroy(&one_md_dst->u.tun_info.dst_cache);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						free_percpu(md_dst);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(metadata_dst_free_percpu);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@
 | 
				
			||||||
#include <linux/timer.h>
 | 
					#include <linux/timer.h>
 | 
				
			||||||
#include <linux/uaccess.h>
 | 
					#include <linux/uaccess.h>
 | 
				
			||||||
#include <asm/unaligned.h>
 | 
					#include <asm/unaligned.h>
 | 
				
			||||||
 | 
					#include <asm/cmpxchg.h>
 | 
				
			||||||
#include <linux/filter.h>
 | 
					#include <linux/filter.h>
 | 
				
			||||||
#include <linux/ratelimit.h>
 | 
					#include <linux/ratelimit.h>
 | 
				
			||||||
#include <linux/seccomp.h>
 | 
					#include <linux/seccomp.h>
 | 
				
			||||||
| 
						 | 
					@ -2987,14 +2988,15 @@ static const struct bpf_func_proto *
 | 
				
			||||||
bpf_get_skb_set_tunnel_proto(enum bpf_func_id which)
 | 
					bpf_get_skb_set_tunnel_proto(enum bpf_func_id which)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!md_dst) {
 | 
						if (!md_dst) {
 | 
				
			||||||
		/* Race is not possible, since it's called from verifier
 | 
							struct metadata_dst __percpu *tmp;
 | 
				
			||||||
		 * that is holding verifier mutex.
 | 
					
 | 
				
			||||||
		 */
 | 
							tmp = metadata_dst_alloc_percpu(IP_TUNNEL_OPTS_MAX,
 | 
				
			||||||
		md_dst = metadata_dst_alloc_percpu(IP_TUNNEL_OPTS_MAX,
 | 
											METADATA_IP_TUNNEL,
 | 
				
			||||||
						   METADATA_IP_TUNNEL,
 | 
											GFP_KERNEL);
 | 
				
			||||||
						   GFP_KERNEL);
 | 
							if (!tmp)
 | 
				
			||||||
		if (!md_dst)
 | 
					 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
 | 
							if (cmpxchg(&md_dst, NULL, tmp))
 | 
				
			||||||
 | 
								metadata_dst_free_percpu(tmp);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (which) {
 | 
						switch (which) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue