netfilter: xtables: slightly better error reporting
When extended status codes are available, such as ENOMEM on failed allocations, or subsequent functions (e.g. nf_ct_get_l3proto), passing them up to userspace seems like a good idea compared to just always EINVAL. Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
This commit is contained in:
		
					parent
					
						
							
								d6b00a5345
							
						
					
				
			
			
				commit
				
					
						4a5a5c73b7
					
				
			
		
					 25 changed files with 107 additions and 61 deletions
				
			
		|  | @ -351,8 +351,8 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) | ||||||
| { | { | ||||||
| 	struct ipt_clusterip_tgt_info *cipinfo = par->targinfo; | 	struct ipt_clusterip_tgt_info *cipinfo = par->targinfo; | ||||||
| 	const struct ipt_entry *e = par->entryinfo; | 	const struct ipt_entry *e = par->entryinfo; | ||||||
| 
 |  | ||||||
| 	struct clusterip_config *config; | 	struct clusterip_config *config; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && | 	if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && | ||||||
| 	    cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && | 	    cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && | ||||||
|  | @ -387,7 +387,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) | ||||||
| 			if (!dev) { | 			if (!dev) { | ||||||
| 				pr_info("no such interface %s\n", | 				pr_info("no such interface %s\n", | ||||||
| 					e->ip.iniface); | 					e->ip.iniface); | ||||||
| 				return -EINVAL; | 				return -ENOENT; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			config = clusterip_config_init(cipinfo, | 			config = clusterip_config_init(cipinfo, | ||||||
|  | @ -395,17 +395,18 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) | ||||||
| 			if (!config) { | 			if (!config) { | ||||||
| 				pr_info("cannot allocate config\n"); | 				pr_info("cannot allocate config\n"); | ||||||
| 				dev_put(dev); | 				dev_put(dev); | ||||||
| 				return -EINVAL; | 				return -ENOMEM; | ||||||
| 			} | 			} | ||||||
| 			dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0); | 			dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	cipinfo->config = config; | 	cipinfo->config = config; | ||||||
| 
 | 
 | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for proto=%u\n", | 		pr_info("cannot load conntrack support for proto=%u\n", | ||||||
| 			par->family); | 			par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -87,6 +87,7 @@ connsecmark_tg(struct sk_buff *skb, const struct xt_target_param *par) | ||||||
| static int connsecmark_tg_check(const struct xt_tgchk_param *par) | static int connsecmark_tg_check(const struct xt_tgchk_param *par) | ||||||
| { | { | ||||||
| 	const struct xt_connsecmark_target_info *info = par->targinfo; | 	const struct xt_connsecmark_target_info *info = par->targinfo; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (strcmp(par->table, "mangle") != 0 && | 	if (strcmp(par->table, "mangle") != 0 && | ||||||
| 	    strcmp(par->table, "security") != 0) { | 	    strcmp(par->table, "security") != 0) { | ||||||
|  | @ -102,13 +103,14 @@ static int connsecmark_tg_check(const struct xt_tgchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	default: | 	default: | ||||||
| 		pr_info("invalid mode: %hu\n", info->mode); | 		pr_info("invalid mode: %hu\n", info->mode); | ||||||
| 		return false; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for proto=%u\n", | 		pr_info("cannot load conntrack support for proto=%u\n", | ||||||
| 			par->family); | 			par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -59,6 +59,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par) | ||||||
| 	struct nf_conntrack_tuple t; | 	struct nf_conntrack_tuple t; | ||||||
| 	struct nf_conn_help *help; | 	struct nf_conn_help *help; | ||||||
| 	struct nf_conn *ct; | 	struct nf_conn *ct; | ||||||
|  | 	int ret = 0; | ||||||
| 	u8 proto; | 	u8 proto; | ||||||
| 
 | 
 | ||||||
| 	if (info->flags & ~XT_CT_NOTRACK) | 	if (info->flags & ~XT_CT_NOTRACK) | ||||||
|  | @ -75,28 +76,34 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par) | ||||||
| 		goto err1; | 		goto err1; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) | ||||||
| 		goto err1; | 		goto err1; | ||||||
| 
 | 
 | ||||||
| 	memset(&t, 0, sizeof(t)); | 	memset(&t, 0, sizeof(t)); | ||||||
| 	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); | 	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); | ||||||
|  | 	ret = PTR_ERR(ct); | ||||||
| 	if (IS_ERR(ct)) | 	if (IS_ERR(ct)) | ||||||
| 		goto err2; | 		goto err2; | ||||||
| 
 | 
 | ||||||
|  | 	ret = 0; | ||||||
| 	if ((info->ct_events || info->exp_events) && | 	if ((info->ct_events || info->exp_events) && | ||||||
| 	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, | 	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, | ||||||
| 				  GFP_KERNEL)) | 				  GFP_KERNEL)) | ||||||
| 		goto err3; | 		goto err3; | ||||||
| 
 | 
 | ||||||
