Пример #1
0
static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
{
	const void *bc = bytecode;
	int  len = bytecode_len;

	while (len > 0) {
		const struct inet_diag_bc_op *op = bc;
		int min_len = sizeof(struct inet_diag_bc_op);

//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
		switch (op->code) {
		case INET_DIAG_BC_S_COND:
		case INET_DIAG_BC_D_COND:
			if (!valid_hostcond(bc, len, &min_len))
				return -EINVAL;
			break;
		case INET_DIAG_BC_S_GE:
		case INET_DIAG_BC_S_LE:
		case INET_DIAG_BC_D_GE:
		case INET_DIAG_BC_D_LE:
			if (!valid_port_comparison(bc, len, &min_len))
				return -EINVAL;
			break;
		case INET_DIAG_BC_AUTO:
		case INET_DIAG_BC_JMP:
		case INET_DIAG_BC_NOP:
			break;
		default:
			return -EINVAL;
		}

		if (op->code != INET_DIAG_BC_NOP) {
			if (op->no < min_len || op->no > len + 4 || op->no & 3)
				return -EINVAL;
			if (op->no < len &&
			    !valid_cc(bytecode, bytecode_len, len - op->no))
				return -EINVAL;
		}

		if (op->yes < min_len || op->yes > len + 4 || op->yes & 3)
			return -EINVAL;
		bc  += op->yes;
		len -= op->yes;
	}
	return len == 0 ? 0 : -EINVAL;
}
Пример #2
0
static int inet_diag_bc_audit(const struct nlattr *attr,
                              const struct sk_buff *skb)
{
    bool net_admin = netlink_net_capable(skb, CAP_NET_ADMIN);
    const void *bytecode, *bc;
    int bytecode_len, len;

    if (!attr || nla_len(attr) < sizeof(struct inet_diag_bc_op))
        return -EINVAL;

    bytecode = bc = nla_data(attr);
    len = bytecode_len = nla_len(attr);

    while (len > 0) {
        int min_len = sizeof(struct inet_diag_bc_op);
        const struct inet_diag_bc_op *op = bc;

        switch (op->code) {
        case INET_DIAG_BC_S_COND:
        case INET_DIAG_BC_D_COND:
            if (!valid_hostcond(bc, len, &min_len))
                return -EINVAL;
            break;
        case INET_DIAG_BC_DEV_COND:
            if (!valid_devcond(bc, len, &min_len))
                return -EINVAL;
            break;
        case INET_DIAG_BC_S_GE:
        case INET_DIAG_BC_S_LE:
        case INET_DIAG_BC_D_GE:
        case INET_DIAG_BC_D_LE:
            if (!valid_port_comparison(bc, len, &min_len))
                return -EINVAL;
            break;
        case INET_DIAG_BC_MARK_COND:
            if (!net_admin)
                return -EPERM;
            if (!valid_markcond(bc, len, &min_len))
                return -EINVAL;
            break;
        case INET_DIAG_BC_AUTO:
        case INET_DIAG_BC_JMP:
        case INET_DIAG_BC_NOP:
            break;
        default:
            return -EINVAL;
        }

        if (op->code != INET_DIAG_BC_NOP) {
            if (op->no < min_len || op->no > len + 4 || op->no & 3)
                return -EINVAL;
            if (op->no < len &&
                    !valid_cc(bytecode, bytecode_len, len - op->no))
                return -EINVAL;
        }

        if (op->yes < min_len || op->yes > len + 4 || op->yes & 3)
            return -EINVAL;
        bc  += op->yes;
        len -= op->yes;
    }
    return len == 0 ? 0 : -EINVAL;
}