Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

buffer overflow fix #182

Merged
merged 8 commits into from Feb 17, 2014
Merged

buffer overflow fix #182

merged 8 commits into from Feb 17, 2014

Conversation

skinowski
Copy link
Contributor

Fix for:

buffer overrun in error handler #181

  1. strcpy buffer overflow fix
  2. compilation warning fix for multiple declarations on single line
  3. modified import to use only strcpy and snprintf
  4. added null character at the end of various string buffers

@msabramo
Copy link
Contributor

msabramo commented Feb 6, 2014

Nice work, @skinowski and thanks for contributing!

I wonder if you think it's possible to write an automated test that can detect the issues that you're fixing?

@skinowski
Copy link
Contributor Author

Thank you.

The build failed it looks like, is it something to do with my fork?

I'll see how I can put together a test case for this.

@msabramo
Copy link
Contributor

msabramo commented Feb 7, 2014

Oh, please ignore the build failure. Yes, it's because we use special "secure environment variables" for Travis CI and those aren't supported in PRs from forks. If I push your branch to our repo, it might build. Let me try...

@msabramo
Copy link
Contributor

msabramo commented Feb 7, 2014

@skinowski: Indeed your change passed the Travis CI build when I pushed the branch to the main repo:

https://travis-ci.org/pymssql/pymssql/builds/18383974

Now if you put together a few tests, I think we can merge this.

@skinowski
Copy link
Contributor Author

I'm having difficulty reproducing this issue in my unit test. I've tried putting up a mock TCP server and played around with sending TCP RST or ignoring incoming SYN. But tests are still passing.

Originally, when I reproduced the problem, it occurred after running series of stress/regression tests using 30-40 connections connecting to a two SQL server IPs. During the tests, I was manipulating iptables on CentOS to drop traffic randomly. It failed the gcc FORTIFY_CODE=2 tests and caused a core dump.

Easier way of testing this could be to expose err_handler() and call it with cooked data. What do you think?

@msabramo
Copy link
Contributor

msabramo commented Feb 7, 2014

Yeah for the purposes of an automated test, it is too much trouble to set up mock TCP servers and manipulate iptables (though I'm very glad and impressed that you did that to test pymssql and uncover this issue!)

Calling err_handler sounds like a good way to go. I think as things are, you won't be able to do this, because it's a cdef function, so it's only visible from C. You might try changing it to a cpdef function and then see if you can call it from Python and then write tests that hand it bad data.

@skinowski
Copy link
Contributor Author

How about something like this?

def test_err_handler( connection, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr ):
    """
    Test err_handler callback and return global last msg state
    """
    cdef DBPROCESS *dbproc = NULL
    if connection:
        dbprod = (<MSSQLConnection>connection).dbproc
    return (
        err_handler( dbproc, severity, dberr, oserr, dberrstr, oserrstr ),
        get_last_msg_str(connection),
        get_last_msg_no(connection),
        get_last_msg_severity(connection),
        get_last_msg_state(connection)
    )

I need to add some more code to be able to pass NULL strings. Maybe another wrapper for msg_handler() as well. I did get the core dump using this without connecting to any database. :-) What do you think?

@skinowski
Copy link
Contributor Author

just noticed something else, shouldn't gil be released before calling
dbopen()?

@msabramo
Copy link
Contributor

msabramo commented Feb 7, 2014

Oh interesting, you wrote a test in Cython -- I wonder if we can have py.test run Cython tests?

@skinowski
Copy link
Contributor Author

It's basically a wrapper function where I would call it from a unitest python file in tests directory using various arguments simulating db, os errors, etc.

@msabramo
Copy link
Contributor

msabramo commented Feb 7, 2014

Yeah I was just looking at it again and I started to think that's what it was. Thanks for clarifying. This looks promising.

@msabramo
Copy link
Contributor

msabramo commented Feb 7, 2014

Yeah it does seem like the gil should be released before calling dbopen since that's FreeTDS and shouldn't be touching any Python interpreter state.

@skinowski
Copy link
Contributor Author

All right, so the unittest file is like this;

from datetime import datetime
import unittest
import _mssql

