1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 4 */ 5 #include <linux/fs.h> 6 #include <linux/namei.h> 7 #include <linux/types.h> 8 #include <linux/dcache.h> 9 #include <linux/security.h> 10 11 #include "ipe.h" 12 #include "policy.h" 13 #include "eval.h" 14 #include "fs.h" 15 16 #define MAX_VERSION_SIZE ARRAY_SIZE("65535.65535.65535") 17 18 /** 19 * ipefs_file - defines a file in securityfs. 20 */ 21 struct ipefs_file { 22 const char *name; 23 umode_t access; 24 const struct file_operations *fops; 25 }; 26 27 /** 28 * read_pkcs7() - Read handler for "ipe/policies/$name/pkcs7". 29 * @f: Supplies a file structure representing the securityfs node. 30 * @data: Supplies a buffer passed to the write syscall. 31 * @len: Supplies the length of @data. 32 * @offset: unused. 33 * 34 * @data will be populated with the pkcs7 blob representing the policy 35 * on success. If the policy is unsigned (like the boot policy), this 36 * will return -ENOENT. 37 * 38 * Return: 39 * * Length of buffer written - Success 40 * * %-ENOENT - Policy initializing/deleted or is unsigned 41 */ 42 static ssize_t read_pkcs7(struct file *f, char __user *data, 43 size_t len, loff_t *offset) 44 { 45 const struct ipe_policy *p = NULL; 46 struct inode *root = NULL; 47 int rc = 0; 48 49 root = d_inode(f->f_path.dentry->d_parent); 50 51 inode_lock_shared(root); 52 p = (struct ipe_policy *)root->i_private; 53 if (!p) { 54 rc = -ENOENT; 55 goto out; 56 } 57 58 if (!p->pkcs7) { 59 rc = -ENOENT; 60 goto out; 61 } 62 63 rc = simple_read_from_buffer(data, len, offset, p->pkcs7, p->pkcs7len); 64 65 out: 66 inode_unlock_shared(root); 67 68 return rc; 69 } 70 71 /** 72 * read_policy() - Read handler for "ipe/policies/$name/policy". 73 * @f: Supplies a file structure representing the securityfs node. 74 * @data: Supplies a buffer passed to the write syscall. 75 * @len: Supplies the length of @data. 76 * @offset: unused. 77 * 78 * @data will be populated with the plain-text version of the policy 79 * on success. 80 * 81 * Return: 82 * * Length of buffer written - Success 83 * * %-ENOENT - Policy initializing/deleted 84 */ 85 static ssize_t read_policy(struct file *f, char __user *data, 86 size_t len, loff_t *offset) 87 { 88 const struct ipe_policy *p = NULL; 89 struct inode *root = NULL; 90 int rc = 0; 91 92 root = d_inode(f->f_path.dentry->d_parent); 93 94 inode_lock_shared(root); 95 p = (struct ipe_policy *)root->i_private; 96 if (!p) { 97 rc = -ENOENT; 98 goto out; 99 } 100 101 rc = simple_read_from_buffer(data, len, offset, p->text, p->textlen); 102 103 out: 104 inode_unlock_shared(root); 105 106 return rc; 107 } 108 109 /** 110 * read_name() - Read handler for "ipe/policies/$name/name". 111 * @f: Supplies a file structure representing the securityfs node. 112 * @data: Supplies a buffer passed to the write syscall. 113 * @len: Supplies the length of @data. 114 * @offset: unused. 115 * 116 * @data will be populated with the policy_name attribute on success. 117 * 118 * Return: 119 * * Length of buffer written - Success 120 * * %-ENOENT - Policy initializing/deleted 121 */ 122 static ssize_t read_name(struct file *f, char __user *data, 123 size_t len, loff_t *offset) 124 { 125 const struct ipe_policy *p = NULL; 126 struct inode *root = NULL; 127 int rc = 0; 128 129 root = d_inode(f->f_path.dentry->d_parent); 130 131 inode_lock_shared(root); 132 p = (struct ipe_policy *)root->i_private; 133 if (!p) { 134 rc = -ENOENT; 135 goto out; 136 } 137 138 rc = simple_read_from_buffer(data, len, offset, p->parsed->name, 139 strlen(p->parsed->name)); 140 141 out: 142 inode_unlock_shared(root); 143 144 return rc; 145 } 146 147 /** 148 * read_version() - Read handler for "ipe/policies/$name/version". 149 * @f: Supplies a file structure representing the securityfs node. 150 * @data: Supplies a buffer passed to the write syscall. 151 * @len: Supplies the length of @data. 152 * @offset: unused. 153 * 154 * @data will be populated with the version string on success. 155 * 156 * Return: 157 * * Length of buffer written - Success 158 * * %-ENOENT - Policy initializing/deleted 159 */ 160 static ssize_t read_version(struct file *f, char __user *data, 161 size_t len, loff_t *offset) 162 { 163 char buffer[MAX_VERSION_SIZE] = { 0 }; 164 const struct ipe_policy *p = NULL; 165 struct inode *root = NULL; 166 size_t strsize = 0; 167 ssize_t rc = 0; 168 169 root = d_inode(f->f_path.dentry->d_parent); 170 171 inode_lock_shared(root); 172 p = (struct ipe_policy *)root->i_private; 173 if (!p) { 174 rc = -ENOENT; 175 goto out; 176 } 177 178 strsize = scnprintf(buffer, ARRAY_SIZE(buffer), "%hu.%hu.%hu", 179 p->parsed->version.major, p->parsed->version.minor, 180 p->parsed->version.rev); 181 182 rc = simple_read_from_buffer(data, len, offset, buffer, strsize); 183 184 out: 185 inode_unlock_shared(root); 186 187 return rc; 188 } 189 190 /** 191 * setactive() - Write handler for "ipe/policies/$name/active". 192 * @f: Supplies a file structure representing the securityfs node. 193 * @data: Supplies a buffer passed to the write syscall. 194 * @len: Supplies the length of @data. 195 * @offset: unused. 196 * 197 * Return: 198 * * Length of buffer written - Success 199 * * %-EPERM - Insufficient permission 200 * * %-EINVAL - Invalid input 201 * * %-ENOENT - Policy initializing/deleted 202 */ 203 static ssize_t setactive(struct file *f, const char __user *data, 204 size_t len, loff_t *offset) 205 { 206 const struct ipe_policy *p = NULL; 207 struct inode *root = NULL; 208 bool value = false; 209 int rc = 0; 210 211 if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) 212 return -EPERM; 213 214 rc = kstrtobool_from_user(data, len, &value); 215 if (rc) 216 return rc; 217 218 if (!value) 219 return -EINVAL; 220 221 root = d_inode(f->f_path.dentry->d_parent); 222 inode_lock(root); 223 224 p = (struct ipe_policy *)root->i_private; 225 if (!p) { 226 rc = -ENOENT; 227 goto out; 228 } 229 230 rc = ipe_set_active_pol(p); 231 232 out: 233 inode_unlock(root); 234 return (rc < 0) ? rc : len; 235 } 236 237 /** 238 * getactive() - Read handler for "ipe/policies/$name/active". 239 * @f: Supplies a file structure representing the securityfs node. 240 * @data: Supplies a buffer passed to the write syscall. 241 * @len: Supplies the length of @data. 242 * @offset: unused. 243 * 244 * @data will be populated with the 1 or 0 depending on if the 245 * corresponding policy is active. 246 * 247 * Return: 248 * * Length of buffer written - Success 249 * * %-ENOENT - Policy initializing/deleted 250 */ 251 static ssize_t getactive(struct file *f, char __user *data, 252 size_t len, loff_t *offset) 253 { 254 const struct ipe_policy *p = NULL; 255 struct inode *root = NULL; 256 const char *str; 257 int rc = 0; 258 259 root = d_inode(f->f_path.dentry->d_parent); 260 261 inode_lock_shared(root); 262 p = (struct ipe_policy *)root->i_private; 263 if (!p) { 264 inode_unlock_shared(root); 265 return -ENOENT; 266 } 267 inode_unlock_shared(root); 268 269 str = (p == rcu_access_pointer(ipe_active_policy)) ? "1" : ""; 270 rc = simple_read_from_buffer(data, len, offset, str, 1); 271 272 return rc; 273 } 274 275 /** 276 * update_policy() - Write handler for "ipe/policies/$name/update". 277 * @f: Supplies a file structure representing the securityfs node. 278 * @data: Supplies a buffer passed to the write syscall. 279 * @len: Supplies the length of @data. 280 * @offset: unused. 281 * 282 * On success this updates the policy represented by $name, 283 * in-place. 284 * 285 * Return: Length of buffer written on success. If an error occurs, 286 * the function will return the -errno. 287 */ 288 static ssize_t update_policy(struct file *f, const char __user *data, 289 size_t len, loff_t *offset) 290 { 291 struct inode *root = NULL; 292 char *copy = NULL; 293 int rc = 0; 294 295 if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) 296 return -EPERM; 297 298 copy = memdup_user(data, len); 299 if (IS_ERR(copy)) 300 return PTR_ERR(copy); 301 302 root = d_inode(f->f_path.dentry->d_parent); 303 inode_lock(root); 304 rc = ipe_update_policy(root, NULL, 0, copy, len); 305 inode_unlock(root); 306 307 kfree(copy); 308 if (rc) 309 return rc; 310 311 return len; 312 } 313 314 /** 315 * delete_policy() - write handler for "ipe/policies/$name/delete". 316 * @f: Supplies a file structure representing the securityfs node. 317 * @data: Supplies a buffer passed to the write syscall. 318 * @len: Supplies the length of @data. 319 * @offset: unused. 320 * 321 * On success this deletes the policy represented by $name. 322 * 323 * Return: 324 * * Length of buffer written - Success 325 * * %-EPERM - Insufficient permission/deleting active policy 326 * * %-EINVAL - Invalid input 327 * * %-ENOENT - Policy initializing/deleted 328 */ 329 static ssize_t delete_policy(struct file *f, const char __user *data, 330 size_t len, loff_t *offset) 331 { 332 struct ipe_policy *ap = NULL; 333 struct ipe_policy *p = NULL; 334 struct inode *root = NULL; 335 bool value = false; 336 int rc = 0; 337 338 if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) 339 return -EPERM; 340 341 rc = kstrtobool_from_user(data, len, &value); 342 if (rc) 343 return rc; 344 345 if (!value) 346 return -EINVAL; 347 348 root = d_inode(f->f_path.dentry->d_parent); 349 inode_lock(root); 350 p = (struct ipe_policy *)root->i_private; 351 if (!p) { 352 inode_unlock(root); 353 return -ENOENT; 354 } 355 356 mutex_lock(&ipe_policy_lock); 357 ap = rcu_dereference_protected(ipe_active_policy, 358 lockdep_is_held(&ipe_policy_lock)); 359 if (p == ap) { 360 mutex_unlock(&ipe_policy_lock); 361 inode_unlock(root); 362 return -EPERM; 363 } 364 mutex_unlock(&ipe_policy_lock); 365 366 root->i_private = NULL; 367 inode_unlock(root); 368 369 synchronize_rcu(); 370 ipe_free_policy(p); 371 372 return len; 373 } 374 375 static const struct file_operations content_fops = { 376 .read = read_policy, 377 }; 378 379 static const struct file_operations pkcs7_fops = { 380 .read = read_pkcs7, 381 }; 382 383 static const struct file_operations name_fops = { 384 .read = read_name, 385 }; 386 387 static const struct file_operations ver_fops = { 388 .read = read_version, 389 }; 390 391 static const struct file_operations active_fops = { 392 .write = setactive, 393 .read = getactive, 394 }; 395 396 static const struct file_operations update_fops = { 397 .write = update_policy, 398 }; 399 400 static const struct file_operations delete_fops = { 401 .write = delete_policy, 402 }; 403 404 /** 405 * policy_subdir - files under a policy subdirectory 406 */ 407 static const struct ipefs_file policy_subdir[] = { 408 { "pkcs7", 0444, &pkcs7_fops }, 409 { "policy", 0444, &content_fops }, 410 { "name", 0444, &name_fops }, 411 { "version", 0444, &ver_fops }, 412 { "active", 0600, &active_fops }, 413 { "update", 0200, &update_fops }, 414 { "delete", 0200, &delete_fops }, 415 }; 416 417 /** 418 * ipe_del_policyfs_node() - Delete a securityfs entry for @p. 419 * @p: Supplies a pointer to the policy to delete a securityfs entry for. 420 */ 421 void ipe_del_policyfs_node(struct ipe_policy *p) 422 { 423 securityfs_recursive_remove(p->policyfs); 424 p->policyfs = NULL; 425 } 426 427 /** 428 * ipe_new_policyfs_node() - Create a securityfs entry for @p. 429 * @p: Supplies a pointer to the policy to create a securityfs entry for. 430 * 431 * Return: %0 on success. If an error occurs, the function will return 432 * the -errno. 433 */ 434 int ipe_new_policyfs_node(struct ipe_policy *p) 435 { 436 const struct ipefs_file *f = NULL; 437 struct dentry *policyfs = NULL; 438 struct inode *root = NULL; 439 struct dentry *d = NULL; 440 size_t i = 0; 441 int rc = 0; 442 443 if (p->policyfs) 444 return 0; 445 446 policyfs = securityfs_create_dir(p->parsed->name, policy_root); 447 if (IS_ERR(policyfs)) 448 return PTR_ERR(policyfs); 449 450 root = d_inode(policyfs); 451 452 for (i = 0; i < ARRAY_SIZE(policy_subdir); ++i) { 453 f = &policy_subdir[i]; 454 455 d = securityfs_create_file(f->name, f->access, policyfs, 456 NULL, f->fops); 457 if (IS_ERR(d)) { 458 rc = PTR_ERR(d); 459 goto err; 460 } 461 } 462 463 inode_lock(root); 464 p->policyfs = policyfs; 465 root->i_private = p; 466 inode_unlock(root); 467 468 return 0; 469 err: 470 securityfs_recursive_remove(policyfs); 471 return rc; 472 } 473
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.