frida-go icon indicating copy to clipboard operation
frida-go copied to clipboard

SIGSEGV: segmentation violation

Open jackie575 opened this issue 2 years ago • 2 comments

HI ,I encounter a problem when many concurrent goroutine execute Script.ExportsCall;Here is The Env And Error Info

OS:  Mac Os  14.1.2 (23B92)
CPU ARCH:  2.6 GHz  Intel Core i7 Amd64

Go Version: go1.21.5
Frida-go-sdk version:  v0.6.10

Android Device Version : Android 12 
Android frida-server version :  16.1.4 Arm64


Updated:  switch the latest Frida-Server 16.1.8 , the problem reproduced

===========

Error Stack:
SIGSEGV: segmentation violation
PC=0x1010b21c2 m=15 sigcode=1
signal arrived during cgo execution

goroutine 2986 [syscall]:
runtime.cgocall(0x100a46800, 0xc00129ae58)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/cgocall.go:157 +0x4b fp=0xc00129ae30 sp=0xc00129adf8 pc=0x10000aaab
github.com/frida/frida-go/frida._Cfunc_g_object_unref(0x7fb31d817380)
        _cgo_gotypes.go:3402 +0x3f fp=0xc00129ae58 sp=0xc00129ae30 pc=0x1002e71df
github.com/frida/frida-go/frida.unrefGObj.func1(0x7fb31d817380)
        /Users/jackie/go/pkg/mod/github.com/frida/[email protected]/frida/cleanups.go:30 +0x3b fp=0xc00129ae90 sp=0xc00129ae58 pc=0x1002eb31b
github.com/frida/frida-go/frida.unrefGObj(0x7fb31d817380)
        /Users/jackie/go/pkg/mod/github.com/frida/[email protected]/frida/cleanups.go:30 +0x18 fp=0xc00129aea8 sp=0xc00129ae90 pc=0x1002eb2b8
github.com/frida/frida-go/frida.clean(0x7fb31d817380, {0x1012f6734, 0xb})
        /Users/jackie/go/pkg/mod/github.com/frida/[email protected]/frida/cleanups.go:37 +0x5e fp=0xc00129aee0 sp=0xc00129aea8 pc=0x1002eb39e
github.com/frida/frida-go/frida.(*Session).Clean(0xc000015900)
        /Users/jackie/go/pkg/mod/github.com/frida/[email protected]/frida/session.go:198 +0x33 fp=0xc00129af10 sp=0xc00129aee0 pc=0x100302d33
frida-go-rpc/MyFridaApp/fridaApiHooker.close({0xc000015800, 0xc0000158a8, 0xc000015900, 0xc0001f02a0})
        /GoProjects/frida-go-rpc/MyApp/ApiHooker.go:35 +0x3c fp=0xc00129af38 sp=0xc00129af10 pc=0x1007bd41c
frida-go-rpc/MyFridaApp/.GetClient.func1.1.1()
        /GoProjects/frida-go-rpc/MyFridaApp/FridaClient.go:158 +0x9e fp=0xc00129afe0 sp=0xc00129af38 pc=0x1007bf91e
runtime.goexit()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/asm_amd64.s:1650 +0x1 fp=0xc00129afe8 sp=0xc00129afe0 pc=0x1000785e1
created by frida-go-rpc/MyFridaApp/.GetClient.func1.1 in goroutine 5
        /GoProjects/frida-go-rpc/MyFridaApp/FridaClient.go:148 +0x145

goroutine 1 [sleep]:
runtime.gopark(0x10135a680, 0xc0002300f0, 0x13, 0x13, 0x1)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:398 +0xfc fp=0xc001491b60 sp=0xc001491b30 pc=0x10004673c
time.Sleep(0x174876e800)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/time.go:195 +0x110 fp=0xc001491ba0 sp=0xc001491b60 pc=0x100075550
main.main()
        /GoProjects/frida-go-rpc/main.go:213 +0x12a fp=0xc001491f68 sp=0xc001491ba0 pc=0x100a4474a
runtime.main()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:267 +0x267 fp=0xc001491fe0 sp=0xc001491f68 pc=0x1000462c7
runtime.goexit()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/asm_amd64.s:1650 +0x1 fp=0xc001491fe8 sp=0xc001491fe0 pc=0x1000785e1

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/asm_amd64.s:1650 +0x1 fp=0xc0015a5fe8 sp=0xc0015a5fe0 pc=0x1000785e1

goroutine 2 [force gc (idle)]:
runtime.gopark(0x10135a640, 0x103fb1d60, 0x11, 0x14, 0x1)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:398 +0xfc fp=0xc00006af80 sp=0xc00006af50 pc=0x10004673c
runtime.goparkunlock(0x0?, 0x0?, 0x0?, 0x0?)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:404 +0x25 fp=0xc00006afb0 sp=0xc00006af80 pc=0x1000467c5
runtime.forcegchelper()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:322 +0xb5 fp=0xc00006afe0 sp=0xc00006afb0 pc=0x100046555
runtime.goexit()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/asm_amd64.s:1650 +0x1 fp=0xc00006afe8 sp=0xc00006afe0 pc=0x1000785e1
created by runtime.init.6 in goroutine 1
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:310 +0x1a

goroutine 18 [GC sweep wait]:
runtime.gopark(0x10135a640, 0x103fb2ba0, 0xc, 0x14, 0x1)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:398 +0xfc fp=0xc000066750 sp=0xc000066720 pc=0x10004673c
runtime.goparkunlock(0x1?, 0x0?, 0x0?, 0x0?)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:404 +0x25 fp=0xc000066780 sp=0xc000066750 pc=0x1000467c5
runtime.bgsweep(0x0?)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mgcsweep.go:321 +0xe5 fp=0xc0000667c8 sp=0xc000066780 pc=0x10002f525
runtime.gcenable.func1()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mgc.go:200 +0x25 fp=0xc0000667e0 sp=0xc0000667c8 pc=0x1000237a5
runtime.goexit()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/asm_amd64.s:1650 +0x1 fp=0xc0000667e8 sp=0xc0000667e0 pc=0x1000785e1
created by runtime.gcenable in goroutine 1
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mgc.go:200 +0x66

goroutine 19 [GC scavenge wait]:
runtime.gopark(0x10135a640, 0x103fb33e0, 0xd, 0x14, 0x2)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:398 +0xfc fp=0xc000066f40 sp=0xc000066f10 pc=0x10004673c
runtime.goparkunlock(0x1013a5288?, 0x0?, 0x0?, 0x0?)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:404 +0x25 fp=0xc000066f70 sp=0xc000066f40 pc=0x1000467c5
runtime.(*scavengerState).park(0x103fb33e0)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mgcscavenge.go:425 +0x45 fp=0xc000066f98 sp=0xc000066f70 pc=0x10002c7e5
runtime.bgscavenge(0x0?)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mgcscavenge.go:658 +0x65 fp=0xc000066fc8 sp=0xc000066f98 pc=0x10002cd85
runtime.gcenable.func2()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mgc.go:201 +0x25 fp=0xc000066fe0 sp=0xc000066fc8 pc=0x100023745
runtime.goexit()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/asm_amd64.s:1650 +0x1 fp=0xc000066fe8 sp=0xc000066fe0 pc=0x1000785e1
created by runtime.gcenable in goroutine 1
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mgc.go:201 +0xa5

goroutine 3 [finalizer wait]:
runtime.gopark(0x10135a370, 0x103feeda8, 0x10, 0x14, 0x1)
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/proc.go:398 +0xfc fp=0xc00006a628 sp=0xc00006a5f8 pc=0x10004673c
runtime.runfinq()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mfinal.go:193 +0xfa fp=0xc00006a7e0 sp=0xc00006a628 pc=0x10002285a
runtime.goexit()
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/asm_amd64.s:1650 +0x1 fp=0xc00006a7e8 sp=0xc00006a7e0 pc=0x1000785e1
created by runtime.createfing in goroutine 1
        /usr/local/Cellar/go/1.21.5/libexec/src/runtime/mfinal.goExiting.

Any Other Info ,when the app call Script.ExportsCall Timeout, i think it is just broken Session,so i close the resource , reopen another DeviceManager 、Device、Session and so on; Here is the code

hooker.script.Clean()
hooker.session.Clean()
hooker.device.Clean()
hooker.deviceManager.Clean()

Can anyone help me to solve it? Many Thanks!

jackie575 avatar Dec 13 '23 11:12 jackie575

Hey, can you paste the code that caused the error

NSEcho avatar Dec 13 '23 11:12 NSEcho

Hey, can you paste the code that caused the error

Thanks For Your Reply!

Here is the code :

type FridaClient struct {
	
	apiHooker *fridaApiHooker
	// 
	refreshChan *chan uint32
	// Client Version,
	version * atomic.Uint32
	// Frida Resource is ok?
	OK bool
}

type fridaApiHooker struct {
	
	deviceManager *frida.DeviceManager
	
	device *frida.Device
	
	session *frida.Session
	
	script *frida.Script
}


