--- Begin Message ---
Package: archivemail
Version: 0.6.2-1
Severity: grave
Tags: security
tempfile.mktemp in python has this comment:
User-callable function to return a unique temporary file name. The
file is not created.
Arguments are as for mkstemp, except that the 'text' argument is
not accepted.
This function is unsafe and should not be used. The file name
refers to a file that did not exist at some point, but by the time
you get around to creating it, someone else may have beaten you to
the punch.
While I was looking over archivemail's source due to bug #385249, I
noticed that it creates temporary files insecurely.
temp_name = tempfile.mktemp("retain")
self.mbox_file = open(temp_name, "w")
So this seems raceable. Here's another one:
temp_name = tempfile.mktemp("archive")
if os.path.isfile(final_name):
vprint("file already exists that is named: %s" % final_name)
shutil.copy2(final_name, temp_name)
_stale.archive = temp_name
self.mbox_file = open(temp_name, "a")
There are a few more like that.
There are also a lot of other uses of mktemp in the test suite, which
could lead to security problems at build time.
I've attached the patch that I came up with after this little audit. I'll be
releasing to unstable, but thought I should file the bug so this can be hadled
for stable and in case someone wants to get a CVE and such. Upstream
maintainers are CC'd.
Oh, one other funny thing, the TODO has this in it:
"Check for symlink attacks for tempfiles (although we don't use /var/tmp)"
--
see shy jo
Index: debian/changelog
===================================================================
--- debian/changelog (revision 12604)
+++ debian/changelog (working copy)
@@ -1,3 +1,10 @@
+archivemail (0.6.2-2) unstable; urgency=HIGH
+
+ * Fix a number of temporary file security holes in archivemail and its
+ test suite.
+
+ -- Joey Hess <[EMAIL PROTECTED]> Wed, 30 Aug 2006 00:09:13 -0400
+
archivemail (0.6.2-1) unstable; urgency=low
* New upstream release.
Index: test_archivemail.py
===================================================================
--- test_archivemail.py (revision 12604)
+++ test_archivemail.py (working copy)
@@ -318,7 +318,7 @@
for execute in ("package", "system"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -346,7 +346,7 @@
From is on this line
This is after the ^From line"""
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181), body=body)
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
archivemail.archive(self.mbox_name)
assert(os.path.exists(self.mbox_name))
@@ -384,7 +384,7 @@
for option in ('--date=2000-07-29', '-D2000-07-29',
'--date="29 Jul 2000"', '--date="29 July 2000"'):
self.mbox_name = make_mbox(messages=3, headers=headers)
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
run = "./archivemail.py -q %s %s" % (option, self.mbox_name)
self.assertEqual(os.system(run), 0)
@@ -400,7 +400,7 @@
for option in ('--date=2000-07-27', '-D2000-07-27',
'--date="27 Jul 2000"', '--date="27 July 2000"'):
self.mbox_name = make_mbox(messages=3, headers=headers)
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
run = "./archivemail.py -q %s %s" % (option, self.mbox_name)
self.assertEqual(os.system(run), 0)
@@ -415,7 +415,7 @@
for execute in ("package", "system"):
self.new_mbox = make_mbox(messages=3, hours_old=(24 * 179))
self.old_mbox = make_mbox(messages=3, hours_old=(24 * 181))
- self.mbox_name = tempfile.mktemp()
+ fd, self.mbox_name = tempfile.mkstemp()
shutil.copyfile(self.new_mbox, self.mbox_name)
append_file(self.old_mbox, self.mbox_name)
if execute == "package":
@@ -441,7 +441,7 @@
for execute in ("package", "system"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 179))
self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -465,7 +465,7 @@
for execute in ("package", "system"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
archive_name = self.mbox_name + "_archive"
shutil.copyfile(self.mbox_name, self.copy_name)
shutil.copyfile(self.mbox_name, archive_name) # archive has 3 msgs
@@ -535,7 +535,7 @@
for headers in weird_headers:
self.setUp()
self.mbox_name = make_mbox(messages=3, headers=headers)
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
archivemail.archive(self.mbox_name)
assert(os.path.exists(self.mbox_name))
@@ -641,7 +641,7 @@
for execute in ("package", "system_long", "system_short"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181), \
headers={"Status":"RO"})
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -670,7 +670,7 @@
"""archiving an unread mailbox should not create an archive"""
for execute in ("package", "system_long", "system_short"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -707,7 +707,7 @@
for suffix in ("_static_", "_%B_%Y", "-%Y-%m-%d"):
for execute in ("system_long", "system_short", "package"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "system_long":
run = "./archivemail.py --quiet --suffix='%s' %s" % \
@@ -750,7 +750,7 @@
"""archiving an old mailbox with the 'dry-run' option"""
for execute in ("package", "system_long", "system_short"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -785,7 +785,7 @@
"""specifying the 'days' option on an older mailbox"""
for execute in ("package", "system", "system_long"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 12))
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -813,7 +813,7 @@
"""specifying the 'days' option on a newer mailbox"""
for execute in ("package", "system", "system_long"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 10))
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -853,7 +853,7 @@
"""archiving a new mailbox with the 'delete' option"""
for execute in ("package", "system"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 179))
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -875,7 +875,7 @@
for execute in ("package", "system"):
self.new_mbox = make_mbox(messages=3, hours_old=(24 * 179))
self.old_mbox = make_mbox(messages=3, hours_old=(24 * 181))
- self.mbox_name = tempfile.mktemp()
+ fd, self.mbox_name = tempfile.mkstemp()
shutil.copyfile(self.new_mbox, self.mbox_name)
append_file(self.old_mbox, self.mbox_name)
if execute == "package":
@@ -897,7 +897,7 @@
"""archiving an old mailbox with the 'delete' option"""
for execute in ("package", "system"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -931,7 +931,7 @@
for execute in ("system", "package"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181), \
headers={"X-Status":"F"})
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -953,7 +953,7 @@
for execute in ("system", "package"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 179), \
headers={"X-Status":"F"})
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -976,7 +976,7 @@
for execute in ("system", "package"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181), \
headers={"X-Status":"F"})
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -1013,7 +1013,7 @@
"""archiving an old mailbox with a sepecified output dir"""
for execute in ("package", "system_long", "system_short"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
self.dir_name = tempfile.mktemp()
os.mkdir(self.dir_name)
@@ -1070,7 +1070,7 @@
for execute in ("package", "system"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.no_compress = 1
@@ -1097,7 +1097,7 @@
for execute in ("package", "system"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 179))
self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.no_compress = 1
@@ -1123,7 +1123,7 @@
for execute in ("package", "system"):
self.new_mbox = make_mbox(messages=3, hours_old=(24 * 179))
self.old_mbox = make_mbox(messages=3, hours_old=(24 * 181))
- self.mbox_name = tempfile.mktemp()
+ fd, self.mbox_name = tempfile.mkstemp()
shutil.copyfile(self.new_mbox, self.mbox_name)
append_file(self.old_mbox, self.mbox_name)
if execute == "package":
@@ -1149,7 +1149,7 @@
for execute in ("package", "system"):
self.mbox_name = make_mbox(messages=3, hours_old=(24 * 181))
self.mbox_mode = os.stat(self.mbox_name)[stat.ST_MODE]
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
archive_name = self.mbox_name + "_archive"
shutil.copyfile(self.mbox_name, self.copy_name)
shutil.copyfile(self.mbox_name, archive_name) # archive has 3 msgs
@@ -1191,7 +1191,7 @@
for execute in ("package", "system_long", "system_short"):
self.mbox_name = make_mbox(messages=1, hours_old=(24 * 181))
size_arg = os.path.getsize(self.mbox_name) - 1
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -1222,7 +1222,7 @@
for execute in ("package", "system_long", "system_short"):
self.mbox_name = make_mbox(messages=1, hours_old=(24 * 181))
size_arg = os.path.getsize(self.mbox_name) + 1
- self.copy_name = tempfile.mktemp()
+ fd, self.copy_name = tempfile.mkstemp()
shutil.copyfile(self.mbox_name, self.copy_name)
if execute == "package":
archivemail.options.quiet = 1
@@ -1351,7 +1351,7 @@
def make_mbox(body=None, headers=None, hours_old=0, messages=1):
- name = tempfile.mktemp()
+ fd, name = tempfile.mkstemp()
file = open(name, "w")
for count in range(messages):
msg = make_message(body=body, default_headers=headers,
Index: archivemail.py
===================================================================
--- archivemail.py (revision 12604)
+++ archivemail.py (working copy)
@@ -439,7 +439,7 @@
"""
assert(final_name)
- temp_name = tempfile.mktemp("retain")
+ temp_fd, temp_name = tempfile.mkstemp("retain")
self.mbox_file = open(temp_name, "w")
self.mbox_file_name = temp_name
_stale.retain = temp_name
@@ -511,7 +511,7 @@
unexpected_error("""There is already a file named '%s'!
Have you been previously compressing this archive? You probably should
uncompress it manually, and try running me again.""" % compressed_archive)
- temp_name = tempfile.mktemp("archive")
+ temp_fd, temp_name = tempfile.mkstemp("archive")
if os.path.isfile(final_name):
vprint("file already exists that is named: %s" % final_name)
shutil.copy2(final_name, temp_name)
@@ -528,7 +528,7 @@
Have you been reading this archive? You probably should re-compress it
manually, and try running me again.""" % final_name)
- temp_name = tempfile.mktemp("archive.gz")
+ temp_fd, temp_name = tempfile.mkstemp("archive.gz")
if os.path.isfile(compressed_filename):
vprint("file already exists that is named: %s" % \
compressed_filename)
signature.asc
Description: Digital signature
--- End Message ---