From owner-svn-src-stable@FreeBSD.ORG Mon Mar 29 12:32:16 2010 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 691C1106564A; Mon, 29 Mar 2010 12:32:16 +0000 (UTC) (envelope-from luigi@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 573668FC0A; Mon, 29 Mar 2010 12:32:16 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o2TCWGFY055697; Mon, 29 Mar 2010 12:32:16 GMT (envelope-from luigi@svn.freebsd.org) Received: (from luigi@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o2TCWGvU055695; Mon, 29 Mar 2010 12:32:16 GMT (envelope-from luigi@svn.freebsd.org) Message-Id: <201003291232.o2TCWGvU055695@svn.freebsd.org> From: Luigi Rizzo Date: Mon, 29 Mar 2010 12:32:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r205833 - stable/8/sys/netinet/ipfw X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 29 Mar 2010 12:32:16 -0000 Author: luigi Date: Mon Mar 29 12:32:16 2010 New Revision: 205833 URL: http://svn.freebsd.org/changeset/base/205833 Log: mfc 205830: fixes to rule set handling (including potential kernel panics) Modified: stable/8/sys/netinet/ipfw/ip_fw_sockopt.c Modified: stable/8/sys/netinet/ipfw/ip_fw_sockopt.c ============================================================================== --- stable/8/sys/netinet/ipfw/ip_fw_sockopt.c Mon Mar 29 12:29:34 2010 (r205832) +++ stable/8/sys/netinet/ipfw/ip_fw_sockopt.c Mon Mar 29 12:32:16 2010 (r205833) @@ -270,23 +270,24 @@ del_entry(struct ip_fw_chain *chain, u_i return EINVAL; } - IPFW_UH_WLOCK(chain); /* prevent conflicts among the writers */ + IPFW_UH_WLOCK(chain); /* arbitrate writers */ chain->reap = NULL; /* prepare for deletions */ switch (cmd) { - case 0: /* delete rules with given number (0 is special means all) */ - case 1: /* delete all rules with given set number, rule->set == rulenum */ - case 5: /* delete rules with given number and with given set number. - * rulenum - given rule number; - * new_set - given set number. - */ - /* locate first rule to delete (start), the one after the - * last one (end), and count how many rules to delete (n) + case 0: /* delete rules number N (N == 0 means all) */ + case 1: /* delete all rules in set N */ + case 5: /* delete rules with number N and set "new_set". */ + + /* + * Locate first rule to delete (start), the rule after + * the last one to delete (end), and count how many + * rules to delete (n) */ n = 0; if (cmd == 1) { /* look for a specific set, must scan all */ + new_set = rulenum; for (start = -1, i = 0; i < chain->n_rules; i++) { - if (chain->map[start]->set != rulenum) + if (chain->map[i]->set != rulenum) continue; if (start < 0) start = i; @@ -314,32 +315,42 @@ del_entry(struct ip_fw_chain *chain, u_i error = EINVAL; break; } - /* copy the initial part of the map */ + /* + * bcopy the initial part of the map, then individually + * copy all matching entries between start and end, + * and then bcopy the final part. + * Once we are done we can swap maps and clean up the + * deleted rules (unfortunately we need to repeat a + * convoluted test). + */ if (start > 0) bcopy(chain->map, map, start * sizeof(struct ip_fw *)); - /* copy active rules between start and end */ for (i = ofs = start; i < end; i++) { rule = chain->map[i]; - if (!(rule->set != RESVD_SET && - (cmd == 0 || rule->set == new_set) )) + if (rule->set == RESVD_SET || cmd == 0 || + (rule->set == new_set && + (cmd == 1 || rule->rulenum == rulenum))) map[ofs++] = chain->map[i]; } - /* finally the tail */ bcopy(chain->map + end, map + ofs, (chain->n_rules - end) * sizeof(struct ip_fw *)); + map = swap_map(chain, map, chain->n_rules - n); /* now remove the rules deleted */ for (i = start; i < end; i++) { + int l; rule = map[i]; - if (rule->set != RESVD_SET && - (cmd == 0 || rule->set == new_set) ) { - int l = RULESIZE(rule); - - chain->static_len -= l; - ipfw_remove_dyn_children(rule); - rule->x_next = chain->reap; - chain->reap = rule; - } + /* same test as above */ + if (rule->set == RESVD_SET || cmd == 0 || + (rule->set == new_set && + (cmd == 1 || rule->rulenum == rulenum))) + continue; + + l = RULESIZE(rule); + chain->static_len -= l; + ipfw_remove_dyn_children(rule); + rule->x_next = chain->reap; + chain->reap = rule; } break; @@ -446,7 +457,7 @@ zero_entry(struct ip_fw_chain *chain, u_ break; } if (!cleared) { /* we did not find any matching rules */ - IPFW_WUNLOCK(chain); + IPFW_UH_RUNLOCK(chain); return (EINVAL); } msg = log_only ? "logging count reset" : "cleared";