Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

apparmor: add user namespace creation mediation

Unprivileged user namespace creation is often used as a first step
in privilege escalation attacks. Instead of disabling it at the
sysrq level, which blocks its legitimate use as for setting up a sandbox,
allow control on a per domain basis.

This allows an admin to quickly lock down a system while also still
allowing legitimate use.

Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>

+75 -2
+1
security/apparmor/apparmorfs.c
··· 2375 2375 static struct aa_sfs_entry aa_sfs_entry_ns[] = { 2376 2376 AA_SFS_FILE_BOOLEAN("profile", 1), 2377 2377 AA_SFS_FILE_BOOLEAN("pivot_root", 0), 2378 + AA_SFS_FILE_STRING("mask", "userns_create"), 2378 2379 { } 2379 2380 }; 2380 2381
+1 -1
security/apparmor/audit.c
··· 58 58 "io_uring", 59 59 "module", 60 60 "lsm", 61 - "unknown", 61 + "namespace", 62 62 "unknown", 63 63 "unknown", 64 64 "unknown",
+1
security/apparmor/include/apparmor.h
··· 33 33 #define AA_CLASS_IO_URING 18 34 34 #define AA_CLASS_MODULE 19 35 35 #define AA_CLASS_DISPLAY_LSM 20 36 + #define AA_CLASS_NS 21 36 37 37 38 #define AA_CLASS_X 31 38 39 #define AA_CLASS_DBUS 32
+1
security/apparmor/include/audit.h
··· 103 103 #define OP_PROF_LOAD "profile_load" 104 104 #define OP_PROF_RM "profile_remove" 105 105 106 + #define OP_USERNS_CREATE "userns_create" 106 107 107 108 struct apparmor_audit_data { 108 109 int error;
+6
security/apparmor/include/task.h
··· 96 96 u32 request); 97 97 98 98 99 + 100 + #define AA_USERNS_CREATE 8 101 + 102 + int aa_profile_ns_perm(struct aa_profile *profile, 103 + struct apparmor_audit_data *ad, u32 request); 104 + 99 105 #endif /* __AA_TASK_H */
+24 -1
security/apparmor/lsm.c
··· 836 836 return error; 837 837 } 838 838 839 + static int apparmor_userns_create(const struct cred *cred) 840 + { 841 + struct aa_label *label; 842 + struct aa_profile *profile; 843 + int error = 0; 844 + DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_TASK, AA_CLASS_NS, 845 + OP_USERNS_CREATE); 846 + 847 + ad.subj_cred = current_cred(); 848 + 849 + label = begin_current_label_crit_section(); 850 + if (!unconfined(label)) { 851 + error = fn_for_each(label, profile, 852 + aa_profile_ns_perm(profile, &ad, 853 + AA_USERNS_CREATE)); 854 + } 855 + end_current_label_crit_section(label); 856 + 857 + return error; 858 + } 859 + 839 860 /** 840 861 * apparmor_sk_alloc_security - allocate and attach the sk_security field 841 862 */ ··· 1334 1313 LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid_obj), 1335 1314 LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), 1336 1315 LSM_HOOK_INIT(task_kill, apparmor_task_kill), 1316 + LSM_HOOK_INIT(userns_create, apparmor_userns_create), 1337 1317 1338 1318 #ifdef CONFIG_AUDIT 1339 1319 LSM_HOOK_INIT(audit_rule_init, aa_audit_rule_init), ··· 1806 1784 } 1807 1785 1808 1786 static struct ctl_table apparmor_sysctl_table[] = { 1787 + #ifdef CONFIG_USER_NS 1809 1788 { 1810 1789 .procname = "unprivileged_userns_apparmor_policy", 1811 1790 .data = &unprivileged_userns_apparmor_policy, ··· 1814 1791 .mode = 0600, 1815 1792 .proc_handler = apparmor_dointvec, 1816 1793 }, 1794 + #endif /* CONFIG_USER_NS */ 1817 1795 { 1818 1796 .procname = "apparmor_display_secid_mode", 1819 1797 .data = &apparmor_display_secid_mode, ··· 1829 1805 .mode = 0600, 1830 1806 .proc_handler = apparmor_dointvec, 1831 1807 }, 1832 - 1833 1808 { } 1834 1809 }; 1835 1810
+41
security/apparmor/task.c
··· 298 298 profile_tracee_perm(tracee_cred, profile, tracer, 299 299 xrequest, &sa)); 300 300 } 301 + 302 + /* call back to audit ptrace fields */ 303 + static void audit_ns_cb(struct audit_buffer *ab, void *va) 304 + { 305 + struct apparmor_audit_data *ad = aad_of_va(va); 306 + 307 + if (ad->request & AA_USERNS_CREATE) 308 + audit_log_format(ab, " requested=\"userns_create\""); 309 + 310 + if (ad->denied & AA_USERNS_CREATE) 311 + audit_log_format(ab, " denied=\"userns_create\""); 312 + } 313 + 314 + int aa_profile_ns_perm(struct aa_profile *profile, 315 + struct apparmor_audit_data *ad, 316 + u32 request) 317 + { 318 + struct aa_perms perms = { }; 319 + int error = 0; 320 + 321 + ad->subj_label = &profile->label; 322 + ad->request = request; 323 + 324 + if (!profile_unconfined(profile)) { 325 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 326 + typeof(*rules), 327 + list); 328 + aa_state_t state; 329 + 330 + state = RULE_MEDIATES(rules, ad->class); 331 + if (!state) 332 + /* TODO: add flag to complain about unmediated */ 333 + return 0; 334 + perms = *aa_lookup_perms(rules->policy, state); 335 + aa_apply_modes_to_perms(profile, &perms); 336 + error = aa_check_perms(profile, &perms, request, ad, 337 + audit_ns_cb); 338 + } 339 + 340 + return error; 341 + }