class ErrHandleTests(unittest.TestCase):

    def test01DBError(self):
        connection = None
        severity = 8
        dberr = 101
        oserr = 0
        dberrstr = "toblerone1"
        oserrstr = None

        expect = "DB-Lib error message %d, severity %d:\n%s\n" % ( dberr, severity, dberrstr )

        values = _mssql.test_err_handler( connection, severity, dberr, oserr, dberrstr, oserrstr )
        self.assertEqual( values[0] , 2 )
        self.assertEqual( values[1] , expect )

    def test02OSError(self):
        connection = None
        # EXCOMM
        severity = 9
        dberr = 102
        oserr = 1001
        dberrstr = "toblerone2"
        oserrstr = "scorpion"

        expect = "DB-Lib error message %d, severity %d:\n%s\nNet-Lib error during %s (%d)\n" % ( 
            dberr, severity, dberrstr, oserrstr, oserr )

        values = _mssql.test_err_handler( connection, severity, dberr, oserr, dberrstr, oserrstr )
        self.assertEqual( values[0] , 2 )
        self.assertEqual( values[1] , expect )

    def test03OSError(self):
        connection = None
        severity = 10
        dberr = 103
        oserr = 1003
        dberrstr = "toblerone3"
        oserrstr = "cabezon"

        expect = "DB-Lib error message %d, severity %d:\n%s\nOperating System error during %s (%d)\n" % ( 
            dberr, severity, dberrstr, oserrstr, oserr )

        values = _mssql.test_err_handler( connection, severity, dberr, oserr, dberrstr, oserrstr )
        self.assertEqual( values[0] , 2 )
        self.assertEqual( values[1] , expect )

    def test04NoError(self):
        connection = None

        # smaller than min error severity, so no output should be generated
        severity = 5
        dberr = 10
        oserr = 4444
        dberrstr = "toblerone4"
        oserrstr = "limpet"

        expect = "" 

        values = _mssql.test_err_handler( connection, severity, dberr, oserr, dberrstr, oserrstr )
        self.assertEqual( values[0] , 2 )
        self.assertEqual( values[1] , expect )

if __name__ == "__main__":
    unittest.main()

@skinowski
Copy link
Contributor Author

It works. :-) Unpatched pymssql gets this;

