Commit 4a5a5c73 authored by Jan Engelhardt's avatar Jan Engelhardt

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: default avatarJan Engelhardt <jengelh@medozas.de>
parent d6b00a53
...@@ -351,8 +351,8 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par) ...@@ -115,7 +122,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par)
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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_ ...@@ -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_ ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment