diff mbox

[2/2] scripts/qemu-binfmt-check.py: a binfmt checker

Message ID 1389191134-16597-3-git-send-email-alex.bennee@linaro.org
State New
Headers show

Commit Message

Alex Bennée Jan. 8, 2014, 2:25 p.m. UTC
From: Alex Bennée <alex.bennee@linaro.org>

This script allows you to check if a given binary will match against any
of the currently registered binfmts on the system.

---

v2 (ajb):
   - cleaned up whitespace and checkpatch fixes
---
 scripts/qemu-binfmt-check.py | 109 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)
 create mode 100755 scripts/qemu-binfmt-check.py
diff mbox

Patch

diff --git a/scripts/qemu-binfmt-check.py b/scripts/qemu-binfmt-check.py
new file mode 100755
index 0000000..c4309a5
--- /dev/null
+++ b/scripts/qemu-binfmt-check.py
@@ -0,0 +1,109 @@ 
+#!/usr/bin/python
+#
+# binfmt check script
+#
+# Copyright 2014 Linaro
+#
+# Authors:
+#  Alex Bennee <alex.bennee@linaro.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+import os
+import re
+import binascii
+
+re_int = re.compile(r"interpreter (.+)$")
+re_off = re.compile(r"offset (\d+)$")
+re_magic = re.compile(r"magic ([\dabcdef]+)")
+re_mask = re.compile(r"mask ([\dabcdef]+)")
+
+# argparse is only available in Python >= 2.7
+from optparse import OptionParser
+parser = OptionParser()
+
+# list of binfmts
+binfmts = []
+
+
+def read_binfmt_spec(f):
+    bfmt = {}
+    with open(f) as fd:
+        content = fd.readlines()
+    for l in content:
+        m = re_int.match(l)
+        if m:
+            bfmt["interpreter"] = m.group(1)
+        m = re_off.match(l)
+        if m:
+            bfmt["offset"] = int(m.group(1))
+        m = re_magic.match(l)
+        if m:
+            bfmt["magic"] = binascii.unhexlify(m.group(1))
+        m = re_mask.match(l)
+        if m:
+            bfmt["mask"] = binascii.unhexlify(m.group(1))
+    print "loaded: %s" % bfmt
+    binfmts.append(bfmt)
+
+
+def load_binfmt_masks():
+    binfmt_dir = "/proc/sys/fs/binfmt_misc"
+    files = os.listdir(binfmt_dir)
+    for f in files:
+        if not f.startswith("status"):
+            fp = "%s/%s" % (binfmt_dir, f)
+            if os.access(fp, os.R_OK):
+                read_binfmt_spec(fp)
+
+
+def check_file_against_binfmt(fmt, f):
+    """
+    Check if a file will match a given binfmt mask
+    """
+    print "checking %s" % (f)
+    nbytes = len(fmt["magic"])
+
+    fd = open(f, "rb")
+    fd.seek(fmt["offset"])
+    header = fd.read(nbytes)
+    magic = fmt["magic"]
+    try:
+        mask = fmt["mask"]
+    except:
+        # TODO, make full mask
+        return
+
+    values = zip(mask, magic, header)
+    failed = False
+    pos = 0
+    for m, g, h in values:
+        mask = ord(m)
+        bits_to_check = ord(h) & mask
+        magic = ord(g)
+        if not bits_to_check == magic:
+            print "failed at %d (%x, %x, %x)" % (pos, mask, magic, bits_to_check)
+            failed = True
+            break
+        pos += 1
+    return not failed
+
+
+def check_file_against_all_binfmts(f):
+    """
+    Check a file against the binfmt masks
+    """
+    path = os.path.abspath(f)
+    print "file is %s" % (path)
+    for b in binfmts:
+        if check_file_against_binfmt(b, path):
+            print "%s will use %s" % (path, b["interpreter"])
+            break
+
+
+if __name__ == "__main__":
+    (opts, args) = parser.parse_args()
+    load_binfmt_masks()
+    for f in args:
+        check_file_against_all_binfmts(f)