Chinaunix首页 | 论坛 | 博客
  • 博客访问: 107779
  • 博文数量: 41
  • 博客积分: 2520
  • 博客等级: 少校
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-22 16:25
文章分类

全部博文(41)

文章存档

2010年(41)

我的朋友

分类: LINUX

2010-01-22 16:45:52

本章主要讲对matchtarget如何进行合法性检查,包括以下内容:

1.     setsockoptipt_match结构体里面checkentry的过程。涉及到.checkentry.destroy函数指针

 

 

 

static struct nf_sockopt_ops ipt_sockopts = {

              .pf                        = PF_INET,

              .set_optmin            = IPT_BASE_CTL,

              .set_optmax           = IPT_SO_SET_MAX+1,

              .set                       = do_ipt_set_ctl,                                             // setsockopt用到的函数,下面分析

#ifdef CONFIG_COMPAT

              .compat_set          = compat_do_ipt_set_ctl,    //当设置了CONFIG_COMPAT是的set函数,下面分析

#endif

              .get_optmin           = IPT_BASE_CTL,

              .get_optmax           = IPT_SO_GET_MAX+1,

              .get                       = do_ipt_get_ctl,

#ifdef CONFIG_COMPAT

              .compat_get           = compat_do_ipt_get_ctl,

#endif

};

 

.set & .compat_set都会对规则进行检查。包括matchtarget
static int

do_ipt_set_ctl(struct sock *sk,            int cmd, void __user *user, unsigned int len)

{

              int ret;

 

              if (!capable(CAP_NET_ADMIN))

                            return -EPERM;

 

              switch (cmd) {

              case IPT_SO_SET_REPLACE:                                       // 改变表的内容的command,由iptables发起

                            ret = do_replace(user, len);                                          // 具体动作,下面解释

                            break;

 

              case IPT_SO_SET_ADD_COUNTERS:

                            ret = do_add_counters(user, len, 0);

                            break;

 

              default:

                            duprintf("do_ipt_set_ctl:  unknown request %i\n", cmd);

                            ret = -EINVAL;

              }

 

              return ret;

}


 

static int

do_replace(void __user *user, unsigned int len)

{

              int ret;

              struct ipt_replace tmp;                                                    // 表注册的两个关键结构体

              struct xt_table_info *newinfo;

              void *loc_cpu_entry;

 

              if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)                         // 从用户空间直接拷贝ipt_replace

                            return -EFAULT;                                                                                                      // 可以看出用户空间传递的数据至少包含

                                                                                                                                                                                      // struct ipt_replace结构体

              /* Hack: Causes ipchains to give correct error msg --RR */

              if (len != sizeof(tmp) + tmp.size)

                            return -ENOPROTOOPT;

 

              /* overflow check */

              if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -

                                          SMP_CACHE_BYTES)

                            return -ENOMEM;

              if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))

                            return -ENOMEM;

 

              newinfo = xt_alloc_table_info(tmp.size);

              if (!newinfo)

                            return -ENOMEM;

 

              /* choose the copy that is our node/cpu */

              loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];

              if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),                                                // 设置newinfoentries部分

                                             tmp.size) != 0) {                                                                                                               // 即设置规则

                            ret = -EFAULT;

                            goto free_newinfo;

              }

 

              ret = translate_table(tmp.name, tmp.valid_hooks,                                                  // 使用tmp设置newinfo并检查表

                                                newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,

                                                tmp.hook_entry, tmp.underflow);

              if (ret != 0)

                            goto free_newinfo;

 

              duprintf("ip_tables: Translated table\n");

 

              ret = __do_replace(tmp.name, tmp.valid_hooks,                                                     // 调用了注册函数xt_replace_table

                                                newinfo, tmp.num_counters,                                                          // 参考后面解释

                                                tmp.counters);

              if (ret)

                            goto free_newinfo_untrans;

              return 0;

 

 free_newinfo_untrans:

              IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);

 free_newinfo:

              xt_free_table_info(newinfo);

              return ret;

}


 

static int

__do_replace(const char *name, unsigned int valid_hooks,

                            struct xt_table_info *newinfo, unsigned int num_counters,

                            void __user *counters_ptr)

