Ejemplo n.º 1
0
    def test_server(self, mock_open):
        with patch('os.path.isfile') as misfile:
            misfile.return_value = False
            server = DScanServer((self.settings.host, self.settings.port),
                                 AgentHandler, options=self.settings)

            server_thread = threading.Thread(target=server.serve_forever)
            # Exit the server thread when the main thread terminates
            server_thread.daemon = True
            server_thread.start()
            log.info(f"Server loop running in thread:{server_thread.name}")
            context = ssl.create_default_context()
            context.check_hostname = False
            context.load_verify_locations(self.settings.sslcert)
            s = context.wrap_socket(socket(AF_INET, SOCK_STREAM),
                                    server_side=False, server_hostname="dscan")
            s.connect(('127.0.0.1', 9011))

            opr = Structure.create(s)
            hmac_hash = hmac.new(self.settings.secret_key, opr.data,
                                 'sha512')
            digest = hmac_hash.hexdigest().encode("utf-8")

            s.sendall(Auth(digest).pack())
            s.close()
            server.shutdown()
Ejemplo n.º 2
0
def test_breakaway_job(pyfile, target, run):
    @pyfile
    def child():
        import os
        from debuggee import backchannel

        backchannel.send(os.getpid())
        backchannel.receive()
        backchannel.send("ok")

    @pyfile
    def parent():
        import debuggee
        import os
        import subprocess
        import sys

        debuggee.setup()
        argv = [sys.executable, sys.argv[1]]
        env = os.environ.copy()
        pipe_in = open(os.devnull, "r")
        pipe_out = open(os.devnull, "w")
        CREATE_BREAKAWAY_FROM_JOB = 0x01000000
        proc = subprocess.Popen(
            argv,
            env=env,
            stdin=pipe_in,
            stdout=pipe_out,
            stderr=pipe_out,
            creationflags=CREATE_BREAKAWAY_FROM_JOB,
        )
        pipe_in.close()
        pipe_out.close()
        proc.wait()

    with debug.Session() as parent_session:
        parent_session.config.update({
            "redirectOutput": False,
            "subProcess": False,
        })
        parent_session.expected_exit_code = some.int
        backchannel = parent_session.open_backchannel()

        with run(parent_session, target(parent, args=[child])):
            pass

        child_pid = backchannel.receive()
        child_process = psutil.Process(child_pid)

        parent_session.request("terminate")
        parent_session.wait_for_exit()

        # child should still be running
        backchannel.send("proceed")
        assert backchannel.receive() == "ok"

    log.info("Waiting for child process...")
    child_process.wait()
Ejemplo n.º 3
0
def test_autokill(daemon, pyfile, target, run):
    @pyfile
    def child():
        import os
        from debuggee import backchannel

        backchannel.send(os.getpid())
        while True:
            pass

    @pyfile
    def parent():
        import debuggee
        import os
        import subprocess
        import sys

        debuggee.setup()
        argv = [sys.executable, sys.argv[1]]
        env = os.environ.copy()
        subprocess.Popen(
            argv,
            env=env,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        ).wait()

    with debug.Session() as parent_session:
        parent_session.expected_exit_code = some.int

        backchannel = parent_session.open_backchannel()
        with run(parent_session, target(parent, args=[child])):
            pass

        child_config = parent_session.wait_for_next_event("debugpyAttach")
        parent_session.proceed()

        with debug.Session(child_config) as child_session:
            with child_session.start():
                pass

            child_pid = backchannel.receive()
            assert child_config["subProcessId"] == child_pid
            child_process = psutil.Process(child_pid)

            parent_session.request("terminate")
            child_session.wait_for_exit()

    log.info("Waiting for child process...")
    child_process.wait()
Ejemplo n.º 4
0
def test_flask_template_exception_no_multiproc(start_flask):
    with debug.Session() as session:
        with start_flask(session):
            session.request("setExceptionBreakpoints",
                            {"filters": ["raised", "uncaught"]})

        with flask_server:
            flask_server.get("/badtemplate")
            stop = session.wait_for_stop(
                "exception",
                expected_frames=[
                    some.dap.frame(
                        some.dap.source(paths.bad_html),
                        name=some.str,  # varies depending on Jinja version
                        line=8,
                    )
                ],
            )

            exception_info = session.request("exceptionInfo",
                                             {"threadId": stop.thread_id})
            assert exception_info == some.dict.containing({
                "exceptionId":
                some.str.ending_with("TemplateSyntaxError"),
                "breakMode":
                "always",
                "description":
                some.str.containing("doesnotexist"),
                "details":
                some.dict.containing({
                    "message":
                    some.str.containing("doesnotexist"),
                    "typeName":
                    some.str.ending_with("TemplateSyntaxError"),
                }),
            })

            # Exception gets reported again as it is re-raised in every frame between
            # the template and app.py. The number of frames is a Flask implementation
            # detail, and varies between versions, so we keep iterating until we see
            # it reported in app.py.
            while True:
                log.info("Exception propagating to next frame...")
                session.request_continue()
                stop = session.wait_for_stop("exception")
                if stop.frames[0] == some.dap.frame(paths.app_py,
                                                    line=some.int):
                    break

            # Let the request finish processing and respond with HTTP 500.
            session.request_continue()
