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

ipe: add userspace interface

As is typical with LSMs, IPE uses securityfs as its interface with
userspace. for a complete list of the interfaces and the respective
inputs/outputs, please see the documentation under
admin-guide/LSM/ipe.rst

Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
Signed-off-by: Fan Wu <wufan@linux.microsoft.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>

authored by

Deven Bowers and committed by
Paul Moore
2261306f 7138679f

+727
+2
security/ipe/Makefile
··· 8 8 obj-$(CONFIG_SECURITY_IPE) += \ 9 9 eval.o \ 10 10 hooks.o \ 11 + fs.o \ 11 12 ipe.o \ 12 13 policy.o \ 14 + policy_fs.o \ 13 15 policy_parser.o \
+105
security/ipe/fs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 4 + */ 5 + 6 + #include <linux/dcache.h> 7 + #include <linux/security.h> 8 + 9 + #include "ipe.h" 10 + #include "fs.h" 11 + #include "policy.h" 12 + 13 + static struct dentry *np __ro_after_init; 14 + static struct dentry *root __ro_after_init; 15 + struct dentry *policy_root __ro_after_init; 16 + 17 + /** 18 + * new_policy() - Write handler for the securityfs node, "ipe/new_policy". 19 + * @f: Supplies a file structure representing the securityfs node. 20 + * @data: Supplies a buffer passed to the write syscall. 21 + * @len: Supplies the length of @data. 22 + * @offset: unused. 23 + * 24 + * Return: 25 + * * Length of buffer written - Success 26 + * * %-EPERM - Insufficient permission 27 + * * %-ENOMEM - Out of memory (OOM) 28 + * * %-EBADMSG - Policy is invalid 29 + * * %-ERANGE - Policy version number overflow 30 + * * %-EINVAL - Policy version parsing error 31 + * * %-EEXIST - Same name policy already deployed 32 + */ 33 + static ssize_t new_policy(struct file *f, const char __user *data, 34 + size_t len, loff_t *offset) 35 + { 36 + struct ipe_policy *p = NULL; 37 + char *copy = NULL; 38 + int rc = 0; 39 + 40 + if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) 41 + return -EPERM; 42 + 43 + copy = memdup_user_nul(data, len); 44 + if (IS_ERR(copy)) 45 + return PTR_ERR(copy); 46 + 47 + p = ipe_new_policy(NULL, 0, copy, len); 48 + if (IS_ERR(p)) { 49 + rc = PTR_ERR(p); 50 + goto out; 51 + } 52 + 53 + rc = ipe_new_policyfs_node(p); 54 + 55 + out: 56 + if (rc < 0) 57 + ipe_free_policy(p); 58 + kfree(copy); 59 + return (rc < 0) ? rc : len; 60 + } 61 + 62 + static const struct file_operations np_fops = { 63 + .write = new_policy, 64 + }; 65 + 66 + /** 67 + * ipe_init_securityfs() - Initialize IPE's securityfs tree at fsinit. 68 + * 69 + * Return: %0 on success. If an error occurs, the function will return 70 + * the -errno. 71 + */ 72 + static int __init ipe_init_securityfs(void) 73 + { 74 + int rc = 0; 75 + 76 + if (!ipe_enabled) 77 + return -EOPNOTSUPP; 78 + 79 + root = securityfs_create_dir("ipe", NULL); 80 + if (IS_ERR(root)) { 81 + rc = PTR_ERR(root); 82 + goto err; 83 + } 84 + 85 + policy_root = securityfs_create_dir("policies", root); 86 + if (IS_ERR(policy_root)) { 87 + rc = PTR_ERR(policy_root); 88 + goto err; 89 + } 90 + 91 + np = securityfs_create_file("new_policy", 0200, root, NULL, &np_fops); 92 + if (IS_ERR(np)) { 93 + rc = PTR_ERR(np); 94 + goto err; 95 + } 96 + 97 + return 0; 98 + err: 99 + securityfs_remove(np); 100 + securityfs_remove(policy_root); 101 + securityfs_remove(root); 102 + return rc; 103 + } 104 + 105 + fs_initcall(ipe_init_securityfs);
+16
security/ipe/fs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 4 + */ 5 + 6 + #ifndef _IPE_FS_H 7 + #define _IPE_FS_H 8 + 9 + #include "policy.h" 10 + 11 + extern struct dentry *policy_root __ro_after_init; 12 + 13 + int ipe_new_policyfs_node(struct ipe_policy *p); 14 + void ipe_del_policyfs_node(struct ipe_policy *p); 15 + 16 + #endif /* _IPE_FS_H */
+3
security/ipe/ipe.c
··· 8 8 #include "eval.h" 9 9 #include "hooks.h" 10 10 11 + bool ipe_enabled; 12 + 11 13 static struct lsm_blob_sizes ipe_blobs __ro_after_init = { 12 14 .lbs_superblock = sizeof(struct ipe_superblock), 13 15 }; ··· 47 45 static int __init ipe_init(void) 48 46 { 49 47 security_add_hooks(ipe_hooks, ARRAY_SIZE(ipe_hooks), &ipe_lsmid); 48 + ipe_enabled = true; 50 49 51 50 return 0; 52 51 }
+2
security/ipe/ipe.h
··· 14 14 #include <linux/lsm_hooks.h> 15 15 struct ipe_superblock *ipe_sb(const struct super_block *sb); 16 16 17 + extern bool ipe_enabled; 18 + 17 19 #endif /* _IPE_H */
+120
security/ipe/policy.c
··· 7 7 #include <linux/verification.h> 8 8 9 9 #include "ipe.h" 10 + #include "eval.h" 11 + #include "fs.h" 10 12 #include "policy.h" 11 13 #include "policy_parser.h" 14 + 15 + /* lock for synchronizing writers across ipe policy */ 16 + DEFINE_MUTEX(ipe_policy_lock); 17 + 18 + /** 19 + * ver_to_u64() - Convert an internal ipe_policy_version to a u64. 20 + * @p: Policy to extract the version from. 21 + * 22 + * Bits (LSB is index 0): 23 + * [48,32] -> Major 24 + * [32,16] -> Minor 25 + * [16, 0] -> Revision 26 + * 27 + * Return: u64 version of the embedded version structure. 28 + */ 29 + static inline u64 ver_to_u64(const struct ipe_policy *const p) 30 + { 31 + u64 r; 32 + 33 + r = (((u64)p->parsed->version.major) << 32) 34 + | (((u64)p->parsed->version.minor) << 16) 35 + | ((u64)(p->parsed->version.rev)); 36 + 37 + return r; 38 + } 12 39 13 40 /** 14 41 * ipe_free_policy() - Deallocate a given IPE policy. ··· 48 21 if (IS_ERR_OR_NULL(p)) 49 22 return; 50 23 24 + ipe_del_policyfs_node(p); 51 25 ipe_free_parsed_policy(p->parsed); 52 26 /* 53 27 * p->text is allocated only when p->pkcs7 is not NULL ··· 69 41 p->textlen = len; 70 42 71 43 return 0; 44 + } 45 + 46 + /** 47 + * ipe_update_policy() - parse a new policy and replace old with it. 48 + * @root: Supplies a pointer to the securityfs inode saved the policy. 49 + * @text: Supplies a pointer to the plain text policy. 50 + * @textlen: Supplies the length of @text. 51 + * @pkcs7: Supplies a pointer to a buffer containing a pkcs7 message. 52 + * @pkcs7len: Supplies the length of @pkcs7len. 53 + * 54 + * @text/@textlen is mutually exclusive with @pkcs7/@pkcs7len - see 55 + * ipe_new_policy. 56 + * 57 + * Context: Requires root->i_rwsem to be held. 58 + * Return: %0 on success. If an error occurs, the function will return 59 + * the -errno. 60 + */ 61 + int ipe_update_policy(struct inode *root, const char *text, size_t textlen, 62 + const char *pkcs7, size_t pkcs7len) 63 + { 64 + struct ipe_policy *old, *ap, *new = NULL; 65 + int rc = 0; 66 + 67 + old = (struct ipe_policy *)root->i_private; 68 + if (!old) 69 + return -ENOENT; 70 + 71 + new = ipe_new_policy(text, textlen, pkcs7, pkcs7len); 72 + if (IS_ERR(new)) 73 + return PTR_ERR(new); 74 + 75 + if (strcmp(new->parsed->name, old->parsed->name)) { 76 + rc = -EINVAL; 77 + goto err; 78 + } 79 + 80 + if (ver_to_u64(old) > ver_to_u64(new)) { 81 + rc = -EINVAL; 82 + goto err; 83 + } 84 + 85 + root->i_private = new; 86 + swap(new->policyfs, old->policyfs); 87 + 88 + mutex_lock(&ipe_policy_lock); 89 + ap = rcu_dereference_protected(ipe_active_policy, 90 + lockdep_is_held(&ipe_policy_lock)); 91 + if (old == ap) { 92 + rcu_assign_pointer(ipe_active_policy, new); 93 + mutex_unlock(&ipe_policy_lock); 94 + } else { 95 + mutex_unlock(&ipe_policy_lock); 96 + } 97 + synchronize_rcu(); 98 + ipe_free_policy(old); 99 + 100 + return 0; 101 + err: 102 + ipe_free_policy(new); 103 + return rc; 72 104 } 73 105 74 106 /** ··· 188 100 err: 189 101 ipe_free_policy(new); 190 102 return ERR_PTR(rc); 103 + } 104 + 105 + /** 106 + * ipe_set_active_pol() - Make @p the active policy. 107 + * @p: Supplies a pointer to the policy to make active. 108 + * 109 + * Context: Requires root->i_rwsem, which i_private has the policy, to be held. 110 + * Return: 111 + * * %0 - Success 112 + * * %-EINVAL - New active policy version is invalid 113 + */ 114 + int ipe_set_active_pol(const struct ipe_policy *p) 115 + { 116 + struct ipe_policy *ap = NULL; 117 + 118 + mutex_lock(&ipe_policy_lock); 119 + 120 + ap = rcu_dereference_protected(ipe_active_policy, 121 + lockdep_is_held(&ipe_policy_lock)); 122 + if (ap == p) { 123 + mutex_unlock(&ipe_policy_lock); 124 + return 0; 125 + } 126 + if (ap && ver_to_u64(ap) > ver_to_u64(p)) { 127 + mutex_unlock(&ipe_policy_lock); 128 + return -EINVAL; 129 + } 130 + 131 + rcu_assign_pointer(ipe_active_policy, p); 132 + mutex_unlock(&ipe_policy_lock); 133 + 134 + return 0; 191 135 }
+7
security/ipe/policy.h
··· 7 7 8 8 #include <linux/list.h> 9 9 #include <linux/types.h> 10 + #include <linux/fs.h> 10 11 11 12 enum ipe_op_type { 12 13 IPE_OP_EXEC = 0, ··· 77 76 size_t textlen; 78 77 79 78 struct ipe_parsed_policy *parsed; 79 + 80 + struct dentry *policyfs; 80 81 }; 81 82 82 83 struct ipe_policy *ipe_new_policy(const char *text, size_t textlen, 83 84 const char *pkcs7, size_t pkcs7len); 84 85 void ipe_free_policy(struct ipe_policy *pol); 86 + int ipe_update_policy(struct inode *root, const char *text, size_t textlen, 87 + const char *pkcs7, size_t pkcs7len); 88 + int ipe_set_active_pol(const struct ipe_policy *p); 89 + extern struct mutex ipe_policy_lock; 85 90 86 91 #endif /* _IPE_POLICY_H */
+472
security/ipe/policy_fs.c
··· 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" : "0"; 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 + }