{

              int ret;

              struct ipt_table *t;

              struct xt_table_info *oldinfo;

              struct xt_counters *counters;

              void *loc_cpu_old_entry;

 

              ret = 0;

              counters = vmalloc(num_counters * sizeof(struct xt_counters));

              if (!counters) {

                            ret = -ENOMEM;

                            goto out;

              }

 

              t = try_then_request_module(xt_find_table_lock(AF_INET, name),                 // 找到表,不存在的话

                                                            "iptable_%s", name);                                                                                          // 加载表模块

              if (!t || IS_ERR(t)) {

                            ret = t ? PTR_ERR(t) : -ENOENT;

                            goto free_newinfo_counters_untrans;

              }

 

              /* You lied! */

              if (valid_hooks != t->valid_hooks) {

                            duprintf("Valid hook crap: %08X vs %08X\n",

                                           valid_hooks, t->valid_hooks);

                            ret = -EINVAL;

                            goto put_module;

              }

 

              oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);                           // 调用了表注册函数

              if (!oldinfo)

                            goto put_module;

 

              /* Update module usage count based on number of rules */

              duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",

                            oldinfo->number, oldinfo->initial_entries, newinfo->number);

              if ((oldinfo->number > oldinfo->initial_entries) ||

                  (newinfo->number <= oldinfo->initial_entries))

                            module_put(t->me);

              if ((oldinfo->number > oldinfo->initial_entries) &&

                  (newinfo->number <= oldinfo->initial_entries))

                            module_put(t->me);

 

              /* Get the old counters. */

              get_counters(oldinfo, counters);

              /* Decrease module usage counts and free resource */

              loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];

              IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);

              xt_free_table_info(oldinfo);

              if (copy_to_user(counters_ptr, counters,

                                           sizeof(struct xt_counters) * num_counters) != 0)

                            ret = -EFAULT;

              vfree(counters);

              xt_table_unlock(t);

              return ret;

 

 put_module:

              module_put(t->me);

              xt_table_unlock(t);

 free_newinfo_counters_untrans:

              vfree(counters);

 out:

              return ret;

}


 

static int

translate_table(const char *name,

                            unsigned int valid_hooks,

                            struct xt_table_info *newinfo,

                            void *entry0,

                            unsigned int size,

                            unsigned int number,

                            const unsigned int *hook_entries,

                            const unsigned int *underflows)

检查表,两个被调用的地方:

1.       ipt_register_table()创建表的时候,会对表模板进行一些检查;

2.       在一个叫do_replace()的函数中被调用;上面分析的是这个地方;

{

              unsigned int i;

              int ret;

 

              newinfo->size = size;                                                                                                // 设置

              newinfo->number = number;

 

              /* Init all hooks to impossible value. */

              for (i = 0; i < NF_IP_NUMHOOKS; i++) {

                            newinfo->hook_entry[i] = 0xFFFFFFFF;

                            newinfo->underflow[i] = 0xFFFFFFFF;

              }

 

              duprintf("translate_table: size %u\n", newinfo->size);

              i = 0;

              /* Walk through entries, checking offsets. */

              ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,

                                                        check_entry_size_and_hooks,

                                                        newinfo,

                                                        entry0,

                                                        entry0 + size,

                                                        hook_entries, underflows, &i);

              if (ret != 0)

                            return ret;

 

              if (i != number) {

                            duprintf("translate_table: %u not %u entries\n",

                                           i, number);

                            return -EINVAL;

              }

 

              /* Check hooks all assigned */

              for (i = 0; i < NF_IP_NUMHOOKS; i++) {

                            /* Only hooks which are valid */

                            if (!(valid_hooks & (1 << i)))

                                          continue;

                            if (newinfo->hook_entry[i] == 0xFFFFFFFF) {

                                          duprintf("Invalid hook entry %u %u\n",

                                                         i, hook_entries[i]);

                                          return -EINVAL;

                            }

                            if (newinfo->underflow[i] == 0xFFFFFFFF) {

                                          duprintf("Invalid underflow %u %u\n",

                                                         i, underflows[i]);

                                          return -EINVAL;

                            }

              }

 

              if (!mark_source_chains(newinfo, valid_hooks, entry0))

                            return -ELOOP;

 

              /* Finally, each sanity check must pass */

              i = 0;

              ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,

                                                        check_entry, name, size, &i);                           // 检查matchtarget等,下面解释

 

              if (ret != 0) {

                            IPT_ENTRY_ITERATE(entry0, newinfo->size,

                                                          cleanup_entry, &i);

                            return ret;

              }

 

              /* And one copy for every other CPU */

              for_each_possible_cpu(i) {

                            if (newinfo->entries[i] && newinfo->entries[i] != entry0)

                                          memcpy(newinfo->entries[i], entry0, newinfo->size);

              }

 

              return ret;

}


 

