diff options
Diffstat (limited to 'kernel/bpf/core.c')
| -rw-r--r-- | kernel/bpf/core.c | 89 | 
1 files changed, 85 insertions, 4 deletions
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index aa6d98154106..1eb4f1303756 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -105,19 +105,29 @@ struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,  	gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO |  			  gfp_extra_flags;  	struct bpf_prog *fp; +	u32 pages, delta; +	int ret;  	BUG_ON(fp_old == NULL);  	size = round_up(size, PAGE_SIZE); -	if (size <= fp_old->pages * PAGE_SIZE) +	pages = size / PAGE_SIZE; +	if (pages <= fp_old->pages)  		return fp_old; +	delta = pages - fp_old->pages; +	ret = __bpf_prog_charge(fp_old->aux->user, delta); +	if (ret) +		return NULL; +  	fp = __vmalloc(size, gfp_flags, PAGE_KERNEL); -	if (fp != NULL) { +	if (fp == NULL) { +		__bpf_prog_uncharge(fp_old->aux->user, delta); +	} else {  		kmemcheck_annotate_bitfield(fp, meta);  		memcpy(fp, fp_old, fp_old->pages * PAGE_SIZE); -		fp->pages = size / PAGE_SIZE; +		fp->pages = pages;  		fp->aux->prog = fp;  		/* We keep fp->aux from fp_old around in the new @@ -136,6 +146,76 @@ void __bpf_prog_free(struct bpf_prog *fp)  	vfree(fp);  } +int bpf_prog_calc_digest(struct bpf_prog *fp) +{ +	const u32 bits_offset = SHA_MESSAGE_BYTES - sizeof(__be64); +	u32 raw_size = bpf_prog_digest_scratch_size(fp); +	u32 ws[SHA_WORKSPACE_WORDS]; +	u32 i, bsize, psize, blocks; +	struct bpf_insn *dst; +	bool was_ld_map; +	u8 *raw, *todo; +	__be32 *result; +	__be64 *bits; + +	raw = vmalloc(raw_size); +	if (!raw) +		return -ENOMEM; + +	sha_init(fp->digest); +	memset(ws, 0, sizeof(ws)); + +	/* We need to take out the map fd for the digest calculation +	 * since they are unstable from user space side. +	 */ +	dst = (void *)raw; +	for (i = 0, was_ld_map = false; i < fp->len; i++) { +		dst[i] = fp->insnsi[i]; +		if (!was_ld_map && +		    dst[i].code == (BPF_LD | BPF_IMM | BPF_DW) && +		    dst[i].src_reg == BPF_PSEUDO_MAP_FD) { +			was_ld_map = true; +			dst[i].imm = 0; +		} else if (was_ld_map && +			   dst[i].code == 0 && +			   dst[i].dst_reg == 0 && +			   dst[i].src_reg == 0 && +			   dst[i].off == 0) { +			was_ld_map = false; +			dst[i].imm = 0; +		} else { +			was_ld_map = false; +		} +	} + +	psize = bpf_prog_insn_size(fp); +	memset(&raw[psize], 0, raw_size - psize); +	raw[psize++] = 0x80; + +	bsize  = round_up(psize, SHA_MESSAGE_BYTES); +	blocks = bsize / SHA_MESSAGE_BYTES; +	todo   = raw; +	if (bsize - psize >= sizeof(__be64)) { +		bits = (__be64 *)(todo + bsize - sizeof(__be64)); +	} else { +		bits = (__be64 *)(todo + bsize + bits_offset); +		blocks++; +	} +	*bits = cpu_to_be64((psize - 1) << 3); + +	while (blocks--) { +		sha_transform(fp->digest, todo, ws); +		todo += SHA_MESSAGE_BYTES; +	} + +	result = (__force __be32 *)fp->digest; +	for (i = 0; i < SHA_DIGEST_WORDS; i++) +		result[i] = cpu_to_be32(fp->digest[i]); + +	vfree(raw); +	return 0; +} +  static bool bpf_is_jmp_and_has_target(const struct bpf_insn *insn)  {  	return BPF_CLASS(insn->code) == BPF_JMP  && @@ -1043,6 +1123,7 @@ const struct bpf_func_proto bpf_map_delete_elem_proto __weak;  const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;  const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak; +const struct bpf_func_proto bpf_get_numa_node_id_proto __weak;  const struct bpf_func_proto bpf_ktime_get_ns_proto __weak;  const struct bpf_func_proto bpf_get_current_pid_tgid_proto __weak; @@ -1077,7 +1158,7 @@ struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_prog *prog)  	return prog;  } -bool __weak bpf_helper_changes_skb_data(void *func) +bool __weak bpf_helper_changes_pkt_data(void *func)  {  	return false;  }  |