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(¶ms); 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(¶ms); 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(¶ms); 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(¶ms); 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(¶ms); 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, }) }