1616#include < sys/syscall.h>
1717#include < unistd.h>
1818#include < linux/landlock.h>
19+ #include < seccomp.h>
1920#include < system_error>
2021#include < unordered_set>
2122#include < utility>
@@ -114,21 +115,6 @@ void install_landlock() {
114115 allow_path (ruleset_fd, " /tmp" , RW);
115116 allow_path (ruleset_fd, " /dev" , RW); // needed for /dev/null etc, used e.g., by triton
116117
117- // Prevent ptrace and /proc/self/mem tampering
118- if (prctl (PR_SET_DUMPABLE, 0 ) < 0 ) {
119- throw std::system_error (errno, std::system_category (), " prctl(PR_SET_DUMPABLE)" );
120- }
121-
122- // Prevent gaining privileges (if attacker tries setuid exploits)
123- if (prctl (PR_SET_NO_NEW_PRIVS, 1 , 0 , 0 , 0 ) < 0 ) {
124- throw std::system_error (errno, std::system_category (), " prctl(PR_SET_NO_NEW_PRIVS)" );
125- };
126- // no new executable code pages
127- // note: this also prevents thread creating, which breaks torch.compile
128- // workaround: run torch.compile once from trusted python code, then the thread already
129- // exists at this point. does not seem reliable, so disabled for now
130- // prctl(PR_SET_MDWE, PR_MDWE_REFUSE_EXEC_GAIN, 0, 0, 0);
131-
132118 landlock_restrict_self (ruleset_fd, 0 );
133119}
134120
@@ -192,4 +178,63 @@ void seal_executable_mappings() {
192178 for (auto & r : to_seal) {
193179 mseal (reinterpret_cast <void *>(r.start ), r.end - r.start , r.src );
194180 }
195- }
181+ }
182+
183+ static inline void check_seccomp (int rc, const char * what) {
184+ if (rc < 0 )
185+ throw std::system_error (-rc, std::generic_category (), what);
186+ }
187+
188+ void setup_seccomp_filter (scmp_filter_ctx ctx) {
189+ check_seccomp (seccomp_rule_add (ctx, SCMP_ACT_ERRNO (EPERM), SCMP_SYS (ptrace), 0 ),
190+ " block ptrace" );
191+
192+ check_seccomp (seccomp_rule_add (ctx, SCMP_ACT_ERRNO (EPERM), SCMP_SYS (prctl), 2 ,
193+ SCMP_A0 (SCMP_CMP_EQ, PR_SET_DUMPABLE),
194+ SCMP_A1 (SCMP_CMP_EQ, 1 )),
195+ " block prctl(SET_DUMPABLE, 1)" );
196+
197+ check_seccomp (seccomp_rule_add (ctx, SCMP_ACT_ERRNO (EPERM), SCMP_SYS (prctl), 1 ,
198+ SCMP_A0 (SCMP_CMP_EQ, PR_SET_SECCOMP)),
199+ " block prctl(SET_SECCOMP)" );
200+ // TODO figure out what else we can and should block
201+ /*
202+ check_seccomp(seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(mprotect), 1,
203+ SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_WRITE, PROT_WRITE)),
204+ "block mprotect+WRITE");
205+
206+ check_seccomp(seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(pkey_mprotect), 1,
207+ SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_WRITE, PROT_WRITE)),
208+ "block pkey_mprotect+WRITE");
209+ */
210+ }
211+
212+ void install_seccomp_filter () {
213+ scmp_filter_ctx ctx = seccomp_init (SCMP_ACT_ALLOW);
214+ if (!ctx) throw std::runtime_error (" seccomp_init failed" );
215+ try {
216+ setup_seccomp_filter (ctx);
217+ } catch (...) {
218+ seccomp_release (ctx);
219+ throw ;
220+ }
221+
222+ // Prevent ptrace and /proc/self/mem tampering
223+ if (prctl (PR_SET_DUMPABLE, 0 ) < 0 ) {
224+ throw std::system_error (errno, std::system_category (), " prctl(PR_SET_DUMPABLE)" );
225+ }
226+
227+ // Prevent gaining privileges (if attacker tries setuid exploits)
228+ if (prctl (PR_SET_NO_NEW_PRIVS, 1 , 0 , 0 , 0 ) < 0 ) {
229+ throw std::system_error (errno, std::system_category (), " prctl(PR_SET_NO_NEW_PRIVS)" );
230+ };
231+ // no new executable code pages
232+ // note: this also prevents thread creating, which breaks torch.compile
233+ // workaround: run torch.compile once from trusted python code, then the thread already
234+ // exists at this point. does not seem reliable, so disabled for now
235+ // prctl(PR_SET_MDWE, PR_MDWE_REFUSE_EXEC_GAIN, 0, 0, 0);
236+
237+ int rc = seccomp_load (ctx);
238+ seccomp_release (ctx);
239+ check_seccomp (rc, " seccomp_load" );
240+ }
0 commit comments