// Close close the resource held by the frida client singleton
func (hooker fridaApiHooker) close()  {

	hooker.script.Clean()
	
	hooker.session.Clean()
	
	hooker.device.Clean()
	
	hooker.deviceManager.Clean()
	
}

// newApiHooker make new frida Resource
func newApiHooker() *fridaApiHooker {
	
	jsScript := readJsScript()
	
	deviceManager := frida.NewDeviceManager()
	

	devices, err := deviceManager.EnumerateDevices()
	if err != nil {
	
		panic("Device Error!")
	}
	
	for _, d := range devices {
		log.Printf("[*] Found device with id:%v", d.ID())
	}
	
	device, err := deviceManager.USBDevice()
	if err != nil {
	
		log.Printf("Could not get usb device: %v", err)
	
		os.Exit(1)
	}


	log.Printf("[*] Attaching to `App`")
	

	session, err := device.Attach(processName, nil)
	if err != nil {
		
		log.Printf("New Session Fail!err:%v", err)
		os.Exit(1)
	}
	
	fridaScript, err := session.CreateScript(jsScript)
	if err != nil {
		
		log.Printf("New Frida Script Fail! err:%v", err)
		os.Exit(1)
	}


	if err := fridaScript.Load(); err != nil {
	
		log.Printf("Load Frida Script Fail!err:%v", err)
		os.Exit(1)
	}

	return &fridaApiHooker{
		deviceManager: deviceManager,
		device:        device,
		session:       session,
		script:   fridaScript,
	}
}


func (client * FridaClient) CallFrida(param *CallFridaParam) (*rpc.CallResult, error) {
	// for loop 3 times
	for i := 0; i < 3; i++ {
		// every iteration , call the func , if err is TimeOutError,close
		// the resource,  reopen it 
		result, err := client.doFridaCallInner(param)

		if err != nil {
			
			if errors.Is(err, timeoutError) {
				// Timeout Error,get Client Version
				ver := client.version.Load()
				*client.refreshChan <- ver

				// wait for the client version greater than current,and 'ok'
				// statuc switch to 'true'

				for !(client.version.Load() > ver && client.OK) {
					// wait for reloader to reload resource
					time.Sleep(1 * time.Second)
				}

				continue
			} else {
				// other error than TimeOut
				return nil, err
			}
		} else {
			// call frida success ,just return it
			return result, nil
		}
	}

	// for loop end ,can't get result ,return err
	return nil, timeoutError

}


func (client *FridaClient) doFridaCallInner(param *FridaCallParam) (*rpc.FridaResult, error) {
	// make chan to recv result
	ch := make(chan FridaResult, 1)

	go func() {
		
		defer close(ch)

		
		resultMap := client.apiHooker.script.ExportsCall("JSFuncName",
			// 
			params
		)
	
		ch <- FridaResult{resultMap, nil}
		
	}()
	// 4. 当前协程等待结果
	select {
	case <-time.After(RpcTimeout * time.Second):
		{
			// 
			return nil, timeoutError
		}
	case result := <-ch:
		{
			return &result,nil
		}
	}
}




// GetFridaClient make FridaClient Singleton
func GetFridaClient() *FridaClient {
	
	clientInitLock.Do(func() {
		log.Printf("init  Frida client! ")
	
	
		apiHooker := newApiHooker()
		
		ch := make(chan uint32, 1)
		
		ver := atomic.Uint32{}
		// incr to version 1 
		ver.Add(1)
		clientSingleton = &FridaClient{
			apiHooker: apiHooker,
			//  version init to 1
			version: &ver,
			// size 1 channel 
			refreshChan: &ch,
			// 
			OK: true,
		}
		// 7. launch a new coroutine , do for refresh Resource
		go func() {
			for {
				// wait for channel recv 
				v := <-*clientSingleton.refreshChan
				
				if v == clientSingleton.version.Load() {
					//  version equals ,do the resource refresh actions
					casSuccess := clientSingleton.version.CompareAndSwap(v, v+1)
					if casSuccess {
						go func() {
							log.Printf("resource clean up")
							// when cas success ,refresh resource 
							clientSingleton.OK = false

							defer func() { clientSingleton.OK = true }()
							
							_ = clientSingleton.apiHooker.close()

							// make new hooker ,update the prop of singleton
							clientSingleton.apiHooker = newApiHooker()
						}()
					}
				} else {
					// Version different,Just return
					log.Printf("", v, clientSingleton.version)
				}
			}
		}()
	})
	
	return clientSingleton
}

jackie575 avatar Dec 13 '23 11:12 jackie575