New submission from David Lukeš <dafydd.lu...@gmail.com>:

I recently came across a non-testing use case for `tempfile.mktemp()` where I 
struggle to find a viable alternative -- temporary named pipes (FIFOs):

```
import os
import tempfile
import subprocess as sp

fifo_path = tempfile.mktemp()
os.mkfifo(fifo_path, 0o600)
try:
    proc = sp.Popen(["cat", fifo_path], stdout=sp.PIPE, text=True)
    with open(fifo_path, "w") as fifo:
        for c in "Kočka leze dírou, pes oknem.":
            print(c, file=fifo)
    proc.wait()
finally:
    os.unlink(fifo_path)

for l in proc.stdout:
    print(l.strip())
```

(`cat` is obviously just a stand-in for some useful program which needs to read 
from a file, but you want to send it input from Python.)

`os.mkfifo()` needs a path which doesn't point to an existing file, so it's not 
possible to use a `tempfile.NamedTemporaryFile(delete=False)`, close it, and 
pass its `.name` attribute to `mkfifo()`.

I know there has been some discussion regarding `mktemp()` in the relatively 
recent past (see the Python-Dev thread starting with 
<https://mail.python.org/pipermail/python-dev/2019-March/156721.html>). There 
has also been some confusion as to what actually makes it unsafe (see 
<https://mail.python.org/pipermail/python-dev/2019-March/156778.html>). Before 
the discussion petered out, it looked like people were reaching a consensus 
"that mktemp() could be made secure by using a longer name generated by a 
secure random generator" (quoting from the previous link).

A secure `mktemp` could be as simple as (see 
<https://mail.python.org/pipermail/python-dev/2019-March/156765.html>):

```
def mktemp(suffix='', prefix='tmp', dir=None):
    if dir is None:
        dir = gettempdir()
    return _os.path.join(dir, prefix + secrets.token_urlsafe(ENTROPY_BYTES) + 
suffix)
```

There's been some discussion as to what `ENTROPY_BYTES` should be. I like 
Steven D'Aprano's suggestion (see 
<https://mail.python.org/pipermail/python-dev/2019-March/156777.html>) of 
having an overkill default just to be on the safe side, which can be overridden 
if needed. Of course, the security implications of lowering it should be 
clearly documented.

Fixing `mktemp` would make it possible to get rid of its hybrid deprecated (in 
the docs) / not depracated (in code) status, which is somewhat confusing for 
users. Speaking from experience -- when I realized I needed it, the deprecation 
notice led me down this rabbit hole of reading mailing list threads and 
submitting issues :) People could stop losing time worrying about `mktemp` and 
trying to weed it out whenever they come across it (see e.g. 
https://bugs.python.org/issue42278).

So I'm wondering whether there would be interest in:

1. A PR which would modify `mktemp` along the lines sketched above, to make it 
safe in practice. Along with that, it would probably make sense to undeprecate 
it in the docs, or at least indicate that while users should prefer `mkstemp` 
when they're fine with the file being created for them, `mktemp` is alright in 
cases where this is not acceptable.
2. Following that, possibly a PR which would encapsulate the new `mktemp` + 
`mkfifo` into a `TemporaryNamedPipe` or `TemporaryFifo`:

```
import os
import tempfile
import subprocess as sp

with tempfile.TemporaryNamedPipe() as fifo:
    proc = sp.Popen(["cat", fifo.name], stdout=sp.PIPE, text=True)
    for c in "Kočka leze dírou, pes oknem.":
        print(c, file=fifo)
    proc.wait()

for l in proc.stdout:
    print(l.strip())
```

(Caveat: opening the FIFO for writing cannot happen in `__enter__`, it would 
have to be delayed until the first call to `fifo.write()` because it hangs if 
no one is reading from it.)

----------
components: Library (Lib)
messages: 389393
nosy: David Lukeš
priority: normal
severity: normal
status: open
title: Fix tempfile.mktemp()
type: security
versions: Python 3.10

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue43604>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to