From 3b2530ce7a0d6aa3bee687bf0167bb4908c7b798 Mon Sep 17 00:00:00 2001 From: Serhey Popovych Date: Wed, 7 Mar 2018 11:10:40 +0200 Subject: xtables: Do not register matches/targets with incompatible revision If kernel tells revision isn't found/supported at the moment we should keep entity in pending list, not register or bail to do so later. Kernel might still load module for entity we asking it for and this could be slow on some embedded devices. Catch double registration attempts by checking me->next being non-NULL in xtables_register_match() and xtables_register_target(). Signed-off-by: Serhey Popovych Signed-off-by: Florian Westphal --- libxtables/xtables.c | 66 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 24 deletions(-) (limited to 'libxtables') diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 60a0231c..afde394b 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -198,8 +198,8 @@ struct xtables_match *xtables_matches; struct xtables_target *xtables_targets; /* Fully register a match/target which was previously partially registered. */ -static void xtables_fully_register_pending_match(struct xtables_match *me); -static void xtables_fully_register_pending_target(struct xtables_target *me); +static bool xtables_fully_register_pending_match(struct xtables_match *me); +static bool xtables_fully_register_pending_target(struct xtables_target *me); void xtables_init(void) { @@ -638,11 +638,11 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) { ptr = *dptr; *dptr = (*dptr)->next; - ptr->next = NULL; - xtables_fully_register_pending_match(ptr); - } else { - dptr = &((*dptr)->next); + if (xtables_fully_register_pending_match(ptr)) + continue; + *dptr = ptr; } + dptr = &((*dptr)->next); } for (ptr = xtables_matches; ptr; ptr = ptr->next) { @@ -728,11 +728,11 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) { ptr = *dptr; *dptr = (*dptr)->next; - ptr->next = NULL; - xtables_fully_register_pending_target(ptr); - } else { - dptr = &((*dptr)->next); + if (xtables_fully_register_pending_target(ptr)) + continue; + *dptr = ptr; } + dptr = &((*dptr)->next); } for (ptr = xtables_targets; ptr; ptr = ptr->next) { @@ -846,6 +846,12 @@ static void xtables_check_options(const char *name, const struct option *opt) void xtables_register_match(struct xtables_match *me) { + if (me->next) { + fprintf(stderr, "%s: match \"%s\" already registered\n", + xt_params->program_name, me->name); + exit(1); + } + if (me->version == NULL) { fprintf(stderr, "%s: match %s<%u> is missing a version\n", xt_params->program_name, me->name, me->revision); @@ -947,12 +953,17 @@ static int xtables_target_prefer(const struct xtables_target *a, b->revision, b->family); } -static void xtables_fully_register_pending_match(struct xtables_match *me) +static bool xtables_fully_register_pending_match(struct xtables_match *me) { struct xtables_match **i, *old; const char *rn; int compare; + /* See if new match can be used. */ + rn = (me->real_name != NULL) ? me->real_name : me->name; + if (!compatible_match_revision(rn, me->revision)) + return false; + old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); if (old) { compare = xtables_match_prefer(old, me); @@ -967,12 +978,7 @@ static void xtables_fully_register_pending_match(struct xtables_match *me) rn = (old->real_name != NULL) ? old->real_name : old->name; if (compare > 0 && compatible_match_revision(rn, old->revision)) - return; - - /* See if new match can be used. */ - rn = (me->real_name != NULL) ? me->real_name : me->name; - if (!compatible_match_revision(rn, me->revision)) - return; + return true; /* Delete old one. */ for (i = &xtables_matches; *i!=old; i = &(*i)->next); @@ -993,6 +999,8 @@ static void xtables_fully_register_pending_match(struct xtables_match *me) me->m = NULL; me->mflags = 0; + + return true; } void xtables_register_matches(struct xtables_match *match, unsigned int n) @@ -1004,6 +1012,12 @@ void xtables_register_matches(struct xtables_match *match, unsigned int n) void xtables_register_target(struct xtables_target *me) { + if (me->next) { + fprintf(stderr, "%s: target \"%s\" already registered\n", + xt_params->program_name, me->name); + exit(1); + } + if (me->version == NULL) { fprintf(stderr, "%s: target %s<%u> is missing a version\n", xt_params->program_name, me->name, me->revision); @@ -1044,12 +1058,19 @@ void xtables_register_target(struct xtables_target *me) xtables_pending_targets = me; } -static void xtables_fully_register_pending_target(struct xtables_target *me) +static bool xtables_fully_register_pending_target(struct xtables_target *me) { struct xtables_target *old; const char *rn; int compare; + if (strcmp(me->name, "standard") != 0) { + /* See if new target can be used. */ + rn = (me->real_name != NULL) ? me->real_name : me->name; + if (!compatible_target_revision(rn, me->revision)) + return false; + } + old = xtables_find_target(me->name, XTF_DURING_LOAD); if (old) { struct xtables_target **i; @@ -1066,12 +1087,7 @@ static void xtables_fully_register_pending_target(struct xtables_target *me) rn = (old->real_name != NULL) ? old->real_name : old->name; if (compare > 0 && compatible_target_revision(rn, old->revision)) - return; - - /* See if new target can be used. */ - rn = (me->real_name != NULL) ? me->real_name : me->name; - if (!compatible_target_revision(rn, me->revision)) - return; + return true; /* Delete old one. */ for (i = &xtables_targets; *i!=old; i = &(*i)->next); @@ -1090,6 +1106,8 @@ static void xtables_fully_register_pending_target(struct xtables_target *me) xtables_targets = me; me->t = NULL; me->tflags = 0; + + return true; } void xtables_register_targets(struct xtables_target *target, unsigned int n) -- cgit v1.2.3