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