1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
Index: etc/rc.d/jail
===================================================================
RCS file: /home/ncvs/src/etc/rc.d/jail,v
retrieving revision 1.23.2.2
diff -u -d -r1.23.2.2 jail
--- etc/rc.d/jail 16 Aug 2005 08:43:06 -0000 1.23.2.2
+++ etc/rc.d/jail 9 Jan 2007 21:45:16 -0000
@@ -66,6 +66,8 @@
[ -z "${jail_fstab}" ] && jail_fstab="/etc/fstab.${_j}"
eval jail_flags=\"\$jail_${_j}_flags\"
[ -z "${jail_flags}" ] && jail_flags="-l -U root"
+ eval _consolelog=\"\${jail_${_j}_consolelog:-${jail_consolelog}}\"
+ [ -z "${_consolelog}" ] && _consolelog="/var/log/jail_${_j}_console.log"
# Debugging aid
#
@@ -84,6 +86,7 @@
debug "$_j exec start: $jail_exec_start"
debug "$_j exec stop: $jail_exec_stop"
debug "$_j flags: $jail_flags"
+ debug "$_j consolelog: $_consolelog"
}
# set_sysctl rc_knob mib msg
@@ -113,6 +116,56 @@
fi
}
+# is_current_mountpoint()
+# Is the directory mount point for a currently mounted file
+# system?
+#
+is_current_mountpoint()
+{
+ local _dir _dir2
+
+ _dir=$1
+
+ _dir=`echo $_dir | sed -Ee 's#//+#/#g' -e 's#/$##'`
+ [ ! -d "${_dir}" ] && return 1
+ _dir2=`df ${_dir} | tail +2 | awk '{ print $6 }'`
+ [ "${_dir}" = "${_dir2}" ]
+ return $?
+}
+
+# is_symlinked_mountpoint()
+# Is a mount point, or any of its parent directories, a symlink?
+#
+is_symlinked_mountpoint()
+{
+ local _dir
+
+ _dir=$1
+
+ [ -L "$_dir" ] && return 0
+ [ "$_dir" = "/" ] && return 1
+ is_symlinked_mountpoint `dirname $_dir`
+ return $?
+}
+
+# secure_umount
+# Try to unmount a mount point without being vulnerable to
+# symlink attacks.
+#
+secure_umount()
+{
+ local _dir
+
+ _dir=$1
+
+ if is_current_mountpoint ${_dir}; then
+ umount -f ${_dir} >/dev/null 2>&1
+ else
+ debug "Nothing mounted on ${_dir} - not unmounting"
+ fi
+}
+
+
# jail_umount_fs
# This function unmounts certain special filesystems in the
# currently selected jail. The caller must call the init_variables()
@@ -120,27 +173,65 @@
#
jail_umount_fs()
{
+ local _device _mountpt _rest
+
if checkyesno jail_fdescfs; then
if [ -d "${jail_fdescdir}" ] ; then
- umount -f ${jail_fdescdir} >/dev/null 2>&1
+ secure_umount ${jail_fdescdir}
fi
fi
if checkyesno jail_devfs; then
if [ -d "${jail_devdir}" ] ; then
- umount -f ${jail_devdir} >/dev/null 2>&1
+ secure_umount ${jail_devdir}
fi
fi
if checkyesno jail_procfs; then
if [ -d "${jail_procdir}" ] ; then
- umount -f ${jail_procdir} >/dev/null 2>&1
+ secure_umount ${jail_procdir}
fi
fi
if checkyesno jail_mount; then
[ -f "${jail_fstab}" ] || warn "${jail_fstab} does not exist"
- umount -a -F "${jail_fstab}" >/dev/null 2>&1
+ tail -r ${jail_fstab} | while read _device _mountpt _rest; do
+ case ":${_device}" in
+ :#* | :)
+ continue
+ ;;
+ esac
+ secure_umount ${_mountpt}
+ done
fi
}
+# jail_mount_fstab()
+# Mount file systems from a per jail fstab while trying to
+# secure against symlink attacks at the mount points.
+#
+# If we are certain we cannot secure against symlink attacks we
+# do not mount all of the file systems (since we cannot just not
+# mount the file system with the problematic mount point).
+#
+# The caller must call the init_variables() routine before
+# calling this one.
+#
+jail_mount_fstab()
+{
+ local _device _mountpt _rest
+
+ while read _device _mountpt _rest; do
+ case ":${_device}" in
+ :#* | :)
+ continue
+ ;;
+ esac
+ if is_symlinked_mountpoint ${_mountpt}; then
+ warn "${_mountpt} has symlink as parent - not mounting from ${jail_fstab}"
+ return
+ fi
+ done <${_fstab}
+ mount -a -F "${jail_fstab}"
+}
+
jail_start()
{
echo -n 'Configuring jails:'
@@ -167,12 +258,16 @@
if [ ! -f "${jail_fstab}" ]; then
err 3 "$name: ${jail_fstab} does not exist"
fi
- mount -a -F "${jail_fstab}"
+ jail_mount_fstab
fi
if checkyesno jail_devfs; then
# If devfs is already mounted here, skip it.
df -t devfs "${jail_devdir}" >/dev/null
if [ $? -ne 0 ]; then
+ if is_symlinked_mountpoint ${jail_devdir}; then
+ warn "${jail_devdir} has symlink as parent - not starting jail ${_jail}"
+ continue
+ fi
info "Mounting devfs on ${jail_devdir}"
devfs_mount_jail "${jail_devdir}" ${jail_ruleset}
# Transitional symlink for old binaries
@@ -193,13 +288,21 @@
# cd "$__pwd"
fi
if checkyesno jail_fdescfs; then
- info "Mounting fdescfs on ${jail_fdescdir}"
- mount -t fdescfs fdesc "${jail_fdescdir}"
+ if is_symlinked_mountpoint ${jail_fdescdir}; then
+ warn "${jail_fdescdir} has symlink as parent, not mounting"
+ else
+ info "Mounting fdescfs on ${jail_fdescdir}"
+ mount -t fdescfs fdesc "${jail_fdescdir}"
+ fi
fi
if checkyesno jail_procfs; then
- info "Mounting procfs onto ${jail_procdir}"
- if [ -d "${jail_procdir}" ] ; then
- mount -t procfs proc "${jail_procdir}"
+ if is_symlinked_mountpoint ${jail_procdir}; then
+ warn "${jail_procdir} has symlink as parent, not mounting"
+ else
+ info "Mounting procfs onto ${jail_procdir}"
+ if [ -d "${jail_procdir}" ] ; then
+ mount -t procfs proc "${jail_procdir}"
+ fi
fi
fi
_tmp_jail=${_tmp_dir}/jail.$$
@@ -207,7 +310,7 @@
${jail_ip} ${jail_exec_start} > ${_tmp_jail} 2>&1
[ "$?" -eq 0 ] && echo -n " $jail_hostname"
_jail_id=$(head -1 ${_tmp_jail})
- tail +2 ${_tmp_jail} >${jail_rootdir}/var/log/console.log
+ tail +2 ${_tmp_jail} >${_consolelog}
rm -f ${_tmp_jail}
echo ${_jail_id} > /var/run/jail_${_jail}.id
done
@@ -226,7 +329,7 @@
init_variables $_jail
if [ -n "${jail_exec_stop}" ]; then
eval env -i /usr/sbin/jexec ${_jail_id} ${jail_exec_stop} \
- >> ${jail_rootdir}/var/log/console.log 2>&1
+ >> ${_consolelog} 2>&1
fi
killall -j ${_jail_id} -TERM > /dev/null 2>&1
sleep 1
|