@@ -42,6 +42,134 @@ import (
4242 "strings"
4343)
4444
45+ //BinaryType is the 'intersection' of elf.Type and macho.Type and partitions
46+ // the binary world into categories we are most interested in. Missing is
47+ // ARCHIVE but that is because it is not an elf format, so we cannot entirely
48+ // eliminate the use of the 'file' utility (cf getFileType below).
49+ type BinaryType uint32
50+
51+ const (
52+ //BinaryUnknown signals that the file does not fit into our three simple minded categories
53+ BinaryUnknown BinaryType = 0
54+ //BinaryObject is the type of an object file, the output unit of compilation
55+ BinaryObject BinaryType = 1
56+ //BinaryExecutable is the type of an executable file
57+ BinaryExecutable BinaryType = 2
58+ //BinaryShared is the type of a shared or dynamic library
59+ BinaryShared BinaryType = 3
60+ )
61+
62+ func elfType2BinaryType (et elf.Type ) (bt BinaryType ) {
63+ bt = BinaryUnknown
64+ switch et {
65+ case elf .ET_NONE :
66+ bt = BinaryUnknown
67+ case elf .ET_REL :
68+ bt = BinaryObject
69+ case elf .ET_EXEC :
70+ bt = BinaryExecutable
71+ case elf .ET_DYN :
72+ bt = BinaryShared
73+ case elf .ET_CORE , elf .ET_LOOS , elf .ET_HIOS , elf .ET_LOPROC , elf .ET_HIPROC :
74+ bt = BinaryUnknown
75+ default :
76+ bt = BinaryUnknown
77+ }
78+ return
79+ }
80+
81+ func machoType2BinaryType (mt macho.Type ) (bt BinaryType ) {
82+ bt = BinaryUnknown
83+ switch mt {
84+ case macho .TypeObj :
85+ bt = BinaryObject
86+ case macho .TypeExec :
87+ bt = BinaryExecutable
88+ case macho .TypeDylib :
89+ bt = BinaryShared
90+ case macho .TypeBundle :
91+ bt = BinaryUnknown
92+ default :
93+ bt = BinaryUnknown
94+ }
95+ return
96+ }
97+
98+ // isPlainFile returns true if the file is stat-able (i.e. exists etc), and is not a directory, else it returns false.
99+ func isPlainFile (objectFile string ) (ok bool ) {
100+ info , err := os .Stat (objectFile )
101+ if os .IsNotExist (err ) || info .IsDir () {
102+ return
103+ }
104+ if err != nil {
105+ return
106+ }
107+ ok = true
108+ return
109+ }
110+
111+ func injectableViaFileType (objectFile string ) (ok bool , err error ) {
112+ plain := isPlainFile (objectFile )
113+ if ! plain {
114+ return
115+ }
116+ fileType , err := getFileType (objectFile )
117+ if err != nil {
118+ return
119+ }
120+ ok = (fileType == fileTypeELFOBJECT ) || (fileType == fileTypeELFOBJECT )
121+ return
122+ }
123+
124+ func injectableViaDebug (objectFile string ) (ok bool , err error ) {
125+ // I guess we are not doing cross compiling. Otherwise we are fucking up here.
126+ ok , err = IsObjectFileForOS (objectFile , runtime .GOOS )
127+ return
128+ }
129+
130+ // ElfFileType returns the elf.Type of the given file name
131+ func ElfFileType (objectFile string ) (code BinaryType , err error ) {
132+ var lbinFile * elf.File
133+ lbinFile , err = elf .Open (objectFile )
134+ if err != nil {
135+ return
136+ }
137+ code = elfType2BinaryType (lbinFile .FileHeader .Type )
138+ return
139+ }
140+
141+ // MachoFileType returns the macho.Type of the given file name
142+ func MachoFileType (objectFile string ) (code BinaryType , err error ) {
143+ var dbinFile * macho.File
144+ dbinFile , err = macho .Open (objectFile )
145+ if err != nil {
146+ return
147+ }
148+ code = machoType2BinaryType (dbinFile .FileHeader .Type )
149+ return
150+ }
151+
152+ //IsObjectFileForOS returns true if the given file is an object file for the given OS, using the debug/elf and debug/macho packages.
153+ func IsObjectFileForOS (objectFile string , operatingSys string ) (ok bool , err error ) {
154+ plain := isPlainFile (objectFile )
155+ if ! plain {
156+ return
157+ }
158+ var binaryType BinaryType
159+ switch operatingSys {
160+ case "linux" , "freebsd" :
161+ binaryType , err = ElfFileType (objectFile )
162+ case "darwin" :
163+ binaryType , err = MachoFileType (objectFile )
164+ }
165+ if err != nil {
166+ return
167+ }
168+ ok = (binaryType == BinaryObject )
169+ return
170+ }
171+
172+ // file types via the unix 'file' utility
45173const (
46174 // File types
47175 fileTypeUNDEFINED = iota
@@ -57,23 +185,19 @@ const (
57185 fileTypeERROR
58186)
59187
60- //iam:
61- // this is not that robust, because it depends on the file utility " file" which is
62- // often missing on docker images (the klee doker file had this problem)
188+ //iam: this is not that robust, because it depends on the file utility "file" which is
189+ // often missing on docker images ( the klee docker file had this problem)
190+ // this is only used in extraction, not in compilation.
63191func getFileType (realPath string ) (fileType int , err error ) {
64-
65192 // We need the file command to guess the file type
66193 fileType = fileTypeERROR
67- err = nil
68194 cmd := exec .Command ("file" , realPath )
69195 out , err := cmd .Output ()
70196 if err != nil {
71197 LogError ("There was an error getting the type of %s. Make sure that the 'file' command is installed." , realPath )
72198 return
73199 }
74-
75200 fo := string (out )
76-
77201 if strings .Contains (fo , "ELF" ) {
78202
79203 if strings .Contains (fo , "executable" ) {
@@ -107,70 +231,3 @@ func getFileType(realPath string) (fileType int, err error) {
107231 }
108232 return
109233}
110-
111- // isPlainFile returns true if the file is stat-able (i.e. exists etc), and is not a directory, else it returns false.
112- func isPlainFile (objectFile string ) (ok bool ) {
113- ok = false
114- info , err := os .Stat (objectFile )
115- if os .IsNotExist (err ) || info .IsDir () {
116- return
117- }
118- if err != nil {
119- return
120- }
121- ok = true
122- return
123- }
124-
125- func injectableViaFileType (objectFile string ) (ok bool , err error ) {
126- ok = false
127- err = nil
128- plain := isPlainFile (objectFile )
129- if ! plain {
130- return
131- }
132- fileType , err := getFileType (objectFile )
133- if err != nil {
134- return
135- }
136- ok = (fileType == fileTypeELFOBJECT ) || (fileType == fileTypeELFOBJECT )
137- return
138- }
139-
140- func injectableViaDebug (objectFile string ) (ok bool , err error ) {
141- ok = false
142- err = nil
143- // I guess we are not doing cross compiling. Otherwise we are fucking up here.
144- ok , err = IsObjectFileForOS (objectFile , runtime .GOOS )
145- return
146- }
147-
148- //IsObjectFileForOS returns true if the given file is an object file for the given OS, using the debug/elf and debug/macho packages.
149- func IsObjectFileForOS (objectFile string , operatingSys string ) (ok bool , err error ) {
150- plain := isPlainFile (objectFile )
151- if ! plain {
152- return
153- }
154- switch operatingSys {
155- case "linux" , "freebsd" :
156- var lbinFile * elf.File
157- lbinFile , err = elf .Open (objectFile )
158- if err != nil {
159- return
160- }
161- dfileType := lbinFile .FileHeader .Type
162- ok = (dfileType == elf .ET_REL )
163- return
164- case "darwin" :
165- var dbinFile * macho.File
166- dbinFile , err = macho .Open (objectFile )
167- if err != nil {
168- return
169- }
170- dfileType := dbinFile .FileHeader .Type
171- ok = (dfileType == macho .TypeObj )
172-
173- return
174- }
175- return
176- }
0 commit comments