Date: Tue, 20 Aug 2002 10:28:15 -0700 (PDT) From: Robert Watson <rwatson@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 16342 for review Message-ID: <200208201728.g7KHSEFD078892@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://people.freebsd.org/~peter/p4db/chv.cgi?CH=16342 Change 16342 by rwatson@rwatson_tislabs on 2002/08/20 10:27:18 Move a chunk of vnode-related label management code to a more logical location away from label initialization/destruction/... Affected files ... .. //depot/projects/trustedbsd/mac/sys/kern/kern_mac.c#255 edit Differences ... ==== //depot/projects/trustedbsd/mac/sys/kern/kern_mac.c#255 (text+ko) ==== @@ -196,7 +196,6 @@ #endif static int error_select(int error1, int error2); -static int mac_externalize(struct label *label, struct mac *mac); static int mac_policy_register(struct mac_policy_conf *mpc); static int mac_policy_unregister(struct mac_policy_conf *mpc); @@ -962,287 +961,6 @@ return (error2); } -void -mac_update_devfsdirent(struct devfs_dirent *de, struct vnode *vp) -{ - - MAC_PERFORM(update_devfsdirent, de, &de->de_label, vp, &vp->v_label); -} - -void -mac_update_procfsvnode(struct vnode *vp, struct ucred *cred) -{ - - MAC_PERFORM(update_procfsvnode, vp, &vp->v_label, cred); -} - -/* - * Support callout for policies that manage their own externalization - * using extended attributes. - */ -static int -mac_update_vnode_from_extattr(struct vnode *vp, struct mount *mp) -{ - int error; - - MAC_CHECK(update_vnode_from_extattr, vp, &vp->v_label, mp, - &mp->mnt_fslabel); - - return (error); -} - -/* - * Given an externalized mac label, internalize it and stamp it on a - * vnode. - */ -static int -mac_update_vnode_from_externalized(struct vnode *vp, struct mac *extmac) -{ - int error; - - MAC_CHECK(update_vnode_from_externalized, vp, &vp->v_label, extmac); - - return (error); -} - -/* - * Call out to individual policies to update the label in a vnode from - * the mountpoint. - */ -void -mac_update_vnode_from_mount(struct vnode *vp, struct mount *mp) -{ - - MAC_PERFORM(update_vnode_from_mount, vp, &vp->v_label, mp, - &mp->mnt_fslabel); - - ASSERT_VOP_LOCKED(vp, "mac_update_vnode_from_mount"); - if (mac_cache_fslabel_in_vnode) - vp->v_vflag |= VV_CACHEDLABEL; -} - -/* - * Implementation of VOP_REFRESHLABEL() that relies on extended attributes - * to store label data. Can be referenced by filesystems supporting - * extended attributes. - */ -int -vop_stdrefreshlabel_ea(struct vop_refreshlabel_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct mac extmac; - int buflen, error; - - ASSERT_VOP_LOCKED(vp, "vop_stdrefreshlabel_ea"); - - /* - * Call out to external policies first. Order doesn't really - * matter, as long as failure of one assures failure of all. - */ - error = mac_update_vnode_from_extattr(vp, vp->v_mount); - if (error) - return (error); - - buflen = sizeof(extmac); - error = vn_extattr_get(vp, IO_NODELOCKED, - FREEBSD_MAC_EXTATTR_NAMESPACE, FREEBSD_MAC_EXTATTR_NAME, &buflen, - (char *)&extmac, curthread); - switch (error) { - case 0: - /* Got it */ - break; - - case ENOATTR: - /* - * Use the label from the mount point. - */ - mac_update_vnode_from_mount(vp, vp->v_mount); - return (0); - - case EOPNOTSUPP: - default: - /* Fail horribly. */ - return (error); - } - - if (buflen != sizeof(extmac)) - error = EPERM; /* Fail very closed. */ - if (error == 0) - error = mac_update_vnode_from_externalized(vp, &extmac); - if (error == 0) - vp->v_vflag |= VV_CACHEDLABEL; - else { - struct vattr va; - - printf("Corrupted label on %s", - vp->v_mount->mnt_stat.f_mntonname); - if (VOP_GETATTR(vp, &va, curthread->td_ucred, curthread) == 0) - printf(" inum %ld", va.va_fileid); - if (mac_debug_label_fallback) { - printf(", falling back.\n"); - mac_update_vnode_from_mount(vp, vp->v_mount); - error = 0; - } else { - printf(".\n"); - error = EPERM; - } - } - - return (error); -} - -/* - * Make sure the vnode label is up-to-date. If EOPNOTSUPP, then we handle - * the labeling activity outselves. Filesystems should be careful not - * to change their minds regarding whether they support vop_refreshlabel() - * for a vnode or not. Don't cache the vnode here, allow the file - * system code to determine if it's safe to cache. If we update from - * the mount, don't cache since a change to the mount label should affect - * all vnodes. - */ -static int -vn_refreshlabel(struct vnode *vp, struct ucred *cred) -{ - int error; - - ASSERT_VOP_LOCKED(vp, "vn_refreshlabel"); - - if (vp->v_mount == NULL) { -/* - Eventually, we probably want to special-case refreshing - of deadfs vnodes, and if there's a lock-free race somewhere, - that case might be handled here. - - mac_update_vnode_deadfs(vp); - return (0); - */ - /* printf("vn_refreshlabel: null v_mount\n"); */ - if (vp->v_tag != VT_NON) - printf( - "vn_refreshlabel: null v_mount with non-VT_NON\n"); - return (EBADF); - } - - if (vp->v_vflag & VV_CACHEDLABEL) { - mac_vnode_label_cache_hits++; - return (0); - } else - mac_vnode_label_cache_misses++; - - if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0) { - mac_update_vnode_from_mount(vp, vp->v_mount); - return (0); - } - - error = VOP_REFRESHLABEL(vp, cred, curthread); - switch (error) { - case EOPNOTSUPP: - /* - * If labels are not supported on this vnode, fall back to - * the label in the mount and propagate it to the vnode. - * There should probably be some sort of policy/flag/decision - * about doing this. - */ - mac_update_vnode_from_mount(vp, vp->v_mount); - error = 0; - default: - return (error); - } -} - -/* - * Helper function for file systems using the vop_std*_ea() calls. This - * function must be called after EA service is available for the vnode, - * but before it's hooked up to the namespace so that the node persists - * if there's a crash, or before it can be accessed. On successful - * commit of the label to disk (etc), do cache the label. - */ -int -vop_stdcreatevnode_ea(struct vnode *dvp, struct vnode *tvp, struct ucred *cred) -{ - struct mac extmac; - int error; - - ASSERT_VOP_LOCKED(tvp, "vop_stdcreatevnode_ea"); - if ((dvp->v_mount->mnt_flag & MNT_MULTILABEL) == 0) { - mac_update_vnode_from_mount(tvp, tvp->v_mount); - } else { - error = vn_refreshlabel(dvp, cred); - if (error) - return (error); - - /* - * Stick the label in the vnode. Then try to write to - * disk. If we fail, return a failure to abort the - * create operation. Really, this failure shouldn't - * happen except in fairly unusual circumstances (out - * of disk, etc). - */ - mac_create_vnode(cred, dvp, tvp); - - error = mac_stdcreatevnode_ea(tvp); - if (error) - return (error); - - /* - * XXX: Eventually this will go away and all policies will - * directly manage their extended attributes. - */ - error = mac_externalize(&tvp->v_label, &extmac); - if (error) - return (error); - - error = vn_extattr_set(tvp, IO_NODELOCKED, - FREEBSD_MAC_EXTATTR_NAMESPACE, FREEBSD_MAC_EXTATTR_NAME, - sizeof(extmac), (char *)&extmac, curthread); - if (error == 0) - tvp->v_vflag |= VV_CACHEDLABEL; - else { -#if 0 - /* - * In theory, we could have fall-back behavior here. - * It would probably be incorrect. - */ -#endif - return (error); - } - } - - return (0); -} - -void -mac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp) -{ - int error; - - ASSERT_VOP_LOCKED(vp, "mac_execve_transition"); - - error = vn_refreshlabel(vp, old); - if (error) { - printf("mac_execve_transition: vn_refreshlabel returned %d\n", - error); - printf("mac_execve_transition: using old vnode label\n"); - } - - MAC_PERFORM(execve_transition, old, new, vp, &vp->v_label); -} - -int -mac_execve_will_transition(struct ucred *old, struct vnode *vp) -{ - int error, result; - - error = vn_refreshlabel(vp, old); - if (error) - return (error); - - result = 0; - MAC_BOOLEAN(execve_will_transition, ||, old, vp, &vp->v_label); - - return (result); -} - static void mac_init_label(struct label *label) { @@ -1584,6 +1302,287 @@ MAC_PERFORM(create_cred, parent_cred, child_cred); } +void +mac_update_devfsdirent(struct devfs_dirent *de, struct vnode *vp) +{ + + MAC_PERFORM(update_devfsdirent, de, &de->de_label, vp, &vp->v_label); +} + +void +mac_update_procfsvnode(struct vnode *vp, struct ucred *cred) +{ + + MAC_PERFORM(update_procfsvnode, vp, &vp->v_label, cred); +} + +/* + * Support callout for policies that manage their own externalization + * using extended attributes. + */ +static int +mac_update_vnode_from_extattr(struct vnode *vp, struct mount *mp) +{ + int error; + + MAC_CHECK(update_vnode_from_extattr, vp, &vp->v_label, mp, + &mp->mnt_fslabel); + + return (error); +} + +/* + * Given an externalized mac label, internalize it and stamp it on a + * vnode. + */ +static int +mac_update_vnode_from_externalized(struct vnode *vp, struct mac *extmac) +{ + int error; + + MAC_CHECK(update_vnode_from_externalized, vp, &vp->v_label, extmac); + + return (error); +} + +/* + * Call out to individual policies to update the label in a vnode from + * the mountpoint. + */ +void +mac_update_vnode_from_mount(struct vnode *vp, struct mount *mp) +{ + + MAC_PERFORM(update_vnode_from_mount, vp, &vp->v_label, mp, + &mp->mnt_fslabel); + + ASSERT_VOP_LOCKED(vp, "mac_update_vnode_from_mount"); + if (mac_cache_fslabel_in_vnode) + vp->v_vflag |= VV_CACHEDLABEL; +} + +/* + * Implementation of VOP_REFRESHLABEL() that relies on extended attributes + * to store label data. Can be referenced by filesystems supporting + * extended attributes. + */ +int +vop_stdrefreshlabel_ea(struct vop_refreshlabel_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct mac extmac; + int buflen, error; + + ASSERT_VOP_LOCKED(vp, "vop_stdrefreshlabel_ea"); + + /* + * Call out to external policies first. Order doesn't really + * matter, as long as failure of one assures failure of all. + */ + error = mac_update_vnode_from_extattr(vp, vp->v_mount); + if (error) + return (error); + + buflen = sizeof(extmac); + error = vn_extattr_get(vp, IO_NODELOCKED, + FREEBSD_MAC_EXTATTR_NAMESPACE, FREEBSD_MAC_EXTATTR_NAME, &buflen, + (char *)&extmac, curthread); + switch (error) { + case 0: + /* Got it */ + break; + + case ENOATTR: + /* + * Use the label from the mount point. + */ + mac_update_vnode_from_mount(vp, vp->v_mount); + return (0); + + case EOPNOTSUPP: + default: + /* Fail horribly. */ + return (error); + } + + if (buflen != sizeof(extmac)) + error = EPERM; /* Fail very closed. */ + if (error == 0) + error = mac_update_vnode_from_externalized(vp, &extmac); + if (error == 0) + vp->v_vflag |= VV_CACHEDLABEL; + else { + struct vattr va; + + printf("Corrupted label on %s", + vp->v_mount->mnt_stat.f_mntonname); + if (VOP_GETATTR(vp, &va, curthread->td_ucred, curthread) == 0) + printf(" inum %ld", va.va_fileid); + if (mac_debug_label_fallback) { + printf(", falling back.\n"); + mac_update_vnode_from_mount(vp, vp->v_mount); + error = 0; + } else { + printf(".\n"); + error = EPERM; + } + } + + return (error); +} + +/* + * Make sure the vnode label is up-to-date. If EOPNOTSUPP, then we handle + * the labeling activity outselves. Filesystems should be careful not + * to change their minds regarding whether they support vop_refreshlabel() + * for a vnode or not. Don't cache the vnode here, allow the file + * system code to determine if it's safe to cache. If we update from + * the mount, don't cache since a change to the mount label should affect + * all vnodes. + */ +static int +vn_refreshlabel(struct vnode *vp, struct ucred *cred) +{ + int error; + + ASSERT_VOP_LOCKED(vp, "vn_refreshlabel"); + + if (vp->v_mount == NULL) { +/* + Eventually, we probably want to special-case refreshing + of deadfs vnodes, and if there's a lock-free race somewhere, + that case might be handled here. + + mac_update_vnode_deadfs(vp); + return (0); + */ + /* printf("vn_refreshlabel: null v_mount\n"); */ + if (vp->v_tag != VT_NON) + printf( + "vn_refreshlabel: null v_mount with non-VT_NON\n"); + return (EBADF); + } + + if (vp->v_vflag & VV_CACHEDLABEL) { + mac_vnode_label_cache_hits++; + return (0); + } else + mac_vnode_label_cache_misses++; + + if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0) { + mac_update_vnode_from_mount(vp, vp->v_mount); + return (0); + } + + error = VOP_REFRESHLABEL(vp, cred, curthread); + switch (error) { + case EOPNOTSUPP: + /* + * If labels are not supported on this vnode, fall back to + * the label in the mount and propagate it to the vnode. + * There should probably be some sort of policy/flag/decision + * about doing this. + */ + mac_update_vnode_from_mount(vp, vp->v_mount); + error = 0; + default: + return (error); + } +} + +/* + * Helper function for file systems using the vop_std*_ea() calls. This + * function must be called after EA service is available for the vnode, + * but before it's hooked up to the namespace so that the node persists + * if there's a crash, or before it can be accessed. On successful + * commit of the label to disk (etc), do cache the label. + */ +int +vop_stdcreatevnode_ea(struct vnode *dvp, struct vnode *tvp, struct ucred *cred) +{ + struct mac extmac; + int error; + + ASSERT_VOP_LOCKED(tvp, "vop_stdcreatevnode_ea"); + if ((dvp->v_mount->mnt_flag & MNT_MULTILABEL) == 0) { + mac_update_vnode_from_mount(tvp, tvp->v_mount); + } else { + error = vn_refreshlabel(dvp, cred); + if (error) + return (error); + + /* + * Stick the label in the vnode. Then try to write to + * disk. If we fail, return a failure to abort the + * create operation. Really, this failure shouldn't + * happen except in fairly unusual circumstances (out + * of disk, etc). + */ + mac_create_vnode(cred, dvp, tvp); + + error = mac_stdcreatevnode_ea(tvp); + if (error) + return (error); + + /* + * XXX: Eventually this will go away and all policies will + * directly manage their extended attributes. + */ + error = mac_externalize(&tvp->v_label, &extmac); + if (error) + return (error); + + error = vn_extattr_set(tvp, IO_NODELOCKED, + FREEBSD_MAC_EXTATTR_NAMESPACE, FREEBSD_MAC_EXTATTR_NAME, + sizeof(extmac), (char *)&extmac, curthread); + if (error == 0) + tvp->v_vflag |= VV_CACHEDLABEL; + else { +#if 0 + /* + * In theory, we could have fall-back behavior here. + * It would probably be incorrect. + */ +#endif + return (error); + } + } + + return (0); +} + +void +mac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp) +{ + int error; + + ASSERT_VOP_LOCKED(vp, "mac_execve_transition"); + + error = vn_refreshlabel(vp, old); + if (error) { + printf("mac_execve_transition: vn_refreshlabel returned %d\n", + error); + printf("mac_execve_transition: using old vnode label\n"); + } + + MAC_PERFORM(execve_transition, old, new, vp, &vp->v_label); +} + +int +mac_execve_will_transition(struct ucred *old, struct vnode *vp) +{ + int error, result; + + error = vn_refreshlabel(vp, old); + if (error) + return (error); + + result = 0; + MAC_BOOLEAN(execve_will_transition, ||, old, vp, &vp->v_label); + + return (result); +} + int mac_check_vnode_access(struct ucred *cred, struct vnode *vp, int flags) { To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe p4-projects" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200208201728.g7KHSEFD078892>