@@ -42,6 +42,134 @@ import (
42
42
"strings"
43
43
)
44
44
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
45
173
const (
46
174
// File types
47
175
fileTypeUNDEFINED = iota
@@ -57,23 +185,19 @@ const (
57
185
fileTypeERROR
58
186
)
59
187
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.
63
191
func getFileType (realPath string ) (fileType int , err error ) {
64
-
65
192
// We need the file command to guess the file type
66
193
fileType = fileTypeERROR
67
- err = nil
68
194
cmd := exec .Command ("file" , realPath )
69
195
out , err := cmd .Output ()
70
196
if err != nil {
71
197
LogError ("There was an error getting the type of %s. Make sure that the 'file' command is installed." , realPath )
72
198
return
73
199
}
74
-
75
200
fo := string (out )
76
-
77
201
if strings .Contains (fo , "ELF" ) {
78
202
79
203
if strings .Contains (fo , "executable" ) {
@@ -107,70 +231,3 @@ func getFileType(realPath string) (fileType int, err error) {
107
231
}
108
232
return
109
233
}
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