static inline int

(struct ipt_entry *e, const char *name, unsigned int size,

                  unsigned int *i)

{

              struct ipt_entry_target *t;

              struct ipt_target *target;

              int ret;

              unsigned int j;

 

              if (!ip_checkentry(&e->ip)) {

                            duprintf("ip_tables: ip check failed %p %s.\n", e, name);

                            return -EINVAL;

              }

 

              j = 0;

              ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);        // 加载并检查match

              if (ret != 0)

                            goto cleanup_matches;

 

              t = ipt_get_target(e);

              target = try_then_request_module(xt_find_target(AF_INET,                                                                  // 加载target

                                                                                         t->u.user.name,

                                                                                         t->u.user.revision),

                                                                       "ipt_%s", t->u.user.name);

              if (IS_ERR(target) || !target) {

                            duprintf("check_entry: `%s' not found\n", t->u.user.name);

                            ret = target ? PTR_ERR(target) : -ENOENT;

                            goto cleanup_matches;

              }

              t->u.kernel.target = target;

 

              ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),

                                                name, e->comefrom, e->ip.proto,

                                                e->ip.invflags & IPT_INV_PROTO);

              if (ret)

                            goto err;

 

              if (t->u.kernel.target == &ipt_standard_target) {

                            if (!standard_check(t, size)) {

                                          ret = -EINVAL;

                                          goto cleanup_matches;

                            }

              } else if (t->u.kernel.target->checkentry

                               && !t->u.kernel.target->checkentry(name, e, target, t->data,                          // checkentry

                                                                                          t->u.target_size

                                                                                          - sizeof(*t),

                                                                                          e->comefrom)) {

                            duprintf("ip_tables: check failed for `%s'.\n",

                                           t->u.kernel.target->name);

                            ret = -EINVAL;

                            goto err;

              }

 

              (*i)++;

              return 0;

 err:

              module_put(t->u.kernel.target->me);

 cleanup_matches:

              IPT_MATCH_ITERATE(e, cleanup_match, &j);                                          // 删除match

              return ret;

}

 

static inline int

cleanup_match(struct ipt_entry_match *m, unsigned int *i)

{

              if (i && (*i)-- == 0)

                            return 1;

 

              if (m->u.kernel.match->destroy)

                            m->u.kernel.match->destroy(m->u.kernel.match, m->data,

                                                                         m->u.match_size - sizeof(*m));      // destroy函数出现了

              module_put(m->u.kernel.match->me);

              return 0;

}


 

static inline int

check_match(struct ipt_entry_match *m,

                  const char *name,

                  const struct ipt_ip *ip,

                  unsigned int hookmask,

                  unsigned int *i)

首先加载match模块,根据(struct ipt_entry_match *)m->u.user.name"ipt_%s", m->u.user.name

然后对这个ipt_entry_match进行检查,返回0表示通过检查

