pmark

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 17, 2026 License: MIT Imports: 19 Imported by: 0

README

p-mark

p-mark is a Go library and command for tagging Linux process lifetimes with 64-bit marks. User-space Go rules decide which processes are explicitly marked, and eBPF programs keep those marks inherited by children of marked processes.

The root package is the process-marking engine. The fwmark package demonstrates one practical consumer: copying process marks into Linux socket SO_MARK / fwmark values so routing policy and firewall rules can match the process' traffic.

[!CAUTION] p-mark is an experimental and unstable software that work under high privileges while havent being audited yet. Do not use in production.
Also check issues.

Binary Usage

The daemon loads eBPF programs and pins maps in bpffs, so it normally needs root or equivalent capabilities.

Usage of pmark:
  -fmark-value string
    	fwmark format value to derive full mark from; overwrites mark-value
  -fwmark
    	enable Linux fwmark socket marking with fwmark eBPF hooks in daemon mode
  -http-addr string
    	daemon HTTP control listen address (default "127.0.0.1:8050")
  -mark-priority int
    	signed int8 priority assigned by the default check callback; higher priority wins
  -mark-value uint
    	mark value assigned by the default check callback (default 16978289124505026561)
  -pin-path string
    	bpffs directory for pinned maps (default "/sys/fs/bpf/pmark")
  -rule-cmd string
    	comma-separated regexps matched against cmdline by the default check callback
  -rule-comm string
    	comma-separated regexps matched against comm by the default check callback (default "firefox")
  -rule-exe string
    	comma-separated regexps matched against exe and exe basename by the default check callback
  -rule-ppid string
    	comma-separated parent process ids matched by the default check callback
  -watch-interval duration
    	interval for watcher refreshes (default 1s)
  -watcher
    	watch the pinned process map instead of running the daemon
Launching The Daemon

Run the default daemon, which marks processes whose comm matches firefox by default:

sudo pmark

Mark by other process properties:

sudo pmark \
  -pin-path /sys/fs/bpf/pmark \
  -rule-comm 'firefox,chromium' \
  -rule-cmd 'profile-name' \
  -rule-exe '/usr/bin/firefox' \
  -mark-value 16978289124505026561 \
  -mark-priority 10

Enable fwmark integration and derive the 64-bit pmark value from a 32-bit Linux fwmark:

sudo ./pmark -fwmark -fmark-value 0xeb9f0001

With -fwmark, new sockets created by marked processes receive the fwmark, and the userspace reconciler attempts to update sockets that were already open.

Launching The Watcher

The watcher does not run the marking logic. It opens the pinned processes map and prints the currently marked process tree:

sudo pmark -watcher -pin-path /sys/fs/bpf/pmark
Process map watcher: /sys/fs/bpf/pmark/processes
Refreshed: 2026-06-07T15:08:12+04:00

Alive entries: 9
Tombstones: 152
Observed tombstones: 152
Collected tombstones: 0
Latest entry update: 1780830491 (857ms ago, boot_ns=15323572543606)

Process tree:
 73006 .firefox-wrappe mark=16978289124505026561 priority=0 gen=1
 └ 73076 forkserver mark=16978289124505026561 priority=0 gen=1
  ├ 73080 Socket Process mark=16978289124505026561 priority=0 gen=1
  ├ 73103 Privileged Cont mark=16978289124505026561 priority=0 gen=1
  ├ 73113 RDD Process mark=16978289124505026561 priority=0 gen=1
  ├ 73156 Isolated Web Co mark=16978289124505026561 priority=0 gen=1
  ├ 73165 Isolated Web Co mark=16978289124505026561 priority=0 gen=1
  ├ 73269 WebExtensions mark=16978289124505026561 priority=0 gen=1
  └ 73322 Utility Process mark=16978289124505026561 priority=0 gen=1

Adjust refresh rate with -watch-interval:

sudo ./pmark -watcher -watch-interval 500ms
Admin Panel

Daemon mode starts an HTTP control server on -http-addr, defaulting to 127.0.0.1:8050. Open that address in a browser to view the admin panel. The panel exposes current state and lets the sample regexp rules and mark settings be updated without restarting the daemon.

admin panel screenshot

Using Marks With nftables

If you've run the daemon with -fwmark, you can use it later in iptables/nftables rules (e.g., for routing traffic of marked apps to different routes).

These rules will drop all packets owned by processes that have the mark attached by the daemon from the examples above, and thus block all firefox traffic:

