免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1056 | 回复: 0
打印 上一主题 下一主题

Check of match/target (2) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-01-22 16:47 |只看该作者 |倒序浏览

本章主要讲对match和target如何进行合法性检查,包括以下内容:
1.     从setsockopt到ipt_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
                            info->hook_entry = 0xFFFFFFFF;
                            info->underflow = 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
                            /* Only hooks which are valid */
                            if (!(valid_hooks & (1
                                          continue;
                            if (info->hook_entry == 0xFFFFFFFF) {
                                          duprintf("Invalid hook entry %u %u\n",
                                                         i, hook_entries);
                                          goto out_unlock;
                            }
                            if (info->underflow == 0xFFFFFFFF) {
                                          duprintf("Invalid underflow %u %u\n",
                                                         i, underflows);
                                          goto out_unlock;
                            }
              }

              ret = -ENOMEM;
              newinfo = xt_alloc_table_info(size);
              if (!newinfo)
                            goto out_unlock;

              newinfo->number = number;
              for (i = 0; i
                            newinfo->hook_entry = info->hook_entry;
                            newinfo->underflow = info->underflow;
              }
              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 && newinfo->entries != entry1)
                                          memcpy(newinfo->entries, 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
                            if ((unsigned char *)de - base hook_entry[h])
                                          newinfo->hook_entry[h] -= origsize - *size;
                            if ((unsigned char *)de - base 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;
}



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/110937/showart_2157912.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP