mirror of
https://github.com/zeek/zeek.git
synced 2025-10-05 16:18:19 +00:00
Fix &raw_output and enable_raw_output interpretation of NUL characters
When using a `print` statement to write to a file that has raw output enabled, NUL characters in string are no longer interpreted into "\0", no newline is appended afterwards, and each argument to `print` is written to the file without any additional separation. (Re)Assigning to identifiers with the &raw_output attribute should also now correctly apply the attribute to the file value being assigned. Note that the write_file BiF should already be capable of raw string data to a file, expect it bypasses the print_hook event. Addresses #474
This commit is contained in:
parent
6c806b0bce
commit
648e1bda26
12 changed files with 108 additions and 21 deletions
|
@ -173,6 +173,10 @@ void ODesc::AddCS(const char* s)
|
||||||
void ODesc::AddBytes(const BroString* s)
|
void ODesc::AddBytes(const BroString* s)
|
||||||
{
|
{
|
||||||
if ( IsReadable() )
|
if ( IsReadable() )
|
||||||
|
{
|
||||||
|
if ( Style() == RAW_STYLE )
|
||||||
|
AddBytes(reinterpret_cast<const char*>(s->Bytes()), s->Len());
|
||||||
|
else
|
||||||
{
|
{
|
||||||
int render_style = BroString::EXPANDED_STRING;
|
int render_style = BroString::EXPANDED_STRING;
|
||||||
if ( Style() == ALTERNATIVE_STYLE )
|
if ( Style() == ALTERNATIVE_STYLE )
|
||||||
|
@ -184,6 +188,7 @@ void ODesc::AddBytes(const BroString* s)
|
||||||
Add(str);
|
Add(str);
|
||||||
delete [] str;
|
delete [] str;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Add(s->Len());
|
Add(s->Len());
|
||||||
|
|
|
@ -17,6 +17,7 @@ typedef enum {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
STANDARD_STYLE,
|
STANDARD_STYLE,
|
||||||
ALTERNATIVE_STYLE,
|
ALTERNATIVE_STYLE,
|
||||||
|
RAW_STYLE,
|
||||||
} desc_style;
|
} desc_style;
|
||||||
|
|
||||||
class BroFile;
|
class BroFile;
|
||||||
|
|
|
@ -319,6 +319,8 @@ void NameExpr::Assign(Frame* f, Val* v, Opcode op)
|
||||||
id->SetVal(v, op);
|
id->SetVal(v, op);
|
||||||
else
|
else
|
||||||
f->SetElement(id->Offset(), v);
|
f->SetElement(id->Offset(), v);
|
||||||
|
if ( v->Type()->Tag() == TYPE_FILE )
|
||||||
|
v->AsFile()->SetAttrs(id->Attrs());
|
||||||
}
|
}
|
||||||
|
|
||||||
int NameExpr::IsPure() const
|
int NameExpr::IsPure() const
|
||||||
|
|
|
@ -2385,7 +2385,7 @@ bool RemoteSerializer::FlushPrintBuffer(Peer* p)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoteSerializer::SendPrintHookEvent(BroFile* f, const char* txt)
|
bool RemoteSerializer::SendPrintHookEvent(BroFile* f, const char* txt, size_t len)
|
||||||
{
|
{
|
||||||
loop_over_list(peers, i)
|
loop_over_list(peers, i)
|
||||||
{
|
{
|
||||||
|
@ -2398,8 +2398,6 @@ bool RemoteSerializer::SendPrintHookEvent(BroFile* f, const char* txt)
|
||||||
if ( ! fname )
|
if ( ! fname )
|
||||||
continue; // not a managed file.
|
continue; // not a managed file.
|
||||||
|
|
||||||
size_t len = strlen(txt);
|
|
||||||
|
|
||||||
// We cut off everything after the max buffer size. That
|
// We cut off everything after the max buffer size. That
|
||||||
// makes the code a bit easier, and we shouldn't have such
|
// makes the code a bit easier, and we shouldn't have such
|
||||||
// long lines anyway.
|
// long lines anyway.
|
||||||
|
|
|
@ -95,7 +95,7 @@ public:
|
||||||
bool SendPing(PeerID peer, uint32 seq);
|
bool SendPing(PeerID peer, uint32 seq);
|
||||||
|
|
||||||
// Broadcast remote print.
|
// Broadcast remote print.
|
||||||
bool SendPrintHookEvent(BroFile* f, const char* txt);
|
bool SendPrintHookEvent(BroFile* f, const char* txt, size_t len);
|
||||||
|
|
||||||
// Send a request to create a writer on a remote side.
|
// Send a request to create a writer on a remote side.
|
||||||
bool SendLogCreateWriter(PeerID peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const LogField* const * fields);
|
bool SendLogCreateWriter(PeerID peer, EnumVal* id, EnumVal* writer, string path, int num_fields, const LogField* const * fields);
|
||||||
|
|
18
src/Stmt.cc
18
src/Stmt.cc
|
@ -277,9 +277,20 @@ Val* PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const
|
||||||
|
|
||||||
bool ph = print_hook && f->IsPrintHookEnabled();
|
bool ph = print_hook && f->IsPrintHookEnabled();
|
||||||
|
|
||||||
desc_style style = f->IsRawOutput() ? ALTERNATIVE_STYLE : STANDARD_STYLE;
|
desc_style style = f->IsRawOutput() ? RAW_STYLE : STANDARD_STYLE;
|
||||||
|
|
||||||
if ( ! (suppress_local_output && ph) )
|
if ( ! (suppress_local_output && ph) )
|
||||||
|
{
|
||||||
|
if ( f->IsRawOutput() )
|
||||||
|
{
|
||||||
|
ODesc d(DESC_READABLE);
|
||||||
|
d.SetFlush(0);
|
||||||
|
d.SetStyle(style);
|
||||||
|
|
||||||
|
PrintVals(&d, vals, offset);
|
||||||
|
f->Write(d.Description(), d.Len());
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ODesc d(DESC_READABLE, f);
|
ODesc d(DESC_READABLE, f);
|
||||||
d.SetFlush(0);
|
d.SetFlush(0);
|
||||||
|
@ -288,6 +299,7 @@ Val* PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const
|
||||||
PrintVals(&d, vals, offset);
|
PrintVals(&d, vals, offset);
|
||||||
f->Write("\n", 1);
|
f->Write("\n", 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( ph )
|
if ( ph )
|
||||||
{
|
{
|
||||||
|
@ -300,14 +312,14 @@ Val* PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const
|
||||||
val_list* vl = new val_list(2);
|
val_list* vl = new val_list(2);
|
||||||
::Ref(f);
|
::Ref(f);
|
||||||
vl->append(new Val(f));
|
vl->append(new Val(f));
|
||||||
vl->append(new StringVal(d.Description()));
|
vl->append(new StringVal(d.Len(), d.Description()));
|
||||||
|
|
||||||
// Note, this doesn't do remote printing.
|
// Note, this doesn't do remote printing.
|
||||||
mgr.Dispatch(new Event(print_hook, vl), true);
|
mgr.Dispatch(new Event(print_hook, vl), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( remote_serializer )
|
if ( remote_serializer )
|
||||||
remote_serializer->SendPrintHookEvent(f, d.Description());
|
remote_serializer->SendPrintHookEvent(f, d.Description(), d.Len());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -3567,7 +3567,7 @@ void describe_vals(const val_list* vals, ODesc* d, int offset)
|
||||||
|
|
||||||
for ( int i = offset; i < vals->length(); ++i )
|
for ( int i = offset; i < vals->length(); ++i )
|
||||||
{
|
{
|
||||||
if ( i > offset && d->IsReadable() )
|
if ( i > offset && d->IsReadable() && d->Style() != RAW_STYLE )
|
||||||
d->Add(", ");
|
d->Add(", ");
|
||||||
|
|
||||||
(*vals)[i]->Describe(d);
|
(*vals)[i]->Describe(d);
|
||||||
|
|
1
testing/btest/Baseline/bifs.enable_raw_output/output
Normal file
1
testing/btest/Baseline/bifs.enable_raw_output/output
Normal file
|
@ -0,0 +1 @@
|
||||||
|
helloXworldhi
|
1
testing/btest/Baseline/language.raw_output_attr-2/output
Normal file
1
testing/btest/Baseline/language.raw_output_attr-2/output
Normal file
|
@ -0,0 +1 @@
|
||||||
|
helloXworldhi
|
1
testing/btest/Baseline/language.raw_output_attr/output
Normal file
1
testing/btest/Baseline/language.raw_output_attr/output
Normal file
|
@ -0,0 +1 @@
|
||||||
|
helloXworldhi
|
23
testing/btest/bifs/enable_raw_output.test
Normal file
23
testing/btest/bifs/enable_raw_output.test
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Files which enable raw output via the BiF shouldn't interpret NUL characters
|
||||||
|
# in strings that are `print`ed to it.
|
||||||
|
|
||||||
|
# @TEST-EXEC: bro %INPUT
|
||||||
|
# @TEST-EXEC: tr '\000' 'X' <myfile >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
# @TEST-EXEC: cmp myfile hookfile
|
||||||
|
|
||||||
|
event bro_init()
|
||||||
|
{
|
||||||
|
local myfile: file;
|
||||||
|
myfile = open("myfile");
|
||||||
|
enable_raw_output(myfile);
|
||||||
|
print myfile, "hello\x00world", "hi";
|
||||||
|
close(myfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
event print_hook(f: file, s: string)
|
||||||
|
{
|
||||||
|
local hookfile = open("hookfile");
|
||||||
|
write_file(hookfile, s);
|
||||||
|
close(hookfile);
|
||||||
|
}
|
43
testing/btest/language/raw_output_attr.test
Normal file
43
testing/btest/language/raw_output_attr.test
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# Files with the &raw_output attribute shouldn't interpret NUL characters
|
||||||
|
# in strings that are `print`ed to it.
|
||||||
|
|
||||||
|
# @TEST-EXEC: bro %INPUT
|
||||||
|
# @TEST-EXEC: tr '\000' 'X' <myfile >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
# @TEST-EXEC: cmp myfile hookfile
|
||||||
|
|
||||||
|
# first check local variable of file type w/ &raw_output
|
||||||
|
|
||||||
|
event bro_init()
|
||||||
|
{
|
||||||
|
local myfile: file &raw_output;
|
||||||
|
myfile = open("myfile");
|
||||||
|
print myfile, "hello\x00world", "hi";
|
||||||
|
close(myfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
event print_hook(f: file, s: string)
|
||||||
|
{
|
||||||
|
local hookfile = open("hookfile");
|
||||||
|
write_file(hookfile, s);
|
||||||
|
close(hookfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
# @TEST-START-NEXT
|
||||||
|
# now check global variables of file type w/ &raw_output
|
||||||
|
|
||||||
|
global myfile: file &raw_output;
|
||||||
|
|
||||||
|
event bro_init()
|
||||||
|
{
|
||||||
|
myfile = open("myfile");
|
||||||
|
print myfile, "hello\x00world", "hi";
|
||||||
|
close(myfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
event print_hook(f: file, s: string)
|
||||||
|
{
|
||||||
|
local hookfile = open("hookfile");
|
||||||
|
write_file(hookfile, s);
|
||||||
|
close(hookfile);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue