1import angr
2
3from cle.backends.externs.simdata.io_file import io_file_data_for_arch
4
5######################################
6# fdopen
7#
8# Reference for implementation:
9#   glibc-2.25/libio/iofdopen.c
10######################################
11
12
13def mode_to_flag(mode):
14    # TODO improve this: handle mode = strings
15    if mode[-1] == b'b': # lol who uses windows
16        mode = mode[:-1]
17    all_modes = {
18        b"r"  : angr.storage.file.Flags.O_RDONLY,
19        b"r+" : angr.storage.file.Flags.O_RDWR,
20        b"w"  : angr.storage.file.Flags.O_WRONLY | angr.storage.file.Flags.O_CREAT,
21        b"w+" : angr.storage.file.Flags.O_RDWR | angr.storage.file.Flags.O_CREAT,
22        b"a"  : angr.storage.file.Flags.O_WRONLY | angr.storage.file.Flags.O_CREAT | angr.storage.file.Flags.O_APPEND,
23        b"a+" : angr.storage.file.Flags.O_RDWR | angr.storage.file.Flags.O_CREAT | angr.storage.file.Flags.O_APPEND
24        }
25    if mode not in all_modes:
26        raise angr.SimProcedureError('unsupported file open mode %s' % mode)
27
28    return all_modes[mode]
29
30class fdopen(angr.SimProcedure):
31    #pylint:disable=arguments-differ
32
33    def run(self, fd_int, m_addr):
34        #pylint:disable=unused-variable
35        strlen = angr.SIM_PROCEDURES['libc']['strlen']
36
37        m_strlen = self.inline_call(strlen, m_addr)
38        m_expr = self.state.memory.load(m_addr, m_strlen.max_null_index, endness='Iend_BE')
39        mode = self.state.solver.eval(m_expr, cast_to=bytes)
40
41        # TODO: handle append and other mode subtleties
42
43        fd = self.state.solver.eval(fd_int)
44        if fd not in self.state.posix.fd:
45            # if file descriptor not found return NULL
46            return 0
47        else:
48            # Allocate a FILE struct in heap
49            malloc = angr.SIM_PROCEDURES['libc']['malloc']
50            io_file_data = io_file_data_for_arch(self.state.arch)
51            file_struct_ptr = self.inline_call(malloc, io_file_data['size']).ret_expr
52
53            # Write the fd
54            fd_bvv = self.state.solver.BVV(fd, 4 * 8) # int
55            self.state.memory.store(file_struct_ptr + io_file_data['fd'],
56                                    fd_bvv,
57                                    endness=self.state.arch.memory_endness)
58
59            return file_struct_ptr
60