{

              struct ipt_match *match;

              int ret;

 

              match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,                           // 加载match模块

                                                                                       m->u.user.revision),

                                                                      "ipt_%s", m->u.user.name);

              if (IS_ERR(match) || !match) {

                            duprintf("check_match: `%s' not found\n", m->u.user.name);

                            return match ? PTR_ERR(match) : -ENOENT;

              }

              m->u.kernel.match = match;

 

              ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),                                     // 总的检查

                                               name, hookmask, ip->proto,

                                               ip->invflags & IPT_INV_PROTO);

              if (ret)

                            goto err;

 

              if (m->u.kernel.match->checkentry                                                                                                                      // checkentry存在

                  && !m->u.kernel.match->checkentry(name, ip, match, m->data,                        

                                                                            m->u.match_size - sizeof(*m),                // 因为前面有个取反,所以checkentry

                                                                            hookmask)) {                                                                    // 返回0表示检查到了问题

                            duprintf("ip_tables: check failed for `%s'.\n",

                                           m->u.kernel.match->name);

                            ret = -EINVAL;                                                                                          // #define EINVAL                22              /* Invalid argument */

                            goto err;

              }

 

              (*i)++;

              return 0;                                                                                                                                // 通过检查,那么check_match返回0

err:

              module_put(m->u.kernel.match->me);

              return ret;

}


 

 

int compat_ip_setsockopt(struct sock *sk, int level, int optname,

                                           char __user *optval, int optlen)

{

              int err;

 

              if (level != SOL_IP)

                            return -ENOPROTOOPT;

 

              err = do_ip_setsockopt(sk, level, optname, optval, optlen);

#ifdef CONFIG_NETFILTER

              /* we need to exclude all possible ENOPROTOOPTs except default case */

              if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&

                  optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY

#ifdef CONFIG_IP_MROUTE

                  && (optname < MRT_BASE || optname > (MRT_BASE + 10))

#endif

                 ) {

                            lock_sock(sk);

                            err = compat_nf_setsockopt(sk, PF_INET, optname,

                                                                         optval, optlen);

                            release_sock(sk);

              }

#endif

              return err;

}

 

int compat_nf_setsockopt(struct sock *sk, int pf,

                            int val, char __user *opt, int len)

{

              return compat_nf_sockopt(sk, pf, val, opt, &len, 0);

}

EXPORT_SYMBOL(compat_nf_setsockopt);

 

int compat_nf_getsockopt(struct sock *sk, int pf,

                            int val, char __user *opt, int *len)

{

              return compat_nf_sockopt(sk, pf, val, opt, len, 1);

}

EXPORT_SYMBOL(compat_nf_getsockopt);

 

 

#ifdef CONFIG_COMPAT

static int compat_nf_sockopt(struct sock *sk, int pf, int val,

                                               char __user *opt, int *len, int get)

{

              struct list_head *i;

              struct nf_sockopt_ops *ops;

              int ret;

 

              if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)

                            return -EINTR;

 

              list_for_each(i, &nf_sockopts) {

                            ops = (struct nf_sockopt_ops *)i;

                            if (ops->pf == pf) {

                                          if (get) {

                                                        if (val >= ops->get_optmin

                                                            && val < ops->get_optmax) {

                                                                      ops->use++;

                                                                      mutex_unlock(&nf_sockopt_mutex);

                                                                      if (ops->compat_get)

                                                                                    ret = ops->compat_get(sk,

                                                                                                  val, opt, len);

                                                                      else

                                                                                    ret = ops->get(sk,

                                                                                                  val, opt, len);

                                                                      goto out;

                                                        }

                                          } else {

                                                        if (val >= ops->set_optmin

                                                            && val < ops->set_optmax) {

                                                                      ops->use++;

                                                                      mutex_unlock(&nf_sockopt_mutex);

                                                                      if (ops->compat_set)

                                                                                    ret = ops->compat_set(sk,

                                                                                                  val, opt, *len);

                                                                      else

                                                                                    ret = ops->set(sk,

                                                                                                  val, opt, *len);

                                                                      goto out;

                                                        }

                                          }

                            }

              }

              mutex_unlock(&nf_sockopt_mutex);

              return -ENOPROTOOPT;

 

 out:

              mutex_lock(&nf_sockopt_mutex);

              ops->use--;

              if (ops->cleanup_task)

                            wake_up_process(ops->cleanup_task);

              mutex_unlock(&nf_sockopt_mutex);

              return ret;

}

 

阅读(581) | 评论(0) | 转发(0) |
0

上一篇:Table Filter

下一篇:Check of match/target (2)

给主人留下些什么吧!~~