示例#1
0
/*
 * @pi must be allocated previously
 * @skb is the buffer passed to the filter
 */
static inline int getPacketInfo(const struct sk_buff *skb, struct packetInfo *src_pi, struct packetInfo *dst_pi)
{
	u32 tmp;
	void *ptr;
	u32 X;

	ptr = load_pointer(skb,23,1,&tmp);
	if(ptr != NULL)
	{
		src_pi->protocol = *(u8 *)ptr;
		dst_pi->protocol = *(u8 *)ptr;
	}else goto out;

	ptr = load_pointer(skb,26,4,&tmp);
	if(ptr !=NULL)
	{
		src_pi->address = get_unaligned_be32(ptr);
	}else goto out;

	ptr = load_pointer(skb,30,4,&tmp);
	if(ptr != NULL)
	{
		dst_pi->address = get_unaligned_be32(ptr);
	}else goto out;

	ptr = load_pointer(skb,14,1,&tmp);
	if(ptr != NULL)
	{
		X = (*(u8 *)ptr & 0xf) << 2;
		X+=14;
		ptr = load_pointer(skb,X,2,&tmp);
		if(ptr != NULL)
		{
			src_pi->port = get_unaligned_be16(ptr);
		}else goto out;

		X+=2;
		ptr = load_pointer(skb,X,2,&tmp);
		if(ptr != NULL)
		{
			dst_pi->port = get_unaligned_be16(ptr);
		}else goto out;
	}else goto out;

	return 0;

out:
	return -1;
}
示例#2
0
unsigned int dynamic_filter(const struct sk_buff *skb, u32 r_size)
{
	void *ptr;
	u32 A;
	u32 tmp;
	
	if(portExists != NULL){
	ptr = load_pointer(skb, 12, 2, &tmp);
	if(ptr!=NULL)
	{
		A = get_unaligned_be16(ptr);
		if(A == 0x800)
		{
			struct packetInfo dst_pi;
			struct packetInfo src_pi;
			int rpi;
			rpi = getPacketInfo(skb,&src_pi,&dst_pi);
			if(rpi == 0)
			{
				int exists = portExists(&src_pi, &dst_pi);
				if(exists == 1)
				return r_size;
				else
				return 0;
			}else {
				//printk(KERN_INFO "could not get Info");
				return 0;
				}
		} // A is not IPV4
		else
			//printk(KERN_INFO "is not ipv4");
			return 0;
	}
	else return 0;
	} //end of portExists
	else // if portExists is == NULL
	return r_size;

	return r_size;
}
示例#3
0
文件: filter.c 项目: kzlin129/tt-gpl
int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
{
    struct sock_filter *fentry;	/* We walk down these */
    void *ptr;
    u32 A = 0;	   		/* Accumulator */
    u32 X = 0;   			/* Index Register */
    u32 mem[BPF_MEMWORDS];		/* Scratch Memory Store */
    u32 tmp;
    int k;
    int pc;

    /*
     * Process array of filter instructions.
     */
    for (pc = 0; pc < flen; pc++) {
        fentry = &filter[pc];

        switch (fentry->code) {
        case BPF_ALU|BPF_ADD|BPF_X:
            A += X;
            continue;
        case BPF_ALU|BPF_ADD|BPF_K:
            A += fentry->k;
            continue;
        case BPF_ALU|BPF_SUB|BPF_X:
            A -= X;
            continue;
        case BPF_ALU|BPF_SUB|BPF_K:
            A -= fentry->k;
            continue;
        case BPF_ALU|BPF_MUL|BPF_X:
            A *= X;
            continue;
        case BPF_ALU|BPF_MUL|BPF_K:
            A *= fentry->k;
            continue;
        case BPF_ALU|BPF_DIV|BPF_X:
            if (X == 0)
                return 0;
            A /= X;
            continue;
        case BPF_ALU|BPF_DIV|BPF_K:
            if (fentry->k == 0)
                return 0;
            A /= fentry->k;
            continue;
        case BPF_ALU|BPF_AND|BPF_X:
            A &= X;
            continue;
        case BPF_ALU|BPF_AND|BPF_K:
            A &= fentry->k;
            continue;
        case BPF_ALU|BPF_OR|BPF_X:
            A |= X;
            continue;
        case BPF_ALU|BPF_OR|BPF_K:
            A |= fentry->k;
            continue;
        case BPF_ALU|BPF_LSH|BPF_X:
            A <<= X;
            continue;
        case BPF_ALU|BPF_LSH|BPF_K:
            A <<= fentry->k;
            continue;
        case BPF_ALU|BPF_RSH|BPF_X:
            A >>= X;
            continue;
        case BPF_ALU|BPF_RSH|BPF_K:
            A >>= fentry->k;
            continue;
        case BPF_ALU|BPF_NEG:
            A = -A;
            continue;
        case BPF_JMP|BPF_JA:
            pc += fentry->k;
            continue;
        case BPF_JMP|BPF_JGT|BPF_K:
            pc += (A > fentry->k) ? fentry->jt : fentry->jf;
            continue;
        case BPF_JMP|BPF_JGE|BPF_K:
            pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
            continue;
        case BPF_JMP|BPF_JEQ|BPF_K:
            pc += (A == fentry->k) ? fentry->jt : fentry->jf;
            continue;
        case BPF_JMP|BPF_JSET|BPF_K:
            pc += (A & fentry->k) ? fentry->jt : fentry->jf;
            continue;
        case BPF_JMP|BPF_JGT|BPF_X:
            pc += (A > X) ? fentry->jt : fentry->jf;
            continue;
        case BPF_JMP|BPF_JGE|BPF_X:
            pc += (A >= X) ? fentry->jt : fentry->jf;
            continue;
        case BPF_JMP|BPF_JEQ|BPF_X:
            pc += (A == X) ? fentry->jt : fentry->jf;
            continue;
        case BPF_JMP|BPF_JSET|BPF_X:
            pc += (A & X) ? fentry->jt : fentry->jf;
            continue;
        case BPF_LD|BPF_W|BPF_ABS:
            k = fentry->k;
load_w:
            ptr = load_pointer(skb, k, 4, &tmp);
            if (ptr != NULL) {
                A = ntohl(*(u32 *)ptr);
                continue;
            }
            return 0;
        case BPF_LD|BPF_H|BPF_ABS:
            k = fentry->k;
load_h:
            ptr = load_pointer(skb, k, 2, &tmp);
            if (ptr != NULL) {
                A = ntohs(*(u16 *)ptr);
                continue;
            }
            return 0;
        case BPF_LD|BPF_B|BPF_ABS:
            k = fentry->k;
load_b:
            ptr = load_pointer(skb, k, 1, &tmp);
            if (ptr != NULL) {
                A = *(u8 *)ptr;
                continue;
            }
            return 0;
        case BPF_LD|BPF_W|BPF_LEN:
            A = skb->len;
            continue;
        case BPF_LDX|BPF_W|BPF_LEN:
            X = skb->len;
            continue;
        case BPF_LD|BPF_W|BPF_IND:
            k = X + fentry->k;
            goto load_w;
        case BPF_LD|BPF_H|BPF_IND:
            k = X + fentry->k;
            goto load_h;
        case BPF_LD|BPF_B|BPF_IND:
            k = X + fentry->k;
            goto load_b;
        case BPF_LDX|BPF_B|BPF_MSH:
            ptr = load_pointer(skb, fentry->k, 1, &tmp);
            if (ptr != NULL) {
                X = (*(u8 *)ptr & 0xf) << 2;
                continue;
            }
            return 0;
        case BPF_LD|BPF_IMM:
            A = fentry->k;
            continue;
        case BPF_LDX|BPF_IMM:
            X = fentry->k;
            continue;
        case BPF_LD|BPF_MEM:
            A = mem[fentry->k];
            continue;
        case BPF_LDX|BPF_MEM:
            X = mem[fentry->k];
            continue;
        case BPF_MISC|BPF_TAX:
            X = A;
            continue;
        case BPF_MISC|BPF_TXA:
            A = X;
            continue;
        case BPF_RET|BPF_K:
            return ((unsigned int)fentry->k);
        case BPF_RET|BPF_A:
            return ((unsigned int)A);
        case BPF_ST:
            mem[fentry->k] = A;
            continue;
        case BPF_STX:
            mem[fentry->k] = X;
            continue;
        default:
            /* Invalid instruction counts as RET */
            return 0;
        }

        /*
         * Handle ancillary data, which are impossible
         * (or very difficult) to get parsing packet contents.
         */
        switch (k-SKF_AD_OFF) {
        case SKF_AD_PROTOCOL:
            A = htons(skb->protocol);
            continue;
        case SKF_AD_PKTTYPE:
            A = skb->pkt_type;
            continue;
        case SKF_AD_IFINDEX:
            A = skb->dev->ifindex;
            continue;
        default:
            return 0;
        }
    }

    return 0;
}
示例#4
0
/**
 *	sk_run_filter - run a filter on a socket
 *	@skb: buffer to run the filter on
 *	@filter: filter to apply
 *
 * Decode and apply filter instructions to the skb->data.
 * Return length to keep, 0 for none. @skb is the data we are
 * filtering, @filter is the array of filter instructions.
 * Because all jumps are guaranteed to be before last instruction,
 * and last instruction guaranteed to be a RET, we dont need to check
 * flen. (We used to pass to this function the length of filter)
 */
