From 950497ac0c47dcc13f038792007e1ec4db052765 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 3 Apr 2026 22:25:05 +0530 Subject: [PATCH] Cleanup previous PR --- kitty/disk-cache.c | 14 +++++++++++++- kitty/dnd.c | 8 +++++--- kitty/png-reader.c | 2 +- kitty/remote_control.py | 19 ++++++++----------- tools/utils/tar.go | 3 ++- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/kitty/disk-cache.c b/kitty/disk-cache.c index 995378a1b..29115d71f 100644 --- a/kitty/disk-cache.c +++ b/kitty/disk-cache.c @@ -7,6 +7,10 @@ #define MAX_KEY_SIZE 16u +#ifdef __APPLE__ +// needed for memset_s +#define __STDC_WANT_LIB_EXT1__ 1 +#endif #include "disk-cache.h" #include "safe-wrappers.h" #include "simd-string.h" @@ -41,7 +45,15 @@ static uint64_t key_hash(KEY_TY k); #define HASH_FN key_hash static bool keys_are_equal(CacheKey a, CacheKey b) { return a.hash_keylen == b.hash_keylen && memcmp(a.hash_key, b.hash_key, a.hash_keylen) == 0; } #define CMPR_FN keys_are_equal -static void free_cache_value(CacheValue *cv) { explicit_bzero(cv->encryption_key, sizeof(cv->encryption_key)); free(cv->data); cv->data = NULL; free(cv); } +static void free_cache_value(CacheValue *cv) { +#ifdef __APPLE__ + memset_s(cv->encryption_key, sizeof(cv->encryption_key), 0, sizeof(cv->encryption_key)); +#else + explicit_bzero(cv->encryption_key, sizeof(cv->encryption_key)); +#endif + free(cv->data); cv->data = NULL; + free(cv); +} static void free_cache_key(CacheKey cv) { free(cv.hash_key); cv.hash_key = NULL; } #define KEY_DTOR_FN free_cache_key #define VAL_DTOR_FN free_cache_value diff --git a/kitty/dnd.c b/kitty/dnd.c index b706e16f0..5f0ceac95 100644 --- a/kitty/dnd.c +++ b/kitty/dnd.c @@ -17,6 +17,8 @@ #include #include +static const size_t MIME_LIST_SIZE_CAP = 1024 * 1024; + // In test mode, this callable is invoked instead of schedule_write_to_child_if_possible. // It receives (window_id: int, data: bytes) and its return value is ignored. static PyObject *g_dnd_test_write_func = NULL; @@ -113,7 +115,7 @@ drop_register_window(Window *w, const uint8_t *payload, size_t payload_sz, bool if (!on) { drop_free_data(w); zero_at_ptr(&w->drop); return; } if (!payload || !payload_sz) return; size_t sz = w->drop.registered_mimes ? strlen(w->drop.registered_mimes) : 0; - if (sz + payload_sz > 1024 * 1024) return; + if (sz + payload_sz > MIME_LIST_SIZE_CAP) return; w->drop.registered_mimes = realloc(w->drop.registered_mimes, sz + payload_sz + 1); if (w->drop.registered_mimes) { memcpy(w->drop.registered_mimes + sz, payload, payload_sz); @@ -308,7 +310,7 @@ drop_set_status(Window *w, int operation, const char *payload, size_t payload_sz } } if (payload_sz) { - if (w->drop.accepted_mimes_sz + payload_sz > 1024 * 1024) return; + if (w->drop.accepted_mimes_sz + payload_sz > MIME_LIST_SIZE_CAP) return; char *new_buf = realloc(w->drop.accepted_mimes, w->drop.accepted_mimes_sz + payload_sz + 2); if (!new_buf) return; w->drop.accepted_mimes = new_buf; @@ -879,7 +881,7 @@ drag_add_mimes(Window *w, int allowed_operations, const char *data, size_t sz, b if (!ds.allowed_operations) { abrt(EINVAL); } ds.offer_being_built = true; size_t new_sz = ds.bufsz + sz; - if (new_sz > 1024 * 1024) abrt(EFBIG); + if (new_sz > MIME_LIST_SIZE_CAP) abrt(EFBIG); ds.mimes_buf = realloc(ds.mimes_buf, ds.bufsz + sz + 1); if (!ds.mimes_buf) abrt(ENOMEM); memcpy(ds.mimes_buf + ds.bufsz, data, sz); diff --git a/kitty/png-reader.c b/kitty/png-reader.c index b6bd56ff6..073536c72 100644 --- a/kitty/png-reader.c +++ b/kitty/png-reader.c @@ -113,7 +113,7 @@ inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz, int max_im png_read_update_info(png, info); png_uint_32 rowbytes = png_get_rowbytes(png, info); - d->sz = (size_t)rowbytes * (size_t)d->height; + d->sz = sizeof(png_byte) * rowbytes * d->height; d->decompressed = malloc(d->sz + 16); if (d->decompressed == NULL) ABRT(ENOMEM, "Out of memory allocating decompression buffer for PNG"); d->row_pointers = malloc(d->height * sizeof(png_bytep)); diff --git a/kitty/remote_control.py b/kitty/remote_control.py index 183d9550d..51cf07113 100644 --- a/kitty/remote_control.py +++ b/kitty/remote_control.py @@ -12,12 +12,7 @@ from contextlib import suppress from functools import lru_cache, partial from time import time_ns from types import GeneratorType -from typing import ( - TYPE_CHECKING, - Any, - Optional, - cast, -) +from typing import TYPE_CHECKING, Any, Optional, TypeVar, cast from .cli import parse_args from .cli_stub import RCOptions @@ -39,6 +34,7 @@ from .utils import TTYIO, log_error, parse_address_spec, resolve_custom_file active_async_requests: dict[str, float] = {} active_streams: dict[str, str] = {} +T = TypeVar('T') if TYPE_CHECKING: from .window import Window @@ -104,10 +100,11 @@ def fnmatch_pattern(pat: str) -> 're.Pattern[str]': return re.compile(translate(pat)) -def _ct_password_lookup(passwords: dict[str, Any], pw: str) -> Any: +def constant_time_lookup(passwords: dict[str, T], pw: str) -> T | None: result = None + c = hmac.compare_digest for k, v in passwords.items(): - if hmac.compare_digest(k, pw): + if c(k, pw): result = v return result @@ -119,7 +116,7 @@ def remote_control_allowed( if not remote_control_passwords: return True pw = pcmd.get('password', '') - auth_items = _ct_password_lookup(remote_control_passwords, pw) + auth_items = constant_time_lookup(remote_control_passwords, pw) if pw == '!': auth_items = None if auth_items is None: @@ -194,10 +191,10 @@ def is_cmd_allowed(pcmd: dict[str, Any], window: Optional['Window'], from_socket return False pa = password_authorizer(auth_items) return pa.is_cmd_allowed(pcmd, window, from_socket, extra_data) - q = _ct_password_lookup(user_password_allowed, pw) + q = constant_time_lookup(user_password_allowed, pw) if q is not None: return q - auth_items = _ct_password_lookup(get_options().remote_control_password, pw) + auth_items = constant_time_lookup(get_options().remote_control_password, pw) if auth_items is None: return None pa = password_authorizer(auth_items) diff --git a/tools/utils/tar.go b/tools/utils/tar.go index 9cdf4f72d..899707000 100644 --- a/tools/utils/tar.go +++ b/tools/utils/tar.go @@ -182,7 +182,8 @@ func ExtractAllFromTar(tr *tar.Reader, dest_path string, optss ...TarExtractOpti dest_path = filepath.Clean(dest_path) mode := func(hdr int64) fs.FileMode { - return fs.FileMode(hdr) & fs.ModePerm + // yes, we really want to preserve sticky bits and setuid/setgid bits + return fs.FileMode(hdr) & (fs.ModePerm | fs.ModeSetgid | fs.ModeSetuid | fs.ModeSticky) } set_metadata := func(chmod func(mode fs.FileMode) error, hdr_mode int64) (err error) {