Ejemplo n.º 5
0
def test_django_template_exception_no_multiproc(start_django):
    with debug.Session() as session:
        with start_django(session):
            session.request("setExceptionBreakpoints",
                            {"filters": ["raised", "uncaught"]})

        with django_server:
            django_server.get("/badtemplate", log_errors=False)
            stop = session.wait_for_stop(
                "exception",
                expected_frames=[
                    some.dap.frame(
                        some.dap.source(paths.bad_html),
                        line=8,
                        name="Django TemplateSyntaxError",
                    )
                ],
            )

            # Will stop once in the plugin
            exception_info = session.request("exceptionInfo",
                                             {"threadId": stop.thread_id})
            assert exception_info == some.dict.containing({
                "exceptionId":
                some.str.ending_with("TemplateSyntaxError"),
                "breakMode":
                "always",
                "description":
                some.str.containing("doesnotexist"),
                "details":
                some.dict.containing({
                    "message":
                    some.str.containing("doesnotexist"),
                    "typeName":
                    some.str.ending_with("TemplateSyntaxError"),
                }),
            })

            session.request_continue()

            log.info("Exception will be reported again in {0}", paths.app_py)
            session.wait_for_stop("exception")
            session.request_continue()
Ejemplo n.º 6
0
def test_exceptions_and_exclude_rules(pyfile, target, run, scenario, exc_type):
    if exc_type == "RuntimeError":

        @pyfile
        def code_to_debug():
            import debuggee

            debuggee.setup()
            raise RuntimeError("unhandled error")  # @raise_line

    elif exc_type == "SystemExit":

        @pyfile
        def code_to_debug():
            import debuggee
            import sys

            debuggee.setup()
            sys.exit(1)  # @raise_line

    else:
        pytest.fail(exc_type)

    if scenario == "exclude_by_name":
        rules = [{"path": "**/" + code_to_debug.basename, "include": False}]
    elif scenario == "exclude_by_dir":
        rules = [{"path": code_to_debug.dirname, "include": False}]
    else:
        pytest.fail(scenario)
    log.info("Rules: {0!j}", rules)

    with debug.Session() as session:
        session.expected_exit_code = some.int
        session.config["rules"] = rules

        with run(session, target(code_to_debug)):
            session.request("setExceptionBreakpoints",
                            {"filters": ["raised", "uncaught"]})

        # No exceptions should be seen.
        session.wait_for_next_event("terminated")
        session.proceed()
Ejemplo n.º 7
0
    def test_client_server_integration(self):

        server = DScanServer((self.settings_srv.host, self.settings_srv.port),
                             AgentHandler,
                             options=self.settings_srv)

        server_thread = threading.Thread(target=server.serve_forever)
        # Exit the server thread when the main thread terminates
        server_thread.daemon = True
        agent = Agent(self.settings_agent)
        try:
            server_thread.start()
            log.info(f"Server loop running in thread:{server_thread.name}")
            out = ContextDisplay(server.ctx)
            out.show()

            agent.start()
        except KeyboardInterrupt:
            print("asking for shutdown !")
            server.shutdown()
            agent.shutdown()
Ejemplo n.º 8
0
def test_autokill_nodebug(daemon, pyfile, target, run):
    @pyfile
    def child():
        import os
        from debuggee import backchannel

        backchannel.send(os.getpid())
        while True:
            pass

    @pyfile
    def parent():
        import os
        import subprocess
        import sys

        argv = [sys.executable, sys.argv[1]]
        env = os.environ.copy()
        subprocess.Popen(
            argv,
            env=env,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        ).wait()

    with debug.Session() as session:
        session.expected_exit_code = some.int
        session.config["noDebug"] = True

        backchannel = session.open_backchannel()
        run(session, target(parent, args=[child]))

        child_pid = backchannel.receive()
        child_process = psutil.Process(child_pid)

        session.request("terminate")

    log.info("Waiting for child process...")
    child_process.wait()