unsigned int sk_run_filter(const struct sk_buff *skb,
			   const struct sock_filter *fentry)
{
	void *ptr;
	u32 A = 0;			/* Accumulator */
	u32 X = 0;			/* Index Register */
	u32 mem[BPF_MEMWORDS];		/* Scratch Memory Store */
	unsigned long memvalid = 0;
	u32 tmp;
	int k;

	BUILD_BUG_ON(BPF_MEMWORDS > BITS_PER_LONG);
	/*
	 * Process array of filter instructions.
	 */
	for (;; fentry++) {
#if defined(CONFIG_X86_32)
#define	K (fentry->k)
#else
		const u32 K = fentry->k;
#endif

		switch (fentry->code) {
		case BPF_S_ALU_ADD_X:
			A += X;
			continue;
		case BPF_S_ALU_ADD_K:
			A += K;
			continue;
		case BPF_S_ALU_SUB_X:
			A -= X;
			continue;
		case BPF_S_ALU_SUB_K:
			A -= K;
			continue;
		case BPF_S_ALU_MUL_X:
			A *= X;
			continue;
		case BPF_S_ALU_MUL_K:
			A *= K;
			continue;
		case BPF_S_ALU_DIV_X:
			if (X == 0)
				return 0;
			A /= X;
			continue;
		case BPF_S_ALU_DIV_K:
			A /= K;
			continue;
		case BPF_S_ALU_AND_X:
			A &= X;
			continue;
		case BPF_S_ALU_AND_K:
			A &= K;
			continue;
		case BPF_S_ALU_OR_X:
			A |= X;
			continue;
		case BPF_S_ALU_OR_K:
			A |= K;
			continue;
		case BPF_S_ALU_LSH_X:
			A <<= X;
			continue;
		case BPF_S_ALU_LSH_K:
			A <<= K;
			continue;
		case BPF_S_ALU_RSH_X:
			A >>= X;
			continue;
		case BPF_S_ALU_RSH_K:
			A >>= K;
			continue;
		case BPF_S_ALU_NEG:
			A = -A;
			continue;
		case BPF_S_JMP_JA:
			fentry += K;
			continue;
		case BPF_S_JMP_JGT_K:
			fentry += (A > K) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGE_K:
			fentry += (A >= K) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JEQ_K:
			fentry += (A == K) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JSET_K:
			fentry += (A & K) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGT_X:
			fentry += (A > X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGE_X:
			fentry += (A >= X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JEQ_X:
			fentry += (A == X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JSET_X:
			fentry += (A & X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_LD_W_ABS:
			k = K;
load_w:
			ptr = load_pointer(skb, k, 4, &tmp);
			if (ptr != NULL) {
				A = get_unaligned_be32(ptr);
				continue;
			}
			break;
		case BPF_S_LD_H_ABS:
			k = K;
load_h:
			ptr = load_pointer(skb, k, 2, &tmp);
			if (ptr != NULL) {
				A = get_unaligned_be16(ptr);
				continue;
			}
			break;
		case BPF_S_LD_B_ABS:
			k = K;
load_b:
			ptr = load_pointer(skb, k, 1, &tmp);
			if (ptr != NULL) {
				A = *(u8 *)ptr;
				continue;
			}
			break;
		case BPF_S_LD_W_LEN:
			A = skb->len;
			continue;
		case BPF_S_LDX_W_LEN:
			X = skb->len;
			continue;
		case BPF_S_LD_W_IND:
			k = X + K;
			goto load_w;
		case BPF_S_LD_H_IND:
			k = X + K;
			goto load_h;
		case BPF_S_LD_B_IND:
			k = X + K;
			goto load_b;
		case BPF_S_LDX_B_MSH:
			ptr = load_pointer(skb, K, 1, &tmp);
			if (ptr != NULL) {
				X = (*(u8 *)ptr & 0xf) << 2;
				continue;
			}
			return 0;
		case BPF_S_LD_IMM:
			A = K;
			continue;
		case BPF_S_LDX_IMM:
			X = K;
			continue;
		case BPF_S_LD_MEM:
			A = (memvalid & (1UL << K)) ?
				mem[K] : 0;
			continue;
		case BPF_S_LDX_MEM:
			X = (memvalid & (1UL << K)) ?
				mem[K] : 0;
			continue;
		case BPF_S_MISC_TAX:
			X = A;
			continue;
		case BPF_S_MISC_TXA:
			A = X;
			continue;
		case BPF_S_RET_K:
			return K;
		case BPF_S_RET_A:
			return A;
		case BPF_S_ST:
			memvalid |= 1UL << K;
			mem[K] = A;
			continue;
		case BPF_S_STX:
			memvalid |= 1UL << K;
			mem[K] = X;
			continue;
		default:
			WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u\n",
				       fentry->code, fentry->jt,
				       fentry->jf, fentry->k);
			return 0;
		}

		/*
		 * Handle ancillary data, which are impossible
		 * (or very difficult) to get parsing packet contents.
		 */
		switch (k-SKF_AD_OFF) {
		case SKF_AD_PROTOCOL:
			A = ntohs(skb->protocol);
			continue;
		case SKF_AD_PKTTYPE:
			A = skb->pkt_type;
			continue;
		case SKF_AD_IFINDEX:
			if (!skb->dev)
				return 0;
			A = skb->dev->ifindex;
			continue;
		case SKF_AD_MARK:
			A = skb->mark;
			continue;
		case SKF_AD_QUEUE:
			A = skb->queue_mapping;
			continue;
		case SKF_AD_HATYPE:
			if (!skb->dev)
				return 0;
			A = skb->dev->type;
			continue;
#if 0
		case SKF_AD_RXHASH:
			A = skb->rxhash;
			continue;
#endif
		case SKF_AD_CPU:
			A = raw_smp_processor_id();
			continue;
		case SKF_AD_NLATTR: {
			struct nlattr *nla;

			if (skb_is_nonlinear(skb))
				return 0;
			if (A > skb->len - sizeof(struct nlattr))
				return 0;

			nla = nla_find((struct nlattr *)&skb->data[A],
				       skb->len - A, X);
			if (nla)
				A = (void *)nla - (void *)skb->data;
			else
				A = 0;
			continue;
		}
		case SKF_AD_NLATTR_NEST: {
			struct nlattr *nla;

			if (skb_is_nonlinear(skb))
				return 0;
			if (A > skb->len - sizeof(struct nlattr))
				return 0;

			nla = (struct nlattr *)&skb->data[A];
			if (nla->nla_len > A - skb->len)
				return 0;

			nla = nla_find_nested(nla, X);
			if (nla)
				A = (void *)nla - (void *)skb->data;
			else
				A = 0;
			continue;
		}
		default:
			return 0;
		}
	}

	return 0;
}
示例#5
0
int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
{
	unsigned char *data = skb->data;
	/* len is UNSIGNED. Byte wide insns relies only on implicit
	   type casts to prevent reading arbitrary memory locations.
	 */
	unsigned int len = skb->len;
	struct sock_filter *fentry;	/* We walk down these */
	u32 A = 0;	   		/* Accumulator */
	u32 X = 0;   			/* Index Register */
	u32 mem[BPF_MEMWORDS];		/* Scratch Memory Store */
	int k;
	int pc;

	/*
	 * Process array of filter instructions.
	 */

	for(pc = 0; pc < flen; pc++)
	{
		fentry = &filter[pc];
			
		switch(fentry->code)
		{
			case BPF_ALU|BPF_ADD|BPF_X:
				A += X;
				continue;

			case BPF_ALU|BPF_ADD|BPF_K:
				A += fentry->k;
				continue;

			case BPF_ALU|BPF_SUB|BPF_X:
				A -= X;
				continue;

			case BPF_ALU|BPF_SUB|BPF_K:
				A -= fentry->k;
				continue;

			case BPF_ALU|BPF_MUL|BPF_X:
				A *= X;
				continue;

			case BPF_ALU|BPF_MUL|BPF_K:
				A *= fentry->k;
				continue;

			case BPF_ALU|BPF_DIV|BPF_X:
				if(X == 0)
					return (0);
				A /= X;
				continue;

			case BPF_ALU|BPF_DIV|BPF_K:
				if(fentry->k == 0)
					return (0);
				A /= fentry->k;
				continue;

			case BPF_ALU|BPF_AND|BPF_X:
				A &= X;
				continue;

			case BPF_ALU|BPF_AND|BPF_K:
				A &= fentry->k;
				continue;

			case BPF_ALU|BPF_OR|BPF_X:
				A |= X;
				continue;

			case BPF_ALU|BPF_OR|BPF_K:
				A |= fentry->k;
				continue;

			case BPF_ALU|BPF_LSH|BPF_X:
				A <<= X;
				continue;

			case BPF_ALU|BPF_LSH|BPF_K:
				A <<= fentry->k;
				continue;

			case BPF_ALU|BPF_RSH|BPF_X:
				A >>= X;
				continue;

			case BPF_ALU|BPF_RSH|BPF_K:
				A >>= fentry->k;
				continue;

			case BPF_ALU|BPF_NEG:
				A = -A;
				continue;

			case BPF_JMP|BPF_JA:
				pc += fentry->k;
				continue;

			case BPF_JMP|BPF_JGT|BPF_K:
				pc += (A > fentry->k) ? fentry->jt : fentry->jf;
				continue;

			case BPF_JMP|BPF_JGE|BPF_K:
				pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
				continue;

			case BPF_JMP|BPF_JEQ|BPF_K:
				pc += (A == fentry->k) ? fentry->jt : fentry->jf;
				continue;

			case BPF_JMP|BPF_JSET|BPF_K:
				pc += (A & fentry->k) ? fentry->jt : fentry->jf;
				continue;

			case BPF_JMP|BPF_JGT|BPF_X:
				pc += (A > X) ? fentry->jt : fentry->jf;
				continue;

			case BPF_JMP|BPF_JGE|BPF_X:
				pc += (A >= X) ? fentry->jt : fentry->jf;
				continue;

			case BPF_JMP|BPF_JEQ|BPF_X:
				pc += (A == X) ? fentry->jt : fentry->jf;
				continue;

			case BPF_JMP|BPF_JSET|BPF_X:
				pc += (A & X) ? fentry->jt : fentry->jf;
				continue;

			case BPF_LD|BPF_W|BPF_ABS:
				k = fentry->k;
load_w:
				if(k+sizeof(u32) <= len) {
					A = ntohl(*(u32*)&data[k]);
					continue;
				}
				if (k<0) {
					u8 *ptr;

					if (k>=SKF_AD_OFF)
						break;
					if ((ptr = load_pointer(skb, k)) != NULL) {
						A = ntohl(*(u32*)ptr);
						continue;
					}
				}
				return 0;

			case BPF_LD|BPF_H|BPF_ABS:
				k = fentry->k;
load_h:
				if(k + sizeof(u16) <= len) {
					A = ntohs(*(u16*)&data[k]);
					continue;
				}
				if (k<0) {
					u8 *ptr;

					if (k>=SKF_AD_OFF)
						break;
					if ((ptr = load_pointer(skb, k)) != NULL) {
						A = ntohs(*(u16*)ptr);
						continue;
					}
				}
				return 0;

			case BPF_LD|BPF_B|BPF_ABS:
				k = fentry->k;
load_b:
				if(k < len) {
					A = data[k];
					continue;
				}
				if (k<0) {
					u8 *ptr;

					if (k>=SKF_AD_OFF)
						break;
					if ((ptr = load_pointer(skb, k)) != NULL) {
						A = *ptr;
						continue;
					}
				}
				return 0;

			case BPF_LD|BPF_W|BPF_LEN:
				A = len;
				continue;

			case BPF_LDX|BPF_W|BPF_LEN:
				X = len;
				continue;

			case BPF_LD|BPF_W|BPF_IND:
				k = X + fentry->k;
				goto load_w;

                       case BPF_LD|BPF_H|BPF_IND:
				k = X + fentry->k;
				goto load_h;

                       case BPF_LD|BPF_B|BPF_IND:
				k = X + fentry->k;
				goto load_b;

			case BPF_LDX|BPF_B|BPF_MSH:
				k = fentry->k;
				if(k >= len)
					return (0);
				X = (data[k] & 0xf) << 2;
				continue;

			case BPF_LD|BPF_IMM:
				A = fentry->k;
				continue;

			case BPF_LDX|BPF_IMM:
				X = fentry->k;
				continue;

			case BPF_LD|BPF_MEM:
				A = mem[fentry->k];
				continue;

			case BPF_LDX|BPF_MEM:
				X = mem[fentry->k];
				continue;

			case BPF_MISC|BPF_TAX:
				X = A;
				continue;

			case BPF_MISC|BPF_TXA:
				A = X;
				continue;

			case BPF_RET|BPF_K:
				return ((unsigned int)fentry->k);

			case BPF_RET|BPF_A:
				return ((unsigned int)A);

			case BPF_ST:
				mem[fentry->k] = A;
				continue;

			case BPF_STX:
				mem[fentry->k] = X;
				continue;

			default:
				/* Invalid instruction counts as RET */
				return (0);
		}

		/* Handle ancillary data, which are impossible
		   (or very difficult) to get parsing packet contents.
		 */
		switch (k-SKF_AD_OFF) {
		case SKF_AD_PROTOCOL:
			A = htons(skb->protocol);
			continue;
		case SKF_AD_PKTTYPE:
			A = skb->pkt_type;
			continue;
		case SKF_AD_IFINDEX:
			A = skb->dev->ifindex;
			continue;
		default:
			return 0;
		}
	}

	return (0);
}
示例#6
0
/**
 *	sk_run_filter - run a filter on a socket
 *	@skb: buffer to run the filter on
 *	@fentry: filter to apply
 *
 * Decode and apply filter instructions to the skb->data.
 * Return length to keep, 0 for none. @skb is the data we are
 * filtering, @filter is the array of filter instructions.
 * Because all jumps are guaranteed to be before last instruction,
 * and last instruction guaranteed to be a RET, we dont need to check
 * flen. (We used to pass to this function the length of filter)
 */
unsigned int sk_run_filter(const struct sk_buff *skb,
			   const struct sock_filter *fentry)
{
	void *ptr;
	u32 A = 0;			/* Accumulator */
	u32 X = 0;			/* Index Register */
	u32 mem[BPF_MEMWORDS];		/* Scratch Memory Store */
	u32 tmp;
	int k;

	/*
	 * Process array of filter instructions.
	 */
	for (;; fentry++) {
#if defined(CONFIG_X86_32)
#define	K (fentry->k)
#else
		const u32 K = fentry->k;
#endif

		switch (fentry->code) {
		case BPF_S_ALU_ADD_X:
			A += X;
			continue;
		case BPF_S_ALU_ADD_K:
			A += K;
			continue;
		case BPF_S_ALU_SUB_X:
			A -= X;
			continue;
		case BPF_S_ALU_SUB_K:
			A -= K;
			continue;
		case BPF_S_ALU_MUL_X:
			A *= X;
			continue;
		case BPF_S_ALU_MUL_K:
			A *= K;
			continue;
		case BPF_S_ALU_DIV_X:
			if (X == 0)
				return 0;
			A /= X;
			continue;
		case BPF_S_ALU_DIV_K:
			A = reciprocal_divide(A, K);
			continue;
		case BPF_S_ALU_AND_X:
			A &= X;
			continue;
		case BPF_S_ALU_AND_K:
			A &= K;
			continue;
		case BPF_S_ALU_OR_X:
			A |= X;
			continue;
		case BPF_S_ALU_OR_K:
			A |= K;
			continue;
		case BPF_S_ALU_LSH_X:
			A <<= X;
			continue;
		case BPF_S_ALU_LSH_K:
			A <<= K;
			continue;
		case BPF_S_ALU_RSH_X:
			A >>= X;
			continue;
		case BPF_S_ALU_RSH_K:
			A >>= K;
			continue;
		case BPF_S_ALU_NEG:
			A = -A;
			continue;
		case BPF_S_JMP_JA:
			fentry += K;
			continue;
		case BPF_S_JMP_JGT_K:
			fentry += (A > K) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGE_K:
			fentry += (A >= K) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JEQ_K:
			fentry += (A == K) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JSET_K:
			fentry += (A & K) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGT_X:
			fentry += (A > X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGE_X:
			fentry += (A >= X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JEQ_X:
			fentry += (A == X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JSET_X:
			fentry += (A & X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_LD_W_ABS:
			k = K;
load_w:
			ptr = load_pointer(skb, k, 4, &tmp);
			if (ptr != NULL) {
				A = get_unaligned_be32(ptr);
				continue;
			}
			return 0;
		case BPF_S_LD_H_ABS:
			k = K;
load_h:
			ptr = load_pointer(skb, k, 2, &tmp);
			if (ptr != NULL) {
				A = get_unaligned_be16(ptr);
				continue;
			}
			return 0;
		case BPF_S_LD_B_ABS:
			k = K;
load_b:
			ptr = load_pointer(skb, k, 1, &tmp);
			if (ptr != NULL) {
				A = *(u8 *)ptr;
				continue;
			}
			return 0;
		case BPF_S_LD_W_LEN:
			A = skb->len;
			continue;
		case BPF_S_LDX_W_LEN:
			X = skb->len;
			continue;
		case BPF_S_LD_W_IND:
			k = X + K;
			goto load_w;
		case BPF_S_LD_H_IND:
			k = X + K;
			goto load_h;
		case BPF_S_LD_B_IND:
			k = X + K;
			goto load_b;
		case BPF_S_LDX_B_MSH:
			ptr = load_pointer(skb, K, 1, &tmp);
			if (ptr != NULL) {
				X = (*(u8 *)ptr & 0xf) << 2;
				continue;
			}
			return 0;
		case BPF_S_LD_IMM:
			A = K;
			continue;
		case BPF_S_LDX_IMM:
			X = K;
			continue;
		case BPF_S_LD_MEM:
			A = mem[K];
			continue;
		case BPF_S_LDX_MEM:
			X = mem[K];
			continue;
		case BPF_S_MISC_TAX:
			X = A;
			continue;
		case BPF_S_MISC_TXA:
			A = X;
			continue;
		case BPF_S_RET_K:
			return K;
		case BPF_S_RET_A:
			return A;
		case BPF_S_ST:
			mem[K] = A;
			continue;
		case BPF_S_STX:
			mem[K] = X;
			continue;
		case BPF_S_ANC_PROTOCOL:
			A = ntohs(skb->protocol);
			continue;
		case BPF_S_ANC_PKTTYPE:
			A = skb->pkt_type;
			continue;
		case BPF_S_ANC_IFINDEX:
			if (!skb->dev)
				return 0;
			A = skb->dev->ifindex;
			continue;
		case BPF_S_ANC_MARK:
			A = skb->mark;
			continue;
		case BPF_S_ANC_QUEUE:
			A = skb->queue_mapping;
			continue;
		case BPF_S_ANC_HATYPE:
			if (!skb->dev)
				return 0;
			A = skb->dev->type;
			continue;
		case BPF_S_ANC_RXHASH:
			A = skb->rxhash;
			continue;
		case BPF_S_ANC_CPU:
			A = raw_smp_processor_id();
			continue;
		case BPF_S_ANC_NLATTR: {
			struct nlattr *nla;

			if (skb_is_nonlinear(skb))
				return 0;
			if (A > skb->len - sizeof(struct nlattr))
				return 0;

			nla = nla_find((struct nlattr *)&skb->data[A],
				       skb->len - A, X);
			if (nla)
				A = (void *)nla - (void *)skb->data;
			else
				A = 0;
			continue;
		}
		case BPF_S_ANC_NLATTR_NEST: {
			struct nlattr *nla;

			if (skb_is_nonlinear(skb))
				return 0;
			if (A > skb->len - sizeof(struct nlattr))
				return 0;

			nla = (struct nlattr *)&skb->data[A];
			if (nla->nla_len > A - skb->len)
				return 0;

			nla = nla_find_nested(nla, X);
			if (nla)
				A = (void *)nla - (void *)skb->data;
			else
				A = 0;
			continue;
		}
#ifdef CONFIG_SECCOMP_FILTER
		case BPF_S_ANC_SECCOMP_LD_W:
			A = seccomp_bpf_load(fentry->k);
			continue;
#endif
		default:
			WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u\n",
				       fentry->code, fentry->jt,
				       fentry->jf, fentry->k);
			return 0;
		}
	}

	return 0;
}
示例#7
0
/**
 *	sk_run_filter - run a filter on a socket
 *	@skb: buffer to run the filter on
 *	@filter: filter to apply
 *	@flen: length of filter
 *
 * Decode and apply filter instructions to the skb->data.
 * Return length to keep, 0 for none. skb is the data we are
 * filtering, filter is the array of filter instructions, and
 * len is the number of filter blocks in the array.
 */
unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
{
	void *ptr;
	u32 A = 0;			/* Accumulator */
	u32 X = 0;			/* Index Register */
	u32 mem[BPF_MEMWORDS];		/* Scratch Memory Store */
	unsigned long memvalid = 0;
	u32 tmp;
	int k;
	int pc;

	BUILD_BUG_ON(BPF_MEMWORDS > BITS_PER_LONG);
	/*
	 * Process array of filter instructions.
	 */
	for (pc = 0; pc < flen; pc++) {
		const struct sock_filter *fentry = &filter[pc];
		u32 f_k = fentry->k;

		switch (fentry->code) {
		case BPF_ALU|BPF_ADD|BPF_X:
			A += X;
			continue;
		case BPF_ALU|BPF_ADD|BPF_K:
			A += f_k;
			continue;
		case BPF_ALU|BPF_SUB|BPF_X:
			A -= X;
			continue;
		case BPF_ALU|BPF_SUB|BPF_K:
			A -= f_k;
			continue;
		case BPF_ALU|BPF_MUL|BPF_X:
			A *= X;
			continue;
		case BPF_ALU|BPF_MUL|BPF_K:
			A *= f_k;
			continue;
		case BPF_ALU|BPF_DIV|BPF_X:
			if (X == 0)
				return 0;
			A /= X;
			continue;
		case BPF_ALU|BPF_DIV|BPF_K:
			A /= f_k;
			continue;
		case BPF_ALU|BPF_AND|BPF_X:
			A &= X;
			continue;
		case BPF_ALU|BPF_AND|BPF_K:
			A &= f_k;
			continue;
		case BPF_ALU|BPF_OR|BPF_X:
			A |= X;
			continue;
		case BPF_ALU|BPF_OR|BPF_K:
			A |= f_k;
			continue;
		case BPF_ALU|BPF_LSH|BPF_X:
			A <<= X;
			continue;
		case BPF_ALU|BPF_LSH|BPF_K:
			A <<= f_k;
			continue;
		case BPF_ALU|BPF_RSH|BPF_X:
			A >>= X;
			continue;
		case BPF_ALU|BPF_RSH|BPF_K:
			A >>= f_k;
			continue;
		case BPF_ALU|BPF_NEG:
			A = -A;
			continue;
		case BPF_JMP|BPF_JA:
			pc += f_k;
			continue;
		case BPF_JMP|BPF_JGT|BPF_K:
			pc += (A > f_k) ? fentry->jt : fentry->jf;
			continue;
		case BPF_JMP|BPF_JGE|BPF_K:
			pc += (A >= f_k) ? fentry->jt : fentry->jf;
			continue;
		case BPF_JMP|BPF_JEQ|BPF_K:
			pc += (A == f_k) ? fentry->jt : fentry->jf;
			continue;
		case BPF_JMP|BPF_JSET|BPF_K:
			pc += (A & f_k) ? fentry->jt : fentry->jf;
			continue;
		case BPF_JMP|BPF_JGT|BPF_X:
			pc += (A > X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_JMP|BPF_JGE|BPF_X:
			pc += (A >= X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_JMP|BPF_JEQ|BPF_X:
			pc += (A == X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_JMP|BPF_JSET|BPF_X:
			pc += (A & X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_LD|BPF_W|BPF_ABS:
			k = f_k;
load_w:
			ptr = load_pointer(skb, k, 4, &tmp);
			if (ptr != NULL) {
				A = get_unaligned_be32(ptr);
				continue;
			}
			break;
		case BPF_LD|BPF_H|BPF_ABS:
			k = f_k;
load_h:
			ptr = load_pointer(skb, k, 2, &tmp);
			if (ptr != NULL) {
				A = get_unaligned_be16(ptr);
				continue;
			}
			break;
		case BPF_LD|BPF_B|BPF_ABS:
			k = f_k;
load_b:
			ptr = load_pointer(skb, k, 1, &tmp);
			if (ptr != NULL) {
				A = *(u8 *)ptr;
				continue;
			}
			break;
		case BPF_LD|BPF_W|BPF_LEN:
			A = skb->len;
			continue;
		case BPF_LDX|BPF_W|BPF_LEN:
			X = skb->len;
			continue;
		case BPF_LD|BPF_W|BPF_IND:
			k = X + f_k;
			goto load_w;
		case BPF_LD|BPF_H|BPF_IND:
			k = X + f_k;
			goto load_h;
		case BPF_LD|BPF_B|BPF_IND:
			k = X + f_k;
			goto load_b;
		case BPF_LDX|BPF_B|BPF_MSH:
			ptr = load_pointer(skb, f_k, 1, &tmp);
			if (ptr != NULL) {
				X = (*(u8 *)ptr & 0xf) << 2;
				continue;
			}
			return 0;
		case BPF_LD|BPF_IMM:
			A = f_k;
			continue;
		case BPF_LDX|BPF_IMM:
			X = f_k;
			continue;
		case BPF_LD|BPF_MEM:
			A = (memvalid & (1UL << f_k)) ?
				mem[f_k] : 0;
			continue;
		case BPF_LDX|BPF_MEM:
			X = (memvalid & (1UL << f_k)) ?
				mem[f_k] : 0;
			continue;
		case BPF_MISC|BPF_TAX:
			X = A;
			continue;
		case BPF_MISC|BPF_TXA:
			A = X;
			continue;
		case BPF_RET|BPF_K:
			return f_k;
		case BPF_RET|BPF_A:
			return A;
		case BPF_ST:
			memvalid |= 1UL << f_k;
			mem[f_k] = A;
			continue;
		case BPF_STX:
			memvalid |= 1UL << f_k;
			mem[f_k] = X;
			continue;
		default:
			WARN_ON(1);
			return 0;
		}

		/*
		 * Handle ancillary data, which are impossible
		 * (or very difficult) to get parsing packet contents.
		 */
		switch (k-SKF_AD_OFF) {
		case SKF_AD_PROTOCOL:
			A = ntohs(skb->protocol);
			continue;
		case SKF_AD_PKTTYPE:
			A = skb->pkt_type;
			continue;
		case SKF_AD_IFINDEX:
			A = skb->dev->ifindex;
			continue;
		case SKF_AD_NLATTR: {
			struct nlattr *nla;

			if (skb_is_nonlinear(skb))
				return 0;
			if (A > skb->len - sizeof(struct nlattr))
				return 0;

			nla = nla_find((struct nlattr *)&skb->data[A],
				       skb->len - A, X);
			if (nla)
				A = (void *)nla - (void *)skb->data;
			else
				A = 0;
			continue;
		}
		case SKF_AD_NLATTR_NEST: {
			struct nlattr *nla;

			if (skb_is_nonlinear(skb))
				return 0;
			if (A > skb->len - sizeof(struct nlattr))
				return 0;

			nla = (struct nlattr *)&skb->data[A];
			if (nla->nla_len > A - skb->len)
				return 0;

			nla = nla_find_nested(nla, X);
			if (nla)
				A = (void *)nla - (void *)skb->data;
			else
				A = 0;
			continue;
		}
		default:
			return 0;
		}
	}

	return 0;
}
示例#8
0
文件: filter.c 项目: Mr-Aloof/wl500g
/**
 *	sk_run_filter - run a filter on a socket
 *	@skb: buffer to run the filter on
 *	@filter: filter to apply
 *	@flen: length of filter
 *
 * Decode and apply filter instructions to the skb->data.
 * Return length to keep, 0 for none. skb is the data we are
 * filtering, filter is the array of filter instructions, and
 * len is the number of filter blocks in the array.
 */
unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
{
	struct sock_filter *fentry;	/* We walk down these */
	void *ptr;
	u32 A = 0;			/* Accumulator */
	u32 X = 0;			/* Index Register */
	u32 mem[BPF_MEMWORDS];		/* Scratch Memory Store */
	u32 tmp;
	int k;
	int pc;

	/*
	 * Process array of filter instructions.
	 */
	for (pc = 0; pc < flen; pc++) {
		fentry = &filter[pc];

		switch (fentry->code) {
		case BPF_S_ALU_ADD_X:
			A += X;
			continue;
		case BPF_S_ALU_ADD_K:
			A += fentry->k;
			continue;
		case BPF_S_ALU_SUB_X:
			A -= X;
			continue;
		case BPF_S_ALU_SUB_K:
			A -= fentry->k;
			continue;
		case BPF_S_ALU_MUL_X:
			A *= X;
			continue;
		case BPF_S_ALU_MUL_K:
			A *= fentry->k;
			continue;
		case BPF_S_ALU_DIV_X:
			if (X == 0)
				return 0;
			A /= X;
			continue;
		case BPF_S_ALU_DIV_K:
			A /= fentry->k;
			continue;
		case BPF_S_ALU_AND_X:
			A &= X;
			continue;
		case BPF_S_ALU_AND_K:
			A &= fentry->k;
			continue;
		case BPF_S_ALU_OR_X:
			A |= X;
			continue;
		case BPF_S_ALU_OR_K:
			A |= fentry->k;
			continue;
		case BPF_S_ALU_LSH_X:
			A <<= X;
			continue;
		case BPF_S_ALU_LSH_K:
			A <<= fentry->k;
			continue;
		case BPF_S_ALU_RSH_X:
			A >>= X;
			continue;
		case BPF_S_ALU_RSH_K:
			A >>= fentry->k;
			continue;
		case BPF_S_ALU_NEG:
			A = -A;
			continue;
		case BPF_S_JMP_JA:
			pc += fentry->k;
			continue;
		case BPF_S_JMP_JGT_K:
			pc += (A > fentry->k) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGE_K:
			pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JEQ_K:
			pc += (A == fentry->k) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JSET_K:
			pc += (A & fentry->k) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGT_X:
			pc += (A > X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JGE_X:
			pc += (A >= X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JEQ_X:
			pc += (A == X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_JMP_JSET_X:
			pc += (A & X) ? fentry->jt : fentry->jf;
			continue;
		case BPF_S_LD_W_ABS:
			k = fentry->k;
load_w:
			ptr = load_pointer(skb, k, 4, &tmp);
			if (ptr != NULL) {
				A = get_unaligned_be32(ptr);
				continue;
			}
			break;
		case BPF_S_LD_H_ABS:
			k = fentry->k;
load_h:
			ptr = load_pointer(skb, k, 2, &tmp);
			if (ptr != NULL) {
				A = get_unaligned_be16(ptr);
				continue;
			}
			break;
		case BPF_S_LD_B_ABS:
			k = fentry->k;
load_b:
			ptr = load_pointer(skb, k, 1, &tmp);
			if (ptr != NULL) {
				A = *(u8 *)ptr;
				continue;
			}
			break;
		case BPF_S_LD_W_LEN:
			A = skb->len;
			continue;
		case BPF_S_LDX_W_LEN:
			X = skb->len;
			continue;
		case BPF_S_LD_W_IND:
			k = X + fentry->k;
			goto load_w;
		case BPF_S_LD_H_IND:
			k = X + fentry->k;
			goto load_h;
		case BPF_S_LD_B_IND:
			k = X + fentry->k;
			goto load_b;
		case BPF_S_LDX_B_MSH:
			ptr = load_pointer(skb, fentry->k, 1, &tmp);
			if (ptr != NULL) {
				X = (*(u8 *)ptr & 0xf) << 2;
				continue;
			}
			return 0;
		case BPF_S_LD_IMM:
			A = fentry->k;
			continue;
		case BPF_S_LDX_IMM:
			X = fentry->k;
			continue;
		case BPF_S_LD_MEM:
			A = mem[fentry->k];
			continue;
		case BPF_S_LDX_MEM:
			X = mem[fentry->k];
			continue;
		case BPF_S_MISC_TAX:
			X = A;
			continue;
		case BPF_S_MISC_TXA:
			A = X;
			continue;
		case BPF_S_RET_K:
			return fentry->k;
		case BPF_S_RET_A:
			return A;
		case BPF_S_ST:
			mem[fentry->k] = A;
			continue;
		case BPF_S_STX:
			mem[fentry->k] = X;
			continue;
		default:
			WARN_ON(1);
			return 0;
		}

		/*
		 * Handle ancillary data, which are impossible
		 * (or very difficult) to get parsing packet contents.
		 */
		switch (k-SKF_AD_OFF) {
		case SKF_AD_PROTOCOL:
			A = ntohs(skb->protocol);
			continue;
		case SKF_AD_PKTTYPE:
			A = skb->pkt_type;
			continue;
		case SKF_AD_IFINDEX:
			A = skb->dev->ifindex;
			continue;
		case SKF_AD_MARK:
			A = skb->mark;
			continue;
		case SKF_AD_NLATTR: {
			struct nlattr *nla;

			if (skb_is_nonlinear(skb))
				return 0;
			if (A > skb->len - sizeof(struct nlattr))
				return 0;

			nla = nla_find((struct nlattr *)&skb->data[A],
				       skb->len - A, X);
			if (nla)
				A = (void *)nla - (void *)skb->data;
			else
				A = 0;
			continue;
		}
		case SKF_AD_NLATTR_NEST: {
			struct nlattr *nla;

			if (skb_is_nonlinear(skb))
				return 0;
			if (A > skb->len - sizeof(struct nlattr))
				return 0;

			nla = (struct nlattr *)&skb->data[A];
			if (nla->nla_len > A - skb->len)
				return 0;

			nla = nla_find_nested(nla, X);
			if (nla)
				A = (void *)nla - (void *)skb->data;
			else
				A = 0;
			continue;
		}
		default:
			return 0;
		}
	}

	return 0;
}