Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/tscore/ink_cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CHOWN_PRIVILEGE entry is not aligned to the same column as the other enum values. All previous entries use column-aligned spacing before = to keep the values visually aligned (e.g., FILE_PRIVILEGE = 0x1u, OWNER_PRIVILEGE = 0x8u), but CHOWN_PRIVILEGE = 0x10u has only a single space before =, breaking the alignment pattern.

Suggested change
CHOWN_PRIVILEGE = 0x10u ///< Change file ownership
CHOWN_PRIVILEGE = 0x10u ///< Change file ownership

Copilot uses AI. Check for mistakes.
};

ElevateAccess(unsigned level = FILE_PRIVILEGE);
Expand Down
9 changes: 7 additions & 2 deletions src/tscore/ink_cap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bounds-check assertion at line 471 compares cap_count (the number of capabilities, max 4) against sizeof(cap_list) (the byte size of the array, which is 4 * sizeof(cap_value_t) = 16 bytes on typical platforms). This means the assertion is effectively cap_count <= 16, which will never catch an actual out-of-bounds write. It should use the element count instead: cap_count <= sizeof(cap_list) / sizeof(cap_list[0]).

This PR brings cap_count up to a potential maximum of 4, exactly matching the array dimension, so the array is not overflowed now — but the guard is broken. Any future capability addition will silently overflow cap_list without the assertion firing.

Suggested change
ink_release_assert(cap_count <= sizeof(cap_list));
ink_release_assert(cap_count <= sizeof(cap_list) / sizeof(cap_list[0]));

Copilot uses AI. Check for mistakes.

if (cap_count > 0) {
Expand Down