| 	if (info->helper[0]) { | 	if (info->helper[0]) { | ||||||
|  | 		ret = -ENOENT; | ||||||
| 		proto = xt_ct_find_proto(par); | 		proto = xt_ct_find_proto(par); | ||||||
| 		if (!proto) | 		if (!proto) | ||||||
| 			goto err3; | 			goto err3; | ||||||
| 
 | 
 | ||||||
|  | 		ret = -ENOMEM; | ||||||
| 		help = nf_ct_helper_ext_add(ct, GFP_KERNEL); | 		help = nf_ct_helper_ext_add(ct, GFP_KERNEL); | ||||||
| 		if (help == NULL) | 		if (help == NULL) | ||||||
| 			goto err3; | 			goto err3; | ||||||
| 
 | 
 | ||||||
|  | 		ret = -ENOENT; | ||||||
| 		help->helper = nf_conntrack_helper_try_module_get(info->helper, | 		help->helper = nf_conntrack_helper_try_module_get(info->helper, | ||||||
| 								  par->family, | 								  par->family, | ||||||
| 								  proto); | 								  proto); | ||||||
|  | @ -115,7 +122,7 @@ err3: | ||||||
| err2: | err2: | ||||||
| 	nf_ct_l3proto_module_put(par->family); | 	nf_ct_l3proto_module_put(par->family); | ||||||
| err1: | err1: | ||||||
| 	return -EINVAL; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) | static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) | ||||||
|  |  | ||||||
|  | @ -66,7 +66,7 @@ static int dscp_tg_check(const struct xt_tgchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	if (info->dscp > XT_DSCP_MAX) { | 	if (info->dscp > XT_DSCP_MAX) { | ||||||
| 		pr_info("dscp %x out of range\n", info->dscp); | 		pr_info("dscp %x out of range\n", info->dscp); | ||||||
| 		return -EINVAL; | 		return -EDOM; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -107,7 +107,7 @@ static int ttl_tg_check(const struct xt_tgchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	if (info->mode > IPT_TTL_MAXMODE) { | 	if (info->mode > IPT_TTL_MAXMODE) { | ||||||
| 		pr_info("TTL: invalid or unknown mode %u\n", info->mode); | 		pr_info("TTL: invalid or unknown mode %u\n", info->mode); | ||||||
| 		return false; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 	if (info->mode != IPT_TTL_SET && info->ttl == 0) | 	if (info->mode != IPT_TTL_SET && info->ttl == 0) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | @ -93,7 +93,7 @@ static int led_tg_check(const struct xt_tgchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL); | 	ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL); | ||||||
| 	if (!ledinternal) | 	if (!ledinternal) | ||||||
| 		return -EINVAL; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	ledinternal->netfilter_led_trigger.name = ledinfo->id; | 	ledinternal->netfilter_led_trigger.name = ledinfo->id; | ||||||
| 
 | 
 | ||||||
|  | @ -115,7 +115,7 @@ static int led_tg_check(const struct xt_tgchk_param *par) | ||||||
| 
 | 
 | ||||||
| exit_alloc: | exit_alloc: | ||||||
| 	kfree(ledinternal); | 	kfree(ledinternal); | ||||||
| 	return -EINVAL; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void led_tg_destroy(const struct xt_tgdtor_param *par) | static void led_tg_destroy(const struct xt_tgdtor_param *par) | ||||||
|  |  | ||||||
|  | @ -98,7 +98,7 @@ static int nfqueue_tg_v1_check(const struct xt_tgchk_param *par) | ||||||
| 	if (maxid > 0xffff) { | 	if (maxid > 0xffff) { | ||||||
| 		pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n", | 		pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n", | ||||||
| 		       info->queues_total, maxid); | 		       info->queues_total, maxid); | ||||||
| 		return -EINVAL; | 		return -ERANGE; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -93,6 +93,7 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) | ||||||
| 		struct nlattr		opt; | 		struct nlattr		opt; | ||||||
| 		struct gnet_estimator	est; | 		struct gnet_estimator	est; | ||||||
| 	} cfg; | 	} cfg; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(!rnd_inited)) { | 	if (unlikely(!rnd_inited)) { | ||||||
| 		get_random_bytes(&jhash_rnd, sizeof(jhash_rnd)); | 		get_random_bytes(&jhash_rnd, sizeof(jhash_rnd)); | ||||||
|  | @ -115,6 +116,7 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	ret = -ENOMEM; | ||||||
| 	est = kzalloc(sizeof(*est), GFP_KERNEL); | 	est = kzalloc(sizeof(*est), GFP_KERNEL); | ||||||
| 	if (!est) | 	if (!est) | ||||||
| 		goto err1; | 		goto err1; | ||||||
|  | @ -130,8 +132,9 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) | ||||||
| 	cfg.est.interval	= info->interval; | 	cfg.est.interval	= info->interval; | ||||||
| 	cfg.est.ewma_log	= info->ewma_log; | 	cfg.est.ewma_log	= info->ewma_log; | ||||||
| 
 | 
 | ||||||
| 	if (gen_new_estimator(&est->bstats, &est->rstats, &est->lock, | 	ret = gen_new_estimator(&est->bstats, &est->rstats, | ||||||
| 			      &cfg.opt) < 0) | 				&est->lock, &cfg.opt); | ||||||
|  | 	if (ret < 0) | ||||||
| 		goto err2; | 		goto err2; | ||||||
| 
 | 
 | ||||||
| 	info->est = est; | 	info->est = est; | ||||||
|  | @ -141,7 +144,7 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) | ||||||
| err2: | err2: | ||||||
| 	kfree(est); | 	kfree(est); | ||||||
| err1: | err1: | ||||||
| 	return -EINVAL; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par) | static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par) | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ secmark_tg(struct sk_buff *skb, const struct xt_target_param *par) | ||||||
| 	return XT_CONTINUE; | 	return XT_CONTINUE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool checkentry_selinux(struct xt_secmark_target_info *info) | static int checkentry_selinux(struct xt_secmark_target_info *info) | ||||||
| { | { | ||||||
| 	int err; | 	int err; | ||||||
| 	struct xt_secmark_target_selinux_info *sel = &info->u.sel; | 	struct xt_secmark_target_selinux_info *sel = &info->u.sel; | ||||||
|  | @ -62,27 +62,28 @@ static bool checkentry_selinux(struct xt_secmark_target_info *info) | ||||||
| 		if (err == -EINVAL) | 		if (err == -EINVAL) | ||||||
| 			pr_info("invalid SELinux context \'%s\'\n", | 			pr_info("invalid SELinux context \'%s\'\n", | ||||||
| 				sel->selctx); | 				sel->selctx); | ||||||
| 		return false; | 		return err; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!sel->selsid) { | 	if (!sel->selsid) { | ||||||
| 		pr_info("unable to map SELinux context \'%s\'\n", sel->selctx); | 		pr_info("unable to map SELinux context \'%s\'\n", sel->selctx); | ||||||
| 		return false; | 		return -ENOENT; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = selinux_secmark_relabel_packet_permission(sel->selsid); | 	err = selinux_secmark_relabel_packet_permission(sel->selsid); | ||||||
| 	if (err) { | 	if (err) { | ||||||
| 		pr_info("unable to obtain relabeling permission\n"); | 		pr_info("unable to obtain relabeling permission\n"); | ||||||
| 		return false; | 		return err; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	selinux_secmark_refcount_inc(); | 	selinux_secmark_refcount_inc(); | ||||||
| 	return true; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int secmark_tg_check(const struct xt_tgchk_param *par) | static int secmark_tg_check(const struct xt_tgchk_param *par) | ||||||
| { | { | ||||||
| 	struct xt_secmark_target_info *info = par->targinfo; | 	struct xt_secmark_target_info *info = par->targinfo; | ||||||
|  | 	int err; | ||||||
| 
 | 
 | ||||||
| 	if (strcmp(par->table, "mangle") != 0 && | 	if (strcmp(par->table, "mangle") != 0 && | ||||||
| 	    strcmp(par->table, "security") != 0) { | 	    strcmp(par->table, "security") != 0) { | ||||||
|  | @ -99,8 +100,9 @@ static int secmark_tg_check(const struct xt_tgchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	switch (info->mode) { | 	switch (info->mode) { | ||||||
| 	case SECMARK_MODE_SEL: | 	case SECMARK_MODE_SEL: | ||||||
| 		if (!checkentry_selinux(info)) | 		err = checkentry_selinux(info); | ||||||
| 			return -EINVAL; | 		if (err <= 0) | ||||||
|  | 			return err; | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	default: | 	default: | ||||||
|  |  | ||||||
|  | @ -145,7 +145,7 @@ static int xt_cluster_mt_checkentry(const struct xt_mtchk_param *par) | ||||||
| 	if (info->node_mask >= (1ULL << info->total_nodes)) { | 	if (info->node_mask >= (1ULL << info->total_nodes)) { | ||||||
| 		pr_info("this node mask cannot be " | 		pr_info("this node mask cannot be " | ||||||
| 			"higher than the total number of nodes\n"); | 			"higher than the total number of nodes\n"); | ||||||
| 		return -EINVAL; | 		return -EDOM; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -96,6 +96,7 @@ connbytes_mt(const struct sk_buff *skb, const struct xt_match_param *par) | ||||||
| static int connbytes_mt_check(const struct xt_mtchk_param *par) | static int connbytes_mt_check(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	const struct xt_connbytes_info *sinfo = par->matchinfo; | 	const struct xt_connbytes_info *sinfo = par->matchinfo; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (sinfo->what != XT_CONNBYTES_PKTS && | 	if (sinfo->what != XT_CONNBYTES_PKTS && | ||||||
| 	    sinfo->what != XT_CONNBYTES_BYTES && | 	    sinfo->what != XT_CONNBYTES_BYTES && | ||||||
|  | @ -107,10 +108,11 @@ static int connbytes_mt_check(const struct xt_mtchk_param *par) | ||||||
| 	    sinfo->direction != XT_CONNBYTES_DIR_BOTH) | 	    sinfo->direction != XT_CONNBYTES_DIR_BOTH) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for proto=%u\n", | 		pr_info("cannot load conntrack support for proto=%u\n", | ||||||
| 			par->family); | 			par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -220,22 +220,24 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	struct xt_connlimit_info *info = par->matchinfo; | 	struct xt_connlimit_info *info = par->matchinfo; | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(!connlimit_rnd_inited)) { | 	if (unlikely(!connlimit_rnd_inited)) { | ||||||
| 		get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd)); | 		get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd)); | ||||||
| 		connlimit_rnd_inited = true; | 		connlimit_rnd_inited = true; | ||||||
| 	} | 	} | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for " | 		pr_info("cannot load conntrack support for " | ||||||
| 			"address family %u\n", par->family); | 			"address family %u\n", par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* init private data */ | 	/* init private data */ | ||||||
| 	info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL); | 	info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL); | ||||||
| 	if (info->data == NULL) { | 	if (info->data == NULL) { | ||||||
| 		nf_ct_l3proto_module_put(par->family); | 		nf_ct_l3proto_module_put(par->family); | ||||||
| 		return -EINVAL; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spin_lock_init(&info->data->lock); | 	spin_lock_init(&info->data->lock); | ||||||
|  |  | ||||||
|  | @ -76,10 +76,13 @@ connmark_tg(struct sk_buff *skb, const struct xt_target_param *par) | ||||||
| 
 | 
 | ||||||
| static int connmark_tg_check(const struct xt_tgchk_param *par) | static int connmark_tg_check(const struct xt_tgchk_param *par) | ||||||
| { | { | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for proto=%u\n", | 		pr_info("cannot load conntrack support for proto=%u\n", | ||||||
| 			par->family); | 			par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -105,10 +108,13 @@ connmark_mt(const struct sk_buff *skb, const struct xt_match_param *par) | ||||||
| 
 | 
 | ||||||
| static int connmark_mt_check(const struct xt_mtchk_param *par) | static int connmark_mt_check(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for proto=%u\n", | 		pr_info("cannot load conntrack support for proto=%u\n", | ||||||
| 			par->family); | 			par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -208,10 +208,13 @@ conntrack_mt_v2(const struct sk_buff *skb, const struct xt_match_param *par) | ||||||
| 
 | 
 | ||||||
| static int conntrack_mt_check(const struct xt_mtchk_param *par) | static int conntrack_mt_check(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for proto=%u\n", | 		pr_info("cannot load conntrack support for proto=%u\n", | ||||||
| 			par->family); | 			par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -48,7 +48,7 @@ static int dscp_mt_check(const struct xt_mtchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	if (info->dscp > XT_DSCP_MAX) { | 	if (info->dscp > XT_DSCP_MAX) { | ||||||
| 		pr_info("dscp %x out of range\n", info->dscp); | 		pr_info("dscp %x out of range\n", info->dscp); | ||||||
| 		return -EINVAL; | 		return -EDOM; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -214,7 +214,7 @@ static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_ | ||||||
| 	hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + | 	hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + | ||||||
| 			sizeof(struct list_head) * size); | 			sizeof(struct list_head) * size); | ||||||
| 	if (!hinfo) | 	if (!hinfo) | ||||||
| 		return -1; | 		return -ENOMEM; | ||||||
| 	minfo->hinfo = hinfo; | 	minfo->hinfo = hinfo; | ||||||
| 
 | 
 | ||||||
| 	/* copy match config into hashtable config */ | 	/* copy match config into hashtable config */ | ||||||
|  | @ -250,7 +250,7 @@ static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_ | ||||||
| 		&dl_file_ops, hinfo); | 		&dl_file_ops, hinfo); | ||||||
| 	if (!hinfo->pde) { | 	if (!hinfo->pde) { | ||||||
| 		vfree(hinfo); | 		vfree(hinfo); | ||||||
| 		return -1; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
| 	hinfo->net = net; | 	hinfo->net = net; | ||||||
| 
 | 
 | ||||||
|  | @ -285,7 +285,7 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, | ||||||
| 	hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + | 	hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + | ||||||
| 	                sizeof(struct list_head) * size); | 	                sizeof(struct list_head) * size); | ||||||
| 	if (hinfo == NULL) | 	if (hinfo == NULL) | ||||||
| 		return -1; | 		return -ENOMEM; | ||||||
| 	minfo->hinfo = hinfo; | 	minfo->hinfo = hinfo; | ||||||
| 
 | 
 | ||||||
| 	/* copy match config into hashtable config */ | 	/* copy match config into hashtable config */ | ||||||
|  | @ -311,7 +311,7 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, | ||||||
| 		&dl_file_ops, hinfo); | 		&dl_file_ops, hinfo); | ||||||
| 	if (hinfo->pde == NULL) { | 	if (hinfo->pde == NULL) { | ||||||
| 		vfree(hinfo); | 		vfree(hinfo); | ||||||
| 		return -1; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
| 	hinfo->net = net; | 	hinfo->net = net; | ||||||
| 
 | 
 | ||||||
|  | @ -675,13 +675,14 @@ static int hashlimit_mt_check_v0(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	struct net *net = par->net; | 	struct net *net = par->net; | ||||||
| 	struct xt_hashlimit_info *r = par->matchinfo; | 	struct xt_hashlimit_info *r = par->matchinfo; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	/* Check for overflow. */ | 	/* Check for overflow. */ | ||||||
| 	if (r->cfg.burst == 0 || | 	if (r->cfg.burst == 0 || | ||||||
| 	    user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) { | 	    user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) { | ||||||
| 		pr_info("overflow, try lower: %u/%u\n", | 		pr_info("overflow, try lower: %u/%u\n", | ||||||
| 			r->cfg.avg, r->cfg.burst); | 			r->cfg.avg, r->cfg.burst); | ||||||
| 		return -EINVAL; | 		return -ERANGE; | ||||||
| 	} | 	} | ||||||
| 	if (r->cfg.mode == 0 || | 	if (r->cfg.mode == 0 || | ||||||
| 	    r->cfg.mode > (XT_HASHLIMIT_HASH_DPT | | 	    r->cfg.mode > (XT_HASHLIMIT_HASH_DPT | | ||||||
|  | @ -698,9 +699,12 @@ static int hashlimit_mt_check_v0(const struct xt_mtchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&hashlimit_mutex); | 	mutex_lock(&hashlimit_mutex); | ||||||
| 	r->hinfo = htable_find_get(net, r->name, par->family); | 	r->hinfo = htable_find_get(net, r->name, par->family); | ||||||
| 	if (!r->hinfo && htable_create_v0(net, r, par->family) != 0) { | 	if (r->hinfo == NULL) { | ||||||
| 		mutex_unlock(&hashlimit_mutex); | 		ret = htable_create_v0(net, r, par->family); | ||||||
| 		return -EINVAL; | 		if (ret < 0) { | ||||||
|  | 			mutex_unlock(&hashlimit_mutex); | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&hashlimit_mutex); | 	mutex_unlock(&hashlimit_mutex); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -710,6 +714,7 @@ static int hashlimit_mt_check(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	struct net *net = par->net; | 	struct net *net = par->net; | ||||||
| 	struct xt_hashlimit_mtinfo1 *info = par->matchinfo; | 	struct xt_hashlimit_mtinfo1 *info = par->matchinfo; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	/* Check for overflow. */ | 	/* Check for overflow. */ | ||||||
| 	if (info->cfg.burst == 0 || | 	if (info->cfg.burst == 0 || | ||||||
|  | @ -717,7 +722,7 @@ static int hashlimit_mt_check(const struct xt_mtchk_param *par) | ||||||
| 	    user2credits(info->cfg.avg)) { | 	    user2credits(info->cfg.avg)) { | ||||||
| 		pr_info("overflow, try lower: %u/%u\n", | 		pr_info("overflow, try lower: %u/%u\n", | ||||||
| 			info->cfg.avg, info->cfg.burst); | 			info->cfg.avg, info->cfg.burst); | ||||||
| 		return -EINVAL; | 		return -ERANGE; | ||||||
| 	} | 	} | ||||||
| 	if (info->cfg.gc_interval == 0 || info->cfg.expire == 0) | 	if (info->cfg.gc_interval == 0 || info->cfg.expire == 0) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  | @ -733,9 +738,12 @@ static int hashlimit_mt_check(const struct xt_mtchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&hashlimit_mutex); | 	mutex_lock(&hashlimit_mutex); | ||||||
| 	info->hinfo = htable_find_get(net, info->name, par->family); | 	info->hinfo = htable_find_get(net, info->name, par->family); | ||||||
| 	if (!info->hinfo && htable_create(net, info, par->family) != 0) { | 	if (info->hinfo == NULL) { | ||||||
| 		mutex_unlock(&hashlimit_mutex); | 		ret = htable_create(net, info, par->family); | ||||||
| 		return -EINVAL; | 		if (ret < 0) { | ||||||
|  | 			mutex_unlock(&hashlimit_mutex); | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&hashlimit_mutex); | 	mutex_unlock(&hashlimit_mutex); | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -57,11 +57,13 @@ helper_mt(const struct sk_buff *skb, const struct xt_match_param *par) | ||||||
| static int helper_mt_check(const struct xt_mtchk_param *par) | static int helper_mt_check(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	struct xt_helper_info *info = par->matchinfo; | 	struct xt_helper_info *info = par->matchinfo; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for proto=%u\n", | 		pr_info("cannot load conntrack support for proto=%u\n", | ||||||
| 			par->family); | 			par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 	info->name[29] = '\0'; | 	info->name[29] = '\0'; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -107,12 +107,12 @@ static int limit_mt_check(const struct xt_mtchk_param *par) | ||||||
| 	    || user2credits(r->avg * r->burst) < user2credits(r->avg)) { | 	    || user2credits(r->avg * r->burst) < user2credits(r->avg)) { | ||||||
| 		pr_info("Overflow, try lower: %u/%u\n", | 		pr_info("Overflow, try lower: %u/%u\n", | ||||||
| 			r->avg, r->burst); | 			r->avg, r->burst); | ||||||
| 		return -EINVAL; | 		return -ERANGE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	priv = kmalloc(sizeof(*priv), GFP_KERNEL); | 	priv = kmalloc(sizeof(*priv), GFP_KERNEL); | ||||||
| 	if (priv == NULL) | 	if (priv == NULL) | ||||||
| 		return -EINVAL; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	/* For SMP, we only want to use one set of state. */ | 	/* For SMP, we only want to use one set of state. */ | ||||||
| 	r->master = priv; | 	r->master = priv; | ||||||
|  |  | ||||||
|  | @ -52,7 +52,7 @@ static int quota_mt_check(const struct xt_mtchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	q->master = kmalloc(sizeof(*q->master), GFP_KERNEL); | 	q->master = kmalloc(sizeof(*q->master), GFP_KERNEL); | ||||||
| 	if (q->master == NULL) | 	if (q->master == NULL) | ||||||
| 		return -EINVAL; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	q->master->quota = q->quota; | 	q->master->quota = q->quota; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -78,6 +78,7 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	struct xt_rateest_match_info *info = par->matchinfo; | 	struct xt_rateest_match_info *info = par->matchinfo; | ||||||
| 	struct xt_rateest *est1, *est2; | 	struct xt_rateest *est1, *est2; | ||||||
|  | 	int ret = false; | ||||||
| 
 | 
 | ||||||
| 	if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | | 	if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | | ||||||
| 				     XT_RATEEST_MATCH_REL)) != 1) | 				     XT_RATEEST_MATCH_REL)) != 1) | ||||||
|  | @ -95,6 +96,7 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) | ||||||
| 		goto err1; | 		goto err1; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	ret  = -ENOENT; | ||||||
| 	est1 = xt_rateest_lookup(info->name1); | 	est1 = xt_rateest_lookup(info->name1); | ||||||
| 	if (!est1) | 	if (!est1) | ||||||
| 		goto err1; | 		goto err1; | ||||||
|  |  | ||||||
|  | @ -355,8 +355,10 @@ static int recent_mt_check(const struct xt_mtchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size, | 	t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size, | ||||||
| 		    GFP_KERNEL); | 		    GFP_KERNEL); | ||||||
| 	if (t == NULL) | 	if (t == NULL) { | ||||||
|  | 		ret = -ENOMEM; | ||||||
| 		goto out; | 		goto out; | ||||||
|  | 	} | ||||||
| 	t->refcnt = 1; | 	t->refcnt = 1; | ||||||
| 	strcpy(t->name, info->name); | 	strcpy(t->name, info->name); | ||||||
| 	INIT_LIST_HEAD(&t->lru_list); | 	INIT_LIST_HEAD(&t->lru_list); | ||||||
|  | @ -367,6 +369,7 @@ static int recent_mt_check(const struct xt_mtchk_param *par) | ||||||
| 		  &recent_mt_fops, t); | 		  &recent_mt_fops, t); | ||||||
| 	if (pde == NULL) { | 	if (pde == NULL) { | ||||||
| 		kfree(t); | 		kfree(t); | ||||||
|  | 		ret = -ENOMEM; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 	pde->uid = ip_list_uid; | 	pde->uid = ip_list_uid; | ||||||
|  |  | ||||||
|  | @ -39,10 +39,13 @@ state_mt(const struct sk_buff *skb, const struct xt_match_param *par) | ||||||
| 
 | 
 | ||||||
| static int state_mt_check(const struct xt_mtchk_param *par) | static int state_mt_check(const struct xt_mtchk_param *par) | ||||||
| { | { | ||||||
| 	if (nf_ct_l3proto_try_module_get(par->family) < 0) { | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = nf_ct_l3proto_try_module_get(par->family); | ||||||
|  | 	if (ret < 0) { | ||||||
| 		pr_info("cannot load conntrack support for proto=%u\n", | 		pr_info("cannot load conntrack support for proto=%u\n", | ||||||
| 			par->family); | 			par->family); | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -62,7 +62,7 @@ static int statistic_mt_check(const struct xt_mtchk_param *par) | ||||||
| 
 | 
 | ||||||
| 	info->master = kzalloc(sizeof(*info->master), GFP_KERNEL); | 	info->master = kzalloc(sizeof(*info->master), GFP_KERNEL); | ||||||
| 	if (info->master == NULL) | 	if (info->master == NULL) | ||||||
| 		return -EINVAL; | 		return -ENOMEM; | ||||||
| 	info->master->count = info->u.nth.count; | 	info->master->count = info->u.nth.count; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -63,7 +63,7 @@ static int string_mt_check(const struct xt_mtchk_param *par) | ||||||
| 	ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen, | 	ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen, | ||||||
| 				     GFP_KERNEL, flags); | 				     GFP_KERNEL, flags); | ||||||
| 	if (IS_ERR(ts_conf)) | 	if (IS_ERR(ts_conf)) | ||||||
| 		return -EINVAL; | 		return PTR_ERR(ts_conf); | ||||||
| 
 | 
 | ||||||
| 	conf->config = ts_conf; | 	conf->config = ts_conf; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -225,7 +225,7 @@ static int time_mt_check(const struct xt_mtchk_param *par) | ||||||
| 	    info->daytime_stop > XT_TIME_MAX_DAYTIME) { | 	    info->daytime_stop > XT_TIME_MAX_DAYTIME) { | ||||||
| 		pr_info("invalid argument - start or " | 		pr_info("invalid argument - start or " | ||||||
| 			"stop time greater than 23:59:59\n"); | 			"stop time greater than 23:59:59\n"); | ||||||
| 		return -EINVAL; | 		return -EDOM; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jan Engelhardt
				Jan Engelhardt