sudo nft delete table inet ebpf_test_fwmark 2>/dev/null
sudo nft add table inet ebpf_test_fwmark
sudo nft 'add chain inet ebpf_test_fwmark output { type filter hook output priority 0; policy accept; }'
sudo nft add rule inet ebpf_test_fwmark output meta mark 0xeb9f0001 counter drop
sudo nft add rule inet ebpf_test_fwmark output socket mark 0xeb9f0001 counter drop

Then you can check stats with:

sudo nft list chain inet ebpf_test_fwmark output

Installation

Nix

Build or run directly from the flake:

nix build github:asciimoth/p-mark#pmark
nix profile add github:asciimoth/p-mark#pmark
Deb, and rpm-based systems

Packages are published to my deb/rpm repository:

Setup it for your sytstem via script (or manually):

curl https://repo.moth.contact/setup.sh | bash

Then install with your system package manager:

sudo apt install pmark
# or
sudo dnf install pmark
# or
sudo yum install pmark
GitHub Releases

Release archives and package artifacts are published on the GitHub releases page.

Arch

AUR is available

Library Usage

Note: You can find more marks usage examples in ebpf-test

pmark

Use the pmark for custom Go logic to decide process marks in your program.

package main

import (
	"log"
	"os"
	"os/signal"
	"syscall"

	pmark "github.com/asciimoth/p-mark"
)

func main() {
	daemon, err := pmark.NewDaemon("/sys/fs/bpf/pmark", pmark.Callbacks{
		Check: func(info pmark.ProcessInfo) (int8, uint64, bool) {
			if info.Comm == "firefox" {
				return 10, 0x0000004200000001, true
			}
			return 0, 0, false
		},
		ProcessUpdate: func(update pmark.ProcessUpdate) {
			log.Printf("pid=%d mark=%#x has_mark=%v",
				update.Key.Tgid, update.Value.Mark, update.Value.HasMark)
		},
		Logf: log.Printf,
	}, 0, 0)
	if err != nil {
		log.Fatal(err)
	}

	if err := daemon.Run(); err != nil {
		log.Fatal(err)
	}

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
	<-stop

	if err := daemon.Stop(); err != nil {
		log.Fatal(err)
	}
}

Important API points:

  • CheckFunc returns (priority, mark, true) to explicitly mark a process.
  • Returning ok=false leaves the process unmarked unless a live parent mark can be inherited.
  • SetChecker replaces rule logic, bumps the checker generation, and re-traverses /proc.
  • ForceProcessTraversal re-checks current processes without bumping the generation.
  • GrabProcessMapState is useful for admin panels and watchers.
multirule

Use multirule when you need a userspace-only view of which processes match multiple independent rules, without creating pmark marks for those matches.

tracker := multirule.New()

browserRule := tracker.RegisterRule(func(info pmark.ProcessInfo) bool {
	return info.Comm == "firefox"
})

daemon, err := pmark.NewDaemon("/sys/fs/bpf/pmark", pmark.Callbacks{
	Check:        tracker.CheckCallback(),
	ProcessEvent: tracker.ProcessEventCallback(),
	Logf:         log.Printf,
}, 0, 0)
if err != nil {
	log.Fatal(err)
}

_ = browserRule

Tracker.CheckCallback observes process information and always returns ok=false, so the tracker does not ask pmark to write any eBPF process marks. Each observed process is checked against registered rules and inherits matched rule IDs from the latest known parent. RegisterRule immediately checks all already observed processes, UnregisterRule removes the ID from every entry, and RuleIDs, Matches, and Snapshot expose the current in-memory state.

For callers that only have a PID, RuleIDsByPID and MatchesPID look up the latest pmark.ProcessKey observed for that PID:

if tracker.MatchesPID(pid, browserRule) {
	log.Printf("pid %d is in the browser rule set", pid)
}

PID-only lookups are convenient but less precise than pmark.ProcessKey lookups. Linux can reuse PIDs, so when multiple process lifetimes have used the same PID, multirule maps that PID to the latest observed ProcessKey. When an exit event removes that ProcessKey, the associated PID lookup is removed too.

fwmark

Use fwmark when the mark should become the Linux socket mark used by routing policy or firewall rules. The fwmark value is stored in the high 32 bits of the 64-bit process mark.

package main

