# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
"""Volatility 3 Linux Constants.
Linux-specific values that aren't found in debug symbols
"""
import enum
from dataclasses import dataclass
# Exec argument limits
# Ref: include/uapi/linux/binfmts.h (linux.git commit f6031913338f1dad5bd8cb7286ff4e53644b6940)
MAX_ARG_STRLEN = 32 * 4096
KERNEL_NAME = "__kernel__"
"""The value hard coded from the Linux Kernel (hence not extracted from the layer itself)"""
# include/linux/sched.h
PF_KTHREAD = 0x00200000 # I'm a kernel thread
# Standard well-defined IP protocols.
# ref: include/uapi/linux/in.h
IP_PROTOCOLS = {
0: "IP",
1: "ICMP",
2: "IGMP",
4: "IPIP",
6: "TCP",
8: "EGP",
12: "PUP",
17: "UDP",
22: "IDP",
29: "TP",
33: "DCCP",
41: "IPV6",
46: "RSVP",
47: "GRE",
50: "ESP",
51: "AH",
92: "MTP",
94: "BEETPH",
98: "ENCAP",
103: "PIM",
108: "COMP",
132: "SCTP",
136: "UDPLITE",
137: "MPLS",
143: "ETHERNET",
255: "RAW",
262: "MPTCP",
}
# IPV6 extension headers
# ref: include/uapi/linux/in6.h
IPV6_PROTOCOLS = {
0: "HOPBYHOP_OPTS",
43: "ROUTING",
44: "FRAGMENT",
58: "ICMPv6",
59: "NO_NEXT",
60: "DESTINATION_OPTS",
135: "MOBILITY",
}
# ref: include/net/tcp_states.h
TCP_STATES = (
"",
"ESTABLISHED",
"SYN_SENT",
"SYN_RECV",
"FIN_WAIT1",
"FIN_WAIT2",
"TIME_WAIT",
"CLOSE",
"CLOSE_WAIT",
"LAST_ACK",
"LISTEN",
"CLOSING",
"TCP_NEW_SYN_RECV",
)
# ref: include/linux/net.h (socket_type enum)
SOCK_TYPES = {
1: "STREAM",
2: "DGRAM",
3: "RAW",
4: "RDM",
5: "SEQPACKET",
6: "DCCP",
10: "PACKET",
}
# Address families
# ref: include/linux/socket.h
SOCK_FAMILY = (
"AF_UNSPEC",
"AF_UNIX",
"AF_INET",
"AF_AX25",
"AF_IPX",
"AF_APPLETALK",
"AF_NETROM",
"AF_BRIDGE",
"AF_ATMPVC",
"AF_X25",
"AF_INET6",
"AF_ROSE",
"AF_DECnet",
"AF_NETBEUI",
"AF_SECURITY",
"AF_KEY",
"AF_NETLINK",
"AF_PACKET",
"AF_ASH",
"AF_ECONET",
"AF_ATMSVC",
"AF_RDS",
"AF_SNA",
"AF_IRDA",
"AF_PPPOX",
"AF_WANPIPE",
"AF_LLC",
"AF_IB",
"AF_MPLS",
"AF_CAN",
"AF_TIPC",
"AF_BLUETOOTH",
"AF_IUCV",
"AF_RXRPC",
"AF_ISDN",
"AF_PHONET",
"AF_IEEE802154",
"AF_CAIF",
"AF_ALG",
"AF_NFC",
"AF_VSOCK",
"AF_KCM",
"AF_QIPCRTR",
"AF_SMC",
"AF_XDP",
)
# Socket states
# ref: include/uapi/linux/net.h
SOCKET_STATES = ("FREE", "UNCONNECTED", "CONNECTING", "CONNECTED", "DISCONNECTING")
# Netlink protocols
# ref: include/uapi/linux/netlink.h
NETLINK_PROTOCOLS = (
"NETLINK_ROUTE",
"NETLINK_UNUSED",
"NETLINK_USERSOCK",
"NETLINK_FIREWALL",
"NETLINK_SOCK_DIAG",
"NETLINK_NFLOG",
"NETLINK_XFRM",
"NETLINK_SELINUX",
"NETLINK_ISCSI",
"NETLINK_AUDIT",
"NETLINK_FIB_LOOKUP",
"NETLINK_CONNECTOR",
"NETLINK_NETFILTER",
"NETLINK_IP6_FW",
"NETLINK_DNRTMSG",
"NETLINK_KOBJECT_UEVENT",
"NETLINK_GENERIC",
"NETLINK_DM",
"NETLINK_SCSITRANSPORT",
"NETLINK_ECRYPTFS",
"NETLINK_RDMA",
"NETLINK_CRYPTO",
"NETLINK_SMC",
)
# Short list of Ethernet Protocol ID's.
# ref: include/uapi/linux/if_ether.h
# Used in AF_PACKET socket family
ETH_PROTOCOLS = {
0x0001: "ETH_P_802_3",
0x0002: "ETH_P_AX25",
0x0003: "ETH_P_ALL",
0x0004: "ETH_P_802_2",
0x0005: "ETH_P_SNAP",
0x0006: "ETH_P_DDCMP",
0x0007: "ETH_P_WAN_PPP",
0x0008: "ETH_P_PPP_MP",
0x0009: "ETH_P_LOCALTALK",
0x000C: "ETH_P_CAN",
0x000F: "ETH_P_CANFD",
0x0010: "ETH_P_PPPTALK",
0x0011: "ETH_P_TR_802_2",
0x0016: "ETH_P_CONTROL",
0x0017: "ETH_P_IRDA",
0x0018: "ETH_P_ECONET",
0x0019: "ETH_P_HDLC",
0x001A: "ETH_P_ARCNET",
0x001B: "ETH_P_DSA",
0x001C: "ETH_P_TRAILER",
0x0060: "ETH_P_LOOP",
0x00F6: "ETH_P_IEEE802154",
0x00F7: "ETH_P_CAIF",
0x00F8: "ETH_P_XDSA",
0x00F9: "ETH_P_MAP",
0x0800: "ETH_P_IP",
0x0805: "ETH_P_X25",
0x0806: "ETH_P_ARP",
0x8035: "ETH_P_RARP",
0x809B: "ETH_P_ATALK",
0x80F3: "ETH_P_AARP",
0x8100: "ETH_P_8021Q",
}
# Connection and socket states
# ref: include/net/bluetooth/bluetooth.h
BLUETOOTH_STATES = (
"",
"CONNECTED",
"OPEN",
"BOUND",
"LISTEN",
"CONNECT",
"CONNECT2",
"CONFIG",
"DISCONN",
"CLOSED",
)
# Bluetooth protocols
# ref: include/net/bluetooth/bluetooth.h
BLUETOOTH_PROTOCOLS = (
"L2CAP",
"HCI",
"SCO",
"RFCOMM",
"BNEP",
"CMTP",
"HIDP",
"AVDTP",
)
# Ref: include/uapi/linux/capability.h
CAPABILITIES = (
"chown",
"dac_override",
"dac_read_search",
"fowner",
"fsetid",
"kill",
"setgid",
"setuid",
"setpcap",
"linux_immutable",
"net_bind_service",
"net_broadcast",
"net_admin",
"net_raw",
"ipc_lock",
"ipc_owner",
"sys_module",
"sys_rawio",
"sys_chroot",
"sys_ptrace",
"sys_pacct",
"sys_admin",
"sys_boot",
"sys_nice",
"sys_resource",
"sys_time",
"sys_tty_config",
"mknod",
"lease",
"audit_write",
"audit_control",
"setfcap",
"mac_override",
"mac_admin",
"syslog",
"wake_alarm",
"block_suspend",
"audit_read",
"perfmon",
"bpf",
"checkpoint_restore",
)
ELF_MAX_EXTRACTION_SIZE = 1024 * 1024 * 1024 * 4 - 1
# For IFA_* below - Ref: include/net/ipv6.h
IPV6_ADDR_LOOPBACK = 0x0010
IPV6_ADDR_LINKLOCAL = 0x0020
IPV6_ADDR_SITELOCAL = 0x0040
# For inet6_ifaddr - Ref: include/net/if_inet6.h
IFA_HOST = IPV6_ADDR_LOOPBACK
IFA_LINK = IPV6_ADDR_LINKLOCAL
IFA_SITE = IPV6_ADDR_SITELOCAL
# Only for kernels < 3.15 when the net_device_flags enum didn't exist
# ref include/uapi/linux/if.h
NET_DEVICE_FLAGS = {
"IFF_UP": 0x1,
"IFF_BROADCAST": 0x2,
"IFF_DEBUG": 0x4,
"IFF_LOOPBACK": 0x8,
"IFF_POINTOPOINT": 0x10,
"IFF_NOTRAILERS": 0x20,
"IFF_RUNNING": 0x40,
"IFF_NOARP": 0x80,
"IFF_PROMISC": 0x100,
"IFF_ALLMULTI": 0x200,
"IFF_MASTER": 0x400,
"IFF_SLAVE": 0x800,
"IFF_MULTICAST": 0x1000,
"IFF_PORTSEL": 0x2000,
"IFF_AUTOMEDIA": 0x4000,
"IFF_DYNAMIC": 0x8000,
"IFF_LOWER_UP": 0x10000,
"IFF_DORMANT": 0x20000,
"IFF_ECHO": 0x40000,
}
# Kernels >= 2.6.17. See IF_OPER_* in include/uapi/linux/if.h
[docs]
class IF_OPER_STATES(enum.Enum):
"""RFC 2863 - Network interface operational status"""
UNKNOWN = 0
NOTPRESENT = 1
DOWN = 2
LOWERLAYERDOWN = 3
TESTING = 4
DORMANT = 5
UP = 6
[docs]
class ELF_IDENT(enum.IntEnum):
"""ELF header e_ident indexes"""
EI_MAG0 = 0
EI_MAG1 = 1
EI_MAG2 = 2
EI_MAG3 = 3
EI_CLASS = 4
EI_DATA = 5
EI_VERSION = 6
EI_OSABI = 7
EI_PAD = 8
[docs]
class ELF_CLASS(enum.IntEnum):
"""ELF header class types"""
ELFCLASSNONE = 0
ELFCLASS32 = 1
ELFCLASS64 = 2
# PTrace
PT_OPT_FLAG_SHIFT = 3
PTRACE_EVENT_FORK = 1
PTRACE_EVENT_VFORK = 2
PTRACE_EVENT_CLONE = 3
PTRACE_EVENT_EXEC = 4
PTRACE_EVENT_VFORK_DONE = 5
PTRACE_EVENT_EXIT = 6
PTRACE_EVENT_SECCOMP = 7
PTRACE_O_EXITKILL = 1 << 20
PTRACE_O_SUSPEND_SECCOMP = 1 << 21
[docs]
class PT_FLAGS(enum.Flag):
"PTrace flags"
PT_PTRACED = 0x00001
PT_SEIZED = 0x10000
PT_TRACESYSGOOD = 1 << (PT_OPT_FLAG_SHIFT + 0)
PT_TRACE_FORK = 1 << (PT_OPT_FLAG_SHIFT + PTRACE_EVENT_FORK)
PT_TRACE_VFORK = 1 << (PT_OPT_FLAG_SHIFT + PTRACE_EVENT_VFORK)
PT_TRACE_CLONE = 1 << (PT_OPT_FLAG_SHIFT + PTRACE_EVENT_CLONE)
PT_TRACE_EXEC = 1 << (PT_OPT_FLAG_SHIFT + PTRACE_EVENT_EXEC)
PT_TRACE_VFORK_DONE = 1 << (PT_OPT_FLAG_SHIFT + PTRACE_EVENT_VFORK_DONE)
PT_TRACE_EXIT = 1 << (PT_OPT_FLAG_SHIFT + PTRACE_EVENT_EXIT)
PT_TRACE_SECCOMP = 1 << (PT_OPT_FLAG_SHIFT + PTRACE_EVENT_SECCOMP)
PT_EXITKILL = PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT
PT_SUSPEND_SECCOMP = PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT
@property
def flags(self) -> str:
"""Returns the ptrace flags string"""
return str(self).replace(self.__class__.__name__ + ".", "")
# Boot time
NSEC_PER_SEC = 1e9
# Valid sizes for modules. Note that the Linux kernel does not define these values; they
# are based on empirical observations of typical memory allocations for kernel modules.
# We use this to verify that the found module falls within reasonable limits.
MODULE_MAXIMUM_CORE_SIZE = 20000000
MODULE_MAXIMUM_CORE_TEXT_SIZE = 20000000
MODULE_MINIMUM_SIZE = 4096
# Kallsyms
KSYM_NAME_LEN = 512
NM_TYPES_DESC = {
"a": "Symbol is absolute and doesn't change during linking",
"b": "Symbol in the BSS section, typically holding zero-initialized or uninitialized data",
"c": "Symbol is common, typically holding uninitialized data",
"d": "Symbol is in the initialized data section",
"g": "Symbol is in an initialized data section for small objects",
"i": "Symbol is an indirect reference to another symbol",
"N": "Symbol is a debugging symbol",
"n": "Symbol is in a non-data, non-code, non-debug read-only section",
"p": "Symbol is in a stack unwind section",
"r": "Symbol is in a read only data section",
"s": "Symbol is in an uninitialized or zero-initialized data section for small objects",
"t": "Symbol is in the text (code) section",
"U": "Symbol is undefined",
"u": "Symbol is a unique global symbol",
"V": "Symbol is a weak object, with a default value",
"v": "Symbol is a weak object",
"W": "Symbol is a weak symbol but not marked as a weak object symbol, with a default value",
"w": "Symbol is a weak symbol but not marked as a weak object symbol",
"?": "Symbol type is unknown",
}
# VMCOREINFO
VMCOREINFO_MAGIC = b"VMCOREINFO\x00"
# Aligned to 4 bytes. See storenote() in kernels < 4.19 or append_kcore_note() in kernels >= 4.19
VMCOREINFO_MAGIC_ALIGNED = VMCOREINFO_MAGIC + b"\x00"
OSRELEASE_TAG = b"OSRELEASE="
ATTRIBUTE_NAME_MAX_SIZE = 255
"""
In 5.9-rc1+, the Linux kernel limits the READ size of a section bin_attribute name to MODULE_SECT_READ_SIZE:
- https://elixir.bootlin.com/linux/v6.15-rc4/source/kernel/module/sysfs.c#L106
- https://github.com/torvalds/linux/commit/11990a5bd7e558e9203c1070fc52fb6f0488e75b
However, the raw section name loaded from the .ko ELF can in theory be thousands of characters,
and unless we do a NULL terminated search we can't set a perfect value.
"""
[docs]
@dataclass
class TaintFlag:
shift: int
desc: str
when_present: bool
module: bool
TAINT_FLAGS = {
"P": TaintFlag(
shift=1 << 0, desc="PROPRIETARY_MODULE", when_present=True, module=True
),
"G": TaintFlag(
shift=1 << 0, desc="PROPRIETARY_MODULE", when_present=False, module=True
),
"F": TaintFlag(shift=1 << 1, desc="FORCED_MODULE", when_present=True, module=False),
"S": TaintFlag(
shift=1 << 2, desc="CPU_OUT_OF_SPEC", when_present=True, module=False
),
"R": TaintFlag(shift=1 << 3, desc="FORCED_RMMOD", when_present=True, module=False),
"M": TaintFlag(shift=1 << 4, desc="MACHINE_CHECK", when_present=True, module=False),
"B": TaintFlag(shift=1 << 5, desc="BAD_PAGE", when_present=True, module=False),
"U": TaintFlag(shift=1 << 6, desc="USER", when_present=True, module=False),
"D": TaintFlag(shift=1 << 7, desc="DIE", when_present=True, module=False),
"A": TaintFlag(
shift=1 << 8, desc="OVERRIDDEN_ACPI_TABLE", when_present=True, module=False
),
"W": TaintFlag(shift=1 << 9, desc="WARN", when_present=True, module=False),
"C": TaintFlag(shift=1 << 10, desc="CRAP", when_present=True, module=True),
"I": TaintFlag(
shift=1 << 11, desc="FIRMWARE_WORKAROUND", when_present=True, module=False
),
"O": TaintFlag(shift=1 << 12, desc="OOT_MODULE", when_present=True, module=True),
"E": TaintFlag(
shift=1 << 13, desc="UNSIGNED_MODULE", when_present=True, module=True
),
"L": TaintFlag(shift=1 << 14, desc="SOFTLOCKUP", when_present=True, module=False),
"K": TaintFlag(shift=1 << 15, desc="LIVEPATCH", when_present=True, module=True),
"X": TaintFlag(shift=1 << 16, desc="AUX", when_present=True, module=True),
"T": TaintFlag(shift=1 << 17, desc="RANDSTRUCT", when_present=True, module=True),
"N": TaintFlag(shift=1 << 18, desc="TEST", when_present=True, module=True),
}
"""Flags used to taint kernel and modules, for debugging purposes.
Map based on 6.12-rc5.
Documentation :
- https://www.kernel.org/doc/Documentation/admin-guide/sysctl/kernel.rst#:~:text=guide/sysrq.rst.-,tainted,-%3D%3D%3D%3D%3D%3D%3D%0A%0ANon%2Dzero%20if
- https://www.kernel.org/doc/Documentation/admin-guide/tainted-kernels.rst#:~:text=More%20detailed%20explanation%20for%20tainting
- taint_flag kernel struct
- taint_flags kernel constant
"""
## ELF related constants
# Elf Symbol Bindings
STB_LOCAL = 0
STB_GLOBAL = 1
# Elf Symbol Types
STT_NOTYPE = 0
STT_OBJECT = 1
STT_FUNC = 2
STT_SECTION = 3
# Elf Section Types
SHT_NULL = 0
SHT_PROGBITS = 1
SHT_SYMTAB = 2
SHT_STRTAB = 3
SHT_RELA = 4
SHT_NOTE = 7
# Elf Section Attributes
SHF_WRITE = 1
SHF_ALLOC = 2
SHF_EXECINSTR = 4