New submission from David Watson <bai...@users.sourceforge.net>: The makesockaddr() function in the socket module assumes that AF_UNIX addresses have a null-terminated sun_path, but Linux actually allows unterminated addresses using all 108 bytes of sun_path (for normal filesystem sockets, that is, not just abstract addresses).
When receiving such an address (e.g. in accept() from a connecting peer), makesockaddr() will run past the end and return extraneous bytes from the stack, or fail because they can't be decoded, or perhaps segfault in extreme cases. This can't currently be tested from within Python as Python also refuses to accept address arguments which would fill the whole of sun_path, but the attached linux-pass-unterminated.diff (for 2.x and 3.x) enables them for Linux. With the patch applied: Python 2.7a4+ (trunk, Apr 8 2010, 18:20:28) [GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> s = socket.socket(socket.AF_UNIX) >>> s.bind("a" * 108) >>> s.getsockname() 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xfa\xbf\xa8)\xfa\xbf\xec\x15\n\x08l\xaaY\xb7\xb8CZ\xb7' >>> len(_) 126 Also attached are some unit tests for use with the above patch, a couple of C programs for checking OS behaviour (you can also see the bug by doing accept() in Python and using the bindconn program), and patches aimed at fixing the problem. Firstly, the return-unterminated-* patches make makesockaddr() scan sun_path for the first null byte as before (if it's not a Linux abstract address), but now stop at the end of the structure as indicated by the addrlen argument. However, there's one more catch before this will work on Linux, which is that Linux system calls return the length of the address they *would* have stored in the structure had there been room for it, which in this case is one byte longer than the official size of a sockaddr_un structure, due to the missing null terminator. The addrlen-* patches handle this by always calling makesockaddr() with the actual buffer size if it is less than the returned length. This silently ignores any truncation, but I'm not sure how to do anything sensible about that, and some operating systems (e.g. FreeBSD) just silently truncate the address anyway and don't return the original length (POSIX doesn't make clear which, if either, behaviour is required). Once these patches are applied, the tests pass. There is one other issue: the patches for 3.x retain the assumption that socket paths are in UTF-8, but they should actually be handled according to PEP 383. I've got a patch for that, but I'll open a separate issue for it since the handling of the Linux abstract namespace isn't documented and there's some slightly unobvious behaviour that people might be depending on. ---------- components: Extension Modules files: linux-pass-unterminated.diff keywords: patch messages: 102861 nosy: baikie severity: normal status: open title: socket: Buffer overrun while reading unterminated AF_UNIX addresses type: behavior versions: Python 2.5, Python 2.6, Python 2.7, Python 3.1, Python 3.2, Python 3.3 Added file: http://bugs.python.org/file16874/linux-pass-unterminated.diff _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue8372> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com