zeek / zeek

Zeek is a powerful network analysis framework that is much different from the typical IDS you may know.
https://www.zeek.org
Other
6.42k stars 1.21k forks source link

Segfault in 5.2.0: bad initializer, first operand should be a list #2933

Open initconf opened 1 year ago

initconf commented 1 year ago

While trying some other code I stumbled across this construct which can trigger a segfault and a coredump.

Here is backtrace:

Core was generated by `zeek ./a.zeek'.
Program terminated with signal SIGSEGV, Segmentation fault.
Address not mapped to object.
#0  zeek::Type::Tag (this=0x0) at /home/bro/install/zeek-5.2.0/src/include/zeek/Type.h:192
192             TypeTag Tag() const { return tag; }
(gdb) bt
#0  zeek::Type::Tag (this=0x0) at /home/bro/install/zeek-5.2.0/src/include/zeek/Type.h:192
#1  zeek::init_type (init=...) at /home/bro/install/zeek-5.2.0/src/Type.cc:2841
#2  0x0000000000aeb19b in zeek::detail::make_var (id=..., t=..., c=zeek::detail::INIT_FULL, init=..., attr=..., dt=zeek::detail::VAR_REGULAR, do_init=<optimized out>) at /home/bro/install/zeek-5.2.0/src/Var.cc:291
#3  0x0000000000aed137 in zeek::detail::add_local (id=..., t=..., c=zeek::detail::INIT_FULL, init=..., attr=..., dt=zeek::detail::VAR_REGULAR) at /home/bro/install/zeek-5.2.0/src/Var.cc:408
#4  0x00000000008021c5 in build_local (id=0x80571b880, t=0x0, ic=zeek::detail::INIT_FULL, e=0x805704ea0, attrs=<optimized out>, dt=zeek::detail::VAR_REGULAR, do_coverage=<optimized out>) at parse.y:341
#5  0x00000000007fa970 in yyparse () at parse.y:1921
#6  0x000000000094f966 in zeek::detail::setup (argc=<optimized out>, argv=0x7fffffffeb68, zopts=<optimized out>) at /home/bro/install/zeek-5.2.0/src/zeek-setup.cc:797
#7  0x00000000007ec365 in main (argc=0, argv=0x80571b900) at /home/bro/install/zeek-5.2.0/src/main.cc:57

here is how to replicate:

event zeek_init()
{
        local active = F;
        local blah : bool;
        local b = (active == T) ?  blah = T: blah= F;
}

]$ zeek ./a.zeek
error in ././a.zeek, line 5: bad initializer, first operand should be a list ((T == active) ? blah = T : blah = F)
Segmentation fault (core dumped)

Let me know if you want access to the coredump and or any other info.

timwoj commented 1 year ago

While it shouldn't crash, it's definitely incorrect usage of the ternary operator. That should fail parsing earlier than it is.

timwoj commented 1 year ago

One real question here is what we should allow for the right side of a ternary operator. Technically the Eval() method of any expression should return a ValPtr and be handled, but is that something we actually want? I could see limiting it to constants and any container type. I grepped through all of the base scripts. The majority of our uses there are constant values or strings, lookups into tables or records, or calls to functions such as fmt.

awelzel commented 1 year ago

it's definitely incorrect usage of the ternary operator. [...] I could see limiting it to constants and any container type.

It's valid in other languages though. This already triggers the crash without the ternary operator (and that doesn't look half wrong). I wonder if there's something else going on.

event zeek_init() {
        local y: count;
        local z = (y = 42);
        print fmt("y=%s z=%s", y, z);
}

This one actually works:

# cat a.zeek 
event zeek_init()
        {
        local active = T;
        local blah: bool;
        local b: bool;
        b = (active == T) ? (blah = T) : (blah = F);
        print active, b, blah;
        }
// ternary.cpp
#include <iostream>

int main(int argc, char *argv[])
{
    int x = 2;
    int y;
    int z = x > 1 ? y = 42 : y = 4711;

    std::cout << "y=" << y << " z=" << z << std::endl;
}
cat ternary.js 
let x = 2;
var y;
let z  = x > 1 ? y = 47 : y = 4711;
console.log(`y=${y} z=${z}`);
timwoj commented 1 year ago

At the very least there's a parsing error finding the various expressions in the line of script. I set a breakpoint in the CondExpr constructor and printed out the three operands passed in from the parser. With the original script:

(lldb) p *op1.ptr_
(zeek::detail::Expr) $2 = {
  zeek::Obj = {
    location = 0x000000011aae17f0
    ref_cnt = 1
    notify_plugins = false
  }
  tag = EXPR_EQ
  paren = true
  type = {
    ptr_ = 0x0000000108c07220
  }
  original = {
    ptr_ = nullptr
  }
  opt_info = 0x000000011a976f70
}
(lldb) p *op2.ptr_
(zeek::detail::Expr) $3 = {
  zeek::Obj = {
    location = 0x000000011aae16a0
    ref_cnt = 1
    notify_plugins = false
  }
  tag = EXPR_ASSIGN
  paren = false
  type = {
    ptr_ = 0x0000000108c07220
  }
  original = {
    ptr_ = nullptr
  }
  opt_info = 0x000000011a976ef0
}
(lldb) p *op3.ptr_
(zeek::detail::Expr) $4 = {
  zeek::Obj = {
    location = 0x000000011aae1640
    ref_cnt = 1
    notify_plugins = false
  }
  tag = EXPR_NAME
  paren = false
  type = {
    ptr_ = 0x0000000108c07220
  }
  original = {
    ptr_ = nullptr
  }
  opt_info = 0x000000011a976eb0
}

With the third line changed to local b = (active == T) ? (blah = T) : (blah = F);:

(lldb) p *op1.ptr_
(zeek::detail::Expr) $0 = {
  zeek::Obj = {
    location = 0x000000011aae1760
    ref_cnt = 1
    notify_plugins = false
  }
  tag = EXPR_EQ
  paren = true
  type = {
    ptr_ = 0x0000000108c07220
  }
  original = {
    ptr_ = nullptr
  }
  opt_info = 0x000000011a976f70
}
(lldb) p *op2.ptr_
(zeek::detail::Expr) $1 = {
  zeek::Obj = {
    location = 0x000000011aae1610
    ref_cnt = 1
    notify_plugins = false
  }
  tag = EXPR_ASSIGN
  paren = true
  type = {
    ptr_ = 0x0000000108c07220
  }
  original = {
    ptr_ = nullptr
  }
  opt_info = 0x000000011a976ef0
}
(lldb) p *op3.ptr_
(zeek::detail::Expr) $2 = {
  zeek::Obj = {
    location = 0x000000011aae14c0
    ref_cnt = 1
    notify_plugins = false
  }
  tag = EXPR_ASSIGN
  paren = true
  type = {
    ptr_ = 0x0000000108c07220
  }
  original = {
    ptr_ = nullptr
  }
  opt_info = 0x000000011a976e70
}

Note how the third operand changed from an EXPR_NAME to EXPR_ASSIGN, which makes a whole lot more sense. It's still not working like that, but at least it's just reporting an error instead of segfaulting:

expression error in /Users/tim/Desktop/2933.zeek, line 5: illegal assignment in initialization ((blah = F))
fatal error: errors occurred while initializing