From ee4c5d45ab9097ebdc56296d6f5553a38e3ace33 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Mon, 23 Feb 2026 13:25:31 -0800 Subject: [PATCH 1/2] Add CAP_CHOWN to permitted capability set Add CAP_CHOWN to the permitted capability set retained after privilege drop. This allows plugins that perform cert file backup writes to set root ownership on newly created files when certs are restricted to root:root 600. Like CAP_DAC_OVERRIDE, CAP_CHOWN is held in the permitted set only and must be explicitly promoted to the effective set before use. It is not active during normal operation. --- src/tscore/ink_cap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tscore/ink_cap.cc b/src/tscore/ink_cap.cc index f464daad3b1..6f12d0e5b3a 100644 --- a/src/tscore/ink_cap.cc +++ b/src/tscore/ink_cap.cc @@ -273,7 +273,7 @@ RestrictCapabilities() cap_t caps_orig = cap_get_proc(); // Capabilities we need. - cap_value_t perm_list[] = {CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_IPC_LOCK, CAP_DAC_OVERRIDE, CAP_FOWNER}; + cap_value_t perm_list[] = {CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_IPC_LOCK, CAP_DAC_OVERRIDE, CAP_FOWNER, CAP_CHOWN}; static int const PERM_CAP_COUNT = sizeof(perm_list) / sizeof(*perm_list); cap_value_t eff_list[] = {CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_IPC_LOCK}; static int const EFF_CAP_COUNT = sizeof(eff_list) / sizeof(*eff_list); From 8bf8f83274097850e8f545395b01e9b182a68335 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 3 Mar 2026 08:34:11 -0800 Subject: [PATCH 2/2] Add CHOWN_PRIVILEGE to ElevateAccess Add CHOWN_PRIVILEGE (0x10u) to the ElevateAccess privilege_level enum and wire up CAP_CHOWN in acquirePrivilege() so plugins can elevate file ownership capability through the standard ATS privilege API. --- include/tscore/ink_cap.h | 3 ++- src/tscore/ink_cap.cc | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/tscore/ink_cap.h b/include/tscore/ink_cap.h index 86a8f31f4d5..f1e50b9f749 100644 --- a/include/tscore/ink_cap.h +++ b/include/tscore/ink_cap.h @@ -81,8 +81,9 @@ class ElevateAccess FILE_PRIVILEGE = 0x1u, ///< Access filesystem objects with privilege TRACE_PRIVILEGE = 0x2u, ///< Trace other processes with privilege LOW_PORT_PRIVILEGE = 0x4u, ///< Bind to privilege ports. - OWNER_PRIVILEGE = 0x8u ///< Bypass permission checks on operations that normally require + OWNER_PRIVILEGE = 0x8u, ///< Bypass permission checks on operations that normally require /// filesystem UID & process UID to match + CHOWN_PRIVILEGE = 0x10u ///< Change file ownership }; ElevateAccess(unsigned level = FILE_PRIVILEGE); diff --git a/src/tscore/ink_cap.cc b/src/tscore/ink_cap.cc index 6f12d0e5b3a..6841c462b02 100644 --- a/src/tscore/ink_cap.cc +++ b/src/tscore/ink_cap.cc @@ -436,7 +436,7 @@ void ElevateAccess::acquirePrivilege(unsigned priv_mask) { unsigned cap_count = 0; - cap_value_t cap_list[3]; + cap_value_t cap_list[4]; cap_t new_cap_state; Dbg(dbg_ctl_privileges, "[acquirePrivilege] level= %x", level); @@ -463,6 +463,11 @@ ElevateAccess::acquirePrivilege(unsigned priv_mask) ++cap_count; } + if (priv_mask & ElevateAccess::CHOWN_PRIVILEGE) { + cap_list[cap_count] = CAP_CHOWN; + ++cap_count; + } + ink_release_assert(cap_count <= sizeof(cap_list)); if (cap_count > 0) {