import (
	"log"
	"os"
	"os/signal"
	"syscall"

	pmark "github.com/asciimoth/p-mark"
	"github.com/asciimoth/p-mark/fwmark"
)

func main() {
	pinPath := "/sys/fs/bpf/pmark"
	mark := fwmark.ToMark(0x42)

	daemon, err := pmark.NewDaemon(pinPath, pmark.Callbacks{
		Check: func(info pmark.ProcessInfo) (int8, uint64, bool) {
			return 0, mark, info.Comm == "firefox"
		},
		Logf: log.Printf,
	}, 0, 0)
	if err != nil {
		log.Fatal(err)
	}

	manager, err := fwmark.NewManager(pinPath, log.Printf)
	if err != nil {
		log.Fatal(err)
	}
	defer manager.Close()

	fwmarkUpdate := manager.ProcessUpdateCallback()
	daemon.UpdateHooks(pmark.Callbacks{
		ProcessUpdate: fwmarkUpdate,
		Logf:          log.Printf,
	})

	if err := daemon.Run(); err != nil {
		log.Fatal(err)
	}

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
	<-stop

	if err := daemon.Stop(); err != nil {
		log.Fatal(err)
	}
}

The fwmark.Manager loads cgroup eBPF programs that share the same pinned processes map as the pmark daemon. Its ProcessUpdateCallback should be connected to the daemon so already-open sockets are reconciled after process marks change.

Architecture

General Working Principle

p-mark splits policy from propagation:

  • Userspace owns policy. Go callbacks inspect /proc metadata and decide which process receive explicit marks.
  • Kernel eBPF owns fast propagation. Tracepoint programs observe fork, exec, and exit transitions and maintain/emit effective mark state.
  • A pinned BPF hash map named processes is the shared state between the root daemon, custom eBPF consumers, watchers, and packages such as fwmark.

Process identity is not just PID. The key is (tgid, start_time), where start_time is /proc/<pid>/stat field 22 in USER_HZ ticks. This avoids most PID-reuse confusion for one boot.

pmark pkg

NewDaemon loads the generated eBPF object, pins processes and events under the configured bpffs directory, and prepares a userspace mirror. Run then:

  1. Traverses /proc before attaching programs and applies CheckFunc.
  2. Attaches tracepoint programs for sched_process_fork, sched_process_exec, and sched_process_exit.
  3. Traverses /proc again after attaching programs. This second traversal narrows the race window between the first traversal and tracepoint attach.
  4. Consumes the ring buffer and reconciles BPF events with userspace rules.

On fork, BPF tries to copy a live parent mark to the child before sending an event. Userspace then reconciles that result with its mirror and calls CheckFunc for the child. If the checker returns a mark, that explicit mark can override inheritance according to normal merge rules.

On exec, BPF reports the current effective value. Userspace can re-check process metadata because cmdline and exe may have changed.

On exit, entries become tombstones instead of immediate deletes. Tombstones keep late events for the same process lifetime from reviving stale marks. The daemon periodically removes old tombstones from both the userspace mirror and kernel map.

fwmark pkg

fwmark loads a cgroup sock_create eBPF program and attaches it to the root cgroup. When a process creates a socket, the program computes the current process key, looks up processes, and if the entry is live and marked, writes:

socket fwmark = process mark >> 32

That covers sockets created after the mark is present. Existing sockets need userspace help. fwmark.Manager.ProcessUpdateCallback returns a pmark.ProcessUpdate hook that walks /proc/<pid>/fd, obtains each target fd through pidfd_getfd, and applies SO_MARK with setsockopt.

eBPF processes Map

The processes map is a pinned BPF_MAP_TYPE_HASH named processes.

Key:

struct process_key {
	__u32 tgid;
	__u64 start_time;
};

Value:

struct process_value {
	bool tombstone;
	bool inheritance;
	bool has_mark;
	__s8 priority;
	__u64 generation;
	__u64 mark;
	__u64 timestamp;
};

Meaning:

  • tombstone: the process lifetime exited; treat as unmarked.
  • inheritance: true means the mark was explicit/original from userspace; false means it was inherited.
  • has_mark: gates whether mark and priority are meaningful.
  • priority: higher priority wins when userspace merges competing live values.
  • generation: checker generation that last reconciled the entry.
  • mark: the 64-bit user-defined process mark.
  • timestamp: CLOCK_BOOTTIME nanoseconds, also used for tombstone expiry.

