Tcl Source Code

View Ticket
Login
Ticket UUID: 0ac9d06895f000b3c83fcb6b14940acc79f11122
Title: Don't call getsockname(2) in Tcl_MakeFileChannel(3) unless absolutely necessary
Type: RFE Version: 8.6.*
Submitter: stu Created on: 2018-06-07 06:25:47
Subsystem: 25. Channel System Assigned To: nobody
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2018-06-13 16:20:03
Resolution: Accepted Closed By: stu
    Closed on: 2018-06-13 16:20:03
Description: (text/html)
Tcl_MakeFileChannel(3) checks if the given fd is a tty or a socket before assuming it's a file.
<br>
If there are <a href="https://man.openbsd.org/pledge">pledge(2)</a>es in effect that are restricting the usage of network functions then Tcl_MakeFileChannel will segfault when it tries to use getsockname(2) to check if the fd is a socket.
<br>
An important time when this happens is when tclsh is fed a script on stdin: tclsh will immediately segfault.
<br>
By using fstat(2) to first check if the fd is a socket, a call to getsockname might be avoided.
<br>
This may have security implications.
<br><br>
Attached is a patch against 8.6.8.
<br>
The patch has the nice side effect of putting all the socket bits in one place.
<br><br>
Here is a test program:
<pre>
#include <unistd.h>
#define TCLSH "/usr/local/bin/tclsh"
int main (int argc, char *argv[]) {
        char *a[] = { TCLSH, NULL };
        char *e[] = { NULL };

#ifdef DNS
        pledge(NULL, "stdio rpath getpw dns");
#else
# ifdef INET
        pledge(NULL, "stdio rpath getpw inet");
# else
        pledge(NULL, "stdio rpath getpw");
# endif
#endif

        execve(TCLSH, a, e);
        return 0;
}
</pre>

Build with no -D's:
<pre>
$ cc -o tpl tpl.c
$ echo 'puts moo' | ./tpl
Abort trap (core dumped) 
</pre>

Build with either -DINET or -DDNS:
<pre>
$ cc -o tpl tpl.c -DINET
$ echo 'puts moo' | ./tpl
moo
</pre>
User Comments: stu added on 2018-06-13 16:20:03: (text/x-fossil-wiki)
[a23a536a48e68141]

stu added on 2018-06-13 16:18:24:
Closed by [a23a536a48].

Attachments: