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

全部博文(41)

文章存档

2010年(41)

我的朋友

分类: LINUX

2010-01-22 16:47:08

本章主要讲对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,                                              // 上面已经分析过了,参考上面

#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

};


 

static int

compat_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:

                            ret = compat_do_replace(user, len);

                            break;

 

              case IPT_SO_SET_ADD_COUNTERS:

                            ret = do_add_counters(user, len, 1);

                            break;

 

              default:

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

                            ret = -EINVAL;

              }

 

              return ret;

}

 


 

static int

compat_do_replace(void __user *user, unsigned int len)

{

              int ret;

              struct compat_ipt_replace tmp;

              struct xt_table_info *newinfo;

              void *loc_cpu_entry;

 

              if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)

                            return -EFAULT;

 

              /* 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),

                                             tmp.size) != 0) {

                            ret = -EFAULT;

                            goto free_newinfo;

              }

 

              ret = translate_compat_table(tmp.name, tmp.valid_hooks,

                                                &newinfo, &loc_cpu_entry, tmp.size,

                                                tmp.num_entries, tmp.hook_entry, tmp.underflow);

              if (ret != 0)

                            goto free_newinfo;

 

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

 

              ret = __do_replace(tmp.name, tmp.valid_hooks,

                                                newinfo, tmp.num_counters,

                                                compat_ptr(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

translate_compat_table(const char *name,

                            unsigned int valid_hooks,

                            struct xt_table_info **pinfo,

                            void **pentry0,

                            unsigned int total_size,

                            unsigned int number,

                            unsigned int *hook_entries,

                            unsigned int *underflows)

{

              unsigned int i;

              struct xt_table_info *newinfo, *info;

              void *pos, *entry0, *entry1;

              unsigned int size;

              int ret;

 

              info = *pinfo;

              entry0 = *pentry0;

              size = total_size;

              info->number = number;

 

              /* Init all hooks to impossible value. */

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

                            info->hook_entry[i] = 0xFFFFFFFF;

                            info->underflow[i] = 0xFFFFFFFF;

              }

 

              duprintf("translate_compat_table: size %u\n", info->size);

              i = 0;

              xt_compat_lock(AF_INET);

              /* Walk through entries, checking offsets. */

              ret = IPT_ENTRY_ITERATE(entry0, total_size,

                                                        check_compat_entry_size_and_hooks,

                                                        info, &size, entry0,

                                                        entry0 + total_size,

                                                        hook_entries, underflows, &i, name);

              if (ret != 0)

                            goto out_unlock;

 

              ret = -EINVAL;

              if (i != number) {

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

                                           i, number);

                            goto out_unlock;

              }

 

              /* Check hooks all assigned */

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

                            /* Only hooks which are valid */

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

                                          continue;

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

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

                                                         i, hook_entries[i]);

                                          goto out_unlock;

                            }

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

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

                                                         i, underflows[i]);

                                          goto out_unlock;

                            }

              }

 

              ret = -ENOMEM;

              newinfo = xt_alloc_table_info(size);

              if (!newinfo)

                            goto out_unlock;

 

              newinfo->number = number;

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

                            newinfo->hook_entry[i] = info->hook_entry[i];

                            newinfo->underflow[i] = info->underflow[i];

              }

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

              pos = entry1;

              size =  total_size;

              ret = IPT_ENTRY_ITERATE(entry0, total_size,

                                          compat_copy_entry_from_user, &pos, &size,

                                          name, newinfo, entry1);

              compat_flush_offsets();

              xt_compat_unlock(AF_INET);

              if (ret)

                            goto free_newinfo;

 

              ret = -ELOOP;

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

                            goto free_newinfo;

 

              /* And one copy for every other CPU */

              for_each_possible_cpu(i)

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

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

 

              *pinfo = newinfo;

              *pentry0 = entry1;

              xt_free_table_info(info);

              return 0;

 

free_newinfo:

              xt_free_table_info(newinfo);

out:

              return ret;

out_unlock:

              xt_compat_unlock(AF_INET);

              goto out;

}


 

static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,

              unsigned int *size, const char *name,

              struct xt_table_info *newinfo, unsigned char *base)

{

              struct ipt_entry_target *t;

              struct ipt_target *target;

              struct ipt_entry *de;

              unsigned int origsize;

              int ret, h;

 

              ret = 0;

              origsize = *size;

              de = (struct ipt_entry *)*dstptr;

              memcpy(de, e, sizeof(struct ipt_entry));

 

              *dstptr += sizeof(struct compat_ipt_entry);

              ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,

                                          name, &de->ip, de->comefrom);

              if (ret)

                            goto out;

              de->target_offset = e->target_offset - (origsize - *size);

              t = ipt_get_target(e);

              target = t->u.kernel.target;

              if (target->compat)

                            target->compat(t, dstptr, size, COMPAT_FROM_USER);

              else

                            xt_compat_target(t, dstptr, size, COMPAT_FROM_USER);

 

              de->next_offset = e->next_offset - (origsize - *size);

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

                            if ((unsigned char *)de - base < newinfo->hook_entry[h])

                                          newinfo->hook_entry[h] -= origsize - *size;

                            if ((unsigned char *)de - base < newinfo->underflow[h])

                                          newinfo->underflow[h] -= origsize - *size;

              }

 

              t = ipt_get_target(de);

              target = t->u.kernel.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 out;

 

              ret = -EINVAL;

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

                            if (!standard_check(t, *size))

                                          goto out;

              } else if (t->u.kernel.target->checkentry                                                                                   // target有自己定义的checkentry函数

                               && !t->u.kernel.target->checkentry(name, de, target,

                                                        t->data, t->u.target_size - sizeof(*t),

                                                        de->comefrom)) {

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

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

                            goto out;

              }

              ret = 0;

out:

              return ret;

}

 

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

上一篇:Check of match/target (1)

下一篇:iptables (1)

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