Correct use:

  • Treat missing entries, tombstones, and has_mark=false as unmarked.
  • Use the full (tgid, start_time) key, not PID alone.
  • Keep C struct layouts exactly aligned with the generated Go layout if you add another BPF object.
  • Let the daemon own tombstone collection and rule-generation updates.
  • If custom userspace writes map entries, use the same merge semantics as the daemon or route writes through daemon APIs such as SetProcessMark.
Attaching Custom Logic To pmark

fwmark is the reference pattern for custom consumers.

From eBPF:

  • Declare a map named processes with the same key/value layout and LIBBPF_PIN_BY_NAME.
  • Load your eBPF collection with ebpf.CollectionOptions{Maps: ebpf.MapOptions{PinPath: pinPath}} so cilium/ebpf reuses the map pinned by the root daemon.
  • In the hook, construct the same process key. For current tasks, use the thread group leader and convert start_boottime to USER_HZ ticks.
  • Only act on values where !tombstone && has_mark.

From userspace:

  • Start the root pmark.Daemon first so the shared map exists and tracepoint programs maintain inheritance.
  • Load your custom manager with the same pinPath.
  • Subscribe to ProcessUpdate to apply side effects that BPF hooks cannot apply retroactively.
  • After installing or replacing hooks, replay or re-traverse existing state. Daemon.UpdateHooks replays current live entries to the new ProcessUpdate callback. ForceProcessTraversal re-checks /proc with the current checker, and SetChecker or ForceBumpGeneration re-check with a new generation.

That replay/re-traversal step is important for race control and for processes that already existed before custom logic was attached. Without it, a consumer may only see future fork/exec transitions and miss live processes that already carry marks.

TODO

  • Figure out what to do with time namespaces.
  • Test on more distros arcs and configurations
  • Security audit
  • Flatpack app name matching in rules?

Licenses

This repository is dual licensed under GPL or MIT; see LICENSE-GPL and LICENSE-MIT.

Note: the Go bindings embed precompiled eBPF object blobs generated by bpf2go (mark_bpf*.o and fwmark/fwmark_bpf*.o). Those blobs are built from the open-source C files in this repository ( mark.c and fwmark/fwmark.c ), which declare Dual MIT/GPL for the kernel verifier.
You can regenerate them with:

go generate ./...

Documentation

Overview

Package pmark tags Linux process lifetimes with 64-bit marks selected by userspace Go callbacks and inherited by children through eBPF.

A Daemon loads tracepoint eBPF programs, pins the shared processes map under a bpffs directory, traverses /proc, and keeps a userspace mirror reconciled with fork, exec, and exit events. Callers provide a CheckFunc to choose explicit marks from ProcessInfo and optional callbacks to observe process events or effective map updates.

Process identity is ProcessKey: TGID plus the process start time in procfs USER_HZ ticks. ProcessValue stores whether the process is live or a tombstone, whether it has an effective mark, mark priority, checker generation, mark value, and a CLOCK_BOOTTIME timestamp. Other eBPF programs can reuse the pinned processes map as a kernel-space communication point, but should treat missing entries, tombstones, and entries with HasMark false as unmarked.

Index

Constants

