+static int
+iopolicysys_vfs_trigger_resolve(struct proc *p __unused, int cmd,
+ int scope, int policy, struct _iopol_param_t *iop_param)
+{
+ int error = 0;
+
+ /* Validate scope */
+ switch (scope) {
+ case IOPOL_SCOPE_PROCESS:
+ /* Only process OK */
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+ /* Validate policy */
+ if (cmd == IOPOL_CMD_SET) {
+ switch (policy) {
+ case IOPOL_VFS_TRIGGER_RESOLVE_DEFAULT:
+ /* fall-through */
+ case IOPOL_VFS_TRIGGER_RESOLVE_OFF:
+ /* These policies are OK */
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+ }
+
+ /* Perform command */
+ switch (cmd) {
+ case IOPOL_CMD_SET:
+ switch (policy) {
+ case IOPOL_VFS_TRIGGER_RESOLVE_DEFAULT:
+ OSBitAndAtomic16(~((uint32_t)P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE), &p->p_vfs_iopolicy);
+ break;
+ case IOPOL_VFS_TRIGGER_RESOLVE_OFF:
+ OSBitOrAtomic16((uint32_t)P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE, &p->p_vfs_iopolicy);
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+ break;
+ case IOPOL_CMD_GET:
+ iop_param->iop_policy = (p->p_vfs_iopolicy & P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE)
+ ? IOPOL_VFS_TRIGGER_RESOLVE_OFF
+ : IOPOL_VFS_TRIGGER_RESOLVE_DEFAULT;
+ break;
+ default:
+ error = EINVAL; /* unknown command */
+ break;
+ }
+
+out:
+ return error;
+}
+
+static int
+iopolicysys_vfs_ignore_content_protection(struct proc *p, int cmd, int scope,
+ int policy, struct _iopol_param_t *iop_param)
+{
+ int error = 0;
+
+ /* Validate scope */
+ switch (scope) {
+ case IOPOL_SCOPE_PROCESS:
+ /* Only process OK */
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+ /* Validate policy */
+ if (cmd == IOPOL_CMD_SET) {
+ switch (policy) {
+ case IOPOL_VFS_CONTENT_PROTECTION_DEFAULT:
+ OS_FALLTHROUGH;
+ case IOPOL_VFS_CONTENT_PROTECTION_IGNORE:
+ /* These policies are OK */
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+ }
+
+ /* Perform command */
+ switch (cmd) {
+ case IOPOL_CMD_SET:
+ if (0 == kauth_cred_issuser(kauth_cred_get())) {
+ /* If it's a non-root process, it needs to have the entitlement to set the policy */
+ boolean_t entitled = FALSE;
+ entitled = IOTaskHasEntitlement(current_task(), "com.apple.private.iopol.case_sensitivity");
+ if (!entitled) {
+ error = EPERM;
+ goto out;
+ }
+ }
+
+ switch (policy) {
+ case IOPOL_VFS_CONTENT_PROTECTION_DEFAULT:
+ os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_IGNORE_CONTENT_PROTECTION, relaxed);
+ break;
+ case IOPOL_VFS_CONTENT_PROTECTION_IGNORE:
+ os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_IGNORE_CONTENT_PROTECTION, relaxed);
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+ break;
+ case IOPOL_CMD_GET:
+ iop_param->iop_policy = (os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_IGNORE_CONTENT_PROTECTION)
+ ? IOPOL_VFS_CONTENT_PROTECTION_IGNORE
+ : IOPOL_VFS_CONTENT_PROTECTION_DEFAULT;
+ break;
+ default:
+ error = EINVAL; /* unknown command */
+ break;
+ }
+
+out:
+ return error;
+}
+
+#define AUTHORIZED_ACCESS_ENTITLEMENT \
+ "com.apple.private.vfs.authorized-access"
+int
+iopolicysys_vfs_ignore_node_permissions(struct proc *p, int cmd, int scope,
+ int policy, __unused struct _iopol_param_t *iop_param)
+{
+ int error = EINVAL;
+
+ switch (scope) {
+ case IOPOL_SCOPE_PROCESS:
+ break;
+ default:
+ goto out;
+ }
+
+ switch (cmd) {
+ case IOPOL_CMD_GET:
+ policy = os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_IGNORE_NODE_PERMISSIONS ?
+ IOPOL_VFS_IGNORE_PERMISSIONS_ON : IOPOL_VFS_IGNORE_PERMISSIONS_OFF;
+ iop_param->iop_policy = policy;
+ goto out_ok;
+ case IOPOL_CMD_SET:
+ /* SET is handled after the switch */
+ break;
+ default:
+ goto out;
+ }
+
+ if (!IOTaskHasEntitlement(current_task(), AUTHORIZED_ACCESS_ENTITLEMENT)) {
+ error = EPERM;
+ goto out;
+ }
+
+ switch (policy) {
+ case IOPOL_VFS_IGNORE_PERMISSIONS_OFF:
+ os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_IGNORE_NODE_PERMISSIONS, relaxed);
+ break;
+ case IOPOL_VFS_IGNORE_PERMISSIONS_ON:
+ os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_IGNORE_NODE_PERMISSIONS, relaxed);
+ break;
+ default:
+ break;
+ }
+
+out_ok:
+ error = 0;
+out:
+ return error;
+}
+
+#define SKIP_MTIME_UPDATE_ENTITLEMENT \
+ "com.apple.private.vfs.skip-mtime-updates"
+int
+iopolicysys_vfs_skip_mtime_update(struct proc *p, int cmd, int scope,
+ int policy, __unused struct _iopol_param_t *iop_param)
+{
+ int error = EINVAL;
+
+ switch (scope) {
+ case IOPOL_SCOPE_PROCESS:
+ break;
+ default:
+ goto out;
+ }
+
+ switch (cmd) {
+ case IOPOL_CMD_GET:
+ policy = os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_SKIP_MTIME_UPDATE ?
+ IOPOL_VFS_SKIP_MTIME_UPDATE_ON : IOPOL_VFS_SKIP_MTIME_UPDATE_OFF;
+ iop_param->iop_policy = policy;
+ goto out_ok;
+ case IOPOL_CMD_SET:
+ break;
+ default:
+ break;
+ }
+
+ if (!IOTaskHasEntitlement(current_task(), SKIP_MTIME_UPDATE_ENTITLEMENT)) {
+ error = EPERM;
+ goto out;
+ }
+
+ switch (policy) {
+ case IOPOL_VFS_SKIP_MTIME_UPDATE_OFF:
+ os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_SKIP_MTIME_UPDATE, relaxed);
+ break;
+ case IOPOL_VFS_SKIP_MTIME_UPDATE_ON:
+ os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_SKIP_MTIME_UPDATE, relaxed);
+ break;
+ default:
+ break;
+ }
+
+out_ok:
+ error = 0;
+out:
+ return error;
+}