Files
ipsw/api/server/routes/kernel/kernel.go

216 lines
6.0 KiB
Go

package kernel
import (
"net/http"
"path/filepath"
"strings"
"github.com/blacktop/ipsw/api/types"
mcmd "github.com/blacktop/ipsw/internal/commands/macho"
"github.com/blacktop/ipsw/pkg/kernelcache"
"github.com/blacktop/ipsw/pkg/kernelcache/cpp"
"github.com/blacktop/ipsw/pkg/signature"
"github.com/gin-gonic/gin"
)
type kernelPathParams struct {
Path string `form:"path" json:"path" binding:"required"`
Arch string `form:"arch" json:"arch"`
}
type kernelCPPParams struct {
Path string `form:"path" json:"path" binding:"required"`
Arch string `form:"arch" json:"arch"`
Entry []string `form:"entry" json:"entry"`
Class string `form:"class" json:"class"`
Limit int `form:"limit" json:"limit"`
}
type kernelSymbolicateParams struct {
Path string `form:"path" json:"path" binding:"required"`
Arch string `form:"arch" json:"arch"`
Signatures string `form:"signatures" json:"signatures"`
}
// swagger:response kernelKextsResponse
type kernelKextsResponse struct {
Path string `json:"path"`
Kexts []kernelcache.CFBundle `json:"kexts"`
}
// swagger:response kernelCPPResponse
type kernelCPPResponse struct {
Path string `json:"path"`
Arch string `json:"arch,omitempty"`
Count int `json:"count"`
Classes []cpp.Class `json:"classes"`
}
// swagger:response kernelSymbolicateResponse
type kernelSymbolicateResponse struct {
Path string `json:"path"`
Arch string `json:"arch,omitempty"`
Symbols signature.SymbolMap `json:"symbols"`
}
func openKernel(path, arch string) (*mcmd.MachO, string, error) {
kernelPath := filepath.Clean(path)
m, err := mcmd.OpenMachONonInteractive(kernelPath, arch, false)
if err != nil {
return nil, "", err
}
return m, kernelPath, nil
}
func listKexts(c *gin.Context) {
var params kernelPathParams
if err := c.BindQuery(&params); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: err.Error()})
return
}
m, kernelPath, err := openKernel(params.Path, params.Arch)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
defer m.Close()
bundles, err := kernelcache.GetKexts(m.File)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
c.JSON(http.StatusOK, kernelKextsResponse{Path: kernelPath, Kexts: bundles})
}
// swagger:response kernelSyscallsResponse
type kernelSyscallsResponse struct {
Path string `json:"path"`
Syscalls []kernelcache.Sysent `json:"syscalls"`
}
func getSyscalls(c *gin.Context) {
var params kernelPathParams
if err := c.BindQuery(&params); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: err.Error()})
return
}
m, kernelPath, err := openKernel(params.Path, params.Arch)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
defer m.Close()
_, syscalls, err := kernelcache.GetSyscallTable(m.File)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
c.JSON(http.StatusOK, kernelSyscallsResponse{Path: kernelPath, Syscalls: syscalls})
}
// swagger:response kernelVersionResponse
type kernelVersionResponse struct {
Path string `json:"path"`
Version *kernelcache.Version `json:"version"`
}
func getVersion(c *gin.Context) {
var params kernelPathParams
if err := c.BindQuery(&params); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: err.Error()})
return
}
m, kernelPath, err := openKernel(params.Path, params.Arch)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
defer m.Close()
v, err := kernelcache.GetVersion(m.File)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"path": kernelPath, "version": v})
}
func kernelCPP(c *gin.Context) {
var params kernelCPPParams
if err := c.BindQuery(&params); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: err.Error()})
return
}
m, kernelPath, err := openKernel(params.Path, params.Arch)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
defer m.Close()
classes, err := cpp.NewScanner(m.File, cpp.Config{
Entries: params.Entry,
ClassName: strings.TrimSpace(params.Class),
}).Scan()
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
if params.Limit > 0 && params.Limit < len(classes) {
classes = classes[:params.Limit]
}
c.IndentedJSON(http.StatusOK, kernelCPPResponse{
Path: kernelPath,
Arch: params.Arch,
Count: len(classes),
Classes: classes,
})
}
func symbolicateKernel(c *gin.Context) {
var params kernelSymbolicateParams
if err := c.BindQuery(&params); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: err.Error()})
return
}
m, kernelPath, err := openKernel(params.Path, params.Arch)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
defer m.Close()
var sigs []signature.Symbolicator
if params.Signatures != "" {
sigs, err = signature.Parse(filepath.Clean(params.Signatures))
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
}
smap := signature.NewSymbolMap()
if err := smap.SymbolicateMachO(m.File, filepath.Base(kernelPath), sigs, true); err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()})
return
}
c.IndentedJSON(http.StatusOK, kernelSymbolicateResponse{
Path: kernelPath,
Arch: params.Arch,
Symbols: smap,
})
}