(root)skinowski@zzz:~/workdir/github/pymssql/tests$ nosetests -vv test_err_handle
nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$']
test01DBError (test_err_handle.ErrHandleTests) ... ok
test02OSError (test_err_handle.ErrHandleTests) ... ok
test03OSError (test_err_handle.ErrHandleTests) ... *** buffer overflow detected ***: /home/skinowski/workdir/github/root/bin/python terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x7f96644faf47]
/lib/x86_64-linux-gnu/libc.so.6(+0x109e40)[0x7f96644f9e40]
/home/skinowski/workdir/github/root/local/lib/python2.7/site-packages/pymssql-2.0.1.2-py2.7-linux-x86_64.egg/_mssql.so(+0x15901)[0x7f96629fc901]
/home/skinowski/workdir/github/root/local/lib/python2.7/site-packages/pymssql-2.0.1.2-py2.7-linux-x86_64.egg/_mssql.so(+0x15dc6)[0x7f96629fcdc6]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x2a4)[0x486614]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0xa92)[0x486e02]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x424522]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x20a8)[0x488418]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x4243f0]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x46762a]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x43758e]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x8fa)[0x486c6a]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0xa92)[0x486e02]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x424522]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x20a8)[0x488418]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x4243f0]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x46762a]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x43758e]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x8fa)[0x486c6a]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x424522]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x20a8)[0x488418]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x4243f0]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x46762a]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x43758e]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x8fa)[0x486c6a]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x424522]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x20a8)[0x488418]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x4243f0]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x46762a]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x43758e]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x8fa)[0x486c6a]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x424522]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalFrameEx+0x20a8)[0x488418]
/home/skinowski/workdir/github/root/bin/python(PyEval_EvalCodeEx+0x1a0)[0x48d930]
/home/skinowski/workdir/github/root/bin/python[0x4243f0]
/home/skinowski/workdir/github/root/bin/python(PyObject_Call+0x36)[0x4f7496]
/home/skinowski/workdir/github/root/bin/python[0x46762a]
======= Memory map: ========
00400000-00670000 r-xp 00000000 08:11 26349493                           /home/skinowski/workdir/github/root/bin/python
00870000-00871000 r--p 00270000 08:11 26349493                           /home/skinowski/workdir/github/root/bin/python
00871000-008da000 rw-p 00271000 08:11 26349493                           /home/skinowski/workdir/github/root/bin/python
008da000-008ec000 rw-p 00000000 00:00 0 
01d81000-02579000 rw-p 00000000 00:00 0                                  [heap]
7f96623b4000-7f96623b8000 r-xp 00000000 08:11 43781720                   /lib/x86_64-linux-gnu/libuuid.so.1.3.0
7f96623b8000-7f96625b7000 ---p 00004000 08:11 43781720                   /lib/x86_64-linux-gnu/libuuid.so.1.3.0
7f96625b7000-7f96625b8000 r--p 00003000 08:11 43781720                   /lib/x86_64-linux-gnu/libuuid.so.1.3.0
7f96625b8000-7f96625b9000 rw-p 00004000 08:11 43781720                   /lib/x86_64-linux-gnu/libuuid.so.1.3.0
7f96625b9000-7f96625da000 r-xp 00000000 08:11 50728921                   /usr/lib/python2.7/lib-dynload/_ctypes.so
7f96625da000-7f96627d9000 ---p 00021000 08:11 50728921                   /usr/lib/python2.7/lib-dynload/_ctypes.so
7f96627d9000-7f96627da000 r--p 00020000 08:11 50728921                   /usr/lib/python2.7/lib-dynload/_ctypes.so
7f96627da000-7f96627de000 rw-p 00021000 08:11 50728921                   /usr/lib/python2.7/lib-dynload/_ctypes.so
7f96627de000-7f96627df000 rw-p 00000000 00:00 0 
7f96627df000-7f96627e6000 r-xp 00000000 08:11 43782943                   /lib/x86_64-linux-gnu/librt-2.15.so
7f96627e6000-7f96629e5000 ---p 00007000 08:11 43782943                   /lib/x86_64-linux-gnu/librt-2.15.so
7f96629e5000-7f96629e6000 r--p 00006000 08:11 43782943                   /lib/x86_64-linux-gnu/librt-2.15.so
7f96629e6000-7f96629e7000 rw-p 00007000 08:11 43782943                   /lib/x86_64-linux-gnu/librt-2.15.so
7f96629e7000-7f9662a80000 r-xp 00000000 08:11 26351779                   /home/skinowski/workdir/github/root/lib/python2.7/site-packages/pymssql-2.0.1.2-py2.7-linux-x86_64.egg/_mssql.so
7f9662a80000-7f9662c80000 ---p 00099000 08:11 26351779                   /home/skinowski/workdir/github/root/lib/python2.7/site-packages/pymssql-2.0.1.2-py2.7-linux-x86_64.egg/_mssql.so
7f9662c80000-7f9662c84000 r--p 00099000 08:11 26351779                   /home/skinowski/workdir/github/root/lib/python2.7/site-packages/pymssql-2.0.1.2-py2.7-linux-x86_64.egg/_mssql.so
7f9662c84000-7f9662c8b000 rw-p 0009d000 08:11 26351779                   /home/skinowski/workdir/github/root/lib/python2.7/site-packages/pymssql-2.0.1.2-py2.7-linux-x86_64.egg/_mssql.so
7f9662c8b000-7f9662c8c000 rw-p 00000000 00:00 0 
7f9662c8c000-7f9662ca0000 r-xp 00000000 08:11 50728910                   /usr/lib/python2.7/lib-dynload/datetime.so
7f9662ca0000-7f9662e9f000 ---p 00014000 08:11 50728910                   /usr/lib/python2.7/lib-dynload/datetime.so
7f9662e9f000-7f9662ea0000 r--p 00013000 08:11 50728910                   /usr/lib/python2.7/lib-dynload/datetime.so
7f9662ea0000-7f9662ea4000 rw-p 00014000 08:11 50728910                   /usr/lib/python2.7/lib-dynload/datetime.so
7f9662ea4000-7f9662ea6000 r-xp 00000000 08:11 50728895                   /usr/lib/python2.7/lib-dynload/resource.so
7f9662ea6000-7f96630a5000 ---p 00002000 08:11 50728895                   /usr/lib/python2.7/lib-dynload/resource.so
7f96630a5000-7f96630a6000 r--p 00001000 08:11 50728895                   /usr/lib/python2.7/lib-dynload/resource.so
7f96630a6000-7f96630a7000 rw-p 00002000 08:11 50728895                   /usr/lib/python2.7/lib-dynload/resource.so
7f96630a7000-7f96630ad000 r-xp 00000000 08:11 50729659                   /usr/lib/python2.7/lib-dynload/_hotshot.so
7f96630ad000-7f96632ac000 ---p 00006000 08:11 50729659                   /usr/lib/python2.7/lib-dynload/_hotshot.so
7f96632ac000-7f96632ad000 r--p 00005000 08:11 50729659                   /usr/lib/python2.7/lib-dynload/_hotshot.so
7f96632ad000-7f96632af000 rw-p 00006000 08:11 50729659                   /usr/lib/python2.7/lib-dynload/_hotshot.so
7f96632af000-7f96632b5000 r-xp 00000000 08:11 50728917                   /usr/lib/python2.7/lib-dynload/_multiprocessing.so
7f96632b5000-7f96634b4000 ---p 00006000 08:11 50728917                   /usr/lib/python2.7/lib-dynload/_multiprocessing.so
7f96634b4000-7f96634b5000 r--p 00005000 08:11 50728917                   /usr/lib/python2.7/lib-dynload/_multiprocessing.so
7f96634b5000-7f96634b6000 rw-p 00006000 08:11 50728917                   /usr/lib/python2.7/lib-dynload/_multiprocessing.so
7f96634b6000-7f96634c9000 r-xp 00000000 08:11 50728894                   /usr/lib/python2.7/lib-dynload/parser.so
7f96634c9000-7f96636c8000 ---p 00013000 08:11 50728894                   /usr/lib/python2.7/lib-dynload/parser.so
7f96636c8000-7f96636c9000 r--p 00012000 08:11 50728894                   /usr/lib/python2.7/lib-dynload/parser.so
7f96636c9000-7f96636ca000 rw-p 00013000 08:11 50728894                   /usr/lib/python2.7/lib-dynload/parser.so
7f96636ca000-7f96636e9000 r-xp 00000000 08:11 50728922                   /usr/lib/python2.7/lib-dynload/_io.so
7f96636e9000-7f96638e8000 ---p 0001f000 08:11 50728922                   /usr/lib/python2.7/lib-dynload/_io.so
7f96638e8000-7f96638e9000 r--p 0001e000 08:11 50728922                   /usr/lib/python2.7/lib-dynload/_io.so
7f96638e9000-7f96638f2000 rw-p 0001f000 08:11 50728922                   /usr/lib/python2.7/lib-dynload/_io.so
7f96638f2000-7f96638f5000 r-xp 00000000 08:11 50728923                   /usr/lib/python2.7/lib-dynload/_heapq.so
7f96638f5000-7f9663af4000 ---p 00003000 08:11 50728923                   /usr/lib/python2.7/lib-dynload/_heapq.so
7f9663af4000-7f9663af5000 r--p 00002000 08:11 50728923                   /usr/lib/python2.7/lib-dynload/_heapq.so
7f9663af5000-7f9663af7000 rw-p 00003000 08:11 50728923                   /usr/lib/python2.7/lib-dynload/_heapq.so
7f9663af7000-7f96641da000 r--p 00000000 08:11 50600029                   /usr/lib/locale/locale-archive
7f96641da000-7f96641ef000 r-xp 00000000 08:11 43781634                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7f96641ef000-7f96643ee000 ---p 00015000 08:11 43781634                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7f96643ee000-7f96643ef000 r--p 00014000 08:11 43781634                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7f96643ef000-7f96643f0000 rw-p 00015000 08:11 43781634                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7f96643f0000-7f96645a5000 r-xp 00000000 08:11 43782936                   /lib/x86_64-linux-gnu/libc-2.15.so
7f96645a5000-7f96647a5000 ---p 001b5000 08:11 43782936                   /lib/x86_64-linux-gnu/libc-2.15.so
7f96647a5000-7f96647a9000 r--p 001b5000 08:11 43782936                   /lib/x86_64-linux-gnu/libc-2.15.so
7f96647a9000-7f96647ab000 rw-p 001b9000 08:11 43782936                   /lib/x86_64-linux-gnu/libc-2.15.so
7f96647ab000-7f96647b0000 rw-p 00000000 00:00 0 
7f96647b0000-7f96648ab000 r-xp 00000000 08:11 43782947                   /lib/x86_64-linux-gnu/libm-2.15.so
7f96648ab000-7f9664aaa000 ---p 000fb000 08:11 43782947                   /lib/x86_64-linux-gnu/libm-2.15.so
7f9664aaa000-7f9664aab000 r--p 000fa000 08:11 43782947                   /lib/x86_64-linux-gnu/libm-2.15.soAborted (core dumped)

