2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <sys/cprotect.h>
30 #include <sys/mount.h>
31 #include <sys/random.h>
32 #include <sys/xattr.h>
33 #include <sys/uio_internal.h>
34 #include <sys/ubc_internal.h>
35 #include <sys/vnode_if.h>
36 #include <sys/vnode_internal.h>
37 #include <sys/fcntl.h>
38 #include <libkern/OSByteOrder.h>
41 #include "hfs_cnode.h"
44 static struct cp_wrap_func g_cp_wrap_func
= {NULL
, NULL
};
45 static struct cp_global_state g_cp_state
= {0, 0, 0};
47 extern int (**hfs_vnodeop_p
) (void *);
50 * CP private functions
52 static int cp_is_valid_class(int);
53 static int cp_root_major_vers(mount_t mp
);
54 static int cp_getxattr(cnode_t
*, struct hfsmount
*hfsmp
, struct cprotect
**);
55 static struct cprotect
*cp_entry_alloc(size_t);
56 static void cp_entry_dealloc(struct cprotect
*entry
);
57 static int cp_setup_aes_ctx(struct cprotect
*);
58 static int cp_make_keys (struct cprotect
**, struct hfsmount
*hfsmp
, cnid_t
, int);
59 static int cp_restore_keys(struct cprotect
*, struct hfsmount
*hfsmp
);
60 static int cp_lock_vfs_callback(mount_t
, void *);
61 static int cp_lock_vnode_callback(vnode_t
, void *);
62 static int cp_vnode_is_eligible (vnode_t
);
63 static int cp_check_access (cnode_t
*, int);
64 static int cp_wrap(int, struct hfsmount
*hfsmp
, cnid_t
, struct cprotect
**);
65 static int cp_unwrap(int, struct cprotect
*);
69 #if DEVELOPMENT || DEBUG
70 #define CP_ASSERT(x) \
72 panic("Content Protection: failed assertion in %s", __FUNCTION__); \
79 cp_key_store_action(int action
)
81 g_cp_state
.lock_state
= action
;
82 if (action
== CP_LOCKED_STATE
) {
84 * Note that because we are using the void* arg to pass the key store
85 * value into the vfs cp iteration, we need to pass around the int as an ptr.
86 * This may silence 32-64 truncation warnings.
88 return vfs_iterate(0, cp_lock_vfs_callback
, (void*)((uintptr_t)action
));
97 cp_register_wraps(cp_wrap_func_t key_store_func
)
99 g_cp_wrap_func
.wrapper
= key_store_func
->wrapper
;
100 g_cp_wrap_func
.unwrapper
= key_store_func
->unwrapper
;
102 g_cp_state
.wrap_functions_set
= 1;
109 * If necessary, this function can be used to
110 * query the device's lock state.
113 cp_isdevice_locked (void) {
114 if (g_cp_state
.lock_state
== CP_UNLOCKED_STATE
) {
122 * Allocate and initialize a cprotect blob for a new cnode.
123 * Called from hfs_getnewvnode: cnode is locked exclusive.
124 * Read xattr data off the cnode. Then, if conditions permit,
125 * unwrap the file key and cache it in the cprotect blob.
128 cp_entry_init(struct cnode
*cp
, struct mount
*mp
)
130 struct cprotect
*entry
= NULL
;
132 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
134 if (!cp_fs_protected (mp
)) {
135 cp
->c_cpentry
= NULL
;
139 if (!S_ISREG(cp
->c_mode
) && !S_ISDIR(cp
->c_mode
)) {
140 cp
->c_cpentry
= NULL
;
144 if (!g_cp_state
.wrap_functions_set
) {
145 printf("hfs: cp_update_entry: wrap functions not yet set\n");
149 if (hfsmp
->hfs_running_cp_major_vers
== 0) {
150 cp_root_major_vers(mp
);
153 CP_ASSERT (cp
->c_cpentry
== NULL
);
155 error
= cp_getxattr(cp
, hfsmp
, &entry
);
158 * Normally, we should always have a CP EA for a file or directory that
159 * we are initializing here. However, there are some extenuating circumstances,
160 * such as the root directory immediately following a newfs_hfs.
162 * As a result, we leave code here to deal with an ENOATTR which will always
163 * default to a 'D' key, though we don't expect to use it much.
165 if (error
== ENOATTR
) {
168 sub_error
= cp_entry_create_keys (&entry
, NULL
, hfsmp
, PROTECTION_CLASS_D
, cp
->c_fileid
, cp
->c_mode
);
170 /* Now we have keys. Write them out. */
171 if (sub_error
== 0) {
172 sub_error
= cp_setxattr (cp
, entry
, hfsmp
, cp
->c_fileid
, XATTR_CREATE
);
176 else if (error
== 0) {
177 if (S_ISREG(cp
->c_mode
)) {
178 entry
->cp_flags
|= CP_KEY_FLUSHED
;
182 * For errors other than ENOATTR, we don't do anything.
183 * cp_entry_destroy can deal with a NULL argument if cp_getxattr
184 * failed malloc or there was a B-Tree error.
187 cp
->c_cpentry
= entry
;
190 cp_entry_destroy(&cp
->c_cpentry
);
197 * Set up initial key/class pair on cnode. The cnode does not yet exist,
198 * so we must take a pointer to the cprotect struct.
201 * We call this function in two places:
202 * 1) hfs_makenode *prior* to taking the journal/b-tree locks.
203 * A successful return value from this function is a pre-requisite for continuing on
204 * with file creation, as a wrap failure should immediately preclude the creation of
207 * 2) cp_entry_init if we are trying to establish keys for a file/directory that did not
208 * have them already. (newfs_hfs may create entries in the namespace).
210 * At this point, we hold the directory cnode lock exclusive if it is available.
213 cp_entry_create_keys(struct cprotect
**entry_ptr
, struct cnode
*dcp
, struct hfsmount
*hfsmp
,
214 uint32_t input_class
, cnid_t fileid
, mode_t cmode
)
217 struct cprotect
*entry
= NULL
;
220 /* Default to class D */
221 uint32_t target_class
= PROTECTION_CLASS_D
;
223 /* Decide the target class. Input argument takes priority. */
224 if (cp_is_valid_class (input_class
)) {
225 target_class
= input_class
;
227 * One exception, F is never valid for a directory
228 * because its children may inherit and userland will be
229 * unable to read/write to the files.
231 if (S_ISDIR(cmode
)) {
232 if (target_class
== PROTECTION_CLASS_F
) {
238 /* If no valid class was supplied, then inherit from parent if possible */
239 if ((dcp
) && (dcp
->c_cpentry
)) {
240 uint32_t parentclass
= dcp
->c_cpentry
->cp_pclass
;
241 /* If the parent class is not valid, default back to D */
242 if (cp_is_valid_class(parentclass
)) {
243 /* Parent class was good. use it. */
244 target_class
= parentclass
;
246 /* Otherwise, we already defaulted to 'D' */
250 keylen
= S_ISDIR(cmode
) ? 0 : CP_INITIAL_WRAPPEDKEYSIZE
;
251 entry
= cp_entry_alloc (keylen
);
257 if (S_ISREG(cmode
)) {
258 entry
->cp_pclass
= target_class
;
259 entry
->cp_flags
|= CP_NEEDS_KEYS
;
261 * The 'fileid' argument to this function will either be
262 * a valid fileid for an existing file/dir, or it will be 0.
263 * If it is 0, then that is an indicator to the layer below
264 * that the file does not yet exist and we need to bypass the
265 * cp_wrap work to the keybag.
267 * If we are being invoked on behalf of a file/dir that does
268 * not yet have a key, then it will be a valid key and we
269 * need to behave like a setclass.
271 error
= cp_make_keys(&entry
, hfsmp
, fileid
, entry
->cp_pclass
);
273 else if (S_ISDIR(cmode
)) {
274 /* Directories just get their cp_pclass set */
275 entry
->cp_pclass
= target_class
;
278 /* Unsupported for non-dir and non-file. */
283 * We only initialize and create the keys here; we cannot
284 * write out the EA until the journal lock and EA b-tree locks
289 /* destroy the CP blob */
290 cp_entry_destroy (&entry
);
294 /* otherwise, emit the cprotect entry */
302 * Set up an initial key/class pair for a disassociated cprotect entry.
303 * This function is used to generate transient keys that will never be
304 * written to disk. We use class F for this since it provides the exact
305 * semantics that are needed here. Because we never attach this blob to
306 * a cnode directly, we take a pointer to the cprotect struct.
308 * This function is primarily used in the HFS FS truncation codepath
309 * where we may rely on AES symmetry to relocate encrypted data from
310 * one spot in the disk to another.
312 int cp_entry_gentempkeys(struct cprotect
**entry_ptr
, struct hfsmount
*hfsmp
) {
314 struct cprotect
*entry
= NULL
;
317 /* Default to class F */
318 uint32_t target_class
= PROTECTION_CLASS_F
;
321 * This should only be used for files, so we default to the
322 * initial wrapped key size
324 keylen
= CP_INITIAL_WRAPPEDKEYSIZE
;
325 entry
= cp_entry_alloc (keylen
);
331 error
= cp_make_keys (&entry
, hfsmp
, 0, target_class
);
334 * We only initialize the keys here; we don't write anything out
338 /* destroy the CP blob */
339 cp_entry_destroy (&entry
);
343 /* otherwise, emit the cprotect entry */
352 * Tear down and clear a cprotect blob for a closing file.
353 * Called at hfs_reclaim_cnode: cnode is locked exclusive.
356 cp_entry_destroy(struct cprotect
**entry_ptr
) {
357 struct cprotect
*entry
= *entry_ptr
;
359 /* nothing to clean up */
363 cp_entry_dealloc(entry
);
368 cp_fs_protected (mount_t mnt
) {
369 return (vfs_flags(mnt
) & MNT_CPROTECT
);
374 * Return a pointer to underlying cnode if there is one for this vnode.
375 * Done without taking cnode lock, inspecting only vnode state.
378 cp_get_protected_cnode(struct vnode
*vp
)
380 if (!cp_vnode_is_eligible(vp
)) {
384 if (!cp_fs_protected(VTOVFS(vp
))) {
385 /* mount point doesn't support it */
389 return (struct cnode
*) vp
->v_data
;
394 * Sets *class to persistent class associated with vnode,
398 cp_vnode_getclass(struct vnode
*vp
, int *class)
400 struct cprotect
*entry
;
403 int took_truncate_lock
= 0;
404 struct hfsmount
*hfsmp
= NULL
;
406 /* Is this an interesting vp? */
407 if (!cp_vnode_is_eligible (vp
)) {
411 /* Is the mount point formatted for content protection? */
412 if (!cp_fs_protected(VTOVFS(vp
))) {
420 * Take the truncate lock up-front in shared mode because we may need
421 * to manipulate the CP blob. Pend lock events until we're done here.
423 hfs_lock_truncate (cp
, HFS_SHARED_LOCK
);
424 took_truncate_lock
= 1;
427 * We take only the shared cnode lock up-front. If it turns out that
428 * we need to manipulate the CP blob to write a key out, drop the
429 * shared cnode lock and acquire an exclusive lock.
431 error
= hfs_lock(cp
, HFS_SHARED_LOCK
);
433 hfs_unlock_truncate(cp
, 0);
437 /* pull the class from the live entry */
438 entry
= cp
->c_cpentry
;
441 panic("Content Protection: uninitialized cnode %p", cp
);
445 * Any vnode on a content protected filesystem must have keys
446 * created by the time the vnode is vended out. If we generate
447 * a vnode that does not have keys, something bad happened.
449 if ((entry
->cp_flags
& CP_NEEDS_KEYS
)) {
450 panic ("cp_vnode_getclass: cp %p has no keys!", cp
);
454 *class = entry
->cp_pclass
;
457 if (took_truncate_lock
) {
458 hfs_unlock_truncate(cp
, 0);
467 * Sets persistent class for this file or directory.
468 * If vnode cannot be protected (system file, non-regular file, non-hfs), EBADF.
469 * If the new class can't be accessed now, EPERM.
470 * Otherwise, record class and re-wrap key if the mount point is content-protected.
473 cp_vnode_setclass(struct vnode
*vp
, uint32_t newclass
)
476 struct cprotect
*entry
= 0;
478 int took_truncate_lock
= 0;
479 u_int32_t keylen
= 0;
480 struct hfsmount
*hfsmp
= NULL
;
482 if (!cp_is_valid_class(newclass
)) {
483 printf("hfs: CP: cp_setclass called with invalid class %d\n", newclass
);
487 if (vnode_isdir(vp
)) {
488 if (newclass
== PROTECTION_CLASS_F
) {
490 * Directories are not allowed to set to class F, since the
491 * children may inherit it and then userland will not be able
492 * to read/write to the file.
498 /* Is this an interesting vp? */
499 if (!cp_vnode_is_eligible(vp
)) {
503 /* Is the mount point formatted for content protection? */
504 if (!cp_fs_protected(VTOVFS(vp
))) {
512 * Take the cnode truncate lock exclusive because we want to manipulate the
513 * CP blob. The lock-event handling code is doing the same. This also forces
514 * all pending IOs to drain before we can re-write the persistent and cache keys.
516 hfs_lock_truncate (cp
, HFS_EXCLUSIVE_LOCK
);
517 took_truncate_lock
= 1;
519 if (hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
)) {
523 entry
= cp
->c_cpentry
;
529 if ((entry
->cp_flags
& CP_NEEDS_KEYS
)) {
531 * We should have created this vnode and its keys atomically during
532 * file/directory creation. If we get here and it doesn't have keys yet,
533 * something bad happened.
535 panic ("cp_vnode_setclass: cp %p has no keys!\n", cp
);
538 if (entry
->cp_flags
& CP_KEY_FLUSHED
) {
539 error
= cp_restore_keys(entry
, hfsmp
);
544 /* re-wrap per-file key with new class */
545 if (vnode_isreg(vp
)) {
546 error
= cp_wrap(newclass
, hfsmp
, cp
->c_fileid
, &cp
->c_cpentry
);
548 /* we didn't have perms to set this class. leave file as-is and error out */
553 /* cp_wrap() potentially updates c_cpentry because we passed in its ptr */
554 entry
= cp
->c_cpentry
;
556 entry
->cp_pclass
= newclass
;
558 /* prepare to write the xattr out */
559 keylen
= entry
->cp_persistent_key_len
;
561 error
= cp_setxattr(cp
, entry
, VTOHFS(vp
), 0,XATTR_REPLACE
);
562 if (error
== ENOATTR
)
563 error
= cp_setxattr(cp
, entry
, VTOHFS(vp
), 0, XATTR_CREATE
);
567 if (took_truncate_lock
) {
568 hfs_unlock_truncate (cp
, 0);
575 int cp_vnode_transcode(vnode_t vp
)
578 struct cprotect
*entry
= 0;
580 int took_truncate_lock
= 0;
581 struct hfsmount
*hfsmp
= NULL
;
583 /* Is this an interesting vp? */
584 if (!cp_vnode_is_eligible(vp
)) {
588 /* Is the mount point formatted for content protection? */
589 if (!cp_fs_protected(VTOVFS(vp
))) {
597 * Take the cnode truncate lock exclusive because we want to manipulate the
598 * CP blob. The lock-event handling code is doing the same. This also forces
599 * all pending IOs to drain before we can re-write the persistent and cache keys.
601 hfs_lock_truncate (cp
, HFS_EXCLUSIVE_LOCK
);
602 took_truncate_lock
= 1;
604 if (hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
)) {
608 entry
= cp
->c_cpentry
;
614 if ((entry
->cp_flags
& CP_NEEDS_KEYS
)) {
616 * If we are transcoding keys for AKB, then we should have already established
617 * a set of keys for this vnode. IF we don't have keys yet, then something bad
620 panic ("cp_vnode_transcode: cp %p has no keys!", cp
);
623 if (entry
->cp_flags
& CP_KEY_FLUSHED
) {
624 error
= cp_restore_keys(entry
, hfsmp
);
631 /* Send the per-file key for re-wrap with the current class information
632 * Send NULLs in the output parameters of the wrapper() and AKS will do the rest.
633 * Don't need to process any outputs, so just clear the locks and pass along the error. */
634 if (vnode_isreg(vp
)) {
636 /* Picked up the following from cp_wrap().
637 * If needed, more comments available there. */
639 if (entry
->cp_pclass
== PROTECTION_CLASS_F
) {
644 error
= g_cp_wrap_func
.wrapper(entry
->cp_pclass
,
647 entry
->cp_cache_key_len
,
656 if (took_truncate_lock
) {
657 hfs_unlock_truncate (cp
, 0);
665 * Check permission for the given operation (read, write) on this node.
666 * Additionally, if the node needs work, do it:
667 * - create a new key for the file if one hasn't been set before
668 * - write out the xattr if it hasn't already been saved
669 * - unwrap the key if needed
671 * Takes cnode lock, and upgrades to exclusive if modifying cprotect.
673 * Note that this function does *NOT* take the cnode truncate lock. This is because
674 * the thread calling us may already have the truncate lock. It is not necessary
675 * because either we successfully finish this function before the keys are tossed
676 * and the IO will fail, or the keys are tossed and then this function will fail.
677 * Either way, the cnode lock still ultimately guards the keys. We only rely on the
678 * truncate lock to protect us against tossing the keys as a cluster call is in-flight.
681 cp_handle_vnop(struct vnode
*vp
, int vnop
, int ioflag
)
683 struct cprotect
*entry
;
685 struct hfsmount
*hfsmp
= NULL
;
686 struct cnode
*cp
= NULL
;
689 * First, do validation against the vnode before proceeding any further:
690 * Is this vnode originating from a valid content-protected filesystem ?
692 if (cp_vnode_is_eligible(vp
) == 0) {
694 * It is either not HFS or not a file/dir. Just return success. This is a valid
695 * case if servicing i/o against another filesystem type from VFS
700 if (cp_fs_protected (VTOVFS(vp
)) == 0) {
702 * The underlying filesystem does not support content protection. This is also
703 * a valid case. Simply return success.
709 * At this point, we know we have a HFS vnode that backs a file or directory on a
710 * filesystem that supports content protection
714 if ((error
= hfs_lock(cp
, HFS_SHARED_LOCK
))) {
718 entry
= cp
->c_cpentry
;
722 * If this cnode is not content protected, simply return success.
723 * Note that this function is called by all I/O-based call sites
724 * when CONFIG_PROTECT is enabled during XNU building.
741 if ((error
= cp_check_access(cp
, vnop
))) {
742 /* check for raw encrypted access before bailing out */
743 if ((vnop
== CP_READ_ACCESS
) && (ioflag
& IO_ENCRYPTED
)) {
745 * read access only + asking for the raw encrypted bytes
746 * is legitimate, so reset the error value to 0
755 if (entry
->cp_flags
== 0) {
756 /* no more work to do */
760 /* upgrade to exclusive lock */
761 if (lck_rw_lock_shared_to_exclusive(&cp
->c_rwlock
) == FALSE
) {
762 if ((error
= hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
))) {
766 cp
->c_lockowner
= current_thread();
769 /* generate new keys if none have ever been saved */
770 if ((entry
->cp_flags
& CP_NEEDS_KEYS
)) {
772 * By the time we're trying to initiate I/O against a content
773 * protected vnode, we should have already created keys for this
774 * file/dir. If we don't have keys, something bad happened.
776 panic ("cp_handle_vnop: cp %p has no keys!", cp
);
779 /* unwrap keys if needed */
780 if (entry
->cp_flags
& CP_KEY_FLUSHED
) {
781 if ((vnop
== CP_READ_ACCESS
) && (ioflag
& IO_ENCRYPTED
)) {
782 /* no need to try to restore keys; they are not going to be used */
786 error
= cp_restore_keys(entry
, hfsmp
);
794 /* write out the xattr if it's new */
795 if (entry
->cp_flags
& CP_NO_XATTR
)
796 error
= cp_setxattr(cp
, entry
, VTOHFS(cp
->c_vp
), 0, XATTR_CREATE
);
806 cp_handle_open(struct vnode
*vp
, int mode
)
808 struct cnode
*cp
= NULL
;
809 struct cprotect
*entry
= NULL
;
812 /* If vnode not eligible, just return success */
813 if (!cp_vnode_is_eligible(vp
)) {
817 /* If mount point not properly set up, then also return success */
818 if (!cp_fs_protected(VTOVFS(vp
))) {
822 /* We know the vnode is in a valid state. acquire cnode and validate */
825 if ((error
= hfs_lock(cp
, HFS_SHARED_LOCK
))) {
829 entry
= cp
->c_cpentry
;
833 if (!S_ISREG(cp
->c_mode
))
836 switch (entry
->cp_pclass
) {
837 case PROTECTION_CLASS_B
:
838 /* Class B always allows creation */
841 case PROTECTION_CLASS_A
:
842 error
= g_cp_wrap_func
.unwrapper(entry
->cp_pclass
,
843 entry
->cp_persistent_key
,
844 entry
->cp_persistent_key_len
,
860 * During hfs resize operations, we have slightly different constraints than during
861 * normal VNOPS that read/write data to files. Specifically, we already have the cnode
862 * locked (so nobody else can modify it), and we are doing the IO with root privileges, since
863 * we are moving the data behind the user's back. So, we skip access checks here (for unlock
864 * vs. lock), and don't worry about non-existing keys. If the file exists on-disk with valid
865 * payload, then it must have keys set up already by definition.
868 cp_handle_relocate (struct cnode
*cp
, struct hfsmount
*hfsmp
) {
869 struct cprotect
*entry
;
872 /* cp is already locked */
873 entry
= cp
->c_cpentry
;
878 * Still need to validate whether to permit access to the file or not
879 * based on lock status
881 if ((error
= cp_check_access(cp
, CP_READ_ACCESS
| CP_WRITE_ACCESS
))) {
885 if (entry
->cp_flags
== 0) {
886 /* no more work to do */
891 /* it must have keys since it is an existing file with actual payload */
893 /* unwrap keys if needed */
894 if (entry
->cp_flags
& CP_KEY_FLUSHED
) {
895 error
= cp_restore_keys(entry
, hfsmp
);
899 * Don't need to write out the EA since if the file has actual extents,
904 /* return the cp still locked */
910 * Gets the EA we set on the root folder (fileid 1) to get information about the
911 * version of Content Protection that was used to write to this filesystem.
912 * Note that all multi-byte fields are written to disk little endian so they must be
913 * converted to native endian-ness as needed.
916 cp_getrootxattr(struct hfsmount
* hfsmp
, struct cp_root_xattr
*outxattr
) {
918 char uio_buf
[UIO_SIZEOF(1)];
919 size_t attrsize
= sizeof(struct cp_root_xattr
);
921 struct vnop_getxattr_args args
;
924 panic("Content Protection: cp_xattr called with xattr == NULL");
927 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
928 uio_addiov(auio
, CAST_USER_ADDR_T(outxattr
), attrsize
);
930 args
.a_desc
= NULL
; // unused
931 args
.a_vp
= NULL
; //unused since we're writing EA to root folder.
932 args
.a_name
= CONTENT_PROTECTION_XATTR_NAME
;
934 args
.a_size
= &attrsize
;
935 args
.a_options
= XATTR_REPLACE
;
936 args
.a_context
= NULL
; // unused
938 error
= hfs_getxattr_internal(NULL
, &args
, hfsmp
, 1);
940 /* Now convert the multi-byte fields to native endianness */
941 outxattr
->major_version
= OSSwapLittleToHostInt16(outxattr
->major_version
);
942 outxattr
->minor_version
= OSSwapLittleToHostInt16(outxattr
->minor_version
);
943 outxattr
->flags
= OSSwapLittleToHostInt64(outxattr
->flags
);
956 * Sets the EA we set on the root folder (fileid 1) to get information about the
957 * version of Content Protection that was used to write to this filesystem.
958 * Note that all multi-byte fields are written to disk little endian so they must be
959 * converted to little endian as needed.
961 * This will be written to the disk when it detects the EA is not there, or when we need
962 * to make a modification to the on-disk version that can be done in-place.
965 cp_setrootxattr(struct hfsmount
*hfsmp
, struct cp_root_xattr
*newxattr
)
968 struct vnop_setxattr_args args
;
972 args
.a_name
= CONTENT_PROTECTION_XATTR_NAME
;
973 args
.a_uio
= NULL
; //pass data ptr instead
975 args
.a_context
= NULL
; //no context needed, only done from mount.
977 /* Now convert the multi-byte fields to little endian before writing to disk. */
978 newxattr
->major_version
= OSSwapHostToLittleInt16(newxattr
->major_version
);
979 newxattr
->minor_version
= OSSwapHostToLittleInt16(newxattr
->minor_version
);
980 newxattr
->flags
= OSSwapHostToLittleInt64(newxattr
->flags
);
982 error
= hfs_setxattr_internal(NULL
, (caddr_t
)newxattr
,
983 sizeof(struct cp_root_xattr
), &args
, hfsmp
, 1);
989 * Stores new xattr data on the cnode.
990 * cnode lock held exclusive (if available).
992 * This function is also invoked during file creation.
994 int cp_setxattr(struct cnode
*cp
, struct cprotect
*entry
, struct hfsmount
*hfsmp
, uint32_t fileid
, int options
)
998 struct vnop_setxattr_args args
;
999 uint32_t target_fileid
;
1000 struct cnode
*arg_cp
= NULL
;
1001 uint32_t tempflags
= 0;
1005 args
.a_vp
= cp
->c_vp
;
1011 * When we set the EA in the same txn as the file creation,
1012 * we do not have a vnode/cnode yet. Use the specified fileid.
1015 target_fileid
= fileid
;
1017 args
.a_name
= CONTENT_PROTECTION_XATTR_NAME
;
1018 args
.a_uio
= NULL
; //pass data ptr instead
1019 args
.a_options
= options
;
1020 args
.a_context
= vfs_context_current();
1022 /* Add asserts for the CP flags in the CP blob. */
1023 if (entry
->cp_flags
& CP_NEEDS_KEYS
) {
1024 panic ("cp_setxattr: cp %p , cpentry %p still needs keys!", cp
, entry
);
1027 /* Disable flags that will be invalid as we're writing the EA out at this point. */
1028 tempflags
= entry
->cp_flags
;
1029 tempflags
&= ~CP_NO_XATTR
;
1031 switch(hfsmp
->hfs_running_cp_major_vers
) {
1032 case CP_NEW_MAJOR_VERS
: {
1033 struct cp_xattr_v4
*newxattr
= NULL
; // 70+ bytes; don't alloc on stack.
1034 MALLOC (newxattr
, struct cp_xattr_v4
*, sizeof(struct cp_xattr_v4
), M_TEMP
, M_WAITOK
);
1035 if (newxattr
== NULL
) {
1039 bzero (newxattr
, sizeof(struct cp_xattr_v4
));
1041 attrsize
= sizeof(*newxattr
) - CP_MAX_WRAPPEDKEYSIZE
+ entry
->cp_persistent_key_len
;
1043 /* Endian swap the multi-byte fields into L.E from host. */
1044 newxattr
->xattr_major_version
= OSSwapHostToLittleInt16 (hfsmp
->hfs_running_cp_major_vers
);
1045 newxattr
->xattr_minor_version
= OSSwapHostToLittleInt16(CP_MINOR_VERS
);
1046 newxattr
->key_size
= OSSwapHostToLittleInt32(entry
->cp_persistent_key_len
);
1047 newxattr
->flags
= OSSwapHostToLittleInt32(tempflags
);
1048 newxattr
->persistent_class
= OSSwapHostToLittleInt32(entry
->cp_pclass
);
1049 bcopy(entry
->cp_persistent_key
, newxattr
->persistent_key
, entry
->cp_persistent_key_len
);
1051 error
= hfs_setxattr_internal(arg_cp
, (caddr_t
)newxattr
, attrsize
, &args
, hfsmp
, target_fileid
);
1053 FREE(newxattr
, M_TEMP
);
1056 case CP_PREV_MAJOR_VERS
: {
1057 struct cp_xattr_v2
*newxattr
= NULL
;
1058 MALLOC (newxattr
, struct cp_xattr_v2
*, sizeof(struct cp_xattr_v2
), M_TEMP
, M_WAITOK
);
1059 if (newxattr
== NULL
) {
1063 bzero (newxattr
, sizeof(struct cp_xattr_v2
));
1065 attrsize
= sizeof(*newxattr
);
1067 /* Endian swap the multi-byte fields into L.E from host. */
1068 newxattr
->xattr_major_version
= OSSwapHostToLittleInt16(hfsmp
->hfs_running_cp_major_vers
);
1069 newxattr
->xattr_minor_version
= OSSwapHostToLittleInt16(CP_MINOR_VERS
);
1070 newxattr
->key_size
= OSSwapHostToLittleInt32(entry
->cp_persistent_key_len
);
1071 newxattr
->flags
= OSSwapHostToLittleInt32(tempflags
);
1072 newxattr
->persistent_class
= OSSwapHostToLittleInt32(entry
->cp_pclass
);
1073 bcopy(entry
->cp_persistent_key
, newxattr
->persistent_key
, entry
->cp_persistent_key_len
);
1075 error
= hfs_setxattr_internal(arg_cp
, (caddr_t
)newxattr
, attrsize
, &args
, hfsmp
, target_fileid
);
1077 FREE (newxattr
, M_TEMP
);
1083 entry
->cp_flags
&= ~CP_NO_XATTR
;
1092 * This function takes a cprotect struct with the cache keys and re-wraps them for
1093 * MKB's sake so that it can update its own data structures. It is useful when
1094 * there may not be a cnode in existence yet (for example, after creating
1098 cp_update_mkb (struct cprotect
*entry
, uint32_t fileid
) {
1102 /* We already validated this pclass earlier */
1103 if (entry
->cp_pclass
!= PROTECTION_CLASS_F
) {
1104 error
= g_cp_wrap_func
.wrapper (entry
->cp_pclass
, fileid
, entry
->cp_cache_key
,
1105 entry
->cp_cache_key_len
, NULL
, NULL
);
1116 * Used by an fcntl to query the underlying FS for its content protection version #
1120 cp_get_root_major_vers(vnode_t vp
, uint32_t *level
) {
1122 struct hfsmount
*hfsmp
= NULL
;
1123 struct mount
*mp
= NULL
;
1127 /* check if it supports content protection */
1128 if (cp_fs_protected(mp
) == 0) {
1132 hfsmp
= VFSTOHFS(mp
);
1133 /* figure out the level */
1135 err
= cp_root_major_vers(mp
);
1138 *level
= hfsmp
->hfs_running_cp_major_vers
;
1140 /* in error case, cp_root_major_vers will just return EINVAL. Use that */
1145 /********************
1147 *******************/
1150 cp_root_major_vers(mount_t mp
)
1153 struct cp_root_xattr xattr
;
1154 struct hfsmount
*hfsmp
= NULL
;
1156 hfsmp
= vfs_fsprivate(mp
);
1157 err
= cp_getrootxattr (hfsmp
, &xattr
);
1160 hfsmp
->hfs_running_cp_major_vers
= xattr
.major_version
;
1170 cp_vnode_is_eligible(struct vnode
*vp
)
1172 return ((vp
->v_op
== hfs_vnodeop_p
) &&
1173 (!vnode_issystem(vp
)) &&
1174 (vnode_isreg(vp
) || vnode_isdir(vp
)));
1180 cp_is_valid_class(int class)
1182 return ((class >= PROTECTION_CLASS_A
) &&
1183 (class <= PROTECTION_CLASS_F
));
1187 static struct cprotect
*
1188 cp_entry_alloc(size_t keylen
)
1190 struct cprotect
*cp_entry
;
1192 if (keylen
> CP_MAX_WRAPPEDKEYSIZE
)
1195 MALLOC(cp_entry
, struct cprotect
*, sizeof(struct cprotect
) + keylen
,
1197 if (cp_entry
== NULL
)
1200 bzero(cp_entry
, sizeof(*cp_entry
) + keylen
);
1201 cp_entry
->cp_persistent_key_len
= keylen
;
1206 cp_entry_dealloc(struct cprotect
*entry
)
1208 uint32_t keylen
= entry
->cp_persistent_key_len
;
1209 bzero(entry
, (sizeof(*entry
) + keylen
));
1210 FREE(entry
, M_TEMP
);
1215 * Initializes a new cprotect entry with xattr data from the cnode.
1216 * cnode lock held shared
1219 cp_getxattr(struct cnode
*cp
, struct hfsmount
*hfsmp
, struct cprotect
**outentry
)
1224 char uio_buf
[UIO_SIZEOF(1)];
1225 struct vnop_getxattr_args args
;
1226 struct cprotect
*entry
= NULL
;
1228 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
1229 args
.a_desc
= NULL
; // unused
1230 args
.a_vp
= cp
->c_vp
;
1231 args
.a_name
= CONTENT_PROTECTION_XATTR_NAME
;
1233 args
.a_options
= XATTR_REPLACE
;
1234 args
.a_context
= vfs_context_current(); // unused
1236 switch (hfsmp
->hfs_running_cp_major_vers
) {
1237 case CP_NEW_MAJOR_VERS
: {
1238 struct cp_xattr_v4
*xattr
= NULL
;
1239 MALLOC (xattr
, struct cp_xattr_v4
*, sizeof(struct cp_xattr_v4
), M_TEMP
, M_WAITOK
);
1240 if (xattr
== NULL
) {
1244 bzero(xattr
, sizeof (struct cp_xattr_v4
));
1245 attrsize
= sizeof(*xattr
);
1247 uio_addiov(auio
, CAST_USER_ADDR_T(xattr
), attrsize
);
1248 args
.a_size
= &attrsize
;
1250 error
= hfs_getxattr_internal(cp
, &args
, VTOHFS(cp
->c_vp
), 0);
1252 FREE (xattr
, M_TEMP
);
1256 /* Endian swap the multi-byte fields into host endianness from L.E. */
1257 xattr
->xattr_major_version
= OSSwapLittleToHostInt16(xattr
->xattr_major_version
);
1258 xattr
->xattr_minor_version
= OSSwapLittleToHostInt16(xattr
->xattr_minor_version
);
1259 xattr
->key_size
= OSSwapLittleToHostInt32(xattr
->key_size
);
1260 xattr
->flags
= OSSwapLittleToHostInt32(xattr
->flags
);
1261 xattr
->persistent_class
= OSSwapLittleToHostInt32(xattr
->persistent_class
);
1263 if (xattr
->xattr_major_version
!= hfsmp
->hfs_running_cp_major_vers
) {
1264 printf("hfs: cp_getxattr: bad xattr version %d expecting %d\n",
1265 xattr
->xattr_major_version
, hfsmp
->hfs_running_cp_major_vers
);
1267 FREE (xattr
, M_TEMP
);
1272 * Prevent a buffer overflow, and validate the key length obtained from the
1273 * EA. If it's too big, then bail out, because the EA can't be trusted at this
1276 if (xattr
->key_size
> CP_MAX_WRAPPEDKEYSIZE
) {
1278 FREE (xattr
, M_TEMP
);
1283 /* set up entry with information from xattr */
1284 entry
= cp_entry_alloc(xattr
->key_size
);
1286 FREE (xattr
, M_TEMP
);
1291 entry
->cp_pclass
= xattr
->persistent_class
;
1292 if (xattr
->xattr_major_version
>= CP_NEW_MAJOR_VERS
) {
1293 entry
->cp_flags
|= CP_OFF_IV_ENABLED
;
1295 bcopy(xattr
->persistent_key
, entry
->cp_persistent_key
, xattr
->key_size
);
1297 FREE (xattr
, M_TEMP
);
1301 case CP_PREV_MAJOR_VERS
: {
1302 struct cp_xattr_v2
*xattr
= NULL
;
1303 MALLOC (xattr
, struct cp_xattr_v2
*, sizeof(struct cp_xattr_v2
), M_TEMP
, M_WAITOK
);
1304 if (xattr
== NULL
) {
1308 bzero (xattr
, sizeof (struct cp_xattr_v2
));
1309 attrsize
= sizeof(*xattr
);
1311 uio_addiov(auio
, CAST_USER_ADDR_T(xattr
), attrsize
);
1312 args
.a_size
= &attrsize
;
1314 error
= hfs_getxattr_internal(cp
, &args
, VTOHFS(cp
->c_vp
), 0);
1316 FREE (xattr
, M_TEMP
);
1320 /* Endian swap the multi-byte fields into host endianness from L.E. */
1321 xattr
->xattr_major_version
= OSSwapLittleToHostInt16(xattr
->xattr_major_version
);
1322 xattr
->xattr_minor_version
= OSSwapLittleToHostInt16(xattr
->xattr_minor_version
);
1323 xattr
->key_size
= OSSwapLittleToHostInt32(xattr
->key_size
);
1324 xattr
->flags
= OSSwapLittleToHostInt32(xattr
->flags
);
1325 xattr
->persistent_class
= OSSwapLittleToHostInt32(xattr
->persistent_class
);
1327 if (xattr
->xattr_major_version
!= hfsmp
->hfs_running_cp_major_vers
) {
1328 printf("hfs: cp_getxattr: bad xattr version %d expecting %d\n",
1329 xattr
->xattr_major_version
, hfsmp
->hfs_running_cp_major_vers
);
1331 FREE (xattr
, M_TEMP
);
1336 * Prevent a buffer overflow, and validate the key length obtained from the
1337 * EA. If it's too big, then bail out, because the EA can't be trusted at this
1340 if (xattr
->key_size
> CP_V2_WRAPPEDKEYSIZE
) {
1342 FREE (xattr
, M_TEMP
);
1345 /* set up entry with information from xattr */
1346 entry
= cp_entry_alloc(xattr
->key_size
);
1348 FREE (xattr
, M_TEMP
);
1352 entry
->cp_pclass
= xattr
->persistent_class
;
1353 bcopy(xattr
->persistent_key
, entry
->cp_persistent_key
, xattr
->key_size
);
1354 FREE (xattr
, M_TEMP
);
1367 /* Setup AES context */
1369 cp_setup_aes_ctx(struct cprotect
*entry
)
1372 uint8_t cp_cache_iv_key
[CP_IV_KEYSIZE
]; /* Kiv */
1374 /* First init the cp_cache_iv_key[] */
1375 SHA1Init(&sha1ctxt
);
1376 SHA1Update(&sha1ctxt
, &entry
->cp_cache_key
[0], CP_MAX_KEYSIZE
);
1377 SHA1Final(&cp_cache_iv_key
[0], &sha1ctxt
);
1379 aes_encrypt_key128(&cp_cache_iv_key
[0], &entry
->cp_cache_iv_ctx
);
1386 * Make a new random per-file key and wrap it.
1387 * Normally this will get default_pclass as PROTECTION_CLASS_D.
1389 * But when the directory's class is set, we use that as the default.
1392 cp_make_keys(struct cprotect
**entry_arg
, struct hfsmount
*hfsmp
, cnid_t fileid
, int default_pclass
)
1394 struct cprotect
*entry
= *entry_arg
;
1395 int target_pclass
= 0;
1398 if (g_cp_state
.wrap_functions_set
!= 1) {
1399 printf("hfs: CP: could not create keys: no wrappers set\n");
1403 /* create new cp data: key and class */
1404 entry
->cp_cache_key_len
= CP_MAX_KEYSIZE
;
1405 read_random(&entry
->cp_cache_key
[0], entry
->cp_cache_key_len
);
1407 if (cp_is_valid_class(default_pclass
) == 0) {
1408 target_pclass
= PROTECTION_CLASS_D
;
1410 target_pclass
= default_pclass
;
1414 * Attempt to wrap the new key in the class key specified by target_pclass
1415 * Note that because we may be inheriting a protection level specified
1416 * by the containing directory, this can fail; we could be trying to
1417 * wrap this cache key in the class 'A' key while the device is locked.
1418 * As such, emit an error if we fail to wrap the key here, instead of
1422 error
= cp_wrap(target_pclass
, hfsmp
, fileid
, entry_arg
);
1427 /* cp_wrap() potentially updates c_cpentry */
1430 /* set the pclass to the target since the wrap was successful */
1431 entry
->cp_pclass
= target_pclass
;
1433 /* No need to go here for older EAs */
1434 if (hfsmp
->hfs_running_cp_major_vers
== CP_NEW_MAJOR_VERS
) {
1435 cp_setup_aes_ctx(entry
);
1436 entry
->cp_flags
|= CP_OFF_IV_ENABLED
;
1439 /* ready for business */
1440 entry
->cp_flags
&= ~CP_NEEDS_KEYS
;
1441 entry
->cp_flags
|= CP_NO_XATTR
;
1448 * If permitted, restore entry's unwrapped key from the persistent key.
1449 * If not, clear key and set CP_KEY_FLUSHED.
1450 * cnode lock held exclusive
1453 cp_restore_keys(struct cprotect
*entry
, struct hfsmount
*hfsmp
)
1457 error
= cp_unwrap(entry
->cp_pclass
, entry
);
1459 entry
->cp_flags
|= CP_KEY_FLUSHED
;
1460 bzero(entry
->cp_cache_key
, entry
->cp_cache_key_len
);
1464 /* No need to go here for older EAs */
1465 if (hfsmp
->hfs_running_cp_major_vers
== CP_NEW_MAJOR_VERS
) {
1466 cp_setup_aes_ctx(entry
);
1467 entry
->cp_flags
|= CP_OFF_IV_ENABLED
;
1470 /* ready for business */
1471 entry
->cp_flags
&= ~CP_KEY_FLUSHED
;
1478 cp_lock_vfs_callback(mount_t mp
, void *arg
) {
1481 * When iterating the various mount points that may
1482 * be present on a content-protected device, we need to skip
1483 * those that do not have it enabled.
1485 if (!cp_fs_protected(mp
)) {
1489 return vnode_iterate(mp
, 0, cp_lock_vnode_callback
, arg
);
1494 * Deny access to protected files if keys have been locked.
1497 cp_check_access(struct cnode
*cp
, int vnop __unused
)
1501 if (g_cp_state
.lock_state
== CP_UNLOCKED_STATE
) {
1505 if (!cp
->c_cpentry
) {
1506 /* unprotected node */
1510 if (!S_ISREG(cp
->c_mode
)) {
1514 /* Deny all access for class A files */
1515 switch (cp
->c_cpentry
->cp_pclass
) {
1516 case PROTECTION_CLASS_A
: {
1529 * Respond to a lock or unlock event.
1530 * On lock: clear out keys from memory, then flush file contents.
1531 * On unlock: nothing (function not called).
1534 cp_lock_vnode_callback(struct vnode
*vp
, void *arg
)
1537 struct cprotect
*entry
= NULL
;
1541 int took_truncate_lock
= 0;
1543 error
= vnode_getwithref (vp
);
1551 * When cleaning cnodes due to a lock event, we must
1552 * take the truncate lock AND the cnode lock. By taking
1553 * the truncate lock here, we force (nearly) all pending IOs
1554 * to drain before we can acquire the truncate lock. All HFS cluster
1555 * io calls except for swapfile IO need to acquire the truncate lock
1556 * prior to calling into the cluster layer.
1558 hfs_lock_truncate (cp
, HFS_EXCLUSIVE_LOCK
);
1559 took_truncate_lock
= 1;
1561 hfs_lock(cp
, HFS_FORCE_LOCK
);
1563 entry
= cp
->c_cpentry
;
1565 /* unprotected vnode: not a regular file */
1569 action
= (int)((uintptr_t) arg
);
1571 case CP_LOCKED_STATE
: {
1573 if (entry
->cp_pclass
!= PROTECTION_CLASS_A
||
1576 * There is no change at lock for other classes than A.
1577 * B is kept in memory for writing, and class F (for VM) does
1578 * not have a wrapped key, so there is no work needed for
1579 * wrapping/unwrapping.
1581 * Note that 'class F' is relevant here because if
1582 * hfs_vnop_strategy does not take the cnode lock
1583 * to protect the cp blob across IO operations, we rely
1584 * implicitly on the truncate lock to be held when doing IO.
1585 * The only case where the truncate lock is not held is during
1586 * swapfile IO because HFS just funnels the VNOP_PAGEOUT
1587 * directly to cluster_pageout.
1592 /* Before doing anything else, zero-fill sparse ranges as needed */
1593 ctx
= vfs_context_current();
1594 (void) hfs_filedone (vp
, ctx
);
1596 /* first, sync back dirty pages */
1598 ubc_msync (vp
, 0, ubc_getsize(vp
), NULL
, UBC_PUSHALL
| UBC_INVALIDATE
| UBC_SYNC
);
1599 hfs_lock (cp
, HFS_FORCE_LOCK
);
1602 * There was a concern here(9206856) about flushing keys before nand layer is done using them.
1603 * But since we are using ubc_msync with UBC_SYNC, it blocks until all IO is completed.
1604 * Once IOFS caches or is done with these keys, it calls the completion routine in IOSF.
1605 * Which in turn calls buf_biodone() and eventually unblocks ubc_msync()
1606 * Also verified that the cached data in IOFS is overwritten by other data, and there
1607 * is no key leakage in that layer.
1610 entry
->cp_flags
|= CP_KEY_FLUSHED
;
1611 bzero(&entry
->cp_cache_key
, entry
->cp_cache_key_len
);
1612 bzero(&entry
->cp_cache_iv_ctx
, sizeof(aes_encrypt_ctx
));
1614 /* some write may have arrived in the mean time. dump those pages */
1618 ubc_msync (vp
, 0, ubc_getsize(vp
), NULL
, UBC_INVALIDATE
| UBC_SYNC
);
1621 case CP_UNLOCKED_STATE
: {
1626 panic("Content Protection: unknown lock action %d\n", action
);
1634 if (took_truncate_lock
) {
1635 hfs_unlock_truncate (cp
, 0);
1643 cp_wrap(int class, struct hfsmount
*hfsmp
, cnid_t fileid
, struct cprotect
**entry_ptr
)
1646 struct cprotect
*entry
= *entry_ptr
;
1647 uint8_t newkey
[CP_MAX_WRAPPEDKEYSIZE
];
1648 size_t keylen
= CP_MAX_WRAPPEDKEYSIZE
;
1652 * PROTECTION_CLASS_F is in-use by VM swapfile; it represents a transient
1653 * key that is only good as long as the file is open. There is no
1654 * wrapped key, so there isn't anything to wrap.
1656 if (class == PROTECTION_CLASS_F
) {
1657 bzero(entry
->cp_persistent_key
, entry
->cp_persistent_key_len
);
1658 entry
->cp_persistent_key_len
= 0;
1663 * inode is passed here to find the backup bag wrapped blob
1664 * from userspace. This lookup will occur shortly after creation
1665 * and only if the file still exists. Beyond this lookup the
1666 * inode is not used. Technically there is a race, we practically
1669 error
= g_cp_wrap_func
.wrapper(class,
1671 entry
->cp_cache_key
,
1672 entry
->cp_cache_key_len
,
1678 * v2 EA's don't support the larger class B keys
1680 if ((keylen
!= CP_V2_WRAPPEDKEYSIZE
) &&
1681 (hfsmp
->hfs_running_cp_major_vers
== CP_PREV_MAJOR_VERS
)) {
1686 * Reallocate the entry if the new persistent key changed length
1688 if (entry
->cp_persistent_key_len
!= keylen
) {
1689 struct cprotect
*oldentry
= entry
;
1691 entry
= cp_entry_alloc(keylen
);
1695 bcopy(oldentry
, entry
, sizeof(struct cprotect
));
1696 entry
->cp_persistent_key_len
= keylen
;
1698 cp_entry_destroy (&oldentry
);
1703 bcopy(newkey
, entry
->cp_persistent_key
, keylen
);
1714 cp_unwrap(int class, struct cprotect
*entry
)
1717 size_t keylen
= CP_MAX_KEYSIZE
;
1720 * PROTECTION_CLASS_F is in-use by VM swapfile; it represents a transient
1721 * key that is only good as long as the file is open. There is no
1722 * wrapped key, so there isn't anything to unwrap.
1724 if (class == PROTECTION_CLASS_F
) {
1728 error
= g_cp_wrap_func
.unwrapper(class,
1729 entry
->cp_persistent_key
,
1730 entry
->cp_persistent_key_len
,
1731 entry
->cp_cache_key
,
1734 entry
->cp_cache_key_len
= keylen
;
1745 int cp_key_store_action(int action __unused
)
1751 int cp_register_wraps(cp_wrap_func_t key_store_func __unused
)
1756 #endif /* CONFIG_PROTECT */