Skip to content

Commit aaafda4

Browse files
committed
catch ABI errors
1 parent 423a86e commit aaafda4

1 file changed

Lines changed: 117 additions & 18 deletions

File tree

ipthelper/xshared.c

Lines changed: 117 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,83 @@
1414
#include <sys/time.h>
1515
#include <unistd.h>
1616
#include <fcntl.h>
17+
#if defined(__unix__) || defined(__APPLE__)
18+
#include <dlfcn.h>
19+
#endif
1720
#include "xtables.h"
1821
#include <math.h>
1922
#include "xshared.h"
2023

24+
#define XS_LONGOPTS_SCAN_LIMIT 4096U
25+
26+
#if defined(__unix__) || defined(__APPLE__)
27+
#define XS_HAVE_DLADDR 1
28+
#else
29+
#define XS_HAVE_DLADDR 0
30+
#endif
31+
32+
static size_t xs_longopts_count(const struct option *opts, const char *ext_name)
33+
{
34+
size_t i;
35+
36+
if (opts == NULL)
37+
return 0;
38+
39+
for (i = 0; i < XS_LONGOPTS_SCAN_LIMIT; ++i) {
40+
if (opts[i].name == NULL)
41+
return i;
42+
}
43+
44+
if (ext_name != NULL)
45+
xtables_error(OTHER_PROBLEM,
46+
"Extension \"%s\" returned an unterminated option table.",
47+
ext_name);
48+
49+
xtables_error(OTHER_PROBLEM,
50+
"xtables option table is missing its terminator.");
51+
return 0;
52+
}
53+
54+
#if XS_HAVE_DLADDR
55+
static bool xs_option_name_pointer_is_valid(const char *name)
56+
{
57+
Dl_info info;
58+
59+
if (name == NULL)
60+
return true;
61+
62+
return dladdr((const void *)name, &info) != 0;
63+
}
64+
#else
65+
static bool xs_option_name_pointer_is_valid(const char *name)
66+
{
67+
(void)name;
68+
return true;
69+
}
70+
#endif
71+
72+
static void xs_validate_new_longopts(struct option *opts, size_t start,
73+
const char *ext_name)
74+
{
75+
size_t total;
76+
size_t i;
77+
78+
if (opts == NULL || ext_name == NULL)
79+
return;
80+
81+
total = xs_longopts_count(opts, ext_name);
82+
if (start >= total)
83+
return;
84+
85+
for (i = start; i < total; ++i) {
86+
if (!xs_option_name_pointer_is_valid(opts[i].name)) {
87+
xtables_error(OTHER_PROBLEM,
88+
"Extension \"%s\" was built against an incompatible libxtables release (detected corrupt option metadata). Please rebuild the module.",
89+
ext_name);
90+
}
91+
}
92+
}
93+
2194
/*
2295
* Print out any special helps. A user might like to be able to add a --help
2396
* to the commandline, and see expected results. So we call help for all
@@ -146,6 +219,7 @@ int command_default(struct iptables_command_state *cs,
146219
m = load_proto(cs);
147220
if (m != NULL) {
148221
size_t size;
222+
size_t merge_start;
149223

150224
cs->proto_used = 1;
151225

@@ -157,18 +231,22 @@ int command_default(struct iptables_command_state *cs,
157231
m->m->u.user.revision = m->revision;
158232
xs_init_match(m);
159233

234+
merge_start = xs_longopts_count(gl->opts, NULL);
160235
if (m->x6_options != NULL)
161236
gl->opts = xtables_options_xfrm(gl->orig_opts,
162237
gl->opts,
163238
m->x6_options,
164239
&m->option_offset);
165240
else
166241
gl->opts = xtables_merge_options(gl->orig_opts,
167-
gl->opts,
168-
m->extra_opts,
169-
&m->option_offset);
242+
gl->opts,
243+
m->extra_opts,
244+
&m->option_offset);
170245
if (gl->opts == NULL)
171246
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
247+
xs_validate_new_longopts(gl->opts, merge_start,
248+
m->real_name != NULL ?
249+
m->real_name : m->name);
172250
optind--;
173251
/* Indicate to rerun getopt *immediately* */
174252
return 1;
@@ -564,18 +642,27 @@ void command_match(struct iptables_command_state *cs)
564642
if (m == m->next)
565643
return;
566644
/* Merge options for non-cloned matches */
567-
if (m->x6_options != NULL){
568-
opts = xtables_options_xfrm(xt_params->orig_opts, opts,
645+
{
646+
bool merged = false;
647+
size_t merge_start = xs_longopts_count(opts, NULL);
648+
649+
if (m->x6_options != NULL) {
650+
opts = xtables_options_xfrm(xt_params->orig_opts, opts,
569651
m->x6_options, &m->option_offset);
570-
int num_orig;
571-
for (num_orig = 0; opts[num_orig].name != NULL; ++num_orig) {}
652+
merged = true;
653+
} else if (m->extra_opts != NULL) {
654+
opts = xtables_merge_options(xt_params->orig_opts, opts,
655+
m->extra_opts, &m->option_offset);
656+
merged = true;
657+
}
572658

659+
if (opts == NULL)
660+
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
661+
if (merged)
662+
xs_validate_new_longopts(opts, merge_start,
663+
m->real_name != NULL ?
664+
m->real_name : m->name);
573665
}
574-
else if (m->extra_opts != NULL)
575-
opts = xtables_merge_options(xt_params->orig_opts, opts,
576-
m->extra_opts, &m->option_offset);
577-
if (opts == NULL)
578-
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
579666
xt_params->opts = opts;
580667
}
581668

@@ -628,15 +715,27 @@ void command_jump(struct iptables_command_state *cs)
628715
cs->target->t->u.user.revision = cs->target->revision;
629716
xs_init_target(cs->target);
630717

631-
if (cs->target->x6_options != NULL)
632-
opts = xtables_options_xfrm(xt_params->orig_opts, opts,
718+
{
719+
bool merged = false;
720+
size_t merge_start = xs_longopts_count(opts, NULL);
721+
722+
if (cs->target->x6_options != NULL) {
723+
opts = xtables_options_xfrm(xt_params->orig_opts, opts,
633724
cs->target->x6_options,
634725
&cs->target->option_offset);
635-
else
636-
opts = xtables_merge_options(xt_params->orig_opts, opts,
726+
merged = true;
727+
} else if (cs->target->extra_opts != NULL) {
728+
opts = xtables_merge_options(xt_params->orig_opts, opts,
637729
cs->target->extra_opts,
638730
&cs->target->option_offset);
639-
if (opts == NULL)
640-
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
731+
merged = true;
732+
}
733+
if (opts == NULL)
734+
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
735+
if (merged)
736+
xs_validate_new_longopts(opts, merge_start,
737+
cs->target->real_name != NULL ?
738+
cs->target->real_name : cs->jumpto);
739+
}
641740
xt_params->opts = opts;
642741
}

0 commit comments

Comments
 (0)