Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何通过boost::iostream防止zip炸弹_C++_Boost_Compression_Boost Iostreams - Fatal编程技术网

C++ 如何通过boost::iostream防止zip炸弹

C++ 如何通过boost::iostream防止zip炸弹,c++,boost,compression,boost-iostreams,C++,Boost,Compression,Boost Iostreams,我编写了如下代码: std::vector<char> unzip(std::vector<char> const& compressed) { std::vector<char> decompressed; boost::iostreams::filtering_ostream os; os.push(boost::iostreams::gzip_decompressor()); os.push(boost::iostre

我编写了如下代码:

std::vector<char> unzip(std::vector<char> const& compressed)
{
   std::vector<char> decompressed;

   boost::iostreams::filtering_ostream os;

   os.push(boost::iostreams::gzip_decompressor());
   os.push(boost::iostreams::back_inserter(decompressed));

   boost::iostreams::write(os, &compressed[0], compressed.size());
   os.reset();
   return decompressed;
}
std::vector解压(std::vector const&compressed)
{
std::向量解压缩;
boost::iostreams::过滤ostream操作系统;
push(boost::iostreams::gzip_decompressor());
push(boost::iostreams::back_inserter(解压缩));
boost::iostreams::write(操作系统,&compressed[0],compressed.size());
os.reset();
减压返回;
}
如果压缩的
是一个压缩炸弹,会发生什么?我认为内存将耗尽,进程将崩溃


那么如何避免这种情况呢?如何在解压缩前检查原始数据大小?

schorsch\u 76刚刚说我可以编写一个自定义的back\u插入器,所以我只编写了一个,它可以工作:

namespace boost {
namespace iostreams {
template<typename Container>
class limit_back_insert_device {
public:
    typedef typename Container::value_type  char_type;
    typedef sink_tag                        category;
    limit_back_insert_device(Container& cnt, size_t max_size)
        : container(&cnt)
        , max_size(max_size) {
        check(0);
    }
    std::streamsize write(const char_type* s, std::streamsize n) {
        check(n);
        container->insert(container->end(), s, s + n);
        return n;
    }
private:
    void check(size_t n) {
        if (std::numeric_limits<size_t>::max() - n < container->size()) {
            throw std::runtime_error("size_t overflow");
        }

        if ((container->size() + n) > max_size) {
            throw std::runtime_error("container->size() > max_size");
        }
    }
protected:
    Container * container;
    size_t const max_size;
};

template<typename Container>
limit_back_insert_device<Container> limit_back_inserter(Container& cnt,
    size_t max_size) {
    return limit_back_insert_device<Container>(cnt, max_size);
}
} 
}
namespace boost{
命名空间iostreams{
模板
类限制\u返回\u插入\u设备{
公众:
typedef typename容器::值\类型字符\类型;
typedef sink_标签类别;
限制返回插入设备(容器和cnt,最大尺寸)
:容器(&cnt)
,最大尺寸(最大尺寸){
检查(0);
}
std::streamsize写入(常量字符类型*s,std::streamsize n){
检查(n);
容器->插入(容器->结束(),s,s+n);
返回n;
}
私人:
无效检查(尺寸){
如果(std::numeric\u limits::max()-nsize()){
抛出std::运行时错误(“大小溢出”);
}
如果((容器->大小()+n)>最大大小){
抛出std::runtime_错误(“容器->大小()>最大大小”);
}
}
受保护的:
集装箱*集装箱;
尺寸常数最大尺寸;
};
模板
限制返回插入设备限制返回插入器(容器和cnt,
尺寸(最大尺寸){
返回限制返回插入设备(cnt,最大尺寸);
}
} 
}

你会这样做,就像往常一样:解压时要注意

您可以使用容量固定/有限的缓冲区(如use
boost::iostreams::array\u sink
),也可以使用最大大小的保护来包装复制操作

此外,在您的示例中,输入是内存缓冲区,因此使用设备比使用流进行输入更有意义。下面是一个简单的例子:

std::vector<char> unzip(size_t limit, std::vector<char> const& compressed) {
   std::vector<char> decompressed;

   boost::iostreams::filtering_istream is;

   is.push(boost::iostreams::gzip_decompressor());
   is.push(boost::iostreams::array_source(compressed.data(), compressed.size()));

   while (is && (decompressed.size() < limit)) {
       char buf[512];
       is.read(buf, sizeof(buf));
       decompressed.insert(decompressed.end(), buf, buf + is.gcount());
   }
   return decompressed;
}
投掷 当然,如果超出限制,您可以选择抛出:

std::vector<char> unzip(size_t limit, std::vector<char> const& compressed) {
   std::vector<char> decompressed;

   boost::iostreams::filtering_istream is;

   is.push(boost::iostreams::gzip_decompressor());
   is.push(boost::iostreams::array_source(compressed.data(), compressed.size()));

   while (is) {
       char buf[512];
       is.read(buf, sizeof(buf)); // can't detect EOF before attempting read on some streams

       if (decompressed.size() + is.gcount() >= limit)
           throw std::runtime_error("unzip limit exceeded");

       decompressed.insert(decompressed.end(), buf, buf + is.gcount());
   }
   return decompressed;
}
std::vector解压(大小限制、std::vector常量和压缩){
std::向量解压缩;
boost::iostreams::filtering\u istream是;
is.push(boost::iostreams::gzip_decompressor());
is.push(boost::iostreams::array_source(compressed.data(),compressed.size());
while(is){
char-buf[512];
is.read(buf,sizeof(buf));//在尝试读取某些流之前无法检测到EOF
if(解压缩的.size()+为.gcount()>=limit)
抛出std::运行时_错误(“超出解压缩限制”);
decompressed.insert(decompressed.end(),buf,buf+is.gcount());
}
减压返回;
}

我将在
std::thread
中运行此程序,检查已解压缩的共享线程的大小,如果超出限制,则终止线程。请参阅编写自定义back_插入器,在其中可以添加终止标志,用于抛出异常以转到添加的try/catch处理程序。@schorsch_76我认为您是对的。否。这个想法太可怕了。它无缘无故地造成了许多复杂性和低效性。(如果您打算这样做,您可以启动一个具有适当资源限制的单独进程。这一点同时具有进程空间隔离的好处,因此它可以防止解压缩编解码器中可能存在的大量其他漏洞)@schorsch_76您无法真正终止线程。
max10k:  10240 bytes
max100k: 20480 bytes
std::vector<char> unzip(size_t limit, std::vector<char> const& compressed) {
   std::vector<char> decompressed;

   boost::iostreams::filtering_istream is;

   is.push(boost::iostreams::gzip_decompressor());
   is.push(boost::iostreams::array_source(compressed.data(), compressed.size()));

   while (is) {
       char buf[512];
       is.read(buf, sizeof(buf)); // can't detect EOF before attempting read on some streams

       if (decompressed.size() + is.gcount() >= limit)
           throw std::runtime_error("unzip limit exceeded");

       decompressed.insert(decompressed.end(), buf, buf + is.gcount());
   }
   return decompressed;
}