@skinowski
Copy link
Contributor Author

Pushed a fix for nogil on dbopen.

@msabramo
Copy link
Contributor

msabramo commented Feb 7, 2014

Nice! Thank you!

I'll try to take a look soon.

@msabramo
Copy link
Contributor

This is looking pretty good, though I noticed some test failures with Python 3:

https://travis-ci.org/pymssql/pymssql/jobs/18916580

It's expecting one or more of the params to be bytes instead of str.

@skinowski
Copy link
Contributor Author

Python 3!!! :-) I'll take a look at this soon...
On Feb 16, 2014 11:06 AM, "Marc Abramowitz" notifications@github.com
wrote:

This is looking pretty good, though I noticed some test failures with
Python 3:

https://travis-ci.org/pymssql/pymssql/jobs/18916580

It's expecting one or more of the params to be bytes instead of str.

Reply to this email directly or view it on GitHubhttps://github.com//pull/182#issuecomment-35207126
.

@msabramo
Copy link
Contributor

It would be also cool to make tests/test_err_handle.py PEP8-compliant. Usually running autopep8 on a file cleans up most of the minor stuff.

@msabramo
Copy link
Contributor

msabramo added a commit that referenced this pull request Feb 17, 2014
@msabramo msabramo merged commit 050d0ea into pymssql:master Feb 17, 2014
@msabramo
Copy link
Contributor

Merged.

Thank you so much for your contribution!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants