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

Configure Feed

Select the types of activity you want to include in your feed.

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