From e882597f9c167cac2a79bdbe1a257987dfc83c01 Mon Sep 17 00:00:00 2001 From: Grissiom Date: Mon, 3 Nov 2014 12:10:25 +0800 Subject: [PATCH 1/2] romfs: check the dirent before use it System will crash when the romfs is erased. Add checks before using them to avoid it. --- components/dfs/filesystems/romfs/dfs_romfs.c | 32 +++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/components/dfs/filesystems/romfs/dfs_romfs.c b/components/dfs/filesystems/romfs/dfs_romfs.c index 03df8a88c..86e7ac88a 100644 --- a/components/dfs/filesystems/romfs/dfs_romfs.c +++ b/components/dfs/filesystems/romfs/dfs_romfs.c @@ -49,6 +49,14 @@ int dfs_romfs_ioctl(struct dfs_fd *file, int cmd, void *args) return -DFS_STATUS_EIO; } +rt_inline int check_dirent(struct romfs_dirent *dirent) +{ + if (!(dirent->type == ROMFS_DIRENT_FILE || dirent->type == ROMFS_DIRENT_DIR) || + (dirent->size == 0 || dirent->size == ~0)) + return -1; + return 0; +} + struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const char *path, rt_size_t *size) { rt_size_t index, found; @@ -56,6 +64,10 @@ struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const ch struct romfs_dirent *dirent; rt_size_t dirent_size; + /* Check the root_dirent. */ + if (check_dirent(root_dirent) != 0) + return RT_NULL; + if (path[0] == '/' && path[1] == '\0') { *size = root_dirent->size; @@ -82,6 +94,8 @@ struct romfs_dirent *dfs_romfs_lookup(struct romfs_dirent *root_dirent, const ch /* search in folder */ for (index = 0; index < dirent_size; index ++) { + if (check_dirent(&dirent[index]) != 0) + return RT_NULL; if (rt_strncmp(dirent[index].name, subpath, (subpath_end - subpath)) == 0) { dirent_size = dirent[index].size; @@ -133,6 +147,11 @@ int dfs_romfs_read(struct dfs_fd *file, void *buf, rt_size_t count) dirent = (struct romfs_dirent *)file->data; RT_ASSERT(dirent != RT_NULL); + if (check_dirent(dirent) != 0) + { + return -DFS_STATUS_EIO; + } + if (count < file->size - file->pos) length = count; else @@ -172,6 +191,9 @@ int dfs_romfs_open(struct dfs_fd *file) root_dirent = (struct romfs_dirent *)file->fs->data; + if (check_dirent(dirent) != 0) + return -DFS_STATUS_EIO; + if (file->flags & (DFS_O_CREAT | DFS_O_WRONLY | DFS_O_APPEND | DFS_O_TRUNC | DFS_O_RDWR)) return -DFS_STATUS_EINVAL; @@ -236,16 +258,18 @@ int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, rt_uint32_t cou struct romfs_dirent *dirent, *sub_dirent; dirent = (struct romfs_dirent *)file->data; + if (check_dirent(dirent) != 0) + return -DFS_STATUS_EIO; RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR); /* enter directory */ dirent = (struct romfs_dirent *)dirent->data; - + /* make integer count */ count = (count / sizeof(struct dirent)); if (count == 0) return -DFS_STATUS_EINVAL; - + index = 0; for (index = 0; index < count && file->pos < file->size; index ++) { @@ -265,13 +289,13 @@ int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, rt_uint32_t cou rt_strncpy(d->d_name, name, rt_strlen(name) + 1); /* move to next position */ - ++ file->pos; + ++ file->pos; } return index * sizeof(struct dirent); } -static const struct dfs_filesystem_operation _romfs = +static const struct dfs_filesystem_operation _romfs = { "rom", DFS_FS_FLAG_DEFAULT, From b43573844dee3df5fd9502857d487ac21b97743e Mon Sep 17 00:00:00 2001 From: Grissiom Date: Mon, 3 Nov 2014 12:12:18 +0800 Subject: [PATCH 2/2] romfs: rewrite mkromfs.py --- components/dfs/filesystems/romfs/mkromfs.py | 344 +++++++++++++------- 1 file changed, 235 insertions(+), 109 deletions(-) diff --git a/components/dfs/filesystems/romfs/mkromfs.py b/components/dfs/filesystems/romfs/mkromfs.py index d1354eb25..9917cf85b 100644 --- a/components/dfs/filesystems/romfs/mkromfs.py +++ b/components/dfs/filesystems/romfs/mkromfs.py @@ -1,126 +1,252 @@ +#!/usr/bin/env python + import sys import os -import string -basename = '' -output = '' -sep = os.sep +import struct +from collections import namedtuple +import StringIO -def mkromfs_output(out): - # print '%s' % out, - output.write(out) +import argparse +parser = argparse.ArgumentParser() +parser.add_argument('rootdir', type=str, help='the path to rootfs') +parser.add_argument('output', type=argparse.FileType('wb'), nargs='?', help='output file name') +parser.add_argument('--dump', action='store_true', help='dump the fs hierarchy') +parser.add_argument('--binary', action='store_true', help='output binary file') +parser.add_argument('--addr', default='0', help='set the base address of the binary file, default to 0.') -def mkromfs_file(filename, arrayname): - f = file(filename, "rb") - arrayname = arrayname.replace('.', '_') - arrayname = arrayname.replace('-', '_') - mkromfs_output('const static unsigned char %s[] = {\n' % arrayname) +class File(object): + def __init__(self, name): + self._name = name + self._data = open(name, 'rb').read() - count = 0 - while True: - byte = f.read(1) + @property + def name(self): + return self._name - if len(byte) != 1: - break + @property + def c_name(self): + return '_' + self._name.replace('.', '_') - mkromfs_output('0x%02x,' % ord(byte)) - - count = count + 1 - if count == 16: - count = 0 - mkromfs_output('\n') - - if count == 0: - mkromfs_output('};\n\n') - else: - mkromfs_output('\n};\n\n') + @property + def bin_name(self): + # Pad to 4 bytes boundary with \0 + pad_len = 4 + bn = self._name + '\0' * (pad_len - len(self._name) % pad_len) + return bn - f.close() + def c_data(self, prefix=''): + '''Get the C code represent of the file content.''' + head = 'static const rt_uint8_t %s[] = {\n' % \ + (prefix + self.c_name) + tail = '\n};' + return head + ','.join(('0x%02x' % ord(i) for i in self._data)) + tail -def mkromfs_dir(dirname, is_root = False): - list = os.listdir(dirname) - path = os.path.abspath(dirname) - - # make for directory - for item in list: - fullpath = os.path.join(path, item) - if os.path.isdir(fullpath): - # if it is an empty directory, ignore it - l = os.listdir(fullpath) - if len(l): - mkromfs_dir(fullpath) - - # make for files - for item in list: - fullpath = os.path.join(path, item) - if os.path.isfile(fullpath): - subpath = fullpath[len(basename):] - array = subpath.split(sep) - arrayname = string.join(array, '_') - mkromfs_file(fullpath, arrayname) + @property + def entry_size(self): + return len(self._data) - subpath = path[len(basename):] - dir = subpath.split(sep) - direntname = string.join(dir, '_') - if is_root: - mkromfs_output('const struct romfs_dirent _root_dirent[] = {\n') - else: - mkromfs_output(('const static struct romfs_dirent %s[] = {\n' % direntname)) - - for item in list: - fullpath = os.path.join(path, item) - fn = fullpath[len(dirname):] - if fn[0] == sep: - fn = fn[1:] - fn = fn.replace('\\', '/') + def bin_data(self, base_addr=0x0): + return bytes(self._data) - subpath = fullpath[len(basename):] - items = subpath.split(sep) - item_name = string.join(items, '_') - item_name = item_name.replace('.', '_') - item_name = item_name.replace('-', '_') - subpath = subpath.replace('\\', '/') - if subpath[0] == '/': - subpath = subpath[1:] + def dump(self, indent=0): + print '%s%s' % (' ' * indent, self._name) - if not os.path.isfile(fullpath): - l = os.listdir(fullpath) - if len(l): - mkromfs_output(('\t{ROMFS_DIRENT_DIR, "%s", (rt_uint8_t*) %s, sizeof(%s)/sizeof(%s[0])},\n' % (fn, item_name, item_name, item_name))) +class Folder(object): + bin_fmt = struct.Struct('IIII') + bin_item = namedtuple('dirent', 'type, name, data, size') + + def __init__(self, name): + self._name = name + self._children = [] + + @property + def name(self): + return self._name + + @property + def c_name(self): + # add _ to avoid conflict with C key words. + return '_' + self._name + + @property + def bin_name(self): + # Pad to 4 bytes boundary with \0 + pad_len = 4 + bn = self._name + '\0' * (pad_len - len(self._name) % pad_len) + return bn + + def walk(self): + # os.listdir will return unicode list if the argument is unicode. + # TODO: take care of the unicode names + for ent in os.listdir(u'.'): + if os.path.isdir(ent): + cwd = os.getcwdu() + d = Folder(ent) + # depth-first + os.chdir(os.path.join(cwd, ent)) + d.walk() + # restore the cwd + os.chdir(cwd) + self._children.append(d) else: - mkromfs_output(('\t{ROMFS_DIRENT_DIR, "%s", RT_NULL, 0},\n' % fn)) + self._children.append(File(ent)) - for item in list: - fullpath = os.path.join(path, item) - fn = fullpath[len(dirname):] - if fn[0] == sep: - fn = fn[1:] - fn = fn.replace('\\', '/') - - subpath = fullpath[len(basename):] - items = subpath.split(sep) - item_name = string.join(items, '_') - item_name = item_name.replace('.', '_') - item_name = item_name.replace('-', '_') - subpath = subpath.replace('\\', '/') - if subpath[0] == '/': - subpath = subpath[1:] - - if os.path.isfile(fullpath): - mkromfs_output(('\t{ROMFS_DIRENT_FILE, "%s", %s, sizeof(%s)},\n' % (fn, item_name, item_name))) - - mkromfs_output('};\n\n') + def sort(self): + def _sort(x, y): + if x.name == y.name: + return 0 + elif x.name > y.name: + return 1 + else: + return -1 + self._children.sort(cmp=_sort) -if __name__ == "__main__": - try: - basename = os.path.abspath(sys.argv[1]) - filename = os.path.abspath(sys.argv[2]) - except IndexError: - print "Usage: %s " % sys.argv[0] - raise SystemExit + # sort recursively + for c in self._children: + if isinstance(c, Folder): + c.sort() - output = file(filename, 'wt') - mkromfs_output("#include \n\n") - mkromfs_dir(basename, is_root = True) - - mkromfs_output("const struct romfs_dirent romfs_root = {ROMFS_DIRENT_DIR, \"/\", (rt_uint8_t*) _root_dirent, sizeof(_root_dirent)/sizeof(_root_dirent[0])};\n\n") + def dump(self, indent=0): + print '%s%s' % (' ' * indent, self._name) + for c in self._children: + c.dump(indent + 1) + + def c_data(self, prefix=''): + '''get the C code represent of the folder. + + It is recursive.''' + # make the current dirent + # static is good. Only root dirent is global visible. + dhead = 'static const struct romfs_dirent %s[] = {\n' % (prefix + self.c_name) + dtail = '\n};' + body_fmt = ' {{{type}, "{name}", (rt_uint8_t *){data}, sizeof({data})/sizeof({data}[0])}}' + # prefix of children + cpf = prefix+self.c_name + body_li = [] + payload_li = [] + for c in self._children: + if isinstance(c, File): + tp = 'ROMFS_DIRENT_FILE' + elif isinstance(c, Folder): + tp = 'ROMFS_DIRENT_DIR' + else: + assert False, 'Unkown instance:%s' % str(c) + body_li.append(body_fmt.format(type=tp, + name=c.name, + data=cpf+c.c_name)) + payload_li.append(c.c_data(prefix=cpf)) + + # All the data we need is defined in payload so we should append the + # dirent to it. It also meet the depth-first policy in this code. + payload_li.append(dhead + ',\n'.join(body_li) + dtail) + + return '\n\n'.join(payload_li) + + @property + def entry_size(self): + return len(self._children) + + def bin_data(self, base_addr=0x0): + '''Return StringIO object''' + # The binary layout is different from the C code layout. We put the + # dirent before the payload in this mode. But the idea is still simple: + # Depth-First. + + #{ + # rt_uint32_t type; + # const char *name; + # const rt_uint8_t *data; + # rt_size_t size; + #} + d_li = [] + # payload base + p_base = base_addr + self.bin_fmt.size * self.entry_size + # the length to record how many data is in + v_len = p_base + # payload + p_li = [] + for c in self._children: + if isinstance(c, File): + # ROMFS_DIRENT_FILE + tp = 0 + elif isinstance(c, Folder): + # ROMFS_DIRENT_DIR + tp = 1 + else: + assert False, 'Unkown instance:%s' % str(c) + + name = bytes(c.bin_name) + name_addr = v_len + v_len += len(name) + + data = c.bin_data(base_addr=v_len) + data_addr = v_len + # pad the data to 4 bytes boundary + pad_len = 4 + if len(data) % pad_len != 0: + data += '\0' * (pad_len - len(data) % pad_len) + v_len += len(data) + + d_li.append(self.bin_fmt.pack(*self.bin_item( + type=tp, + name=name_addr, + data=data_addr, + size=c.entry_size))) + + p_li.extend((name, data)) + + return bytes().join(d_li) + bytes().join(p_li) + +def get_c_data(tree): + # Handle the root dirent specially. + root_dirent_fmt = '''/* Generated by mkromfs. Edit with caution. */ +#include +#include + +{data} + +const struct romfs_dirent {name} = {{ + ROMFS_DIRENT_DIR, "/", (rt_uint8_t *){rootdirent}, sizeof({rootdirent})/sizeof({rootdirent}[0]) +}}; +''' + + return root_dirent_fmt.format(name='romfs_root', + rootdirent=tree.c_name, + data=tree.c_data()) + +def get_bin_data(tree, base_addr): + v_len = base_addr + Folder.bin_fmt.size + name = bytes('/\0\0\0') + name_addr = v_len + v_len += len(name) + data_addr = v_len + # root entry + data = Folder.bin_fmt.pack(*Folder.bin_item(type=1, + name=name_addr, + data=data_addr, + size=tree.entry_size)) + return data + name + tree.bin_data(v_len) + +if __name__ == '__main__': + args = parser.parse_args() + + os.chdir(args.rootdir) + + tree = Folder('romfs_root') + tree.walk() + tree.sort() + + if args.dump: + tree.dump() + + if args.binary: + data = get_bin_data(tree, int(args.addr, 16)) + else: + data = get_c_data(tree) + + output = args.output + if not output: + output = sys.stdout + + output.write(data)