@@ -1543,21 +1543,21 @@ def euid(self):
15431543
15441544
15451545class kernel_cap_struct (objects .StructType ):
1546- # struct kernel_cap_struct was added in kernels 2.5.0
1546+ # struct kernel_cap_struct exists from 2.1.92 <= kernels < 6.3
15471547 @classmethod
15481548 def get_last_cap_value (cls ) -> int :
15491549 """Returns the latest capability ID supported by the framework.
15501550
15511551 Returns:
1552- int: The latest supported capability ID supported by the framework.
1552+ int: The latest capability ID supported by the framework.
15531553 """
15541554 return len (CAPABILITIES ) - 1
15551555
15561556 def get_kernel_cap_full (self ) -> int :
15571557 """Return the maximum value allowed for this kernel for a capability
15581558
15591559 Returns:
1560- int: _description_
1560+ int: The capability full bitfield mask
15611561 """
15621562 vmlinux = linux .LinuxUtilities .get_module_from_volobj_type (self ._context , self )
15631563 try :
@@ -1593,17 +1593,29 @@ def get_capabilities(self) -> int:
15931593 int: The capability bitfield value.
15941594 """
15951595
1596+ if not self .has_member ("cap" ):
1597+ raise exceptions .VolatilityException (
1598+ "Unsupported kernel capabilities implementation"
1599+ )
1600+
15961601 if isinstance (self .cap , objects .Array ):
1597- # In 2.6.25.x <= kernels < 6.3 kernel_cap_struct::cap is a two
1598- # elements __u32 array that constitutes a 64bit bitfield.
1599- # Technically, it can also be an array of 1 element if
1600- # _KERNEL_CAPABILITY_U32S = _LINUX_CAPABILITY_U32S_1
1601- # However, in the source code, that never happens.
1602- # From 2.6.24 to 2.6.25 cap became an array of 2 elements.
1603- cap_value = (self .cap [1 ] << 32 ) | self .cap [0 ]
1602+ if len (self .cap ) == 1 :
1603+ # At least in the vanilla kernel, from 2.6.24 to 2.6.25
1604+ # kernel_cap_struct::cap become a two elements array.
1605+ # However, in some distros or custom kernel can technically
1606+ # be _KERNEL_CAPABILITY_U32S = _LINUX_CAPABILITY_U32S_1
1607+ # Leaving this code here for the sake of ensuring completeness.
1608+ cap_value = self .cap [0 ]
1609+ elif len (self .cap ) == 2 :
1610+ # In 2.6.25.x <= kernels < 6.3 kernel_cap_struct::cap is a two
1611+ # elements __u32 array that constitutes a 64bit bitfield.
1612+ cap_value = (self .cap [1 ] << 32 ) | self .cap [0 ]
1613+ else :
1614+ raise exceptions .VolatilityException (
1615+ "Unsupported kernel capabilities implementation"
1616+ )
16041617 else :
1605- # In kernels < 2.6.25.x kernel_cap_struct::cap was a __u32
1606- # In kernels >= 6.3 kernel_cap_struct::cap is a u64
1618+ # In kernels < 2.6.25.x kernel_cap_struct::cap is a __u32
16071619 cap_value = self .cap
16081620
16091621 return cap_value & self .get_kernel_cap_full ()
@@ -1634,3 +1646,23 @@ def has_capability(self, capability: str) -> bool:
16341646
16351647 cap_value = 1 << CAPABILITIES .index (capability )
16361648 return cap_value & self .get_capabilities () != 0
1649+
1650+
1651+ class kernel_cap_t (kernel_cap_struct ):
1652+ # In kernels 6.3 kernel_cap_struct became the kernel_cap_t typedef
1653+ def get_capabilities (self ) -> int :
1654+ """Returns the capability bitfield value
1655+
1656+ Returns:
1657+ int: The capability bitfield value.
1658+ """
1659+
1660+ if self .has_member ("val" ):
1661+ # In kernels >= 6.3 kernel_cap_t::val is a u64
1662+ cap_value = self .val
1663+ else :
1664+ raise exceptions .VolatilityException (
1665+ "Unsupported kernel capabilities implementation"
1666+ )
1667+
1668+ return cap_value & self .get_kernel_cap_full ()
0 commit comments