⬢ DragonFlyBSD Kernel Audit
DF-4507 / static_proof.log
← back to finding ↓ download raw
=== [1] The only vm_lowmem references in the whole kernel tree ===
# (expect: only ttm_page_alloc.c REGISTER/DEREGISTER — no DECLARATION, no INVOKE)
NO OTHER REFS: vm_lowmem is never declared/invoked anywhere
447:	manager->lowmem_handler = EVENTHANDLER_REGISTER(vm_lowmem,
453:	EVENTHANDLER_DEREGISTER(vm_lowmem, manager->lowmem_handler);

=== [2] Every EVENTHANDLER_INVOKE site in the kernel (none fire vm_lowmem) ===
sys/bus/u4b/usb_device.c:1351:EVENTHANDLER_INVOKE
sys/dev/acpica/acpi.c:3028:EVENTHANDLER_INVOKE
sys/dev/acpica/acpi.c:3040:EVENTHANDLER_INVOKE
sys/dev/acpica/acpi.c:3052:EVENTHANDLER_INVOKE
sys/dev/acpica/acpi.c:3064:EVENTHANDLER_INVOKE
sys/dev/acpica/acpi_lid.c:175:EVENTHANDLER_INVOKE
sys/dev/acpica/acpi_lid.c:177:EVENTHANDLER_INVOKE
sys/kern/kern_shutdown.c:278:EVENTHANDLER_INVOKE
sys/kern/kern_shutdown.c:402:EVENTHANDLER_INVOKE
sys/kern/kern_shutdown.c:405:EVENTHANDLER_INVOKE
sys/kern/subr_power.c:105:EVENTHANDLER_INVOKE
sys/net/bpf.c:299:EVENTHANDLER_INVOKE
sys/net/bpf.c:328:EVENTHANDLER_INVOKE
sys/net/if.c:1120:EVENTHANDLER_INVOKE
sys/net/if.c:1138:EVENTHANDLER_INVOKE
sys/net/if.c:1190:EVENTHANDLER_INVOKE
sys/net/if.c:1227:EVENTHANDLER_INVOKE
sys/net/if.c:1822:EVENTHANDLER_INVOKE
sys/net/if.c:1844:EVENTHANDLER_INVOKE
sys/net/if.c:1860:EVENTHANDLER_INVOKE
sys/net/if.c:2206:EVENTHANDLER_INVOKE
sys/net/if.c:2232:EVENTHANDLER_INVOKE
sys/net/if.c:2382:EVENTHANDLER_INVOKE
sys/net/if.c:750:EVENTHANDLER_INVOKE
sys/net/if.c:958:EVENTHANDLER_INVOKE
sys/net/if_clone.c:180:EVENTHANDLER_INVOKE
sys/net/lagg/if_lagg.c:261:EVENTHANDLER_INVOKE
sys/net/lagg/if_lagg.c:287:EVENTHANDLER_INVOKE
sys/net/lagg/if_lagg.c:473:EVENTHANDLER_INVOKE
sys/net/tap/if_tap.c:433:EVENTHANDLER_INVOKE
sys/net/tun/if_tun.c:330:EVENTHANDLER_INVOKE
sys/netinet/in.c:634:EVENTHANDLER_INVOKE
sys/netinet/in.c:691:EVENTHANDLER_INVOKE
sys/netinet/in.c:726:EVENTHANDLER_INVOKE
sys/netinet6/in6.c:803:EVENTHANDLER_INVOKE
sys/netinet6/in6.c:852:EVENTHANDLER_INVOKE
sys/sys/eventhandler.h:114:EVENTHANDLER_INVOKE
COUNT=0: EVENTHANDLER_INVOKE(vm_lowmem) does not exist

=== [3] register_shrinker is never defined (only called from dead code) ===
sys/dev/drm/i915/i915_gem_shrinker.c:525:	WARN_ON(register_shrinker(&i915->mm.shrinker));
sys/dev/drm/i915/i915_gem_shrinker.c:546:	unregister_shrinker(&i915->mm.shrinker);
sys/dev/drm/ttm/ttm_page_alloc_dma.c:161: * @shrinker: The structure used by [un|]register_shrinker
sys/dev/drm/ttm/ttm_page_alloc_dma.c:1149:	return register_shrinker(&manager->mm_shrink);
sys/dev/drm/ttm/ttm_page_alloc_dma.c:1154:	unregister_shrinker(&manager->mm_shrink);
# i915's call is inside '#if 0':
	i915->mm.shrinker.seeks = DEFAULT_SEEKS;
#if 0
	i915->mm.shrinker.batch = 4096;
#endif
#if 0
	WARN_ON(register_shrinker(&i915->mm.shrinker));

	i915->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
	WARN_ON(register_oom_notifier(&i915->mm.oom_notifier));

	i915->mm.vmap_notifier.notifier_call = i915_gem_shrinker_vmap;
	WARN_ON(register_vmap_purge_notifier(&i915->mm.vmap_notifier));
#endif
# dma pool variant is preprocessed out:
 */

#if defined(CONFIG_SWIOTLB) || defined(CONFIG_INTEL_IOMMU)
#define pr_fmt(fmt) "[TTM] " fmt

# the shrinker shim defines types only — no registration API:
#include <linux/types.h>

struct shrink_control {
	gfp_t gfp_mask;
	unsigned long nr_to_scan;
};

struct shrinker {
	unsigned long (*count_objects)(struct shrinker *,
				       struct shrink_control *sc);
	unsigned long (*scan_objects)(struct shrinker *,
				      struct shrink_control *sc);
	int seeks;
};

#define DEFAULT_SEEKS	2

#define SHRINK_STOP	(~0UL)

#endif	/* _LINUX_SHRINKER_H_ */

=== [4] ttm_page_alloc.c itself is LIVE (no guard) and registers the callback ===
static void ttm_pool_mm_shrink_init(struct ttm_pool_manager *manager)
{
	manager->mm_shrink.count_objects = ttm_pool_shrink_count;
	manager->mm_shrink.scan_objects = ttm_pool_shrink_scan;
	manager->mm_shrink.seeks = 1;
	manager->lowmem_handler = EVENTHANDLER_REGISTER(vm_lowmem,
	    ttm_pool_shrink_scan, manager, EVENTHANDLER_PRI_ANY);
}

static void ttm_pool_mm_shrink_fini(struct ttm_pool_manager *manager)
{
	EVENTHANDLER_DEREGISTER(vm_lowmem, manager->lowmem_handler);
}

=== [5] The only LIVE reclamation path: put-path trim at options.max_size ===
	/* Check that we don't go over the pool limit */
	npages = 0;
	if (pool->npages > _manager->options.max_size) {
		npages = pool->npages - _manager->options.max_size;
		/* free at least NUM_PAGES_TO_ALLOC number of pages
		 * to reduce calls to set_memory_wb */
		if (npages < NUM_PAGES_TO_ALLOC)
			npages = NUM_PAGES_TO_ALLOC;
	}
	spin_unlock_irqrestore(&pool->lock, irq_flags);
	if (npages)
		ttm_page_pool_free(pool, npages, false);
}
# max_size source (half the kernel zone, in pages):
			zone->name, (unsigned long long)zone->max_mem >> 10);
	}
	ttm_page_alloc_init(glob, glob->zone_kernel->max_mem/(2*PAGE_SIZE));
	ttm_dma_page_alloc_init(glob, glob->zone_kernel->max_mem/(2*PAGE_SIZE));
	return 0;

