@@ -1472,21 +1472,21 @@ def euid(self):
14721472
14731473
14741474class kernel_cap_struct (objects .StructType ):
1475- # struct kernel_cap_struct was added in kernels 2.5.0
1475+ # struct kernel_cap_struct exists from 2.1.92 <= kernels < 6.3
14761476 @classmethod
14771477 def get_last_cap_value (cls ) -> int :
14781478 """Returns the latest capability ID supported by the framework.
14791479
14801480 Returns:
1481- int: The latest supported capability ID supported by the framework.
1481+ int: The latest capability ID supported by the framework.
14821482 """
14831483 return len (CAPABILITIES ) - 1
14841484
14851485 def get_kernel_cap_full (self ) -> int :
14861486 """Return the maximum value allowed for this kernel for a capability
14871487
14881488 Returns:
1489- int: _description_
1489+ int: The capability full bitfield mask
14901490 """
14911491 vmlinux = linux .LinuxUtilities .get_module_from_volobj_type (self ._context , self )
14921492 try :
@@ -1522,17 +1522,29 @@ def get_capabilities(self) -> int:
15221522 int: The capability bitfield value.
15231523 """
15241524
1525+ if not self .has_member ("cap" ):
1526+ raise exceptions .VolatilityException (
1527+ "Unsupported kernel capabilities implementation"
1528+ )
1529+
15251530 if isinstance (self .cap , objects .Array ):
1526- # In 2.6.25.x <= kernels < 6.3 kernel_cap_struct::cap is a two
1527- # elements __u32 array that constitutes a 64bit bitfield.
1528- # Technically, it can also be an array of 1 element if
1529- # _KERNEL_CAPABILITY_U32S = _LINUX_CAPABILITY_U32S_1
1530- # However, in the source code, that never happens.
1531- # From 2.6.24 to 2.6.25 cap became an array of 2 elements.
1532- cap_value = (self .cap [1 ] << 32 ) | self .cap [0 ]
1531+ if len (self .cap ) == 1 :
1532+ # At least in the vanilla kernel, from 2.6.24 to 2.6.25
1533+ # kernel_cap_struct::cap become a two elements array.
1534+ # However, in some distros or custom kernel can techically
1535+ # be _KERNEL_CAPABILITY_U32S = _LINUX_CAPABILITY_U32S_1
1536+ # Leaving this code here for the sake of ensuring completeness.
1537+ cap_value = self .cap [0 ]
1538+ elif len (self .cap ) == 2 :
1539+ # In 2.6.25.x <= kernels < 6.3 kernel_cap_struct::cap is a two
1540+ # elements __u32 array that constitutes a 64bit bitfield.
1541+ cap_value = (self .cap [1 ] << 32 ) | self .cap [0 ]
1542+ else :
1543+ raise exceptions .VolatilityException (
1544+ "Unsupported kernel capabilities implementation"
1545+ )
15331546 else :
1534- # In kernels < 2.6.25.x kernel_cap_struct::cap was a __u32
1535- # In kernels >= 6.3 kernel_cap_struct::cap is a u64
1547+ # In kernels < 2.6.25.x kernel_cap_struct::cap is a __u32
15361548 cap_value = self .cap
15371549
15381550 return cap_value & self .get_kernel_cap_full ()
@@ -1563,3 +1575,23 @@ def has_capability(self, capability: str) -> bool:
15631575
15641576 cap_value = 1 << CAPABILITIES .index (capability )
15651577 return cap_value & self .get_capabilities () != 0
1578+
1579+
1580+ class kernel_cap_t (kernel_cap_struct ):
1581+ # In kernels 6.3 kernel_cap_struct became the kernel_cap_t typedef
1582+ def get_capabilities (self ) -> int :
1583+ """Returns the capability bitfield value
1584+
1585+ Returns:
1586+ int: The capability bitfield value.
1587+ """
1588+
1589+ if self .has_member ("val" ):
1590+ # In kernels >= 6.3 kernel_cap_t::val is a u64
1591+ cap_value = self .val
1592+ else :
1593+ raise exceptions .VolatilityException (
1594+ "Unsupported kernel capabilities implementation"
1595+ )
1596+
1597+ return cap_value & self .get_kernel_cap_full ()
0 commit comments