From e6a175800f1d9e20aeb7ed35ea2b3fc627049e8f Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 8 Jul 2021 19:19:18 +1000 Subject: pkg/ifuzz/powerpc: add some RTAS fuzzing RunTime Abstraction Services (RTAS) is an API used by the Linux powerpc/pseries platform to talk to the hypervisor. Under KVM, this is implemented as a custom hypercall (which we have support for) and an in memory array of parameters. The hypercall is H_RTAS and its only parameter is a pointer to the mentioned array. The vast majority of RTAS calls are handled normally by QEMU and only a handful by KVM. This adds fuzzing of 4 RTAS calls. This uses a chunk from main 256MB RAM for parameters. The parameters are big endian hence "<<24" for the token. To allow more targeted fuzzing, use iset.GenerateInt(). Signed-off-by: Alexey Kardashevskiy --- pkg/ifuzz/powerpc/powerpc.go | 27 +++++++++++++++++++++++++++ pkg/ifuzz/powerpc/pseudo.go | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) (limited to 'pkg/ifuzz') diff --git a/pkg/ifuzz/powerpc/powerpc.go b/pkg/ifuzz/powerpc/powerpc.go index 2704ae33b..48c39d4a1 100644 --- a/pkg/ifuzz/powerpc/powerpc.go +++ b/pkg/ifuzz/powerpc/powerpc.go @@ -174,6 +174,33 @@ func (imap insnSetMap) ld64(reg uint, v uint64) []byte { return ret } +func (imap insnSetMap) ld32(reg uint, v uint32) []byte { + ret := make([]byte, 0) + + ret = append(ret, imap["addis"].enc(map[string]uint{ + "RT": reg, + "RA": 0, // In "addis", '0' means 0, not GPR0 + "SI": uint((v >> 16) & 0xffff)})...) + ret = append(ret, imap["ori"].enc(map[string]uint{ + "RA": reg, + "RS": reg, + "UI": uint(v & 0xffff)})...) + + return ret +} + +func (imap insnSetMap) ldgpr32(regaddr, regval uint, addr uint64, v uint32) []byte { + ret := make([]byte, 0) + + ret = append(ret, imap.ld64(regaddr, addr)...) + ret = append(ret, imap.ld32(regval, v)...) + ret = append(ret, imap["stw"].enc(map[string]uint{ + "RA": regaddr, + "RS": regval})...) + + return ret +} + func (imap insnSetMap) sc(lev uint) []byte { return imap["sc"].enc(map[string]uint{"LEV": lev}) } diff --git a/pkg/ifuzz/powerpc/pseudo.go b/pkg/ifuzz/powerpc/pseudo.go index 91b705b02..c2a1b568f 100644 --- a/pkg/ifuzz/powerpc/pseudo.go +++ b/pkg/ifuzz/powerpc/pseudo.go @@ -46,11 +46,21 @@ func (insnset *InsnSet) initPseudo() { return gen.text }, }) + insnset.Insns = append(insnset.Insns, &Insn{ + Name: "PSEUDO_rtas", + Priv: true, + Pseudo: true, + generator: func(cfg *iset.Config, r *rand.Rand) []byte { + gen := makeGen(insnset, cfg, r) + gen.rtas() + return gen.text + }, + }) } type generator struct { imap insnSetMap - mode iset.Mode + cfg *iset.Config r *rand.Rand text []byte } @@ -58,7 +68,7 @@ type generator struct { func makeGen(insnset *InsnSet, cfg *iset.Config, r *rand.Rand) *generator { return &generator{ imap: insnset.insnMap, - mode: cfg.Mode, + cfg: cfg, r: r, } } @@ -77,3 +87,21 @@ func (gen *generator) sc(lev uint) { } gen.byte(imap.sc(lev)) } + +func (gen *generator) rtas() { + imap := gen.imap + + addr := iset.GenerateInt(gen.cfg, gen.r, 8) + token := uint32(gen.r.Intn(8) << 24) // There are only 4 tokens handled by KVM and it is BigEndian. + reg := uint(iset.GenerateInt(gen.cfg, gen.r, 4)) + + gen.byte(imap.ldgpr32(reg, reg+uint(1), addr, token)) + for i := 0; i < gen.r.Intn(4)+1; i++ { + gen.byte(imap.ldgpr32(reg, reg+uint(1), addr+uint64(i*4), + uint32(iset.GenerateInt(gen.cfg, gen.r, 4)))) + } + gen.byte(imap.ld64(3, 0xF000)) // 0xF000 is a custom H_RTAS hypercall + gen.byte(imap.ld64(4, addr)) + + gen.byte(imap.sc(1)) +} -- cgit mrf-deployment