Graphics protocol: Only delete temporary image-data files if they are in a known temporary file location

This commit is contained in:
Kovid Goyal 2018-12-11 10:00:43 +05:30
parent 4a8562a85f
commit d20c65ef80
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 41 additions and 7 deletions

View File

@ -201,7 +201,11 @@ Value of `t` Meaning
================== ============ ================== ============
``d`` Direct (the data is transmitted within the escape code itself) ``d`` Direct (the data is transmitted within the escape code itself)
``f`` A simple file ``f`` A simple file
``t`` A temporary file, the terminal emulator will delete the file after reading the pixel data ``t`` A temporary file, the terminal emulator will delete the file after reading the pixel data. For security reasons
the terminal emulator should only delete the file if it
is in a known temporary directory, such as :file:`/tmp`,
:file:`/dev/shm`, :file:`TMPDIR env var if present` and any platform
specific temporary directories.
``s`` A `POSIX shared memory object <http://man7.org/linux/man-pages/man7/shm_overview.7.html>`_. ``s`` A `POSIX shared memory object <http://man7.org/linux/man-pages/man7/shm_overview.7.html>`_.
The terminal emulator will delete it after reading the pixel data The terminal emulator will delete it after reading the pixel data
================== ============ ================== ============

View File

@ -32,9 +32,9 @@ from .rgb import Color, color_from_int
from .session import create_session from .session import create_session
from .tabs import SpecialWindow, SpecialWindowInstance, TabManager from .tabs import SpecialWindow, SpecialWindowInstance, TabManager
from .utils import ( from .utils import (
get_editor, get_primary_selection, log_error, open_url, parse_address_spec, get_editor, get_primary_selection, is_path_in_temp_dir, log_error,
remove_socket_file, safe_print, set_primary_selection, single_instance, open_url, parse_address_spec, remove_socket_file, safe_print,
startup_notification_handler set_primary_selection, single_instance, startup_notification_handler
) )
@ -959,3 +959,7 @@ class Boss:
for tm in self.all_tab_managers: for tm in self.all_tab_managers:
tm.tab_bar.patch_colors(spec) tm.tab_bar.patch_colors(spec)
patch_global_colors(spec, configured) patch_global_colors(spec, configured)
def safe_delete_temp_file(self, path):
if is_path_in_temp_dir(path):
os.remove(path)

View File

@ -368,7 +368,7 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
if (fd == -1) ABRT(EBADF, "Failed to open file %s for graphics transmission with error: [%d] %s", fname, errno, strerror(errno)); if (fd == -1) ABRT(EBADF, "Failed to open file %s for graphics transmission with error: [%d] %s", fname, errno, strerror(errno));
img->data_loaded = mmap_img_file(self, img, fd, g->data_sz, g->data_offset); img->data_loaded = mmap_img_file(self, img, fd, g->data_sz, g->data_offset);
close(fd); close(fd);
if (tt == 't') unlink(fname); if (tt == 't') { call_boss(safe_delete_temp_file, "s", fname); }
else if (tt == 's') shm_unlink(fname); else if (tt == 's') shm_unlink(fname);
break; break;
default: default:

View File

@ -432,3 +432,20 @@ def get_editor():
ans = shlex.split(ans) ans = shlex.split(ans)
get_editor.ans = ans get_editor.ans = ans
return ans return ans
def is_path_in_temp_dir(path):
if not path:
return False
def abspath(x):
if x:
return os.path.abspath(os.path.realpath(x))
import tempfile
path = abspath(path)
candidates = frozenset(map(abspath, ('/tmp', '/dev/shm', os.environ.get('TMPDIR', None), tempfile.gettempdir())))
for q in candidates:
if q and path.startswith(q):
return True
return False

View File

@ -2,13 +2,16 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import os
import tempfile
from kitty.config import build_ansi_color_table, defaults from kitty.config import build_ansi_color_table, defaults
from kitty.fast_data_types import ( from kitty.fast_data_types import (
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf, REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf,
parse_input_from_terminal, wcswidth, wcwidth, truncate_point_for_length parse_input_from_terminal, truncate_point_for_length, wcswidth, wcwidth
) )
from kitty.rgb import to_color from kitty.rgb import to_color
from kitty.utils import sanitize_title from kitty.utils import is_path_in_temp_dir, sanitize_title
from . import BaseTest, filled_cursor, filled_history_buf, filled_line_buf from . import BaseTest, filled_cursor, filled_history_buf, filled_line_buf
@ -384,6 +387,12 @@ class TestDataTypes(BaseTest):
tp('a\033', '_', 'x\033', '\\b', text='a b', apc='x') tp('a\033', '_', 'x\033', '\\b', text='a b', apc='x')
tp('a\033_', 'x', '\033', '\\', 'b', text='a b', apc='x') tp('a\033_', 'x', '\033', '\\', 'b', text='a b', apc='x')
for prefix in ('/tmp', tempfile.gettempdir()):
for path in ('a.png', 'x/b.jpg', 'y/../c.jpg'):
self.assertTrue(is_path_in_temp_dir(os.path.join(prefix, path)))
for path in ('/home/xy/d.png', '/tmp/../home/x.jpg'):
self.assertFalse(is_path_in_temp_dir(os.path.join(path)))
def test_color_profile(self): def test_color_profile(self):
c = ColorProfile() c = ColorProfile()
c.update_ansi_color_table(build_ansi_color_table()) c.update_ansi_color_table(build_ansi_color_table())