1{ config, lib, pkgs, ... }:
2with lib;
3
4let
5 cfg = config.environment.memoryAllocator;
6
7 # The set of alternative malloc(3) providers.
8 providers = {
9 graphene-hardened = {
10 libPath = "${pkgs.graphene-hardened-malloc}/lib/libhardened_malloc.so";
11 description = ''
12 An allocator designed to mitigate memory corruption attacks, such as
13 those caused by use-after-free bugs.
14 '';
15 };
16
17 jemalloc = {
18 libPath = "${pkgs.jemalloc}/lib/libjemalloc.so";
19 description = ''
20 A general purpose allocator that emphasizes fragmentation avoidance
21 and scalable concurrency support.
22 '';
23 };
24
25 scudo = {
26 libPath = "${pkgs.llvmPackages_latest.compiler-rt}/lib/linux/libclang_rt.scudo-x86_64.so";
27 description = ''
28 A user-mode allocator based on LLVM Sanitizer’s CombinedAllocator,
29 which aims at providing additional mitigations against heap based
30 vulnerabilities, while maintaining good performance.
31 '';
32 };
33
34 mimalloc = {
35 libPath = "${pkgs.mimalloc}/lib/libmimalloc.so";
36 description = ''
37 A compact and fast general purpose allocator, which may
38 optionally be built with mitigations against various heap
39 vulnerabilities.
40 '';
41 };
42 };
43
44 providerConf = providers.${cfg.provider};
45
46 # An output that contains only the shared library, to avoid
47 # needlessly bloating the system closure
48 mallocLib = pkgs.runCommand "malloc-provider-${cfg.provider}"
49 rec {
50 preferLocalBuild = true;
51 allowSubstitutes = false;
52 origLibPath = providerConf.libPath;
53 libName = baseNameOf origLibPath;
54 }
55 ''
56 mkdir -p $out/lib
57 cp -L $origLibPath $out/lib/$libName
58 '';
59
60 # The full path to the selected provider shlib.
61 providerLibPath = "${mallocLib}/lib/${mallocLib.libName}";
62in
63
64{
65 meta = {
66 maintainers = [ maintainers.joachifm ];
67 };
68
69 options = {
70 environment.memoryAllocator.provider = mkOption {
71 type = types.enum ([ "libc" ] ++ attrNames providers);
72 default = "libc";
73 description = ''
74 The system-wide memory allocator.
75
76 Briefly, the system-wide memory allocator providers are:
77 <itemizedlist>
78 <listitem><para><literal>libc</literal>: the standard allocator provided by libc</para></listitem>
79 ${toString (mapAttrsToList
80 (name: value: "<listitem><para><literal>${name}</literal>: ${value.description}</para></listitem>")
81 providers)}
82 </itemizedlist>
83
84 <warning>
85 <para>
86 Selecting an alternative allocator (i.e., anything other than
87 <literal>libc</literal>) may result in instability, data loss,
88 and/or service failure.
89 </para>
90 </warning>
91 '';
92 };
93 };
94
95 config = mkIf (cfg.provider != "libc") {
96 environment.etc."ld-nix.so.preload".text = ''
97 ${providerLibPath}
98 '';
99 security.apparmor.includes = {
100 "abstractions/base" = ''
101 r /etc/ld-nix.so.preload,
102 r ${config.environment.etc."ld-nix.so.preload".source},
103 include "${pkgs.apparmorRulesFromClosure {
104 name = "mallocLib";
105 baseRules = ["mr $path/lib/**.so*"];
106 } [ mallocLib ] }"
107 '';
108 };
109 };
110}