Ejemplo n.º 9
0
 def callback(pressed):
     log.info("Pressed: %s", pressed)
Ejemplo n.º 10
0
 def callback(color, unk1, unk2=None):
     name = COLORS[color] if color is not None else 'NONE'
     log.info("Color: %s %s %s", name, unk1, unk2)
Ejemplo n.º 11
0
def test_exceptions_and_partial_exclude_rules(pyfile, target, run, scenario):
    @pyfile
    def code_to_debug():
        from debug_me import backchannel
        import sys

        call_me_back_dir = backchannel.receive()
        sys.path.insert(0, call_me_back_dir)

        import call_me_back

        def call_func():
            raise RuntimeError("unhandled error")  # @raise

        call_me_back.call_me_back(call_func)  # @call_me_back
        print("done")

    call_me_back_dir = test_data / "call_me_back"
    call_me_back_py = call_me_back_dir / "call_me_back.py"
    call_me_back_py.lines = code.get_marked_line_numbers(call_me_back_py)

    if scenario == "exclude_code_to_debug":
        rules = [{"path": "**/" + code_to_debug.basename, "include": False}]
    elif scenario == "exclude_callback_dir":
        rules = [{"path": call_me_back_dir, "include": False}]
    else:
        pytest.fail(scenario)
    log.info("Rules: {0!j}", rules)

    with debug.Session() as session:
        session.expected_exit_code = some.int
        session.config["rules"] = rules

        backchannel = session.open_backchannel()
        with run(session, target(code_to_debug)):
            session.request(
                "setExceptionBreakpoints", {"filters": ["raised", "uncaught"]}
            )

        backchannel.send(call_me_back_dir)

        if scenario == "exclude_code_to_debug":
            # Stop at handled exception, with code_to_debug.py excluded.
            #
            # Since the module raising the exception is excluded, it must not stop at
            # @raise, but rather at @callback (i.e. the closest non-excluded frame).

            stop = session.wait_for_stop(
                "exception",
                expected_frames=[
                    some.dap.frame(
                        some.dap.source(call_me_back_py),
                        line=call_me_back_py.lines["callback"],
                    )
                ],
            )
            assert stop.frames != some.list.containing(
                [some.dap.frame(some.dap.source(code_to_debug), line=some.int)]
            )

            # As exception unwinds the stack, we shouldn't stop at @call_me_back,
            # since that line is in the excluded file. Furthermore, although the
            # exception is unhandled, we shouldn't get a stop for that, either,
            # because the exception is last seen in an excluded file.
            session.request_continue()

        elif scenario == "exclude_callback_dir":
            # Stop at handled exception, with call_me_back.py excluded.
            #
            # Since the module raising the exception is not excluded, it must stop at
            # @raise.

            stop = session.wait_for_stop(
                "exception",
                expected_frames=[
                    some.dap.frame(
                        some.dap.source(code_to_debug),
                        name="call_func",
                        line=code_to_debug.lines["raise"],
                    ),
                    some.dap.frame(
                        some.dap.source(code_to_debug),
                        name="<module>",
                        line=code_to_debug.lines["call_me_back"],
                    ),
                ],
            )
            assert stop.frames != some.list.containing(
                [some.dap.frame(some.dap.source(call_me_back_py), line=some.int)]
            )

            session.request_continue()

            # As exception unwinds the stack, it must not stop at @callback, since that
            # line is in the excluded file. However, it must stop at @call_me_back.
            stop = session.wait_for_stop(
                "exception",
                expected_frames=[
                    some.dap.frame(
                        some.dap.source(code_to_debug),
                        name="<module>",
                        line=code_to_debug.lines["call_me_back"],
                    )
                ],
            )
            assert stop.frames != some.list.containing(
                [some.dap.frame(some.dap.source(call_me_back_py), line=some.int)]
            )

            session.request_continue()

            # Now the exception is unhandled, and should be reported as such.
            stop = session.wait_for_stop(
                "exception",
                expected_frames=[
                    some.dap.frame(
                        some.dap.source(code_to_debug),
                        name="call_func",
                        line=code_to_debug.lines["raise"],
                    ),
                    some.dap.frame(
                        some.dap.source(code_to_debug),
                        name="<module>",
                        line=code_to_debug.lines["call_me_back"],
                    ),
                ],
            )
            assert stop.frames != some.list.containing(
                [some.dap.frame(some.dap.source(call_me_back_py), line=some.int)]
            )

            # Let the process crash due to unhandled exception.
            session.request_continue()

        else:
            pytest.fail(scenario)