1 /*- 2 * Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <sys/cdefs.h> 8 #include "opt_mac.h" 9 10 #include <sys/param.h> 11 #include <sys/condvar.h> 12 #include <sys/imgact.h> 13 #include <sys/jail.h> 14 #include <sys/kernel.h> 15 #include <sys/lock.h> 16 #include <sys/malloc.h> 17 #include <sys/mutex.h> 18 #include <sys/mac.h> 19 #include <sys/proc.h> 20 #include <sys/sbuf.h> 21 #include <sys/sdt.h> 22 #include <sys/systm.h> 23 #include <sys/vnode.h> 24 #include <sys/mount.h> 25 #include <sys/file.h> 26 #include <sys/namei.h> 27 #include <sys/sysctl.h> 28 29 #include <security/mac/mac_framework.h> 30 #include <security/mac/mac_internal.h> 31 #include <security/mac/mac_policy.h> 32 33 void 34 mac_prison_label_free(struct label *label) 35 { 36 if (label == NULL) 37 return; 38 39 MAC_POLICY_PERFORM_NOSLEEP(prison_destroy_label, label); 40 mac_labelzone_free(label); 41 } 42 43 struct label * 44 mac_prison_label_alloc(int flag) 45 { 46 struct label *label; 47 int error; 48 49 label = mac_labelzone_alloc(flag); 50 if (label == NULL) 51 return (NULL); 52 53 if (flag & M_WAITOK) 54 MAC_POLICY_CHECK(prison_init_label, label, flag); 55 else 56 MAC_POLICY_CHECK_NOSLEEP(prison_init_label, label, flag); 57 if (error) { 58 mac_prison_label_free(label); 59 return (NULL); 60 } 61 return (label); 62 } 63 64 /* 65 * The caller's expecting us to return with the prison locked if we were 66 * successful, since we're also setting pr->pr_label. On error, it remains 67 * unlocked. 68 */ 69 int 70 mac_prison_init(struct prison *pr, int flag) 71 { 72 struct label *prlabel; 73 74 mtx_assert(&pr->pr_mtx, MA_NOTOWNED); 75 if ((mac_labeled & MPC_OBJECT_PRISON) == 0) { 76 mtx_lock(&pr->pr_mtx); 77 pr->pr_label = NULL; 78 return (0); 79 } 80 81 prlabel = mac_prison_label_alloc(flag); 82 if (prlabel == NULL) { 83 KASSERT((flag & M_WAITOK) == 0, 84 ("MAC policy prison_init_label failed under M_WAITOK")); 85 return (ENOMEM); 86 } 87 88 mtx_lock(&pr->pr_mtx); 89 pr->pr_label = prlabel; 90 return (0); 91 } 92 93 void 94 mac_prison_destroy(struct prison *pr) 95 { 96 mtx_assert(&pr->pr_mtx, MA_OWNED); 97 mac_prison_label_free(pr->pr_label); 98 pr->pr_label = NULL; 99 } 100 101 void 102 mac_prison_copy_label(struct label *src, struct label *dest) 103 { 104 105 MAC_POLICY_PERFORM_NOSLEEP(prison_copy_label, src, dest); 106 } 107 108 int 109 mac_prison_externalize_label(struct label *label, char *elements, 110 char *outbuf, size_t outbuflen) 111 { 112 int error; 113 114 MAC_POLICY_EXTERNALIZE(prison, label, elements, outbuf, outbuflen); 115 return (error); 116 } 117 118 int 119 mac_prison_internalize_label(struct label *label, char *string) 120 { 121 int error; 122 123 MAC_POLICY_INTERNALIZE(prison, label, string); 124 return (error); 125 } 126 127 void 128 mac_prison_relabel(struct ucred *cred, struct prison *pr, 129 struct label *newlabel) 130 { 131 mtx_assert(&pr->pr_mtx, MA_OWNED); 132 MAC_POLICY_PERFORM_NOSLEEP(prison_relabel, cred, pr, pr->pr_label, 133 newlabel); 134 } 135 136 int 137 mac_prison_label_set(struct ucred *cred, struct prison *pr, 138 struct label *label) 139 { 140 int error; 141 142 mtx_assert(&pr->pr_mtx, MA_OWNED); 143 144 error = mac_prison_check_relabel(cred, pr, label); 145 if (error) 146 return (error); 147 148 mac_prison_relabel(cred, pr, label); 149 150 return (0); 151 } 152 153 MAC_CHECK_PROBE_DEFINE4(prison_check_relabel, "struct ucred *", 154 "struct prison *", "struct label *", "struct label *"); 155 int 156 mac_prison_check_relabel(struct ucred *cred, struct prison *pr, 157 struct label *newlabel) 158 { 159 int error; 160 161 mtx_assert(&pr->pr_mtx, MA_OWNED); 162 MAC_POLICY_CHECK_NOSLEEP(prison_check_relabel, cred, pr, 163 pr->pr_label, newlabel); 164 MAC_CHECK_PROBE4(prison_check_relabel, error, cred, pr, 165 pr->pr_label, newlabel); 166 167 return (error); 168 } 169 170 MAC_CHECK_PROBE_DEFINE3(prison_check_attach, "struct ucred *", 171 "struct prison *", "struct label *"); 172 int 173 mac_prison_check_attach(struct ucred *cred, struct prison *pr) 174 { 175 int error; 176 177 MAC_POLICY_CHECK_NOSLEEP(prison_check_attach, cred, pr, pr->pr_label); 178 MAC_CHECK_PROBE3(prison_check_attach, error, cred, pr, pr->pr_label); 179 180 return (error); 181 } 182 183 MAC_CHECK_PROBE_DEFINE3(prison_check_create, "struct ucred *", 184 "struct vfsoptlist *", "int"); 185 int 186 mac_prison_check_create(struct ucred *cred, struct vfsoptlist *opts, 187 int flags) 188 { 189 int error; 190 191 MAC_POLICY_CHECK_NOSLEEP(prison_check_create, cred, opts, flags); 192 MAC_CHECK_PROBE3(prison_check_create, error, cred, opts, flags); 193 194 return (error); 195 } 196 197 MAC_CHECK_PROBE_DEFINE5(prison_check_get, "struct ucred *", 198 "struct prison *", "struct label *", "struct vfsoptlist *", "int"); 199 int 200 mac_prison_check_get(struct ucred *cred, struct prison *pr, 201 struct vfsoptlist *opts, int flags) 202 { 203 int error; 204 205 MAC_POLICY_CHECK_NOSLEEP(prison_check_get, cred, pr, pr->pr_label, 206 opts, flags); 207 MAC_CHECK_PROBE5(prison_check_get, error, cred, pr, pr->pr_label, opts, 208 flags); 209 210 return (error); 211 } 212 213 MAC_CHECK_PROBE_DEFINE5(prison_check_set, "struct ucred *", 214 "struct prison *", "struct label *", "struct vfsoptlist *", "int"); 215 int 216 mac_prison_check_set(struct ucred *cred, struct prison *pr, 217 struct vfsoptlist *opts, int flags) 218 { 219 int error; 220 221 MAC_POLICY_CHECK_NOSLEEP(prison_check_set, cred, pr, pr->pr_label, 222 opts, flags); 223 MAC_CHECK_PROBE5(prison_check_set, error, cred, pr, pr->pr_label, opts, 224 flags); 225 226 return (error); 227 } 228 229 MAC_CHECK_PROBE_DEFINE3(prison_check_remove, "struct ucred *", 230 "struct prison *", "struct label *"); 231 int 232 mac_prison_check_remove(struct ucred *cred, struct prison *pr) 233 { 234 int error; 235 236 MAC_POLICY_CHECK_NOSLEEP(prison_check_remove, cred, pr, pr->pr_label); 237 MAC_CHECK_PROBE3(prison_check_remove, error, cred, pr, pr->pr_label); 238 239 return (error); 240 } 241 242 void 243 mac_prison_created(struct ucred *cred, struct prison *pr) 244 { 245 246 MAC_POLICY_PERFORM(prison_created, cred, pr, pr->pr_label); 247 } 248 249 void 250 mac_prison_attached(struct ucred *cred, struct prison *pr, struct proc *p) 251 { 252 253 MAC_POLICY_PERFORM(prison_attached, cred, pr, pr->pr_label, p, 254 p->p_label); 255 } 256