?? ebtables.c
字號:
so there is no misunderstanding */ BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set " "in distinguisher\n"); return -EINVAL; } /* this checks if the previous chain has as many entries as it said it has */ if (*n != *cnt) { BUGPRINT("nentries does not equal the nr of entries " "in the chain\n"); return -EINVAL; } /* before we look at the struct, be sure it is not too big */ if ((char *)hook_entries[i] + sizeof(struct ebt_entries) > limit) { BUGPRINT("entries_size too small\n"); return -EINVAL; } if (((struct ebt_entries *)e)->policy != EBT_DROP && ((struct ebt_entries *)e)->policy != EBT_ACCEPT) { /* only RETURN from udc */ if (i != NF_BR_NUMHOOKS || ((struct ebt_entries *)e)->policy != EBT_RETURN) { BUGPRINT("bad policy\n"); return -EINVAL; } } if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */ (*udc_cnt)++; else newinfo->hook_entry[i] = (struct ebt_entries *)e; if (((struct ebt_entries *)e)->counter_offset != *totalcnt) { BUGPRINT("counter_offset != totalcnt"); return -EINVAL; } *n = ((struct ebt_entries *)e)->nentries; *cnt = 0; return 0; } /* a plain old entry, heh */ if (sizeof(struct ebt_entry) > e->watchers_offset || e->watchers_offset > e->target_offset || e->target_offset >= e->next_offset) { BUGPRINT("entry offsets not in right order\n"); return -EINVAL; } /* this is not checked anywhere else */ if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) { BUGPRINT("target size too small\n"); return -EINVAL; } (*cnt)++; (*totalcnt)++; return 0;}struct ebt_cl_stack{ struct ebt_chainstack cs; int from; unsigned int hookmask;};/* * we need these positions to check that the jumps to a different part of the * entries is a jump to the beginning of a new chain. */static inline intebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo, struct ebt_entries **hook_entries, unsigned int *n, unsigned int valid_hooks, struct ebt_cl_stack *udc){ int i; /* we're only interested in chain starts */ if (e->bitmask & EBT_ENTRY_OR_ENTRIES) return 0; for (i = 0; i < NF_BR_NUMHOOKS; i++) { if ((valid_hooks & (1 << i)) == 0) continue; if (newinfo->hook_entry[i] == (struct ebt_entries *)e) break; } /* only care about udc */ if (i != NF_BR_NUMHOOKS) return 0; udc[*n].cs.chaininfo = (struct ebt_entries *)e; /* these initialisations are depended on later in check_chainloops() */ udc[*n].cs.n = 0; udc[*n].hookmask = 0; (*n)++; return 0;}static inline intebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i){ if (i && (*i)-- == 0) return 1; if (m->u.match->destroy) m->u.match->destroy(m->data, m->match_size); module_put(m->u.match->me); return 0;}static inline intebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i){ if (i && (*i)-- == 0) return 1; if (w->u.watcher->destroy) w->u.watcher->destroy(w->data, w->watcher_size); module_put(w->u.watcher->me); return 0;}static inline intebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt){ struct ebt_entry_target *t; if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) return 0; /* we're done */ if (cnt && (*cnt)-- == 0) return 1; EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL); EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL); t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); if (t->u.target->destroy) t->u.target->destroy(t->data, t->target_size); module_put(t->u.target->me); return 0;}static inline intebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, const char *name, unsigned int *cnt, unsigned int valid_hooks, struct ebt_cl_stack *cl_s, unsigned int udc_cnt){ struct ebt_entry_target *t; struct ebt_target *target; unsigned int i, j, hook = 0, hookmask = 0; int ret; /* don't mess with the struct ebt_entries */ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) return 0; if (e->bitmask & ~EBT_F_MASK) { BUGPRINT("Unknown flag for bitmask\n"); return -EINVAL; } if (e->invflags & ~EBT_INV_MASK) { BUGPRINT("Unknown flag for inv bitmask\n"); return -EINVAL; } if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) { BUGPRINT("NOPROTO & 802_3 not allowed\n"); return -EINVAL; } /* what hook do we belong to? */ for (i = 0; i < NF_BR_NUMHOOKS; i++) { if ((valid_hooks & (1 << i)) == 0) continue; if ((char *)newinfo->hook_entry[i] < (char *)e) hook = i; else break; } /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on a base chain */ if (i < NF_BR_NUMHOOKS) hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); else { for (i = 0; i < udc_cnt; i++) if ((char *)(cl_s[i].cs.chaininfo) > (char *)e) break; if (i == 0) hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); else hookmask = cl_s[i - 1].hookmask; } i = 0; ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i); if (ret != 0) goto cleanup_matches; j = 0; ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j); if (ret != 0) goto cleanup_watchers; t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); target = find_target_lock(t->u.name, &ret, &ebt_mutex); if (!target) goto cleanup_watchers; if (!try_module_get(target->me)) { up(&ebt_mutex); ret = -ENOENT; goto cleanup_watchers; } up(&ebt_mutex); t->u.target = target; if (t->u.target == &ebt_standard_target) { if (e->target_offset + sizeof(struct ebt_standard_target) > e->next_offset) { BUGPRINT("Standard target size too big\n"); ret = -EFAULT; goto cleanup_watchers; } if (((struct ebt_standard_target *)t)->verdict < -NUM_STANDARD_TARGETS) { BUGPRINT("Invalid standard target\n"); ret = -EFAULT; goto cleanup_watchers; } } else if ((e->target_offset + t->target_size + sizeof(struct ebt_entry_target) > e->next_offset) || (t->u.target->check && t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){ module_put(t->u.target->me); ret = -EFAULT; goto cleanup_watchers; } (*cnt)++; return 0;cleanup_watchers: EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);cleanup_matches: EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i); return ret;}/* * checks for loops and sets the hook mask for udc * the hook mask for udc tells us from which base chains the udc can be * accessed. This mask is a parameter to the check() functions of the extensions */static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s, unsigned int udc_cnt, unsigned int hooknr, char *base){ int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict; struct ebt_entry *e = (struct ebt_entry *)chain->data; struct ebt_entry_target *t; while (pos < nentries || chain_nr != -1) { /* end of udc, go back one 'recursion' step */ if (pos == nentries) { /* put back values of the time when this chain was called */ e = cl_s[chain_nr].cs.e; if (cl_s[chain_nr].from != -1) nentries = cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries; else nentries = chain->nentries; pos = cl_s[chain_nr].cs.n; /* make sure we won't see a loop that isn't one */ cl_s[chain_nr].cs.n = 0; chain_nr = cl_s[chain_nr].from; if (pos == nentries) continue; } t = (struct ebt_entry_target *) (((char *)e) + e->target_offset); if (strcmp(t->u.name, EBT_STANDARD_TARGET)) goto letscontinue; if (e->target_offset + sizeof(struct ebt_standard_target) > e->next_offset) { BUGPRINT("Standard target size too big\n"); return -1; } verdict = ((struct ebt_standard_target *)t)->verdict; if (verdict >= 0) { /* jump to another chain */ struct ebt_entries *hlp2 = (struct ebt_entries *)(base + verdict); for (i = 0; i < udc_cnt; i++) if (hlp2 == cl_s[i].cs.chaininfo) break; /* bad destination or loop */ if (i == udc_cnt) { BUGPRINT("bad destination\n"); return -1; } if (cl_s[i].cs.n) { BUGPRINT("loop\n"); return -1; } /* this can't be 0, so the above test is correct */ cl_s[i].cs.n = pos + 1; pos = 0; cl_s[i].cs.e = ((void *)e + e->next_offset); e = (struct ebt_entry *)(hlp2->data); nentries = hlp2->nentries; cl_s[i].from = chain_nr; chain_nr = i; /* this udc is accessible from the base chain for hooknr */ cl_s[i].hookmask |= (1 << hooknr); continue; }letscontinue: e = (void *)e + e->next_offset; pos++; } return 0;}/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */static int translate_table(struct ebt_replace *repl, struct ebt_table_info *newinfo){ unsigned int i, j, k, udc_cnt; int ret; struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */ i = 0; while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i))) i++; if (i == NF_BR_NUMHOOKS) { BUGPRINT("No valid hooks specified\n"); return -EINVAL; } if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) { BUGPRINT("Chains don't start at beginning\n"); return -EINVAL; } /* make sure chains are ordered after each other in same order as their corresponding hooks */ for (j = i + 1; j < NF_BR_NUMHOOKS; j++) { if (!(repl->valid_hooks & (1 << j))) continue; if ( repl->hook_entry[j] <= repl->hook_entry[i] ) { BUGPRINT("Hook order must be followed\n"); return -EINVAL; } i = j; } for (i = 0; i < NF_BR_NUMHOOKS; i++) newinfo->hook_entry[i] = NULL; newinfo->entries_size = repl->entries_size; newinfo->nentries = repl->nentries; /* do some early checkings and initialize some things */ i = 0; /* holds the expected nr. of entries for the chain */ j = 0; /* holds the up to now counted entries for the chain */ k = 0; /* holds the total nr. of entries, should equal newinfo->nentries afterwards */ udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */ ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ebt_check_entry_size_and_hooks, newinfo, repl->entries, repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k, &udc_cnt, repl->valid_hooks); if (ret != 0) return ret; if (i != j) { BUGPRINT("nentries does not equal the nr of entries in the " "(last) chain\n"); return -EINVAL; } if (k != newinfo->nentries) { BUGPRINT("Total nentries is wrong\n"); return -EINVAL; } /* check if all valid hooks have a chain */ for (i = 0; i < NF_BR_NUMHOOKS; i++) { if (newinfo->hook_entry[i] == NULL && (repl->valid_hooks & (1 << i))) { BUGPRINT("Valid hook without chain\n"); return -EINVAL; } } /* get the location of the udc, put them in an array while we're at it, allocate the chainstack */ if (udc_cnt) { /* this will get free'd in do_replace()/ebt_register_table() if an error occurs */ newinfo->chainstack = (struct ebt_chainstack **) vmalloc(NR_CPUS * sizeof(struct ebt_chainstack)); if (!newinfo->chainstack) return -ENOMEM; for (i = 0; i < NR_CPUS; i++) { newinfo->chainstack[i] = vmalloc(udc_cnt * sizeof(struct ebt_chainstack)); if (!newinfo->chainstack[i]) { while (i) vfree(newinfo->chainstack[--i]); vfree(newinfo->chainstack); newinfo->chainstack = NULL; return -ENOMEM; } } cl_s = (struct ebt_cl_stack *) vmalloc(udc_cnt * sizeof(struct ebt_cl_stack)); if (!cl_s) return -ENOMEM; i = 0; /* the i'th udc */ EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ebt_get_udc_positions, newinfo, repl->hook_entry, &i, repl->valid_hooks, cl_s); /* sanity check */ if (i != udc_cnt) { BUGPRINT("i != udc_cnt\n"); vfree(cl_s); return -EFAULT; } } /* Check for loops */ for (i = 0; i < NF_BR_NUMHOOKS; i++) if (repl->valid_hooks & (1 << i)) if (check_chainloops(newinfo->hook_entry[i], cl_s, udc_cnt, i, newinfo->entries)) { if (cl_s) vfree(cl_s); return -EINVAL; } /* we now know the following (along with E=mc
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -