aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-12-08 19:03:09 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-12-08 19:08:08 +0100
commitc7918378631992d874c99736272ed342d5d77b2c (patch)
tree5e67097471fda876d532c270dc4b7f3db0e850c5 /pkg
parent33508266251f6db13ef34741e36b1dce2c9e1b49 (diff)
executor: fix handling of big-endian bitfields
Currently we apply big-endian-ness and bitfield-ness in the wrong order in copyin. This leads to totally bogus result. Fix this.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/compiler/check.go3
-rw-r--r--pkg/compiler/testdata/errors.txt1
-rw-r--r--pkg/compiler/types.go18
-rw-r--r--pkg/csource/csource.go16
-rw-r--r--pkg/csource/generated.go27
5 files changed, 39 insertions, 26 deletions
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go
index 6ec2fa9e2..cc0535449 100644
--- a/pkg/compiler/check.go
+++ b/pkg/compiler/check.go
@@ -751,7 +751,8 @@ func (comp *compiler) checkTypeBasic(t *ast.Type, desc *typeDesc, flags checkFla
comp.error(t.Pos, "%v can't be type alias target", t.Ident)
return
}
- if flags&checkIsResourceBase != 0 && !desc.ResourceBase {
+ if flags&checkIsResourceBase != 0 &&
+ (desc.CanBeResourceBase == nil || !desc.CanBeResourceBase(comp, t)) {
comp.error(t.Pos, "%v can't be resource base (int types can)", t.Ident)
return
}
diff --git a/pkg/compiler/testdata/errors.txt b/pkg/compiler/testdata/errors.txt
index fed520e6e..55ec40901 100644
--- a/pkg/compiler/testdata/errors.txt
+++ b/pkg/compiler/testdata/errors.txt
@@ -65,6 +65,7 @@ resource r2[r0]: 2
resource r3[int32:1] ### unexpected ':', only struct fields can be bitfields
resource r4[int32[opt]] ### resource base can't be marked as opt
resource r5[non_existent] ### unknown type non_existent
+resource r6[int64be] ### int64be can't be resource base (int types can)
resource r9["foo"] ### unexpected string "foo", expect type
foo$7(a r0, a1 r2[opt])
diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go
index 98edc9d74..30ff8884a 100644
--- a/pkg/compiler/types.go
+++ b/pkg/compiler/types.go
@@ -18,11 +18,12 @@ type typeDesc struct {
CantBeOpt bool // can't be marked as opt?
NeedBase bool // needs base type when used as field?
AllowColon bool // allow colon (int8:2) on fields?
- ResourceBase bool // can be resource base type?
OptArgs int // number of optional arguments in Args array
Args []namedArg // type arguments
// CanBeArgRet returns if this type can be syscall argument/return (false if nil).
CanBeArgRet func(comp *compiler, t *ast.Type) (bool, bool)
+ // CanBeResourceBase returns if this type can be a resource base type (false if nil.
+ CanBeResourceBase func(comp *compiler, t *ast.Type) bool
// Check does custom verification of the type (optional, consts are not patched yet).
Check func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon)
// CheckConsts does custom verification of the type (optional, consts are patched).
@@ -67,9 +68,16 @@ var typeInt = &typeDesc{
CanBeArgRet: canBeArg,
CanBeTypedef: true,
AllowColon: true,
- ResourceBase: true,
OptArgs: 1,
Args: []namedArg{{Name: "range", Type: typeArgIntRange}},
+ CanBeResourceBase: func(comp *compiler, t *ast.Type) bool {
+ // Big-endian resources can always be converted to non-big-endian,
+ // since we will always revert bytes during copyout and during copyin,
+ // so the result is the same as not reverting at all.
+ // Big-endian resources are also not implemented and don't have tests.
+ _, be := comp.parseIntType(t.Ident)
+ return !be
+ },
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
typeArgBase.Type.Check(comp, t)
},
@@ -653,8 +661,10 @@ var typeArgType = &typeArg{}
var typeResource = &typeDesc{
// No Names, but getTypeDesc knows how to match it.
- CanBeArgRet: canBeArgRet,
- ResourceBase: true,
+ CanBeArgRet: canBeArgRet,
+ CanBeResourceBase: func(comp *compiler, t *ast.Type) bool {
+ return true
+ },
// Gen is assigned below to avoid initialization loop.
}
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index 49431f655..aa5f615e1 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -229,7 +229,7 @@ func (ctx *context) emitCall(w *bytes.Buffer, call prog.ExecCall, ci int, haveCo
if arg.Format != prog.FormatNative && arg.Format != prog.FormatBigEndian {
panic("sring format in syscall argument")
}
- fmt.Fprintf(w, "%v", ctx.constArgToStr(arg))
+ fmt.Fprintf(w, "%v", ctx.constArgToStr(arg, true))
case prog.ExecArgResult:
if arg.Format != prog.FormatNative && arg.Format != prog.FormatBigEndian {
panic("sring format in syscall argument")
@@ -282,13 +282,17 @@ func (ctx *context) copyin(w *bytes.Buffer, csumSeq *int, copyin prog.ExecCopyin
switch arg := copyin.Arg.(type) {
case prog.ExecArgConst:
if arg.BitfieldOffset == 0 && arg.BitfieldLength == 0 {
- ctx.copyinVal(w, copyin.Addr, arg.Size, ctx.constArgToStr(arg), arg.Format)
+ ctx.copyinVal(w, copyin.Addr, arg.Size, ctx.constArgToStr(arg, true), arg.Format)
} else {
if arg.Format != prog.FormatNative && arg.Format != prog.FormatBigEndian {
panic("bitfield+string format")
}
- fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v, 0x%x, %v, %v, %v));\n",
- arg.Size*8, copyin.Addr, ctx.constArgToStr(arg),
+ htobe := ""
+ if arg.Format == prog.FormatBigEndian {
+ htobe = fmt.Sprintf("htobe%v", arg.Size*8)
+ }
+ fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v, %v, 0x%x, %v, %v, %v));\n",
+ arg.Size*8, htobe, copyin.Addr, ctx.constArgToStr(arg, false),
arg.BitfieldOffset, arg.BitfieldLength)
}
case prog.ExecArgResult:
@@ -363,7 +367,7 @@ func (ctx *context) copyout(w *bytes.Buffer, call prog.ExecCall, resCopyout bool
}
}
-func (ctx *context) constArgToStr(arg prog.ExecArgConst) string {
+func (ctx *context) constArgToStr(arg prog.ExecArgConst, handleBigEndian bool) string {
mask := (uint64(1) << (arg.Size * 8)) - 1
v := arg.Value & mask
val := fmt.Sprintf("%v", v)
@@ -375,7 +379,7 @@ func (ctx *context) constArgToStr(arg prog.ExecArgConst) string {
if ctx.opts.Procs > 1 && arg.PidStride != 0 {
val += fmt.Sprintf(" + procid*%v", arg.PidStride)
}
- if arg.Format == prog.FormatBigEndian {
+ if handleBigEndian && arg.Format == prog.FormatBigEndian {
val = fmt.Sprintf("htobe%v(%v)", arg.Size*8, val)
}
return val
diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go
index a7bfe74d0..0c3ecb4e8 100644
--- a/pkg/csource/generated.go
+++ b/pkg/csource/generated.go
@@ -310,19 +310,10 @@ static int event_timedwait(event_t* ev, uint64 timeout)
#endif
#if SYZ_EXECUTOR || SYZ_USE_BITMASKS
-#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1)
-
-#define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, (bf_len)) << (bf_off))
-
-#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \
- if ((bf_off) == 0 && (bf_len) == 0) { \
- *(type*)(addr) = (type)(val); \
- } else { \
- type new_val = *(type*)(addr); \
- new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \
- new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \
- *(type*)(addr) = new_val; \
- }
+#define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
+#define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \
+ *(type*)(addr) = htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
+ (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
#endif
#if SYZ_EXECUTOR || SYZ_USE_CHECKSUMS
@@ -3945,7 +3936,10 @@ static long syz_compare(long want, long want_len, long got, long got_len)
return -1;
}
if (memcmp((void*)want, (void*)got, want_len)) {
- debug("syz_compare: data differs\n");
+ debug("syz_compare: data differs, want:\n");
+ debug_dump_data((char*)want, want_len);
+ debug("got:\n");
+ debug_dump_data((char*)got, got_len);
errno = EINVAL;
return -1;
}
@@ -4106,7 +4100,10 @@ static long syz_compare(long want, long want_len, long got, long got_len)
return -1;
}
if (memcmp((void*)want, (void*)got, want_len)) {
- debug("syz_compare: data differs\n");
+ debug("syz_compare: data differs, want:\n");
+ debug_dump_data((char*)want, want_len);
+ debug("got:\n");
+ debug_dump_data((char*)got, got_len);
errno = EINVAL;
return -1;
}