=== [6] Signature landmine if the event ever gets wired naively ===
# vm_lowmem handlers would be invoked as func(arg, <int>); the registered
# ttm_pool_shrink_scan expects (struct shrinker *, struct shrink_control *)
# and dereferences sc at line 398 (sc->gfp_mask = M_WAITOK) and 418:
static unsigned long
ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
{
	static DEFINE_MUTEX(lock);
	static unsigned start_pool;
	unsigned i;
	unsigned pool_offset;
	struct ttm_page_pool *pool;
	int shrink_pages = 100; /* XXXKIB */
	unsigned long freed = 0;
	unsigned int nr_free_pool;

#ifdef __DragonFly__
	sc->gfp_mask = M_WAITOK;
#endif

	if (!mutex_trylock(&lock))
		return SHRINK_STOP;
	pool_offset = ++start_pool % NUM_POOLS;
	/* select start pool in round robin fashion */
	for (i = 0; i < NUM_POOLS; ++i) {
		unsigned nr_free = shrink_pages;
		unsigned page_nr;

		if (shrink_pages == 0)
			break;

		pool = &_manager->pools[(i + pool_offset)%NUM_POOLS];
		page_nr = (1 << pool->order);
		/* OK to use static buffer since global mutex is held. */
		nr_free_pool = roundup(nr_free, page_nr) >> pool->order;
		shrink_pages = ttm_page_pool_free(pool, nr_free_pool, true);
		freed += (nr_free_pool - shrink_pages) << pool->order;
		if (freed >= sc->nr_to_scan)
			break;
		shrink_pages <<= pool->order;
	}
	mutex_unlock(&lock);
	return freed;
}