Print this page
7656 unlinking directory on tmpfs can cause kernel panic
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Rich Lowe <richlowe@richlowe.net>
Reviewed by: Vitaliy Gusev <vgusev@racktopsystems.com>


1086 static int
1087 tmp_remove(
1088         struct vnode *dvp,
1089         char *nm,
1090         struct cred *cred,
1091         caller_context_t *ct,
1092         int flags)
1093 {
1094         struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
1095         int error;
1096         struct tmpnode *tp = NULL;
1097 
1098         error = tdirlookup(parent, nm, &tp, cred);
1099         if (error)
1100                 return (error);
1101 
1102         ASSERT(tp);
1103         rw_enter(&parent->tn_rwlock, RW_WRITER);
1104         rw_enter(&tp->tn_rwlock, RW_WRITER);
1105 
1106         if (tp->tn_type != VDIR ||
1107             (error = secpolicy_fs_linkdir(cred, dvp->v_vfsp)) == 0)
1108                 error = tdirdelete(parent, tp, nm, tp->tn_type == VDIR ?
1109                     DR_RMDIR : DR_REMOVE, cred);
1110 
1111         rw_exit(&tp->tn_rwlock);
1112         rw_exit(&parent->tn_rwlock);
1113         vnevent_remove(TNTOV(tp), dvp, nm, ct);
1114         tmpnode_rele(tp);
1115 
1116         TRACE_3(TR_FAC_TMPFS, TR_TMPFS_REMOVE,
1117             "tmpfs remove:dvp %p nm %s error %d", dvp, nm, error);
1118         return (error);
1119 }
1120 
1121 /* ARGSUSED4 */
1122 static int
1123 tmp_link(
1124         struct vnode *dvp,
1125         struct vnode *srcvp,
1126         char *tnm,
1127         struct cred *cred,
1128         caller_context_t *ct,
1129         int flags)
1130 {
1131         struct tmpnode *parent;
1132         struct tmpnode *from;
1133         struct tmount *tm = (struct tmount *)VTOTM(dvp);
1134         int error;
1135         struct tmpnode *found = NULL;
1136         struct vnode *realvp;
1137 
1138         if (VOP_REALVP(srcvp, &realvp, ct) == 0)
1139                 srcvp = realvp;
1140 
1141         parent = (struct tmpnode *)VTOTN(dvp);
1142         from = (struct tmpnode *)VTOTN(srcvp);
1143 
1144         if ((srcvp->v_type == VDIR &&
1145             secpolicy_fs_linkdir(cred, dvp->v_vfsp)) ||
1146             (from->tn_uid != crgetuid(cred) && secpolicy_basic_link(cred)))
1147                 return (EPERM);
1148 
1149         /*
1150          * Make sure link for extended attributes is valid
1151          * We only support hard linking of xattr's in xattrdir to an xattrdir
1152          */
1153         if ((from->tn_flags & ISXATTR) != (parent->tn_flags & ISXATTR))
1154                 return (EINVAL);
1155 
1156         error = tdirlookup(parent, tnm, &found, cred);
1157         if (error == 0) {
1158                 ASSERT(found);
1159                 tmpnode_rele(found);
1160                 return (EEXIST);
1161         }
1162 
1163         if (error != ENOENT)
1164                 return (error);
1165 




1086 static int
1087 tmp_remove(
1088         struct vnode *dvp,
1089         char *nm,
1090         struct cred *cred,
1091         caller_context_t *ct,
1092         int flags)
1093 {
1094         struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
1095         int error;
1096         struct tmpnode *tp = NULL;
1097 
1098         error = tdirlookup(parent, nm, &tp, cred);
1099         if (error)
1100                 return (error);
1101 
1102         ASSERT(tp);
1103         rw_enter(&parent->tn_rwlock, RW_WRITER);
1104         rw_enter(&tp->tn_rwlock, RW_WRITER);
1105 
1106         error = tp->tn_type == VDIR ? EPERM :
1107             tdirdelete(parent, tp, nm, DR_REMOVE, cred);


1108 
1109         rw_exit(&tp->tn_rwlock);
1110         rw_exit(&parent->tn_rwlock);
1111         vnevent_remove(TNTOV(tp), dvp, nm, ct);
1112         tmpnode_rele(tp);
1113 
1114         TRACE_3(TR_FAC_TMPFS, TR_TMPFS_REMOVE,
1115             "tmpfs remove:dvp %p nm %s error %d", dvp, nm, error);
1116         return (error);
1117 }
1118 
1119 /* ARGSUSED4 */
1120 static int
1121 tmp_link(
1122         struct vnode *dvp,
1123         struct vnode *srcvp,
1124         char *tnm,
1125         struct cred *cred,
1126         caller_context_t *ct,
1127         int flags)
1128 {
1129         struct tmpnode *parent;
1130         struct tmpnode *from;
1131         struct tmount *tm = (struct tmount *)VTOTM(dvp);
1132         int error;
1133         struct tmpnode *found = NULL;
1134         struct vnode *realvp;
1135 
1136         if (VOP_REALVP(srcvp, &realvp, ct) == 0)
1137                 srcvp = realvp;
1138 
1139         parent = (struct tmpnode *)VTOTN(dvp);
1140         from = (struct tmpnode *)VTOTN(srcvp);
1141 
1142         if (srcvp->v_type == VDIR ||

1143             (from->tn_uid != crgetuid(cred) && secpolicy_basic_link(cred)))
1144                 return (EPERM);
1145 
1146         /*
1147          * Make sure link for extended attributes is valid
1148          * We only support hard linking of xattr's in xattrdir to an xattrdir
1149          */
1150         if ((from->tn_flags & ISXATTR) != (parent->tn_flags & ISXATTR))
1151                 return (EINVAL);
1152 
1153         error = tdirlookup(parent, tnm, &found, cred);
1154         if (error == 0) {
1155                 ASSERT(found);
1156                 tmpnode_rele(found);
1157                 return (EEXIST);
1158         }
1159 
1160         if (error != ENOENT)
1161                 return (error);
1162