View Source
const (

	// DefaultTombCollectionEvents bounds tombstone cleanup work by doing it
	// after a fixed number of processed ring events instead of on every event.
	DefaultTombCollectionEvents = 1024

	// DefaultTombTTL is the grace period during which exited process identities
	// remain in both userspace and kernel mirrors as tombstones.
	DefaultTombTTL = time.Minute
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Callbacks

type Callbacks struct {
	// Check selects explicit marks for processes. Nil means no process is
	// explicitly marked by userspace, though inheritance from existing marks can
	// still occur.
	Check CheckFunc

	// ProcessEvent observes fork, exec, exit, and unknown BPF events after
	// userspace reconciliation. It is for transition logging or side effects
	// that need event context such as ParentKey and Kernel.
	ProcessEvent func(ProcessEvent)

	// ProcessUpdate observes effective map state changes after the daemon has
	// attempted to write them to the kernel map. It is for consumers that care
	// about the current mark state rather than the transition that caused it.
	ProcessUpdate func(ProcessUpdate)

	// Logf receives recoverable daemon diagnostics such as parse errors,
	// traversal failures, map sync failures, and tombstone cleanup failures.
	Logf func(format string, args ...any)
}

Callbacks contains optional hooks used by Daemon.

All callbacks are invoked synchronously by daemon code. Check and ProcessUpdate can run during Run before it returns because initial process traversal may create marks. After Run starts the event loop, Check, ProcessEvent, ProcessUpdate, and Logf can run on the event goroutine. Implementations should avoid long blocking work and should not call Stop, Close, or other methods that wait for the daemon from inside a callback.

type CheckFunc

type CheckFunc func(ProcessInfo) (int8, uint64, bool)

CheckFunc decides whether a process should receive an explicit mark.

It is called while the daemon walks the current /proc tree before attaching BPF programs, again immediately after attach to cover the race window, and on each fork event for the child process. It is not called on exit events.

Returning (priority, mark, true) creates or refreshes an explicit live mark for the supplied process in the current checker generation. Returning (_, _, false) leaves the process unmarked unless it can inherit a live HasMark value from its parent. If the process already had an entry, the daemon keeps a live HasMark=false entry for the rest of that process lifetime. CheckFunc should be quick and must not call back into the same Daemon; after Run starts event processing, a blocked CheckFunc blocks ring-buffer consumption.

func CombineChecks

func CombineChecks(left, right CheckFunc) CheckFunc

type Daemon

type Daemon struct {
	// contains filtered or unexported fields
}

Daemon owns loaded eBPF objects, links, ring reader, and userspace mirror.

func NewDaemon

func NewDaemon(
	pinPath string, callbacks Callbacks, tcev uint64, tttl time.Duration,
) (*Daemon, error)

NewDaemon prepares a daemon instance. Call Run to attach programs and start consuming events, and Stop to detach and close resources.

func (*Daemon) Close

func (d *Daemon) Close() error

func (*Daemon) CurrentGeneration

func (d *Daemon) CurrentGeneration() uint64

CurrentGeneration returns the active checker generation.

func (*Daemon) Done

func (d *Daemon) Done() <-chan error

func (*Daemon) ForceBumpGeneration

func (d *Daemon) ForceBumpGeneration() (uint64, error)

ForceBumpGeneration increments the checker generation, immediately traverses /proc with the current checker, and returns the resulting generation.

It has the same reconciliation effect as SetChecker with the existing checker, but does not replace the checker function. Use it when the checker closes over proving state that changed internally and all live processes need re-checking.

func (*Daemon) ForceProcessTraversal

func (d *Daemon) ForceProcessTraversal() error

ForceProcessTraversal immediately traverses /proc with the current checker.

This is useful when a caller needs to refresh process state outside the daemon's normal startup, event, and cleanup ordering. It does not advance the checker generation.

func (*Daemon) Run

func (d *Daemon) Run() error

func (*Daemon) SetChecker

func (d *Daemon) SetChecker(check CheckFunc) (uint64, error)

SetChecker installs a new checker, increments the checker generation, immediately traverses /proc with the new checker, and returns the resulting generation.

Processes matched by the new checker receive live HasMark=true entries at the new generation. Existing live entries that no longer match and cannot inherit a live mark are updated to HasMark=false at the new generation and kept until that process exits and its tombstone is collected.

func (*Daemon) SetProcessMark

func (d *Daemon) SetProcessMark(key ProcessKey, priority int8, mark uint64)

SetProcessMark explicitly sets a live mark for one process lifetime.

The mark is applied with the current checker generation and the same merge, kernel-sync, and ProcessUpdate behavior used for marks found in BPF events or returned by Check. Higher-priority, newer-generation, or tombstone values that already exist may still win according to the normal ProcessValue merge rules.

func (*Daemon) Stop

func (d *Daemon) Stop() error

func (*Daemon) UpdateHooks

func (d *Daemon) UpdateHooks(callbacks Callbacks)

UpdateHooks replaces the non-check callbacks used by the daemon.

The Check field is intentionally ignored; use SetChecker so checker changes always advance the generation and trigger a full traversal. Existing in-flight callbacks are synchronous, so this method is best called from outside daemon callbacks.

type KernelMark

type KernelMark struct {
	// HasMark reports whether BPF saw a live mark for the process.
	HasMark bool

	// Inherited reports whether the mark seen by BPF was inherited from a
	// parent rather than explicitly selected by Check.
	Inherited bool

	// Mark is meaningful when HasMark is true.
	Mark uint64

	// Priority is meaningful when HasMark is true. Higher values win when
	// userspace merges otherwise comparable process updates.
	Priority int8
}

KernelMark is the BPF program's view of a process mark at event time.

type ProcessEvent

type ProcessEvent struct {
	Type      string
	Key       ProcessKey
	ParentKey *ProcessKey
	Kernel    KernelMark
	Process   ProcessInfo
	Value     *ProcessValue
}

ProcessEvent describes a process transition that produced an effective mark state worth reporting.

Type is "fork", "exec", "exit", or "unknown". Fork and exec events are reported only when the process has an effective live mark after userspace reconciliation: a BPF mark, an existing userspace mirror entry, a new Check match, or fork inheritance from a marked parent. Unmarked fork and exec events are intentionally suppressed. Exit events are reported when BPF saw a live mark or userspace had a live mirror entry for the exiting process; the Value is a tombstone. Unknown events are reported for unexpected BPF event types and may have nil Value.

Process contains the best process metadata available at callback time. ParentKey is set for fork events and nil otherwise. Kernel is the raw BPF mark state from the event, before userspace Check and mirror reconciliation. Value is the effective userspace value after reconciliation; it is non-nil for reported fork and exit events.

type ProcessInfo

type ProcessInfo struct {
	Key     ProcessKey
	PPID    uint32
	Comm    string
	Cmdline string
	Exe     string
}

ProcessInfo is the userspace-enriched process view passed to callbacks.

During process-tree traversal it is read from /proc and normally includes PPID, Comm, Cmdline, and Exe. During fork and exit events the daemon first tries to refresh the data from /proc; if the process is already gone or the identity no longer matches, only Key, PPID, and Comm from the BPF event are guaranteed to be present. Cmdline and Exe may be empty in that case.

func ListProcesses

func ListProcesses() ([]ProcessInfo, error)

ListProcesses returns the current /proc process tree using the same process identity parsing as the daemon.

type ProcessKey

type ProcessKey = markProcessKey // public re-export from generated code

ProcessKey is the per-boot process-lifetime identity shared with BPF.

TGID is the process ID. StartTime is /proc/<pid>/stat field 22 expressed in USER_HZ ticks since boot. The pair is used instead of TGID alone because PIDs can be reused after exit.

type ProcessMapState

type ProcessMapState struct {
	Alive      int
	Tombstones int
	Latest     uint64
	Entries    map[ProcessKey]ProcessValue
	Procs      []ProcessInfo
}

ProcessMapState is a point-in-time view of the pinned process map plus procfs.

func GrabProcessMapState

func GrabProcessMapState(pinPath string) (ProcessMapState, error)

GrabProcessMapState reads the pinned processes map under pinPath.

type ProcessUpdate

type ProcessUpdate struct {
	Key   ProcessKey
	Value ProcessValue
}

ProcessUpdate is emitted after the userspace mirror and kernel map have been updated for a process key.

Updates can come from initial traversal, fork handling, exec handling, exit tombstoning, or event reconciliation. They are not emitted for unchanged values, for suppressed unmarked events, or when old tombstones are physically deleted during periodic cleanup.

type ProcessValue

type ProcessValue = markProcessValue // public re-export from generated code

ProcessValue is the effective mark state stored in the pinned process map.

A missing map entry, a live value with HasMark false, and a Tombstone value all mean "unmarked" for policy purposes. Live no-mark entries are retained after a process had an effective mark once, allowing newer checker rules to remove a mark without losing the process lifetime record. Tombstones are retained for a short grace period after exit so late events for an old process lifetime do not revive stale marks. Tombstone collection is the only operation that physically deletes entries.

The generated Inheritance field is true for an explicit/original mark chosen by Check and false for a mark inherited from a parent. HasMark gates whether Mark and Priority are currently meaningful and whether this value can be inherited. Generation records the checker generation that last reconciled the entry. When competing updates are merged, tombstones win first, higher generations win second, higher priorities win third, and timestamps order otherwise-equivalent values. Timestamp is in CLOCK_BOOTTIME nanoseconds and is also used to expire tombstones.

Directories

Path Synopsis
Command pmark runs the process-marking daemon or watches the daemon's pinned process map.
Command pmark runs the process-marking daemon or watches the daemon's pinned process map.
Package fwmark applies pmark process marks to Linux socket fwmarks.
Package fwmark applies pmark process marks to Linux socket fwmarks.
Package multirule provides a userspace-only rule tracker for pmark process callbacks.
Package multirule provides a userspace-only rule tracker for pmark process callbacks.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL