1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.environment.memoryAllocator;
9
10 # The set of alternative malloc(3) providers.
11 providers = {
12 graphene-hardened = {
13 libPath = "${pkgs.graphene-hardened-malloc}/lib/libhardened_malloc.so";
14 description = ''
15 Hardened memory allocator coming from GrapheneOS project.
16 The default configuration template has all normal optional security
17 features enabled and is quite aggressive in terms of sacrificing
18 performance and memory usage for security.
19 '';
20 };
21
22 graphene-hardened-light = {
23 libPath = "${pkgs.graphene-hardened-malloc}/lib/libhardened_malloc-light.so";
24 description = ''
25 Hardened memory allocator coming from GrapheneOS project.
26 The light configuration template disables the slab quarantines,
27 write after free check, slot randomization and raises the guard
28 slab interval from 1 to 8 but leaves zero-on-free and slab canaries enabled.
29 The light configuration has solid performance and memory usage while still
30 being far more secure than mainstream allocators with much better security
31 properties.
32 '';
33 };
34
35 jemalloc = {
36 libPath = "${pkgs.jemalloc}/lib/libjemalloc.so";
37 description = ''
38 A general purpose allocator that emphasizes fragmentation avoidance
39 and scalable concurrency support.
40 '';
41 };
42
43 scudo =
44 let
45 platformMap = {
46 aarch64-linux = "aarch64";
47 x86_64-linux = "x86_64";
48 };
49
50 systemPlatform =
51 platformMap.${pkgs.stdenv.hostPlatform.system}
52 or (throw "scudo not supported on ${pkgs.stdenv.hostPlatform.system}");
53 in
54 {
55 libPath = "${pkgs.llvmPackages_14.compiler-rt}/lib/linux/libclang_rt.scudo-${systemPlatform}.so";
56 description = ''
57 A user-mode allocator based on LLVM Sanitizer’s CombinedAllocator,
58 which aims at providing additional mitigations against heap based
59 vulnerabilities, while maintaining good performance.
60 '';
61 };
62
63 mimalloc = {
64 libPath = "${pkgs.mimalloc}/lib/libmimalloc.so";
65 description = ''
66 A compact and fast general purpose allocator, which may
67 optionally be built with mitigations against various heap
68 vulnerabilities.
69 '';
70 };
71 };
72
73 providerConf = providers.${cfg.provider};
74
75 # An output that contains only the shared library, to avoid
76 # needlessly bloating the system closure
77 mallocLib =
78 pkgs.runCommand "malloc-provider-${cfg.provider}"
79 rec {
80 preferLocalBuild = true;
81 allowSubstitutes = false;
82 origLibPath = providerConf.libPath;
83 libName = baseNameOf origLibPath;
84 }
85 ''
86 mkdir -p $out/lib
87 cp -L $origLibPath $out/lib/$libName
88 '';
89
90 # The full path to the selected provider shlib.
91 providerLibPath = "${mallocLib}/lib/${mallocLib.libName}";
92in
93
94{
95 meta = {
96 maintainers = [ lib.maintainers.joachifm ];
97 };
98
99 options = {
100 environment.memoryAllocator.provider = lib.mkOption {
101 type = lib.types.enum ([ "libc" ] ++ lib.attrNames providers);
102 default = "libc";
103 description = ''
104 The system-wide memory allocator.
105
106 Briefly, the system-wide memory allocator providers are:
107
108 - `libc`: the standard allocator provided by libc
109 ${lib.concatStringsSep "\n" (
110 lib.mapAttrsToList (
111 name: value: "- `${name}`: ${lib.replaceStrings [ "\n" ] [ " " ] value.description}"
112 ) providers
113 )}
114
115 ::: {.warning}
116 Selecting an alternative allocator (i.e., anything other than
117 `libc`) may result in instability, data loss,
118 and/or service failure.
119 :::
120 '';
121 };
122 };
123
124 config = lib.mkIf (cfg.provider != "libc") {
125 environment.etc."ld-nix.so.preload".text = ''
126 ${providerLibPath}
127 '';
128 security.apparmor.includes = {
129 "abstractions/base" = ''
130 r /etc/ld-nix.so.preload,
131 r ${config.environment.etc."ld-nix.so.preload".source},
132 include "${
133 pkgs.apparmorRulesFromClosure {
134 name = "mallocLib";
135 baseRules = [ "mr $path/lib/**.so*" ];
136 } [ mallocLib ]
137 }"
138 '';
139 };
140 };
141}