diff mbox series

scripts/selinux: modernize mdp

Message ID 20190221184213.31303-1-sds@tycho.nsa.gov (mailing list archive)
State Superseded
Headers show
Series scripts/selinux: modernize mdp | expand

Commit Message

Stephen Smalley Feb. 21, 2019, 6:42 p.m. UTC
Derived in part from a patch by Dominick Grift.

The MDP example no longer works on modern systems.  Fix it.
While we are at it, add MLS support and enable it.

NB This still does not work on systems using dbus-daemon instead of
dbus-broker because dbus-daemon does not yet gracefully handle unknown
classes/permissions.  This is a deficiency in libselinux's
selinux_set_mapping() interface and underlying implementation,
which was never fully updated to deal with unknown classes/permissions
unlike the kernel.  Programs that instead use selinux_check_access()
like dbus-broker do not have this problem.

Other known issues:
- Not everything appears to be relabeled, so some files are left with invalid
contexts and remapped to the unlabeled SID/context.
- X will fail due to lack of a x_contexts file
- libvirtd will fail due to lack of a virtual_domain_context file
- crond reports an error with "No security context"

Changes to mdp:
Add support for devtmpfs, required by modern Linux distributions.
Add MLS support, with sample sensitivities, categories, and constraints.
Generate fs_use and genfscon rules based on kernel configuration.
Update list of filesystem types for fs_use and genfscon rules.
Use object_r for object contexts.

Changes to install_policy.sh:
Bail immediately on any errors.
Provide more helpful error messages when unable to find userspace tools.
Refuse to run if SELinux is already enabled.
Unconditionally move aside /etc/selinux/config and create a new one.
Build policy with -U allow so that userspace object managers do not break.
Build policy with MLS enabled by default.
Add default seusers mapping and failsafe context for use by
pam_selinux / libselinux.
Set to permissive mode rather than enforcing to permit initial autorelabel.
Update the list of filesystem types to be relabeled.
Create /.autorelabel to trigger an autorelabel on reboot.
Drop broken attempt to relabel the /dev mountpoint directory.

Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
---
 scripts/selinux/install_policy.sh |  82 ++++++++-------
 scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
 2 files changed, 183 insertions(+), 63 deletions(-)

Comments

Stephen Smalley Feb. 21, 2019, 7:34 p.m. UTC | #1
On 2/21/19 1:42 PM, Stephen Smalley wrote:
> Derived in part from a patch by Dominick Grift.
> 
> The MDP example no longer works on modern systems.  Fix it.
> While we are at it, add MLS support and enable it.
> 
> NB This still does not work on systems using dbus-daemon instead of
> dbus-broker because dbus-daemon does not yet gracefully handle unknown
> classes/permissions.  This is a deficiency in libselinux's
> selinux_set_mapping() interface and underlying implementation,
> which was never fully updated to deal with unknown classes/permissions
> unlike the kernel.  Programs that instead use selinux_check_access()
> like dbus-broker do not have this problem.

We could perhaps avoid this problem by having mdp always include at 
least a core set of userspace classes/permissions in the policy it 
generates.  We could also fix libselinux but that won't help on any 
existing distro.

> 
> Other known issues:
> - Not everything appears to be relabeled, so some files are left with invalid
> contexts and remapped to the unlabeled SID/context.

This appears to be partly due to overuse of <<none>> in file_contexts 
(.fc) files.  That excludes those parts of the filesystem from being 
relabeled at all.  This was used to exclude pseudo filesystems 
(obsoleted by seclabel mount option detection) or runtime 
directories/files whose labels were derived from the creating process 
and couldn't be statically specified by file_contexts.  To get my system 
back into working order even with targeted policy, I had to strip all 
<<none>> entries out of my file_contexts* files and then run setfiles -F 
with the list of filesystem mounts to relabel.  Otherwise, I'd have 
files left in the old contexts and the system wouldn't even come up to 
user login, even if permissive.

FWIW, Android policy doesn't use <<none>> at all.  But they also don't 
have a /.* or equivalent entry as a default match, so anything not 
covered by a more specific match is likewise not labeled. 
seapp_contexts handles the more dynamic aspect of app directory labeling 
for Android.

The other problem case for relabeling is the mount point directories, 
which requires unmounting them all and relabeling them if we care. 
Otherwise they'll just get the unlabeled context and as long as we allow 
mounting on that, it should be ok.

> - X will fail due to lack of a x_contexts file
> - libvirtd will fail due to lack of a virtual_domain_context file

We could easily add these to the mdp policy.

> - crond reports an error with "No security context"

This is probably due to the lack of a contexts/default_contexts or any 
contexts/users/ files in the dummy policy.

> 
> Changes to mdp:
> Add support for devtmpfs, required by modern Linux distributions.
> Add MLS support, with sample sensitivities, categories, and constraints.
> Generate fs_use and genfscon rules based on kernel configuration.
> Update list of filesystem types for fs_use and genfscon rules.
> Use object_r for object contexts.
> 
> Changes to install_policy.sh:
> Bail immediately on any errors.
> Provide more helpful error messages when unable to find userspace tools.
> Refuse to run if SELinux is already enabled.
> Unconditionally move aside /etc/selinux/config and create a new one.
> Build policy with -U allow so that userspace object managers do not break.
> Build policy with MLS enabled by default.
> Add default seusers mapping and failsafe context for use by
> pam_selinux / libselinux.
> Set to permissive mode rather than enforcing to permit initial autorelabel.
> Update the list of filesystem types to be relabeled.
> Create /.autorelabel to trigger an autorelabel on reboot.
> Drop broken attempt to relabel the /dev mountpoint directory.
> 
> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> ---
>   scripts/selinux/install_policy.sh |  82 ++++++++-------
>   scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
>   2 files changed, 183 insertions(+), 63 deletions(-)
> 
> diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
> index 0b86c47baf7d..09eab4d0da5c 100755
> --- a/scripts/selinux/install_policy.sh
> +++ b/scripts/selinux/install_policy.sh
> @@ -1,30 +1,51 @@
>   #!/bin/sh
>   # SPDX-License-Identifier: GPL-2.0
> +set -e
>   if [ `id -u` -ne 0 ]; then
>   	echo "$0: must be root to install the selinux policy"
>   	exit 1
>   fi
> +
>   SF=`which setfiles`
>   if [ $? -eq 1 ]; then
> -	if [ -f /sbin/setfiles ]; then
> -		SF="/usr/setfiles"
> -	else
> -		echo "no selinux tools installed: setfiles"
> -		exit 1
> -	fi
> +	echo "Could not find setfiles"
> +	echo "Do you have policycoreutils installed?"
> +	exit 1
>   fi
>   
> -cd mdp
> -
>   CP=`which checkpolicy`
> +if [ $? -eq 1 ]; then
> +	echo "Could not find checkpolicy"
> +	echo "Do you have checkpolicy installed?"
> +	exit 1
> +fi
>   VERS=`$CP -V | awk '{print $1}'`
>   
> -./mdp policy.conf file_contexts
> -$CP -o policy.$VERS policy.conf
> +ENABLED=`which selinuxenabled`
> +if [ $? -eq 1 ]; then
> +	echo "Could not find selinuxenabled"
> +	echo "Do you have libselinux-utils installed?"
> +	exit 1
> +fi
> +
> +if selinuxenabled; then
> +    echo "SELinux is already enabled"
> +    echo "This prevents safely relabeling all files."
> +    echo "Boot with selinux=0 on the kernel command-line or"
> +    echo "SELINUX=disabled in /etc/selinux/config."
> +    exit 1
> +fi
> +
> +cd mdp
> +./mdp -m policy.conf file_contexts
> +$CP -U allow -M -o policy.$VERS policy.conf
>   
>   mkdir -p /etc/selinux/dummy/policy
>   mkdir -p /etc/selinux/dummy/contexts/files
>   
> +echo "__default__:user_u" > /etc/selinux/dummy/seusers
> +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
> +
>   cp file_contexts /etc/selinux/dummy/contexts/files
>   cp dbus_contexts /etc/selinux/dummy/contexts
>   cp policy.$VERS /etc/selinux/dummy/policy
> @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
>   if [ ! -d /etc/selinux ]; then
>   	mkdir -p /etc/selinux
>   fi
> -if [ ! -f /etc/selinux/config ]; then
> -	cat > /etc/selinux/config << EOF
> -SELINUX=enforcing
> +if [ -f /etc/selinux/config ]; then
> +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
> +    mv /etc/selinux/config /etc/selinux/config.bak
> +fi
> +echo "Creating new /etc/selinux/config for dummy policy."
> +cat > /etc/selinux/config << EOF
> +SELINUX=permissive
>   SELINUXTYPE=dummy
>   EOF
> -else
> -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
> -	if [ "eq$TYPE" != "eqdummy" ]; then
> -		selinuxenabled
> -		if [ $? -eq 0 ]; then
> -			echo "SELinux already enabled with a non-dummy policy."
> -			echo "Exiting.  Please install policy by hand if that"
> -			echo "is what you REALLY want."
> -			exit 1
> -		fi
> -		mv /etc/selinux/config /etc/selinux/config.mdpbak
> -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
> -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
> -	fi
> -fi
>   
>   cd /etc/selinux/dummy/contexts/files
> -$SF file_contexts /
> +$SF -F file_contexts /
>   
> -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
> -$SF file_contexts $mounts
> +mounts=`cat /proc/$$/mounts | \
> +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
> +	awk '{ print $2 '}`
> +$SF -F file_contexts $mounts
>   
> -
> -dodev=`cat /proc/$$/mounts | grep "/dev "`
> -if [ "eq$dodev" != "eq" ]; then
> -	mount --move /dev /mnt
> -	$SF file_contexts /dev
> -	mount --move /mnt /dev
> -fi
> +touch /.autorelabel
> diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
> index 073fe7537f6c..daad333c7252 100644
> --- a/scripts/selinux/mdp/mdp.c
> +++ b/scripts/selinux/mdp/mdp.c
> @@ -33,6 +33,7 @@
>   #include <unistd.h>
>   #include <string.h>
>   #include <sys/socket.h>
> +#include <linux/kconfig.h>
>   
>   static void usage(char *name)
>   {
> @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
>   	}
>   	fprintf(fout, "\n");
>   
> -	/* NOW PRINT OUT MLS STUFF */
> +	/* print out mls declarations and constraints */
>   	if (mls) {
> -		printf("MLS not yet implemented\n");
> -		exit(1);
> +		fprintf(fout, "sensitivity s0;\n");
> +		fprintf(fout, "sensitivity s1;\n");
> +		fprintf(fout, "dominance { s0 s1 }\n");
> +		fprintf(fout, "category c0;\n");
> +		fprintf(fout, "category c1;\n");
> +		fprintf(fout, "level s0:c0.c1;\n");
> +		fprintf(fout, "level s1:c0.c1;\n");
> +#define SYSTEMLOW "s0"
> +#define SYSTEMHIGH "s1:c0.c1"
> +		for (i = 0; secclass_map[i].name; i++) {
> +			struct security_class_mapping *map = &secclass_map[i];
> +
> +			fprintf(fout, "mlsconstrain %s {\n", map->name);
> +			for (j = 0; map->perms[j]; j++)
> +				fprintf(fout, "\t%s\n", map->perms[j]);
> +			/*
> +			 * This requires all subjects and objects to be
> +			 * single-level (l2 eq h2), and that the subject
> +			 * level dominate the object level (h1 dom h2)
> +			 * in order to have any permissions to it.
> +			 */
> +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
> +		}
>   	}
>   
>   	/* types, roles, and allows */
> @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
>   	for (i = 0; secclass_map[i].name; i++)
>   		fprintf(fout, "allow base_t base_t:%s *;\n",
>   			secclass_map[i].name);
> -	fprintf(fout, "user user_u roles { base_r };\n");
> -	fprintf(fout, "\n");
> +	fprintf(fout, "user user_u roles { base_r }");
> +	if (mls)
> +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
> +			SYSTEMLOW, SYSTEMHIGH);
> +	fprintf(fout, ";\n");
> +
> +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
> +#define OBJUSERROLETYPE "user_u:object_r:base_t"
>   
>   	/* default sids */
>   	for (i = 1; i < initial_sid_to_string_len; i++)
> -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
> +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
> +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
>   	fprintf(fout, "\n");
>   
> -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
> +#define FS_USE(behavior, fstype)			    \
> +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
> +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
> +
> +	/*
> +	 * Filesystems whose inode labels can be fetched via getxattr.
> +	 */
> +#ifdef CONFIG_EXT2_FS_SECURITY
> +	FS_USE("xattr", "ext2");
> +#endif
> +#ifdef CONFIG_EXT3_FS_SECURITY
> +	FS_USE("xattr", "ext3");
> +#endif
> +#ifdef CONFIG_EXT4_FS_SECURITY
> +	FS_USE("xattr", "ext4");
> +#endif
> +#ifdef CONFIG_JFS_SECURITY
> +	FS_USE("xattr", "jfs");
> +#endif
> +#ifdef CONFIG_REISERFS_FS_SECURITY
> +	FS_USE("xattr", "reiserfs");
> +#endif
> +#ifdef CONFIG_JFFS2_FS_SECURITY
> +	FS_USE("xattr", "jffs2");
> +#endif
> +#ifdef CONFIG_XFS_FS
> +	FS_USE("xattr", "xfs");
> +#endif
> +#ifdef CONFIG_GFS2_FS
> +	FS_USE("xattr", "gfs2");
> +#endif
> +#ifdef CONFIG_BTRFS_FS
> +	FS_USE("xattr", "btrfs");
> +#endif
> +#ifdef CONFIG_F2FS_FS_SECURITY
> +	FS_USE("xattr", "f2fs");
> +#endif
> +#ifdef CONFIG_OCFS2_FS
> +	FS_USE("xattr", "ocsfs2");
> +#endif
> +#ifdef CONFIG_OVERLAY_FS
> +	FS_USE("xattr", "overlay");
> +#endif
> +#ifdef CONFIG_SQUASHFS_XATTR
> +	FS_USE("xattr", "squashfs");
> +#endif
> +
> +	/*
> +	 * Filesystems whose inodes are labeled from allocating task.
> +	 */
> +	FS_USE("task", "pipefs");
> +	FS_USE("task", "sockfs");
>   
> -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
> +	/*
> +	 * Filesystems whose inode labels are computed from both
> +	 * the allocating task and the superblock label.
> +	 */
> +#ifdef CONFIG_UNIX98_PTYS
> +	FS_USE("trans", "devpts");
> +#endif
> +#ifdef CONFIG_HUGETLBFS
> +	FS_USE("trans", "hugetlbfs");
> +#endif
> +#ifdef CONFIG_TMPFS
> +	FS_USE("trans", "tmpfs");
> +#endif
> +#ifdef CONFIG_DEVTMPFS
> +	FS_USE("trans", "devtmpfs");
> +#endif
> +#ifdef CONFIG_POSIX_MQUEUE
> +	FS_USE("trans", "mqueue");
> +#endif
>   
> -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
> +#define GENFSCON(fstype, prefix)			     \
> +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
> +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
>   
> -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
> +	/*
> +	 * Filesystems whose inodes are labeled from path prefix match
> +	 * relative to the filesystem root.  Depending on the filesystem,
> +	 * only a single label for all inodes may be supported.  Here
> +	 * we list the filesystem types for which per-file labeling is
> +	 * supported using genfscon; any other filesystem type can also
> +	 * be added by only with a single entry for all of its inodes.
> +	 */
> +#ifdef CONFIG_PROC_FS
> +	GENFSCON("proc", "/");
> +#endif
> +#ifdef CONFIG_SECURITY_SELINUX
> +	GENFSCON("selinuxfs", "/");
> +#endif
> +#ifdef CONFIG_SYSFS
> +	GENFSCON("sysfs", "/");
> +#endif
> +#ifdef CONFIG_DEBUG_FS
> +	GENFSCON("debugfs", "/");
> +#endif
> +#ifdef CONFIG_TRACING
> +	GENFSCON("tracefs", "/");
> +#endif
> +#ifdef CONFIG_PSTORE
> +	GENFSCON("pstore", "/");
> +#endif
> +	GENFSCON("cgroup", "/");
> +	GENFSCON("cgroup2", "/");
>   
>   	fclose(fout);
>   
> @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
>   		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
>   		usage(argv[0]);
>   	}
> -	fprintf(fout, "/ user_u:base_r:base_t\n");
> -	fprintf(fout, "/.* user_u:base_r:base_t\n");
> +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>   	fclose(fout);
>   
>   	return 0;
>
Dominick Grift Feb. 21, 2019, 7:44 p.m. UTC | #2
On Thu, Feb 21, 2019 at 02:34:38PM -0500, Stephen Smalley wrote:
> On 2/21/19 1:42 PM, Stephen Smalley wrote:
> > Derived in part from a patch by Dominick Grift.
> > 
> > The MDP example no longer works on modern systems.  Fix it.
> > While we are at it, add MLS support and enable it.
> > 
> > NB This still does not work on systems using dbus-daemon instead of
> > dbus-broker because dbus-daemon does not yet gracefully handle unknown
> > classes/permissions.  This is a deficiency in libselinux's
> > selinux_set_mapping() interface and underlying implementation,
> > which was never fully updated to deal with unknown classes/permissions
> > unlike the kernel.  Programs that instead use selinux_check_access()
> > like dbus-broker do not have this problem.
> 
> We could perhaps avoid this problem by having mdp always include at least a
> core set of userspace classes/permissions in the policy it generates.  We
> could also fix libselinux but that won't help on any existing distro.
> 
> > 
> > Other known issues:
> > - Not everything appears to be relabeled, so some files are left with invalid
> > contexts and remapped to the unlabeled SID/context.
> 
> This appears to be partly due to overuse of <<none>> in file_contexts (.fc)
> files.  That excludes those parts of the filesystem from being relabeled at
> all.  This was used to exclude pseudo filesystems (obsoleted by seclabel
> mount option detection) or runtime directories/files whose labels were
> derived from the creating process and couldn't be statically specified by
> file_contexts.  To get my system back into working order even with targeted
> policy, I had to strip all <<none>> entries out of my file_contexts* files
> and then run setfiles -F with the list of filesystem mounts to relabel.
> Otherwise, I'd have files left in the old contexts and the system wouldn't
> even come up to user login, even if permissive.

What <<none>> spec(s) in fedora would be so important that it causes the system to not come up to user login, even in permissive?
Does the unlabeled isid not address these particular scenario's? and why not?

I am testing the patch now here (but in my scenario its a very minimal fedora with dssp2-standard policy)

> 
> FWIW, Android policy doesn't use <<none>> at all.  But they also don't have
> a /.* or equivalent entry as a default match, so anything not covered by a
> more specific match is likewise not labeled. seapp_contexts handles the more
> dynamic aspect of app directory labeling for Android.
> 
> The other problem case for relabeling is the mount point directories, which
> requires unmounting them all and relabeling them if we care. Otherwise
> they'll just get the unlabeled context and as long as we allow mounting on
> that, it should be ok.
> 
> > - X will fail due to lack of a x_contexts file
> > - libvirtd will fail due to lack of a virtual_domain_context file
> 
> We could easily add these to the mdp policy.
> 
> > - crond reports an error with "No security context"
> 
> This is probably due to the lack of a contexts/default_contexts or any
> contexts/users/ files in the dummy policy.
> 
> > 
> > Changes to mdp:
> > Add support for devtmpfs, required by modern Linux distributions.
> > Add MLS support, with sample sensitivities, categories, and constraints.
> > Generate fs_use and genfscon rules based on kernel configuration.
> > Update list of filesystem types for fs_use and genfscon rules.
> > Use object_r for object contexts.
> > 
> > Changes to install_policy.sh:
> > Bail immediately on any errors.
> > Provide more helpful error messages when unable to find userspace tools.
> > Refuse to run if SELinux is already enabled.
> > Unconditionally move aside /etc/selinux/config and create a new one.
> > Build policy with -U allow so that userspace object managers do not break.
> > Build policy with MLS enabled by default.
> > Add default seusers mapping and failsafe context for use by
> > pam_selinux / libselinux.
> > Set to permissive mode rather than enforcing to permit initial autorelabel.
> > Update the list of filesystem types to be relabeled.
> > Create /.autorelabel to trigger an autorelabel on reboot.
> > Drop broken attempt to relabel the /dev mountpoint directory.
> > 
> > Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> > ---
> >   scripts/selinux/install_policy.sh |  82 ++++++++-------
> >   scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
> >   2 files changed, 183 insertions(+), 63 deletions(-)
> > 
> > diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
> > index 0b86c47baf7d..09eab4d0da5c 100755
> > --- a/scripts/selinux/install_policy.sh
> > +++ b/scripts/selinux/install_policy.sh
> > @@ -1,30 +1,51 @@
> >   #!/bin/sh
> >   # SPDX-License-Identifier: GPL-2.0
> > +set -e
> >   if [ `id -u` -ne 0 ]; then
> >   	echo "$0: must be root to install the selinux policy"
> >   	exit 1
> >   fi
> > +
> >   SF=`which setfiles`
> >   if [ $? -eq 1 ]; then
> > -	if [ -f /sbin/setfiles ]; then
> > -		SF="/usr/setfiles"
> > -	else
> > -		echo "no selinux tools installed: setfiles"
> > -		exit 1
> > -	fi
> > +	echo "Could not find setfiles"
> > +	echo "Do you have policycoreutils installed?"
> > +	exit 1
> >   fi
> > -cd mdp
> > -
> >   CP=`which checkpolicy`
> > +if [ $? -eq 1 ]; then
> > +	echo "Could not find checkpolicy"
> > +	echo "Do you have checkpolicy installed?"
> > +	exit 1
> > +fi
> >   VERS=`$CP -V | awk '{print $1}'`
> > -./mdp policy.conf file_contexts
> > -$CP -o policy.$VERS policy.conf
> > +ENABLED=`which selinuxenabled`
> > +if [ $? -eq 1 ]; then
> > +	echo "Could not find selinuxenabled"
> > +	echo "Do you have libselinux-utils installed?"
> > +	exit 1
> > +fi
> > +
> > +if selinuxenabled; then
> > +    echo "SELinux is already enabled"
> > +    echo "This prevents safely relabeling all files."
> > +    echo "Boot with selinux=0 on the kernel command-line or"
> > +    echo "SELINUX=disabled in /etc/selinux/config."
> > +    exit 1
> > +fi
> > +
> > +cd mdp
> > +./mdp -m policy.conf file_contexts
> > +$CP -U allow -M -o policy.$VERS policy.conf
> >   mkdir -p /etc/selinux/dummy/policy
> >   mkdir -p /etc/selinux/dummy/contexts/files
> > +echo "__default__:user_u" > /etc/selinux/dummy/seusers
> > +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
> > +
> >   cp file_contexts /etc/selinux/dummy/contexts/files
> >   cp dbus_contexts /etc/selinux/dummy/contexts
> >   cp policy.$VERS /etc/selinux/dummy/policy
> > @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
> >   if [ ! -d /etc/selinux ]; then
> >   	mkdir -p /etc/selinux
> >   fi
> > -if [ ! -f /etc/selinux/config ]; then
> > -	cat > /etc/selinux/config << EOF
> > -SELINUX=enforcing
> > +if [ -f /etc/selinux/config ]; then
> > +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
> > +    mv /etc/selinux/config /etc/selinux/config.bak
> > +fi
> > +echo "Creating new /etc/selinux/config for dummy policy."
> > +cat > /etc/selinux/config << EOF
> > +SELINUX=permissive
> >   SELINUXTYPE=dummy
> >   EOF
> > -else
> > -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
> > -	if [ "eq$TYPE" != "eqdummy" ]; then
> > -		selinuxenabled
> > -		if [ $? -eq 0 ]; then
> > -			echo "SELinux already enabled with a non-dummy policy."
> > -			echo "Exiting.  Please install policy by hand if that"
> > -			echo "is what you REALLY want."
> > -			exit 1
> > -		fi
> > -		mv /etc/selinux/config /etc/selinux/config.mdpbak
> > -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
> > -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
> > -	fi
> > -fi
> >   cd /etc/selinux/dummy/contexts/files
> > -$SF file_contexts /
> > +$SF -F file_contexts /
> > -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
> > -$SF file_contexts $mounts
> > +mounts=`cat /proc/$$/mounts | \
> > +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
> > +	awk '{ print $2 '}`
> > +$SF -F file_contexts $mounts
> > -
> > -dodev=`cat /proc/$$/mounts | grep "/dev "`
> > -if [ "eq$dodev" != "eq" ]; then
> > -	mount --move /dev /mnt
> > -	$SF file_contexts /dev
> > -	mount --move /mnt /dev
> > -fi
> > +touch /.autorelabel
> > diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
> > index 073fe7537f6c..daad333c7252 100644
> > --- a/scripts/selinux/mdp/mdp.c
> > +++ b/scripts/selinux/mdp/mdp.c
> > @@ -33,6 +33,7 @@
> >   #include <unistd.h>
> >   #include <string.h>
> >   #include <sys/socket.h>
> > +#include <linux/kconfig.h>
> >   static void usage(char *name)
> >   {
> > @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
> >   	}
> >   	fprintf(fout, "\n");
> > -	/* NOW PRINT OUT MLS STUFF */
> > +	/* print out mls declarations and constraints */
> >   	if (mls) {
> > -		printf("MLS not yet implemented\n");
> > -		exit(1);
> > +		fprintf(fout, "sensitivity s0;\n");
> > +		fprintf(fout, "sensitivity s1;\n");
> > +		fprintf(fout, "dominance { s0 s1 }\n");
> > +		fprintf(fout, "category c0;\n");
> > +		fprintf(fout, "category c1;\n");
> > +		fprintf(fout, "level s0:c0.c1;\n");
> > +		fprintf(fout, "level s1:c0.c1;\n");
> > +#define SYSTEMLOW "s0"
> > +#define SYSTEMHIGH "s1:c0.c1"
> > +		for (i = 0; secclass_map[i].name; i++) {
> > +			struct security_class_mapping *map = &secclass_map[i];
> > +
> > +			fprintf(fout, "mlsconstrain %s {\n", map->name);
> > +			for (j = 0; map->perms[j]; j++)
> > +				fprintf(fout, "\t%s\n", map->perms[j]);
> > +			/*
> > +			 * This requires all subjects and objects to be
> > +			 * single-level (l2 eq h2), and that the subject
> > +			 * level dominate the object level (h1 dom h2)
> > +			 * in order to have any permissions to it.
> > +			 */
> > +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
> > +		}
> >   	}
> >   	/* types, roles, and allows */
> > @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
> >   	for (i = 0; secclass_map[i].name; i++)
> >   		fprintf(fout, "allow base_t base_t:%s *;\n",
> >   			secclass_map[i].name);
> > -	fprintf(fout, "user user_u roles { base_r };\n");
> > -	fprintf(fout, "\n");
> > +	fprintf(fout, "user user_u roles { base_r }");
> > +	if (mls)
> > +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
> > +			SYSTEMLOW, SYSTEMHIGH);
> > +	fprintf(fout, ";\n");
> > +
> > +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
> > +#define OBJUSERROLETYPE "user_u:object_r:base_t"
> >   	/* default sids */
> >   	for (i = 1; i < initial_sid_to_string_len; i++)
> > -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
> > +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
> > +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
> >   	fprintf(fout, "\n");
> > -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
> > +#define FS_USE(behavior, fstype)			    \
> > +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
> > +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
> > +
> > +	/*
> > +	 * Filesystems whose inode labels can be fetched via getxattr.
> > +	 */
> > +#ifdef CONFIG_EXT2_FS_SECURITY
> > +	FS_USE("xattr", "ext2");
> > +#endif
> > +#ifdef CONFIG_EXT3_FS_SECURITY
> > +	FS_USE("xattr", "ext3");
> > +#endif
> > +#ifdef CONFIG_EXT4_FS_SECURITY
> > +	FS_USE("xattr", "ext4");
> > +#endif
> > +#ifdef CONFIG_JFS_SECURITY
> > +	FS_USE("xattr", "jfs");
> > +#endif
> > +#ifdef CONFIG_REISERFS_FS_SECURITY
> > +	FS_USE("xattr", "reiserfs");
> > +#endif
> > +#ifdef CONFIG_JFFS2_FS_SECURITY
> > +	FS_USE("xattr", "jffs2");
> > +#endif
> > +#ifdef CONFIG_XFS_FS
> > +	FS_USE("xattr", "xfs");
> > +#endif
> > +#ifdef CONFIG_GFS2_FS
> > +	FS_USE("xattr", "gfs2");
> > +#endif
> > +#ifdef CONFIG_BTRFS_FS
> > +	FS_USE("xattr", "btrfs");
> > +#endif
> > +#ifdef CONFIG_F2FS_FS_SECURITY
> > +	FS_USE("xattr", "f2fs");
> > +#endif
> > +#ifdef CONFIG_OCFS2_FS
> > +	FS_USE("xattr", "ocsfs2");
> > +#endif
> > +#ifdef CONFIG_OVERLAY_FS
> > +	FS_USE("xattr", "overlay");
> > +#endif
> > +#ifdef CONFIG_SQUASHFS_XATTR
> > +	FS_USE("xattr", "squashfs");
> > +#endif
> > +
> > +	/*
> > +	 * Filesystems whose inodes are labeled from allocating task.
> > +	 */
> > +	FS_USE("task", "pipefs");
> > +	FS_USE("task", "sockfs");
> > -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
> > +	/*
> > +	 * Filesystems whose inode labels are computed from both
> > +	 * the allocating task and the superblock label.
> > +	 */
> > +#ifdef CONFIG_UNIX98_PTYS
> > +	FS_USE("trans", "devpts");
> > +#endif
> > +#ifdef CONFIG_HUGETLBFS
> > +	FS_USE("trans", "hugetlbfs");
> > +#endif
> > +#ifdef CONFIG_TMPFS
> > +	FS_USE("trans", "tmpfs");
> > +#endif
> > +#ifdef CONFIG_DEVTMPFS
> > +	FS_USE("trans", "devtmpfs");
> > +#endif
> > +#ifdef CONFIG_POSIX_MQUEUE
> > +	FS_USE("trans", "mqueue");
> > +#endif
> > -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
> > -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
> > +#define GENFSCON(fstype, prefix)			     \
> > +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
> > +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
> > -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
> > +	/*
> > +	 * Filesystems whose inodes are labeled from path prefix match
> > +	 * relative to the filesystem root.  Depending on the filesystem,
> > +	 * only a single label for all inodes may be supported.  Here
> > +	 * we list the filesystem types for which per-file labeling is
> > +	 * supported using genfscon; any other filesystem type can also
> > +	 * be added by only with a single entry for all of its inodes.
> > +	 */
> > +#ifdef CONFIG_PROC_FS
> > +	GENFSCON("proc", "/");
> > +#endif
> > +#ifdef CONFIG_SECURITY_SELINUX
> > +	GENFSCON("selinuxfs", "/");
> > +#endif
> > +#ifdef CONFIG_SYSFS
> > +	GENFSCON("sysfs", "/");
> > +#endif
> > +#ifdef CONFIG_DEBUG_FS
> > +	GENFSCON("debugfs", "/");
> > +#endif
> > +#ifdef CONFIG_TRACING
> > +	GENFSCON("tracefs", "/");
> > +#endif
> > +#ifdef CONFIG_PSTORE
> > +	GENFSCON("pstore", "/");
> > +#endif
> > +	GENFSCON("cgroup", "/");
> > +	GENFSCON("cgroup2", "/");
> >   	fclose(fout);
> > @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
> >   		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
> >   		usage(argv[0]);
> >   	}
> > -	fprintf(fout, "/ user_u:base_r:base_t\n");
> > -	fprintf(fout, "/.* user_u:base_r:base_t\n");
> > +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> > +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> >   	fclose(fout);
> >   	return 0;
> > 
>
Dominick Grift Feb. 21, 2019, 8:11 p.m. UTC | #3
On Thu, Feb 21, 2019 at 01:42:13PM -0500, Stephen Smalley wrote:
> Derived in part from a patch by Dominick Grift.
> 
> The MDP example no longer works on modern systems.  Fix it.
> While we are at it, add MLS support and enable it.
> 
> NB This still does not work on systems using dbus-daemon instead of
> dbus-broker because dbus-daemon does not yet gracefully handle unknown
> classes/permissions.  This is a deficiency in libselinux's
> selinux_set_mapping() interface and underlying implementation,
> which was never fully updated to deal with unknown classes/permissions
> unlike the kernel.  Programs that instead use selinux_check_access()
> like dbus-broker do not have this problem.
> 
> Other known issues:
> - Not everything appears to be relabeled, so some files are left with invalid
> contexts and remapped to the unlabeled SID/context.
> - X will fail due to lack of a x_contexts file
> - libvirtd will fail due to lack of a virtual_domain_context file
> - crond reports an error with "No security context"
> 
> Changes to mdp:
> Add support for devtmpfs, required by modern Linux distributions.
> Add MLS support, with sample sensitivities, categories, and constraints.
> Generate fs_use and genfscon rules based on kernel configuration.
> Update list of filesystem types for fs_use and genfscon rules.
> Use object_r for object contexts.
> 
> Changes to install_policy.sh:
> Bail immediately on any errors.
> Provide more helpful error messages when unable to find userspace tools.
> Refuse to run if SELinux is already enabled.
> Unconditionally move aside /etc/selinux/config and create a new one.
> Build policy with -U allow so that userspace object managers do not break.
> Build policy with MLS enabled by default.
> Add default seusers mapping and failsafe context for use by
> pam_selinux / libselinux.
> Set to permissive mode rather than enforcing to permit initial autorelabel.
> Update the list of filesystem types to be relabeled.
> Create /.autorelabel to trigger an autorelabel on reboot.
> Drop broken attempt to relabel the /dev mountpoint directory.
> 
> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> ---
>  scripts/selinux/install_policy.sh |  82 ++++++++-------
>  scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
>  2 files changed, 183 insertions(+), 63 deletions(-)
> 
> diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
> index 0b86c47baf7d..09eab4d0da5c 100755
> --- a/scripts/selinux/install_policy.sh
> +++ b/scripts/selinux/install_policy.sh
> @@ -1,30 +1,51 @@
>  #!/bin/sh
>  # SPDX-License-Identifier: GPL-2.0
> +set -e
>  if [ `id -u` -ne 0 ]; then
>  	echo "$0: must be root to install the selinux policy"
>  	exit 1
>  fi
> +
>  SF=`which setfiles`
>  if [ $? -eq 1 ]; then
> -	if [ -f /sbin/setfiles ]; then
> -		SF="/usr/setfiles"
> -	else
> -		echo "no selinux tools installed: setfiles"
> -		exit 1
> -	fi
> +	echo "Could not find setfiles"
> +	echo "Do you have policycoreutils installed?"
> +	exit 1
>  fi
>  
> -cd mdp
> -
>  CP=`which checkpolicy`
> +if [ $? -eq 1 ]; then
> +	echo "Could not find checkpolicy"
> +	echo "Do you have checkpolicy installed?"
> +	exit 1
> +fi
>  VERS=`$CP -V | awk '{print $1}'`
>  
> -./mdp policy.conf file_contexts
> -$CP -o policy.$VERS policy.conf
> +ENABLED=`which selinuxenabled`
> +if [ $? -eq 1 ]; then
> +	echo "Could not find selinuxenabled"
> +	echo "Do you have libselinux-utils installed?"
> +	exit 1
> +fi
> +
> +if selinuxenabled; then
> +    echo "SELinux is already enabled"
> +    echo "This prevents safely relabeling all files."
> +    echo "Boot with selinux=0 on the kernel command-line or"
> +    echo "SELINUX=disabled in /etc/selinux/config."
> +    exit 1
> +fi
> +
> +cd mdp
> +./mdp -m policy.conf file_contexts
> +$CP -U allow -M -o policy.$VERS policy.conf
>  
>  mkdir -p /etc/selinux/dummy/policy
>  mkdir -p /etc/selinux/dummy/contexts/files
>  
> +echo "__default__:user_u" > /etc/selinux/dummy/seusers

Should this be "__default__:user_u:s0-s0"?

> +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context

Should this be "base_r:base_t:s0"?

> +
>  cp file_contexts /etc/selinux/dummy/contexts/files
>  cp dbus_contexts /etc/selinux/dummy/contexts
>  cp policy.$VERS /etc/selinux/dummy/policy
> @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
>  if [ ! -d /etc/selinux ]; then
>  	mkdir -p /etc/selinux
>  fi
> -if [ ! -f /etc/selinux/config ]; then
> -	cat > /etc/selinux/config << EOF
> -SELINUX=enforcing
> +if [ -f /etc/selinux/config ]; then
> +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
> +    mv /etc/selinux/config /etc/selinux/config.bak
> +fi
> +echo "Creating new /etc/selinux/config for dummy policy."
> +cat > /etc/selinux/config << EOF
> +SELINUX=permissive
>  SELINUXTYPE=dummy
>  EOF
> -else
> -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
> -	if [ "eq$TYPE" != "eqdummy" ]; then
> -		selinuxenabled
> -		if [ $? -eq 0 ]; then
> -			echo "SELinux already enabled with a non-dummy policy."
> -			echo "Exiting.  Please install policy by hand if that"
> -			echo "is what you REALLY want."
> -			exit 1
> -		fi
> -		mv /etc/selinux/config /etc/selinux/config.mdpbak
> -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
> -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
> -	fi
> -fi
>  
>  cd /etc/selinux/dummy/contexts/files
> -$SF file_contexts /
> +$SF -F file_contexts /
>  
> -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
> -$SF file_contexts $mounts
> +mounts=`cat /proc/$$/mounts | \
> +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
> +	awk '{ print $2 '}`
> +$SF -F file_contexts $mounts
>  
> -
> -dodev=`cat /proc/$$/mounts | grep "/dev "`
> -if [ "eq$dodev" != "eq" ]; then
> -	mount --move /dev /mnt
> -	$SF file_contexts /dev
> -	mount --move /mnt /dev
> -fi
> +touch /.autorelabel

Probably best to instead: "echo "-F" > /.autorelabel"?

> diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
> index 073fe7537f6c..daad333c7252 100644
> --- a/scripts/selinux/mdp/mdp.c
> +++ b/scripts/selinux/mdp/mdp.c
> @@ -33,6 +33,7 @@
>  #include <unistd.h>
>  #include <string.h>
>  #include <sys/socket.h>
> +#include <linux/kconfig.h>
>  
>  static void usage(char *name)
>  {
> @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
>  	}
>  	fprintf(fout, "\n");
>  
> -	/* NOW PRINT OUT MLS STUFF */
> +	/* print out mls declarations and constraints */
>  	if (mls) {
> -		printf("MLS not yet implemented\n");
> -		exit(1);
> +		fprintf(fout, "sensitivity s0;\n");
> +		fprintf(fout, "sensitivity s1;\n");
> +		fprintf(fout, "dominance { s0 s1 }\n");
> +		fprintf(fout, "category c0;\n");
> +		fprintf(fout, "category c1;\n");
> +		fprintf(fout, "level s0:c0.c1;\n");
> +		fprintf(fout, "level s1:c0.c1;\n");
> +#define SYSTEMLOW "s0"
> +#define SYSTEMHIGH "s1:c0.c1"
> +		for (i = 0; secclass_map[i].name; i++) {
> +			struct security_class_mapping *map = &secclass_map[i];
> +
> +			fprintf(fout, "mlsconstrain %s {\n", map->name);
> +			for (j = 0; map->perms[j]; j++)
> +				fprintf(fout, "\t%s\n", map->perms[j]);
> +			/*
> +			 * This requires all subjects and objects to be
> +			 * single-level (l2 eq h2), and that the subject
> +			 * level dominate the object level (h1 dom h2)
> +			 * in order to have any permissions to it.
> +			 */
> +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
> +		}
>  	}
>  
>  	/* types, roles, and allows */
> @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
>  	for (i = 0; secclass_map[i].name; i++)
>  		fprintf(fout, "allow base_t base_t:%s *;\n",
>  			secclass_map[i].name);
> -	fprintf(fout, "user user_u roles { base_r };\n");
> -	fprintf(fout, "\n");
> +	fprintf(fout, "user user_u roles { base_r }");
> +	if (mls)
> +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
> +			SYSTEMLOW, SYSTEMHIGH);
> +	fprintf(fout, ";\n");
> +
> +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
> +#define OBJUSERROLETYPE "user_u:object_r:base_t"
>  
>  	/* default sids */
>  	for (i = 1; i < initial_sid_to_string_len; i++)
> -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
> +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
> +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
>  	fprintf(fout, "\n");
>  
> -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
> +#define FS_USE(behavior, fstype)			    \
> +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
> +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
> +
> +	/*
> +	 * Filesystems whose inode labels can be fetched via getxattr.
> +	 */
> +#ifdef CONFIG_EXT2_FS_SECURITY
> +	FS_USE("xattr", "ext2");
> +#endif
> +#ifdef CONFIG_EXT3_FS_SECURITY
> +	FS_USE("xattr", "ext3");
> +#endif
> +#ifdef CONFIG_EXT4_FS_SECURITY
> +	FS_USE("xattr", "ext4");
> +#endif
> +#ifdef CONFIG_JFS_SECURITY
> +	FS_USE("xattr", "jfs");
> +#endif
> +#ifdef CONFIG_REISERFS_FS_SECURITY
> +	FS_USE("xattr", "reiserfs");
> +#endif
> +#ifdef CONFIG_JFFS2_FS_SECURITY
> +	FS_USE("xattr", "jffs2");
> +#endif
> +#ifdef CONFIG_XFS_FS
> +	FS_USE("xattr", "xfs");
> +#endif
> +#ifdef CONFIG_GFS2_FS
> +	FS_USE("xattr", "gfs2");
> +#endif
> +#ifdef CONFIG_BTRFS_FS
> +	FS_USE("xattr", "btrfs");
> +#endif
> +#ifdef CONFIG_F2FS_FS_SECURITY
> +	FS_USE("xattr", "f2fs");
> +#endif
> +#ifdef CONFIG_OCFS2_FS
> +	FS_USE("xattr", "ocsfs2");
> +#endif
> +#ifdef CONFIG_OVERLAY_FS
> +	FS_USE("xattr", "overlay");
> +#endif
> +#ifdef CONFIG_SQUASHFS_XATTR
> +	FS_USE("xattr", "squashfs");
> +#endif
> +
> +	/*
> +	 * Filesystems whose inodes are labeled from allocating task.
> +	 */
> +	FS_USE("task", "pipefs");
> +	FS_USE("task", "sockfs");
>  
> -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
> +	/*
> +	 * Filesystems whose inode labels are computed from both
> +	 * the allocating task and the superblock label.
> +	 */
> +#ifdef CONFIG_UNIX98_PTYS
> +	FS_USE("trans", "devpts");
> +#endif
> +#ifdef CONFIG_HUGETLBFS
> +	FS_USE("trans", "hugetlbfs");
> +#endif
> +#ifdef CONFIG_TMPFS
> +	FS_USE("trans", "tmpfs");
> +#endif
> +#ifdef CONFIG_DEVTMPFS
> +	FS_USE("trans", "devtmpfs");
> +#endif
> +#ifdef CONFIG_POSIX_MQUEUE
> +	FS_USE("trans", "mqueue");
> +#endif
>  
> -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
> -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
> +#define GENFSCON(fstype, prefix)			     \
> +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
> +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
>  
> -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
> +	/*
> +	 * Filesystems whose inodes are labeled from path prefix match
> +	 * relative to the filesystem root.  Depending on the filesystem,
> +	 * only a single label for all inodes may be supported.  Here
> +	 * we list the filesystem types for which per-file labeling is
> +	 * supported using genfscon; any other filesystem type can also
> +	 * be added by only with a single entry for all of its inodes.
> +	 */
> +#ifdef CONFIG_PROC_FS
> +	GENFSCON("proc", "/");
> +#endif
> +#ifdef CONFIG_SECURITY_SELINUX
> +	GENFSCON("selinuxfs", "/");
> +#endif
> +#ifdef CONFIG_SYSFS
> +	GENFSCON("sysfs", "/");
> +#endif
> +#ifdef CONFIG_DEBUG_FS
> +	GENFSCON("debugfs", "/");
> +#endif
> +#ifdef CONFIG_TRACING
> +	GENFSCON("tracefs", "/");
> +#endif
> +#ifdef CONFIG_PSTORE
> +	GENFSCON("pstore", "/");
> +#endif
> +	GENFSCON("cgroup", "/");
> +	GENFSCON("cgroup2", "/");
>  
>  	fclose(fout);
>  
> @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
>  		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
>  		usage(argv[0]);
>  	}
> -	fprintf(fout, "/ user_u:base_r:base_t\n");
> -	fprintf(fout, "/.* user_u:base_r:base_t\n");
> +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>  	fclose(fout);
>  
>  	return 0;
> -- 
> 2.20.1
>
Stephen Smalley Feb. 21, 2019, 8:22 p.m. UTC | #4
On 2/21/19 3:11 PM, Dominick Grift wrote:
> On Thu, Feb 21, 2019 at 01:42:13PM -0500, Stephen Smalley wrote:
>> Derived in part from a patch by Dominick Grift.
>>
>> The MDP example no longer works on modern systems.  Fix it.
>> While we are at it, add MLS support and enable it.
>>
>> NB This still does not work on systems using dbus-daemon instead of
>> dbus-broker because dbus-daemon does not yet gracefully handle unknown
>> classes/permissions.  This is a deficiency in libselinux's
>> selinux_set_mapping() interface and underlying implementation,
>> which was never fully updated to deal with unknown classes/permissions
>> unlike the kernel.  Programs that instead use selinux_check_access()
>> like dbus-broker do not have this problem.
>>
>> Other known issues:
>> - Not everything appears to be relabeled, so some files are left with invalid
>> contexts and remapped to the unlabeled SID/context.
>> - X will fail due to lack of a x_contexts file
>> - libvirtd will fail due to lack of a virtual_domain_context file
>> - crond reports an error with "No security context"
>>
>> Changes to mdp:
>> Add support for devtmpfs, required by modern Linux distributions.
>> Add MLS support, with sample sensitivities, categories, and constraints.
>> Generate fs_use and genfscon rules based on kernel configuration.
>> Update list of filesystem types for fs_use and genfscon rules.
>> Use object_r for object contexts.
>>
>> Changes to install_policy.sh:
>> Bail immediately on any errors.
>> Provide more helpful error messages when unable to find userspace tools.
>> Refuse to run if SELinux is already enabled.
>> Unconditionally move aside /etc/selinux/config and create a new one.
>> Build policy with -U allow so that userspace object managers do not break.
>> Build policy with MLS enabled by default.
>> Add default seusers mapping and failsafe context for use by
>> pam_selinux / libselinux.
>> Set to permissive mode rather than enforcing to permit initial autorelabel.
>> Update the list of filesystem types to be relabeled.
>> Create /.autorelabel to trigger an autorelabel on reboot.
>> Drop broken attempt to relabel the /dev mountpoint directory.
>>
>> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
>> ---
>>   scripts/selinux/install_policy.sh |  82 ++++++++-------
>>   scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
>>   2 files changed, 183 insertions(+), 63 deletions(-)
>>
>> diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
>> index 0b86c47baf7d..09eab4d0da5c 100755
>> --- a/scripts/selinux/install_policy.sh
>> +++ b/scripts/selinux/install_policy.sh
>> @@ -1,30 +1,51 @@
>>   #!/bin/sh
>>   # SPDX-License-Identifier: GPL-2.0
>> +set -e
>>   if [ `id -u` -ne 0 ]; then
>>   	echo "$0: must be root to install the selinux policy"
>>   	exit 1
>>   fi
>> +
>>   SF=`which setfiles`
>>   if [ $? -eq 1 ]; then
>> -	if [ -f /sbin/setfiles ]; then
>> -		SF="/usr/setfiles"
>> -	else
>> -		echo "no selinux tools installed: setfiles"
>> -		exit 1
>> -	fi
>> +	echo "Could not find setfiles"
>> +	echo "Do you have policycoreutils installed?"
>> +	exit 1
>>   fi
>>   
>> -cd mdp
>> -
>>   CP=`which checkpolicy`
>> +if [ $? -eq 1 ]; then
>> +	echo "Could not find checkpolicy"
>> +	echo "Do you have checkpolicy installed?"
>> +	exit 1
>> +fi
>>   VERS=`$CP -V | awk '{print $1}'`
>>   
>> -./mdp policy.conf file_contexts
>> -$CP -o policy.$VERS policy.conf
>> +ENABLED=`which selinuxenabled`
>> +if [ $? -eq 1 ]; then
>> +	echo "Could not find selinuxenabled"
>> +	echo "Do you have libselinux-utils installed?"
>> +	exit 1
>> +fi
>> +
>> +if selinuxenabled; then
>> +    echo "SELinux is already enabled"
>> +    echo "This prevents safely relabeling all files."
>> +    echo "Boot with selinux=0 on the kernel command-line or"
>> +    echo "SELINUX=disabled in /etc/selinux/config."
>> +    exit 1
>> +fi
>> +
>> +cd mdp
>> +./mdp -m policy.conf file_contexts
>> +$CP -U allow -M -o policy.$VERS policy.conf
>>   
>>   mkdir -p /etc/selinux/dummy/policy
>>   mkdir -p /etc/selinux/dummy/contexts/files
>>   
>> +echo "__default__:user_u" > /etc/selinux/dummy/seusers
> 
> Should this be "__default__:user_u:s0-s0"?
> 
>> +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
> 
> Should this be "base_r:base_t:s0"?

Ah, thanks - good catch.  I couldn't really tell because I'm fighting 
with a broken dbus-daemon (F29) and X, so my ability to test is limited. 
  I'll fix in the next version along with a few other items I've noticed.

> 
>> +
>>   cp file_contexts /etc/selinux/dummy/contexts/files
>>   cp dbus_contexts /etc/selinux/dummy/contexts
>>   cp policy.$VERS /etc/selinux/dummy/policy
>> @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
>>   if [ ! -d /etc/selinux ]; then
>>   	mkdir -p /etc/selinux
>>   fi
>> -if [ ! -f /etc/selinux/config ]; then
>> -	cat > /etc/selinux/config << EOF
>> -SELINUX=enforcing
>> +if [ -f /etc/selinux/config ]; then
>> +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
>> +    mv /etc/selinux/config /etc/selinux/config.bak
>> +fi
>> +echo "Creating new /etc/selinux/config for dummy policy."
>> +cat > /etc/selinux/config << EOF
>> +SELINUX=permissive
>>   SELINUXTYPE=dummy
>>   EOF
>> -else
>> -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
>> -	if [ "eq$TYPE" != "eqdummy" ]; then
>> -		selinuxenabled
>> -		if [ $? -eq 0 ]; then
>> -			echo "SELinux already enabled with a non-dummy policy."
>> -			echo "Exiting.  Please install policy by hand if that"
>> -			echo "is what you REALLY want."
>> -			exit 1
>> -		fi
>> -		mv /etc/selinux/config /etc/selinux/config.mdpbak
>> -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
>> -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
>> -	fi
>> -fi
>>   
>>   cd /etc/selinux/dummy/contexts/files
>> -$SF file_contexts /
>> +$SF -F file_contexts /
>>   
>> -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
>> -$SF file_contexts $mounts
>> +mounts=`cat /proc/$$/mounts | \
>> +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
>> +	awk '{ print $2 '}`
>> +$SF -F file_contexts $mounts
>>   
>> -
>> -dodev=`cat /proc/$$/mounts | grep "/dev "`
>> -if [ "eq$dodev" != "eq" ]; then
>> -	mount --move /dev /mnt
>> -	$SF file_contexts /dev
>> -	mount --move /mnt /dev
>> -fi
>> +touch /.autorelabel
> 
> Probably best to instead: "echo "-F" > /.autorelabel"?
> 
>> diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
>> index 073fe7537f6c..daad333c7252 100644
>> --- a/scripts/selinux/mdp/mdp.c
>> +++ b/scripts/selinux/mdp/mdp.c
>> @@ -33,6 +33,7 @@
>>   #include <unistd.h>
>>   #include <string.h>
>>   #include <sys/socket.h>
>> +#include <linux/kconfig.h>
>>   
>>   static void usage(char *name)
>>   {
>> @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
>>   	}
>>   	fprintf(fout, "\n");
>>   
>> -	/* NOW PRINT OUT MLS STUFF */
>> +	/* print out mls declarations and constraints */
>>   	if (mls) {
>> -		printf("MLS not yet implemented\n");
>> -		exit(1);
>> +		fprintf(fout, "sensitivity s0;\n");
>> +		fprintf(fout, "sensitivity s1;\n");
>> +		fprintf(fout, "dominance { s0 s1 }\n");
>> +		fprintf(fout, "category c0;\n");
>> +		fprintf(fout, "category c1;\n");
>> +		fprintf(fout, "level s0:c0.c1;\n");
>> +		fprintf(fout, "level s1:c0.c1;\n");
>> +#define SYSTEMLOW "s0"
>> +#define SYSTEMHIGH "s1:c0.c1"
>> +		for (i = 0; secclass_map[i].name; i++) {
>> +			struct security_class_mapping *map = &secclass_map[i];
>> +
>> +			fprintf(fout, "mlsconstrain %s {\n", map->name);
>> +			for (j = 0; map->perms[j]; j++)
>> +				fprintf(fout, "\t%s\n", map->perms[j]);
>> +			/*
>> +			 * This requires all subjects and objects to be
>> +			 * single-level (l2 eq h2), and that the subject
>> +			 * level dominate the object level (h1 dom h2)
>> +			 * in order to have any permissions to it.
>> +			 */
>> +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
>> +		}
>>   	}
>>   
>>   	/* types, roles, and allows */
>> @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
>>   	for (i = 0; secclass_map[i].name; i++)
>>   		fprintf(fout, "allow base_t base_t:%s *;\n",
>>   			secclass_map[i].name);
>> -	fprintf(fout, "user user_u roles { base_r };\n");
>> -	fprintf(fout, "\n");
>> +	fprintf(fout, "user user_u roles { base_r }");
>> +	if (mls)
>> +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
>> +			SYSTEMLOW, SYSTEMHIGH);
>> +	fprintf(fout, ";\n");
>> +
>> +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
>> +#define OBJUSERROLETYPE "user_u:object_r:base_t"
>>   
>>   	/* default sids */
>>   	for (i = 1; i < initial_sid_to_string_len; i++)
>> -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
>> +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
>> +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
>>   	fprintf(fout, "\n");
>>   
>> -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
>> +#define FS_USE(behavior, fstype)			    \
>> +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
>> +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
>> +
>> +	/*
>> +	 * Filesystems whose inode labels can be fetched via getxattr.
>> +	 */
>> +#ifdef CONFIG_EXT2_FS_SECURITY
>> +	FS_USE("xattr", "ext2");
>> +#endif
>> +#ifdef CONFIG_EXT3_FS_SECURITY
>> +	FS_USE("xattr", "ext3");
>> +#endif
>> +#ifdef CONFIG_EXT4_FS_SECURITY
>> +	FS_USE("xattr", "ext4");
>> +#endif
>> +#ifdef CONFIG_JFS_SECURITY
>> +	FS_USE("xattr", "jfs");
>> +#endif
>> +#ifdef CONFIG_REISERFS_FS_SECURITY
>> +	FS_USE("xattr", "reiserfs");
>> +#endif
>> +#ifdef CONFIG_JFFS2_FS_SECURITY
>> +	FS_USE("xattr", "jffs2");
>> +#endif
>> +#ifdef CONFIG_XFS_FS
>> +	FS_USE("xattr", "xfs");
>> +#endif
>> +#ifdef CONFIG_GFS2_FS
>> +	FS_USE("xattr", "gfs2");
>> +#endif
>> +#ifdef CONFIG_BTRFS_FS
>> +	FS_USE("xattr", "btrfs");
>> +#endif
>> +#ifdef CONFIG_F2FS_FS_SECURITY
>> +	FS_USE("xattr", "f2fs");
>> +#endif
>> +#ifdef CONFIG_OCFS2_FS
>> +	FS_USE("xattr", "ocsfs2");
>> +#endif
>> +#ifdef CONFIG_OVERLAY_FS
>> +	FS_USE("xattr", "overlay");
>> +#endif
>> +#ifdef CONFIG_SQUASHFS_XATTR
>> +	FS_USE("xattr", "squashfs");
>> +#endif
>> +
>> +	/*
>> +	 * Filesystems whose inodes are labeled from allocating task.
>> +	 */
>> +	FS_USE("task", "pipefs");
>> +	FS_USE("task", "sockfs");
>>   
>> -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
>> +	/*
>> +	 * Filesystems whose inode labels are computed from both
>> +	 * the allocating task and the superblock label.
>> +	 */
>> +#ifdef CONFIG_UNIX98_PTYS
>> +	FS_USE("trans", "devpts");
>> +#endif
>> +#ifdef CONFIG_HUGETLBFS
>> +	FS_USE("trans", "hugetlbfs");
>> +#endif
>> +#ifdef CONFIG_TMPFS
>> +	FS_USE("trans", "tmpfs");
>> +#endif
>> +#ifdef CONFIG_DEVTMPFS
>> +	FS_USE("trans", "devtmpfs");
>> +#endif
>> +#ifdef CONFIG_POSIX_MQUEUE
>> +	FS_USE("trans", "mqueue");
>> +#endif
>>   
>> -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
>> -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
>> +#define GENFSCON(fstype, prefix)			     \
>> +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
>> +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
>>   
>> -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
>> +	/*
>> +	 * Filesystems whose inodes are labeled from path prefix match
>> +	 * relative to the filesystem root.  Depending on the filesystem,
>> +	 * only a single label for all inodes may be supported.  Here
>> +	 * we list the filesystem types for which per-file labeling is
>> +	 * supported using genfscon; any other filesystem type can also
>> +	 * be added by only with a single entry for all of its inodes.
>> +	 */
>> +#ifdef CONFIG_PROC_FS
>> +	GENFSCON("proc", "/");
>> +#endif
>> +#ifdef CONFIG_SECURITY_SELINUX
>> +	GENFSCON("selinuxfs", "/");
>> +#endif
>> +#ifdef CONFIG_SYSFS
>> +	GENFSCON("sysfs", "/");
>> +#endif
>> +#ifdef CONFIG_DEBUG_FS
>> +	GENFSCON("debugfs", "/");
>> +#endif
>> +#ifdef CONFIG_TRACING
>> +	GENFSCON("tracefs", "/");
>> +#endif
>> +#ifdef CONFIG_PSTORE
>> +	GENFSCON("pstore", "/");
>> +#endif
>> +	GENFSCON("cgroup", "/");
>> +	GENFSCON("cgroup2", "/");
>>   
>>   	fclose(fout);
>>   
>> @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
>>   		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
>>   		usage(argv[0]);
>>   	}
>> -	fprintf(fout, "/ user_u:base_r:base_t\n");
>> -	fprintf(fout, "/.* user_u:base_r:base_t\n");
>> +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>> +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>   	fclose(fout);
>>   
>>   	return 0;
>> -- 
>> 2.20.1
>>
>
Stephen Smalley Feb. 21, 2019, 8:28 p.m. UTC | #5
On 2/21/19 2:44 PM, Dominick Grift wrote:
> On Thu, Feb 21, 2019 at 02:34:38PM -0500, Stephen Smalley wrote:
>> On 2/21/19 1:42 PM, Stephen Smalley wrote:
>>> Derived in part from a patch by Dominick Grift.
>>>
>>> The MDP example no longer works on modern systems.  Fix it.
>>> While we are at it, add MLS support and enable it.
>>>
>>> NB This still does not work on systems using dbus-daemon instead of
>>> dbus-broker because dbus-daemon does not yet gracefully handle unknown
>>> classes/permissions.  This is a deficiency in libselinux's
>>> selinux_set_mapping() interface and underlying implementation,
>>> which was never fully updated to deal with unknown classes/permissions
>>> unlike the kernel.  Programs that instead use selinux_check_access()
>>> like dbus-broker do not have this problem.
>>
>> We could perhaps avoid this problem by having mdp always include at least a
>> core set of userspace classes/permissions in the policy it generates.  We
>> could also fix libselinux but that won't help on any existing distro.
>>
>>>
>>> Other known issues:
>>> - Not everything appears to be relabeled, so some files are left with invalid
>>> contexts and remapped to the unlabeled SID/context.
>>
>> This appears to be partly due to overuse of <<none>> in file_contexts (.fc)
>> files.  That excludes those parts of the filesystem from being relabeled at
>> all.  This was used to exclude pseudo filesystems (obsoleted by seclabel
>> mount option detection) or runtime directories/files whose labels were
>> derived from the creating process and couldn't be statically specified by
>> file_contexts.  To get my system back into working order even with targeted
>> policy, I had to strip all <<none>> entries out of my file_contexts* files
>> and then run setfiles -F with the list of filesystem mounts to relabel.
>> Otherwise, I'd have files left in the old contexts and the system wouldn't
>> even come up to user login, even if permissive.
> 
> What <<none>> spec(s) in fedora would be so important that it causes the system to not come up to user login, even in permissive?
> Does the unlabeled isid not address these particular scenario's? and why not?

Yes, I don't fully understand it myself; I just know that certain 
services won't start successfully and it never reaches the point where I 
can login locally or remotely.  But stripping the <<none>> entries and 
running setfiles -F did fix it for me.  NB This was for converting back 
from mdp to the Fedora targeted policy.  It wouldn't be an issue for 
converting to mdp since that file_contexts has no <<none>> entries and 
has a default match for /.*.

Maybe it is a case of processes with CAP_MAC_ADMIN fetching the raw 
context (which is invalid under the current policy) and then trying to 
feed them back to the kernel via a selinuxfs interface, e.g. 
security_compute_create() or similar.  The kernel would reject those.

> 
> I am testing the patch now here (but in my scenario its a very minimal fedora with dssp2-standard policy)
> 
>>
>> FWIW, Android policy doesn't use <<none>> at all.  But they also don't have
>> a /.* or equivalent entry as a default match, so anything not covered by a
>> more specific match is likewise not labeled. seapp_contexts handles the more
>> dynamic aspect of app directory labeling for Android.
>>
>> The other problem case for relabeling is the mount point directories, which
>> requires unmounting them all and relabeling them if we care. Otherwise
>> they'll just get the unlabeled context and as long as we allow mounting on
>> that, it should be ok.
>>
>>> - X will fail due to lack of a x_contexts file
>>> - libvirtd will fail due to lack of a virtual_domain_context file
>>
>> We could easily add these to the mdp policy.
>>
>>> - crond reports an error with "No security context"
>>
>> This is probably due to the lack of a contexts/default_contexts or any
>> contexts/users/ files in the dummy policy.
>>
>>>
>>> Changes to mdp:
>>> Add support for devtmpfs, required by modern Linux distributions.
>>> Add MLS support, with sample sensitivities, categories, and constraints.
>>> Generate fs_use and genfscon rules based on kernel configuration.
>>> Update list of filesystem types for fs_use and genfscon rules.
>>> Use object_r for object contexts.
>>>
>>> Changes to install_policy.sh:
>>> Bail immediately on any errors.
>>> Provide more helpful error messages when unable to find userspace tools.
>>> Refuse to run if SELinux is already enabled.
>>> Unconditionally move aside /etc/selinux/config and create a new one.
>>> Build policy with -U allow so that userspace object managers do not break.
>>> Build policy with MLS enabled by default.
>>> Add default seusers mapping and failsafe context for use by
>>> pam_selinux / libselinux.
>>> Set to permissive mode rather than enforcing to permit initial autorelabel.
>>> Update the list of filesystem types to be relabeled.
>>> Create /.autorelabel to trigger an autorelabel on reboot.
>>> Drop broken attempt to relabel the /dev mountpoint directory.
>>>
>>> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
>>> ---
>>>    scripts/selinux/install_policy.sh |  82 ++++++++-------
>>>    scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
>>>    2 files changed, 183 insertions(+), 63 deletions(-)
>>>
>>> diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
>>> index 0b86c47baf7d..09eab4d0da5c 100755
>>> --- a/scripts/selinux/install_policy.sh
>>> +++ b/scripts/selinux/install_policy.sh
>>> @@ -1,30 +1,51 @@
>>>    #!/bin/sh
>>>    # SPDX-License-Identifier: GPL-2.0
>>> +set -e
>>>    if [ `id -u` -ne 0 ]; then
>>>    	echo "$0: must be root to install the selinux policy"
>>>    	exit 1
>>>    fi
>>> +
>>>    SF=`which setfiles`
>>>    if [ $? -eq 1 ]; then
>>> -	if [ -f /sbin/setfiles ]; then
>>> -		SF="/usr/setfiles"
>>> -	else
>>> -		echo "no selinux tools installed: setfiles"
>>> -		exit 1
>>> -	fi
>>> +	echo "Could not find setfiles"
>>> +	echo "Do you have policycoreutils installed?"
>>> +	exit 1
>>>    fi
>>> -cd mdp
>>> -
>>>    CP=`which checkpolicy`
>>> +if [ $? -eq 1 ]; then
>>> +	echo "Could not find checkpolicy"
>>> +	echo "Do you have checkpolicy installed?"
>>> +	exit 1
>>> +fi
>>>    VERS=`$CP -V | awk '{print $1}'`
>>> -./mdp policy.conf file_contexts
>>> -$CP -o policy.$VERS policy.conf
>>> +ENABLED=`which selinuxenabled`
>>> +if [ $? -eq 1 ]; then
>>> +	echo "Could not find selinuxenabled"
>>> +	echo "Do you have libselinux-utils installed?"
>>> +	exit 1
>>> +fi
>>> +
>>> +if selinuxenabled; then
>>> +    echo "SELinux is already enabled"
>>> +    echo "This prevents safely relabeling all files."
>>> +    echo "Boot with selinux=0 on the kernel command-line or"
>>> +    echo "SELINUX=disabled in /etc/selinux/config."
>>> +    exit 1
>>> +fi
>>> +
>>> +cd mdp
>>> +./mdp -m policy.conf file_contexts
>>> +$CP -U allow -M -o policy.$VERS policy.conf
>>>    mkdir -p /etc/selinux/dummy/policy
>>>    mkdir -p /etc/selinux/dummy/contexts/files
>>> +echo "__default__:user_u" > /etc/selinux/dummy/seusers
>>> +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
>>> +
>>>    cp file_contexts /etc/selinux/dummy/contexts/files
>>>    cp dbus_contexts /etc/selinux/dummy/contexts
>>>    cp policy.$VERS /etc/selinux/dummy/policy
>>> @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
>>>    if [ ! -d /etc/selinux ]; then
>>>    	mkdir -p /etc/selinux
>>>    fi
>>> -if [ ! -f /etc/selinux/config ]; then
>>> -	cat > /etc/selinux/config << EOF
>>> -SELINUX=enforcing
>>> +if [ -f /etc/selinux/config ]; then
>>> +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
>>> +    mv /etc/selinux/config /etc/selinux/config.bak
>>> +fi
>>> +echo "Creating new /etc/selinux/config for dummy policy."
>>> +cat > /etc/selinux/config << EOF
>>> +SELINUX=permissive
>>>    SELINUXTYPE=dummy
>>>    EOF
>>> -else
>>> -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
>>> -	if [ "eq$TYPE" != "eqdummy" ]; then
>>> -		selinuxenabled
>>> -		if [ $? -eq 0 ]; then
>>> -			echo "SELinux already enabled with a non-dummy policy."
>>> -			echo "Exiting.  Please install policy by hand if that"
>>> -			echo "is what you REALLY want."
>>> -			exit 1
>>> -		fi
>>> -		mv /etc/selinux/config /etc/selinux/config.mdpbak
>>> -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
>>> -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
>>> -	fi
>>> -fi
>>>    cd /etc/selinux/dummy/contexts/files
>>> -$SF file_contexts /
>>> +$SF -F file_contexts /
>>> -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
>>> -$SF file_contexts $mounts
>>> +mounts=`cat /proc/$$/mounts | \
>>> +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
>>> +	awk '{ print $2 '}`
>>> +$SF -F file_contexts $mounts
>>> -
>>> -dodev=`cat /proc/$$/mounts | grep "/dev "`
>>> -if [ "eq$dodev" != "eq" ]; then
>>> -	mount --move /dev /mnt
>>> -	$SF file_contexts /dev
>>> -	mount --move /mnt /dev
>>> -fi
>>> +touch /.autorelabel
>>> diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
>>> index 073fe7537f6c..daad333c7252 100644
>>> --- a/scripts/selinux/mdp/mdp.c
>>> +++ b/scripts/selinux/mdp/mdp.c
>>> @@ -33,6 +33,7 @@
>>>    #include <unistd.h>
>>>    #include <string.h>
>>>    #include <sys/socket.h>
>>> +#include <linux/kconfig.h>
>>>    static void usage(char *name)
>>>    {
>>> @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
>>>    	}
>>>    	fprintf(fout, "\n");
>>> -	/* NOW PRINT OUT MLS STUFF */
>>> +	/* print out mls declarations and constraints */
>>>    	if (mls) {
>>> -		printf("MLS not yet implemented\n");
>>> -		exit(1);
>>> +		fprintf(fout, "sensitivity s0;\n");
>>> +		fprintf(fout, "sensitivity s1;\n");
>>> +		fprintf(fout, "dominance { s0 s1 }\n");
>>> +		fprintf(fout, "category c0;\n");
>>> +		fprintf(fout, "category c1;\n");
>>> +		fprintf(fout, "level s0:c0.c1;\n");
>>> +		fprintf(fout, "level s1:c0.c1;\n");
>>> +#define SYSTEMLOW "s0"
>>> +#define SYSTEMHIGH "s1:c0.c1"
>>> +		for (i = 0; secclass_map[i].name; i++) {
>>> +			struct security_class_mapping *map = &secclass_map[i];
>>> +
>>> +			fprintf(fout, "mlsconstrain %s {\n", map->name);
>>> +			for (j = 0; map->perms[j]; j++)
>>> +				fprintf(fout, "\t%s\n", map->perms[j]);
>>> +			/*
>>> +			 * This requires all subjects and objects to be
>>> +			 * single-level (l2 eq h2), and that the subject
>>> +			 * level dominate the object level (h1 dom h2)
>>> +			 * in order to have any permissions to it.
>>> +			 */
>>> +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
>>> +		}
>>>    	}
>>>    	/* types, roles, and allows */
>>> @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
>>>    	for (i = 0; secclass_map[i].name; i++)
>>>    		fprintf(fout, "allow base_t base_t:%s *;\n",
>>>    			secclass_map[i].name);
>>> -	fprintf(fout, "user user_u roles { base_r };\n");
>>> -	fprintf(fout, "\n");
>>> +	fprintf(fout, "user user_u roles { base_r }");
>>> +	if (mls)
>>> +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
>>> +			SYSTEMLOW, SYSTEMHIGH);
>>> +	fprintf(fout, ";\n");
>>> +
>>> +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
>>> +#define OBJUSERROLETYPE "user_u:object_r:base_t"
>>>    	/* default sids */
>>>    	for (i = 1; i < initial_sid_to_string_len; i++)
>>> -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
>>> +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
>>> +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
>>>    	fprintf(fout, "\n");
>>> -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
>>> +#define FS_USE(behavior, fstype)			    \
>>> +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
>>> +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
>>> +
>>> +	/*
>>> +	 * Filesystems whose inode labels can be fetched via getxattr.
>>> +	 */
>>> +#ifdef CONFIG_EXT2_FS_SECURITY
>>> +	FS_USE("xattr", "ext2");
>>> +#endif
>>> +#ifdef CONFIG_EXT3_FS_SECURITY
>>> +	FS_USE("xattr", "ext3");
>>> +#endif
>>> +#ifdef CONFIG_EXT4_FS_SECURITY
>>> +	FS_USE("xattr", "ext4");
>>> +#endif
>>> +#ifdef CONFIG_JFS_SECURITY
>>> +	FS_USE("xattr", "jfs");
>>> +#endif
>>> +#ifdef CONFIG_REISERFS_FS_SECURITY
>>> +	FS_USE("xattr", "reiserfs");
>>> +#endif
>>> +#ifdef CONFIG_JFFS2_FS_SECURITY
>>> +	FS_USE("xattr", "jffs2");
>>> +#endif
>>> +#ifdef CONFIG_XFS_FS
>>> +	FS_USE("xattr", "xfs");
>>> +#endif
>>> +#ifdef CONFIG_GFS2_FS
>>> +	FS_USE("xattr", "gfs2");
>>> +#endif
>>> +#ifdef CONFIG_BTRFS_FS
>>> +	FS_USE("xattr", "btrfs");
>>> +#endif
>>> +#ifdef CONFIG_F2FS_FS_SECURITY
>>> +	FS_USE("xattr", "f2fs");
>>> +#endif
>>> +#ifdef CONFIG_OCFS2_FS
>>> +	FS_USE("xattr", "ocsfs2");
>>> +#endif
>>> +#ifdef CONFIG_OVERLAY_FS
>>> +	FS_USE("xattr", "overlay");
>>> +#endif
>>> +#ifdef CONFIG_SQUASHFS_XATTR
>>> +	FS_USE("xattr", "squashfs");
>>> +#endif
>>> +
>>> +	/*
>>> +	 * Filesystems whose inodes are labeled from allocating task.
>>> +	 */
>>> +	FS_USE("task", "pipefs");
>>> +	FS_USE("task", "sockfs");
>>> -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
>>> +	/*
>>> +	 * Filesystems whose inode labels are computed from both
>>> +	 * the allocating task and the superblock label.
>>> +	 */
>>> +#ifdef CONFIG_UNIX98_PTYS
>>> +	FS_USE("trans", "devpts");
>>> +#endif
>>> +#ifdef CONFIG_HUGETLBFS
>>> +	FS_USE("trans", "hugetlbfs");
>>> +#endif
>>> +#ifdef CONFIG_TMPFS
>>> +	FS_USE("trans", "tmpfs");
>>> +#endif
>>> +#ifdef CONFIG_DEVTMPFS
>>> +	FS_USE("trans", "devtmpfs");
>>> +#endif
>>> +#ifdef CONFIG_POSIX_MQUEUE
>>> +	FS_USE("trans", "mqueue");
>>> +#endif
>>> -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
>>> -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
>>> +#define GENFSCON(fstype, prefix)			     \
>>> +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
>>> +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
>>> -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
>>> +	/*
>>> +	 * Filesystems whose inodes are labeled from path prefix match
>>> +	 * relative to the filesystem root.  Depending on the filesystem,
>>> +	 * only a single label for all inodes may be supported.  Here
>>> +	 * we list the filesystem types for which per-file labeling is
>>> +	 * supported using genfscon; any other filesystem type can also
>>> +	 * be added by only with a single entry for all of its inodes.
>>> +	 */
>>> +#ifdef CONFIG_PROC_FS
>>> +	GENFSCON("proc", "/");
>>> +#endif
>>> +#ifdef CONFIG_SECURITY_SELINUX
>>> +	GENFSCON("selinuxfs", "/");
>>> +#endif
>>> +#ifdef CONFIG_SYSFS
>>> +	GENFSCON("sysfs", "/");
>>> +#endif
>>> +#ifdef CONFIG_DEBUG_FS
>>> +	GENFSCON("debugfs", "/");
>>> +#endif
>>> +#ifdef CONFIG_TRACING
>>> +	GENFSCON("tracefs", "/");
>>> +#endif
>>> +#ifdef CONFIG_PSTORE
>>> +	GENFSCON("pstore", "/");
>>> +#endif
>>> +	GENFSCON("cgroup", "/");
>>> +	GENFSCON("cgroup2", "/");
>>>    	fclose(fout);
>>> @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
>>>    		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
>>>    		usage(argv[0]);
>>>    	}
>>> -	fprintf(fout, "/ user_u:base_r:base_t\n");
>>> -	fprintf(fout, "/.* user_u:base_r:base_t\n");
>>> +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>> +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>>    	fclose(fout);
>>>    	return 0;
>>>
>>
>
Dominick Grift Feb. 21, 2019, 8:32 p.m. UTC | #6
On Thu, Feb 21, 2019 at 03:22:46PM -0500, Stephen Smalley wrote:
> On 2/21/19 3:11 PM, Dominick Grift wrote:
> > On Thu, Feb 21, 2019 at 01:42:13PM -0500, Stephen Smalley wrote:
> > > Derived in part from a patch by Dominick Grift.
> > > 
> > > The MDP example no longer works on modern systems.  Fix it.
> > > While we are at it, add MLS support and enable it.
> > > 
> > > NB This still does not work on systems using dbus-daemon instead of
> > > dbus-broker because dbus-daemon does not yet gracefully handle unknown
> > > classes/permissions.  This is a deficiency in libselinux's
> > > selinux_set_mapping() interface and underlying implementation,
> > > which was never fully updated to deal with unknown classes/permissions
> > > unlike the kernel.  Programs that instead use selinux_check_access()
> > > like dbus-broker do not have this problem.
> > > 
> > > Other known issues:
> > > - Not everything appears to be relabeled, so some files are left with invalid
> > > contexts and remapped to the unlabeled SID/context.
> > > - X will fail due to lack of a x_contexts file
> > > - libvirtd will fail due to lack of a virtual_domain_context file
> > > - crond reports an error with "No security context"
> > > 
> > > Changes to mdp:
> > > Add support for devtmpfs, required by modern Linux distributions.
> > > Add MLS support, with sample sensitivities, categories, and constraints.
> > > Generate fs_use and genfscon rules based on kernel configuration.
> > > Update list of filesystem types for fs_use and genfscon rules.
> > > Use object_r for object contexts.
> > > 
> > > Changes to install_policy.sh:
> > > Bail immediately on any errors.
> > > Provide more helpful error messages when unable to find userspace tools.
> > > Refuse to run if SELinux is already enabled.
> > > Unconditionally move aside /etc/selinux/config and create a new one.
> > > Build policy with -U allow so that userspace object managers do not break.
> > > Build policy with MLS enabled by default.
> > > Add default seusers mapping and failsafe context for use by
> > > pam_selinux / libselinux.
> > > Set to permissive mode rather than enforcing to permit initial autorelabel.
> > > Update the list of filesystem types to be relabeled.
> > > Create /.autorelabel to trigger an autorelabel on reboot.
> > > Drop broken attempt to relabel the /dev mountpoint directory.
> > > 
> > > Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> > > ---
> > >   scripts/selinux/install_policy.sh |  82 ++++++++-------
> > >   scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
> > >   2 files changed, 183 insertions(+), 63 deletions(-)
> > > 
> > > diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
> > > index 0b86c47baf7d..09eab4d0da5c 100755
> > > --- a/scripts/selinux/install_policy.sh
> > > +++ b/scripts/selinux/install_policy.sh
> > > @@ -1,30 +1,51 @@
> > >   #!/bin/sh
> > >   # SPDX-License-Identifier: GPL-2.0
> > > +set -e
> > >   if [ `id -u` -ne 0 ]; then
> > >   	echo "$0: must be root to install the selinux policy"
> > >   	exit 1
> > >   fi
> > > +
> > >   SF=`which setfiles`
> > >   if [ $? -eq 1 ]; then
> > > -	if [ -f /sbin/setfiles ]; then
> > > -		SF="/usr/setfiles"
> > > -	else
> > > -		echo "no selinux tools installed: setfiles"
> > > -		exit 1
> > > -	fi
> > > +	echo "Could not find setfiles"
> > > +	echo "Do you have policycoreutils installed?"
> > > +	exit 1
> > >   fi
> > > -cd mdp
> > > -
> > >   CP=`which checkpolicy`
> > > +if [ $? -eq 1 ]; then
> > > +	echo "Could not find checkpolicy"
> > > +	echo "Do you have checkpolicy installed?"
> > > +	exit 1
> > > +fi
> > >   VERS=`$CP -V | awk '{print $1}'`
> > > -./mdp policy.conf file_contexts
> > > -$CP -o policy.$VERS policy.conf
> > > +ENABLED=`which selinuxenabled`
> > > +if [ $? -eq 1 ]; then
> > > +	echo "Could not find selinuxenabled"
> > > +	echo "Do you have libselinux-utils installed?"
> > > +	exit 1
> > > +fi
> > > +
> > > +if selinuxenabled; then
> > > +    echo "SELinux is already enabled"
> > > +    echo "This prevents safely relabeling all files."
> > > +    echo "Boot with selinux=0 on the kernel command-line or"
> > > +    echo "SELINUX=disabled in /etc/selinux/config."
> > > +    exit 1
> > > +fi
> > > +
> > > +cd mdp
> > > +./mdp -m policy.conf file_contexts
> > > +$CP -U allow -M -o policy.$VERS policy.conf
> > >   mkdir -p /etc/selinux/dummy/policy
> > >   mkdir -p /etc/selinux/dummy/contexts/files
> > > +echo "__default__:user_u" > /etc/selinux/dummy/seusers
> > 
> > Should this be "__default__:user_u:s0-s0"?
> > 
> > > +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
> > 
> > Should this be "base_r:base_t:s0"?
> 
> Ah, thanks - good catch.  I couldn't really tell because I'm fighting with a
> broken dbus-daemon (F29) and X, so my ability to test is limited.  I'll fix
> in the next version along with a few other items I've noticed.

Yes I am fighting with a broken setfiles so I make do as well

Also note the comment about `echo "-F" > /.autorelabel` below

But i see you're playing it safe by adding SELINUXTYPE=permissive and triggering an extra autorelabel on boot.

Anyhow i tested it to the best of my ability and I can confirm that it works for me if you:

echo "__default__:user_u:s0-s0" > /etc/selinux/dummy/seusers
echo "base_r:base_t:s0" > /etc/selinux/dummy/contexts/failsafe_context
echo "-F" > /.autorelabel


> 
> > 
> > > +
> > >   cp file_contexts /etc/selinux/dummy/contexts/files
> > >   cp dbus_contexts /etc/selinux/dummy/contexts
> > >   cp policy.$VERS /etc/selinux/dummy/policy
> > > @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
> > >   if [ ! -d /etc/selinux ]; then
> > >   	mkdir -p /etc/selinux
> > >   fi
> > > -if [ ! -f /etc/selinux/config ]; then
> > > -	cat > /etc/selinux/config << EOF
> > > -SELINUX=enforcing
> > > +if [ -f /etc/selinux/config ]; then
> > > +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
> > > +    mv /etc/selinux/config /etc/selinux/config.bak
> > > +fi
> > > +echo "Creating new /etc/selinux/config for dummy policy."
> > > +cat > /etc/selinux/config << EOF
> > > +SELINUX=permissive
> > >   SELINUXTYPE=dummy
> > >   EOF
> > > -else
> > > -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
> > > -	if [ "eq$TYPE" != "eqdummy" ]; then
> > > -		selinuxenabled
> > > -		if [ $? -eq 0 ]; then
> > > -			echo "SELinux already enabled with a non-dummy policy."
> > > -			echo "Exiting.  Please install policy by hand if that"
> > > -			echo "is what you REALLY want."
> > > -			exit 1
> > > -		fi
> > > -		mv /etc/selinux/config /etc/selinux/config.mdpbak
> > > -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
> > > -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
> > > -	fi
> > > -fi
> > >   cd /etc/selinux/dummy/contexts/files
> > > -$SF file_contexts /
> > > +$SF -F file_contexts /
> > > -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
> > > -$SF file_contexts $mounts
> > > +mounts=`cat /proc/$$/mounts | \
> > > +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
> > > +	awk '{ print $2 '}`
> > > +$SF -F file_contexts $mounts
> > > -
> > > -dodev=`cat /proc/$$/mounts | grep "/dev "`
> > > -if [ "eq$dodev" != "eq" ]; then
> > > -	mount --move /dev /mnt
> > > -	$SF file_contexts /dev
> > > -	mount --move /mnt /dev
> > > -fi
> > > +touch /.autorelabel
> > 
> > Probably best to instead: "echo "-F" > /.autorelabel"?
> > 
> > > diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
> > > index 073fe7537f6c..daad333c7252 100644
> > > --- a/scripts/selinux/mdp/mdp.c
> > > +++ b/scripts/selinux/mdp/mdp.c
> > > @@ -33,6 +33,7 @@
> > >   #include <unistd.h>
> > >   #include <string.h>
> > >   #include <sys/socket.h>
> > > +#include <linux/kconfig.h>
> > >   static void usage(char *name)
> > >   {
> > > @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
> > >   	}
> > >   	fprintf(fout, "\n");
> > > -	/* NOW PRINT OUT MLS STUFF */
> > > +	/* print out mls declarations and constraints */
> > >   	if (mls) {
> > > -		printf("MLS not yet implemented\n");
> > > -		exit(1);
> > > +		fprintf(fout, "sensitivity s0;\n");
> > > +		fprintf(fout, "sensitivity s1;\n");
> > > +		fprintf(fout, "dominance { s0 s1 }\n");
> > > +		fprintf(fout, "category c0;\n");
> > > +		fprintf(fout, "category c1;\n");
> > > +		fprintf(fout, "level s0:c0.c1;\n");
> > > +		fprintf(fout, "level s1:c0.c1;\n");
> > > +#define SYSTEMLOW "s0"
> > > +#define SYSTEMHIGH "s1:c0.c1"
> > > +		for (i = 0; secclass_map[i].name; i++) {
> > > +			struct security_class_mapping *map = &secclass_map[i];
> > > +
> > > +			fprintf(fout, "mlsconstrain %s {\n", map->name);
> > > +			for (j = 0; map->perms[j]; j++)
> > > +				fprintf(fout, "\t%s\n", map->perms[j]);
> > > +			/*
> > > +			 * This requires all subjects and objects to be
> > > +			 * single-level (l2 eq h2), and that the subject
> > > +			 * level dominate the object level (h1 dom h2)
> > > +			 * in order to have any permissions to it.
> > > +			 */
> > > +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
> > > +		}
> > >   	}
> > >   	/* types, roles, and allows */
> > > @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
> > >   	for (i = 0; secclass_map[i].name; i++)
> > >   		fprintf(fout, "allow base_t base_t:%s *;\n",
> > >   			secclass_map[i].name);
> > > -	fprintf(fout, "user user_u roles { base_r };\n");
> > > -	fprintf(fout, "\n");
> > > +	fprintf(fout, "user user_u roles { base_r }");
> > > +	if (mls)
> > > +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
> > > +			SYSTEMLOW, SYSTEMHIGH);
> > > +	fprintf(fout, ";\n");
> > > +
> > > +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
> > > +#define OBJUSERROLETYPE "user_u:object_r:base_t"
> > >   	/* default sids */
> > >   	for (i = 1; i < initial_sid_to_string_len; i++)
> > > -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
> > > +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
> > > +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
> > >   	fprintf(fout, "\n");
> > > -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
> > > +#define FS_USE(behavior, fstype)			    \
> > > +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
> > > +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
> > > +
> > > +	/*
> > > +	 * Filesystems whose inode labels can be fetched via getxattr.
> > > +	 */
> > > +#ifdef CONFIG_EXT2_FS_SECURITY
> > > +	FS_USE("xattr", "ext2");
> > > +#endif
> > > +#ifdef CONFIG_EXT3_FS_SECURITY
> > > +	FS_USE("xattr", "ext3");
> > > +#endif
> > > +#ifdef CONFIG_EXT4_FS_SECURITY
> > > +	FS_USE("xattr", "ext4");
> > > +#endif
> > > +#ifdef CONFIG_JFS_SECURITY
> > > +	FS_USE("xattr", "jfs");
> > > +#endif
> > > +#ifdef CONFIG_REISERFS_FS_SECURITY
> > > +	FS_USE("xattr", "reiserfs");
> > > +#endif
> > > +#ifdef CONFIG_JFFS2_FS_SECURITY
> > > +	FS_USE("xattr", "jffs2");
> > > +#endif
> > > +#ifdef CONFIG_XFS_FS
> > > +	FS_USE("xattr", "xfs");
> > > +#endif
> > > +#ifdef CONFIG_GFS2_FS
> > > +	FS_USE("xattr", "gfs2");
> > > +#endif
> > > +#ifdef CONFIG_BTRFS_FS
> > > +	FS_USE("xattr", "btrfs");
> > > +#endif
> > > +#ifdef CONFIG_F2FS_FS_SECURITY
> > > +	FS_USE("xattr", "f2fs");
> > > +#endif
> > > +#ifdef CONFIG_OCFS2_FS
> > > +	FS_USE("xattr", "ocsfs2");
> > > +#endif
> > > +#ifdef CONFIG_OVERLAY_FS
> > > +	FS_USE("xattr", "overlay");
> > > +#endif
> > > +#ifdef CONFIG_SQUASHFS_XATTR
> > > +	FS_USE("xattr", "squashfs");
> > > +#endif
> > > +
> > > +	/*
> > > +	 * Filesystems whose inodes are labeled from allocating task.
> > > +	 */
> > > +	FS_USE("task", "pipefs");
> > > +	FS_USE("task", "sockfs");
> > > -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
> > > +	/*
> > > +	 * Filesystems whose inode labels are computed from both
> > > +	 * the allocating task and the superblock label.
> > > +	 */
> > > +#ifdef CONFIG_UNIX98_PTYS
> > > +	FS_USE("trans", "devpts");
> > > +#endif
> > > +#ifdef CONFIG_HUGETLBFS
> > > +	FS_USE("trans", "hugetlbfs");
> > > +#endif
> > > +#ifdef CONFIG_TMPFS
> > > +	FS_USE("trans", "tmpfs");
> > > +#endif
> > > +#ifdef CONFIG_DEVTMPFS
> > > +	FS_USE("trans", "devtmpfs");
> > > +#endif
> > > +#ifdef CONFIG_POSIX_MQUEUE
> > > +	FS_USE("trans", "mqueue");
> > > +#endif
> > > -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
> > > +#define GENFSCON(fstype, prefix)			     \
> > > +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
> > > +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
> > > -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
> > > +	/*
> > > +	 * Filesystems whose inodes are labeled from path prefix match
> > > +	 * relative to the filesystem root.  Depending on the filesystem,
> > > +	 * only a single label for all inodes may be supported.  Here
> > > +	 * we list the filesystem types for which per-file labeling is
> > > +	 * supported using genfscon; any other filesystem type can also
> > > +	 * be added by only with a single entry for all of its inodes.
> > > +	 */
> > > +#ifdef CONFIG_PROC_FS
> > > +	GENFSCON("proc", "/");
> > > +#endif
> > > +#ifdef CONFIG_SECURITY_SELINUX
> > > +	GENFSCON("selinuxfs", "/");
> > > +#endif
> > > +#ifdef CONFIG_SYSFS
> > > +	GENFSCON("sysfs", "/");
> > > +#endif
> > > +#ifdef CONFIG_DEBUG_FS
> > > +	GENFSCON("debugfs", "/");
> > > +#endif
> > > +#ifdef CONFIG_TRACING
> > > +	GENFSCON("tracefs", "/");
> > > +#endif
> > > +#ifdef CONFIG_PSTORE
> > > +	GENFSCON("pstore", "/");
> > > +#endif
> > > +	GENFSCON("cgroup", "/");
> > > +	GENFSCON("cgroup2", "/");
> > >   	fclose(fout);
> > > @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
> > >   		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
> > >   		usage(argv[0]);
> > >   	}
> > > -	fprintf(fout, "/ user_u:base_r:base_t\n");
> > > -	fprintf(fout, "/.* user_u:base_r:base_t\n");
> > > +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> > > +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> > >   	fclose(fout);
> > >   	return 0;
> > > -- 
> > > 2.20.1
> > > 
> > 
>
Dominick Grift Feb. 21, 2019, 8:46 p.m. UTC | #7
On Thu, Feb 21, 2019 at 03:22:46PM -0500, Stephen Smalley wrote:
> On 2/21/19 3:11 PM, Dominick Grift wrote:
> > On Thu, Feb 21, 2019 at 01:42:13PM -0500, Stephen Smalley wrote:
> > > Derived in part from a patch by Dominick Grift.
> > > 
> > > The MDP example no longer works on modern systems.  Fix it.
> > > While we are at it, add MLS support and enable it.
> > > 
> > > NB This still does not work on systems using dbus-daemon instead of
> > > dbus-broker because dbus-daemon does not yet gracefully handle unknown
> > > classes/permissions.  This is a deficiency in libselinux's
> > > selinux_set_mapping() interface and underlying implementation,
> > > which was never fully updated to deal with unknown classes/permissions
> > > unlike the kernel.  Programs that instead use selinux_check_access()
> > > like dbus-broker do not have this problem.
> > > 
> > > Other known issues:
> > > - Not everything appears to be relabeled, so some files are left with invalid
> > > contexts and remapped to the unlabeled SID/context.
> > > - X will fail due to lack of a x_contexts file
> > > - libvirtd will fail due to lack of a virtual_domain_context file
> > > - crond reports an error with "No security context"
> > > 
> > > Changes to mdp:
> > > Add support for devtmpfs, required by modern Linux distributions.
> > > Add MLS support, with sample sensitivities, categories, and constraints.
> > > Generate fs_use and genfscon rules based on kernel configuration.
> > > Update list of filesystem types for fs_use and genfscon rules.
> > > Use object_r for object contexts.
> > > 
> > > Changes to install_policy.sh:
> > > Bail immediately on any errors.
> > > Provide more helpful error messages when unable to find userspace tools.
> > > Refuse to run if SELinux is already enabled.
> > > Unconditionally move aside /etc/selinux/config and create a new one.
> > > Build policy with -U allow so that userspace object managers do not break.
> > > Build policy with MLS enabled by default.
> > > Add default seusers mapping and failsafe context for use by
> > > pam_selinux / libselinux.
> > > Set to permissive mode rather than enforcing to permit initial autorelabel.
> > > Update the list of filesystem types to be relabeled.
> > > Create /.autorelabel to trigger an autorelabel on reboot.
> > > Drop broken attempt to relabel the /dev mountpoint directory.
> > > 
> > > Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> > > ---
> > >   scripts/selinux/install_policy.sh |  82 ++++++++-------
> > >   scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
> > >   2 files changed, 183 insertions(+), 63 deletions(-)
> > > 
> > > diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
> > > index 0b86c47baf7d..09eab4d0da5c 100755
> > > --- a/scripts/selinux/install_policy.sh
> > > +++ b/scripts/selinux/install_policy.sh
> > > @@ -1,30 +1,51 @@
> > >   #!/bin/sh
> > >   # SPDX-License-Identifier: GPL-2.0
> > > +set -e
> > >   if [ `id -u` -ne 0 ]; then
> > >   	echo "$0: must be root to install the selinux policy"
> > >   	exit 1
> > >   fi
> > > +
> > >   SF=`which setfiles`
> > >   if [ $? -eq 1 ]; then
> > > -	if [ -f /sbin/setfiles ]; then
> > > -		SF="/usr/setfiles"
> > > -	else
> > > -		echo "no selinux tools installed: setfiles"
> > > -		exit 1
> > > -	fi
> > > +	echo "Could not find setfiles"
> > > +	echo "Do you have policycoreutils installed?"
> > > +	exit 1
> > >   fi
> > > -cd mdp
> > > -
> > >   CP=`which checkpolicy`
> > > +if [ $? -eq 1 ]; then
> > > +	echo "Could not find checkpolicy"
> > > +	echo "Do you have checkpolicy installed?"
> > > +	exit 1
> > > +fi
> > >   VERS=`$CP -V | awk '{print $1}'`
> > > -./mdp policy.conf file_contexts
> > > -$CP -o policy.$VERS policy.conf
> > > +ENABLED=`which selinuxenabled`
> > > +if [ $? -eq 1 ]; then
> > > +	echo "Could not find selinuxenabled"
> > > +	echo "Do you have libselinux-utils installed?"
> > > +	exit 1
> > > +fi
> > > +
> > > +if selinuxenabled; then
> > > +    echo "SELinux is already enabled"
> > > +    echo "This prevents safely relabeling all files."
> > > +    echo "Boot with selinux=0 on the kernel command-line or"
> > > +    echo "SELINUX=disabled in /etc/selinux/config."
> > > +    exit 1
> > > +fi
> > > +
> > > +cd mdp
> > > +./mdp -m policy.conf file_contexts
> > > +$CP -U allow -M -o policy.$VERS policy.conf
> > >   mkdir -p /etc/selinux/dummy/policy
> > >   mkdir -p /etc/selinux/dummy/contexts/files
> > > +echo "__default__:user_u" > /etc/selinux/dummy/seusers
> > 
> > Should this be "__default__:user_u:s0-s0"?
> > 
> > > +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
> > 
> > Should this be "base_r:base_t:s0"?
> 
> Ah, thanks - good catch.  I couldn't really tell because I'm fighting with a
> broken dbus-daemon (F29) and X, so my ability to test is limited.  I'll fix
> in the next version along with a few other items I've noticed.
> 

Regarding X: one workaround is as i do in dssp2-minimal:

cat > /etc/X11/xorg.conf.d/99-selinux.conf <<EOF
Section "Module"
SubSection "extmod"
Option "SELinux mode disabled"
EndSubSection
EndSection
EOF

But that has its limitations as well since Xwayland segfaults then when you quit xserver (bug in Xwayland but works with plain X)

> > 
> > > +
> > >   cp file_contexts /etc/selinux/dummy/contexts/files
> > >   cp dbus_contexts /etc/selinux/dummy/contexts
> > >   cp policy.$VERS /etc/selinux/dummy/policy
> > > @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
> > >   if [ ! -d /etc/selinux ]; then
> > >   	mkdir -p /etc/selinux
> > >   fi
> > > -if [ ! -f /etc/selinux/config ]; then
> > > -	cat > /etc/selinux/config << EOF
> > > -SELINUX=enforcing
> > > +if [ -f /etc/selinux/config ]; then
> > > +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
> > > +    mv /etc/selinux/config /etc/selinux/config.bak
> > > +fi
> > > +echo "Creating new /etc/selinux/config for dummy policy."
> > > +cat > /etc/selinux/config << EOF
> > > +SELINUX=permissive
> > >   SELINUXTYPE=dummy
> > >   EOF
> > > -else
> > > -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
> > > -	if [ "eq$TYPE" != "eqdummy" ]; then
> > > -		selinuxenabled
> > > -		if [ $? -eq 0 ]; then
> > > -			echo "SELinux already enabled with a non-dummy policy."
> > > -			echo "Exiting.  Please install policy by hand if that"
> > > -			echo "is what you REALLY want."
> > > -			exit 1
> > > -		fi
> > > -		mv /etc/selinux/config /etc/selinux/config.mdpbak
> > > -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
> > > -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
> > > -	fi
> > > -fi
> > >   cd /etc/selinux/dummy/contexts/files
> > > -$SF file_contexts /
> > > +$SF -F file_contexts /
> > > -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
> > > -$SF file_contexts $mounts
> > > +mounts=`cat /proc/$$/mounts | \
> > > +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
> > > +	awk '{ print $2 '}`
> > > +$SF -F file_contexts $mounts
> > > -
> > > -dodev=`cat /proc/$$/mounts | grep "/dev "`
> > > -if [ "eq$dodev" != "eq" ]; then
> > > -	mount --move /dev /mnt
> > > -	$SF file_contexts /dev
> > > -	mount --move /mnt /dev
> > > -fi
> > > +touch /.autorelabel
> > 
> > Probably best to instead: "echo "-F" > /.autorelabel"?
> > 
> > > diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
> > > index 073fe7537f6c..daad333c7252 100644
> > > --- a/scripts/selinux/mdp/mdp.c
> > > +++ b/scripts/selinux/mdp/mdp.c
> > > @@ -33,6 +33,7 @@
> > >   #include <unistd.h>
> > >   #include <string.h>
> > >   #include <sys/socket.h>
> > > +#include <linux/kconfig.h>
> > >   static void usage(char *name)
> > >   {
> > > @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
> > >   	}
> > >   	fprintf(fout, "\n");
> > > -	/* NOW PRINT OUT MLS STUFF */
> > > +	/* print out mls declarations and constraints */
> > >   	if (mls) {
> > > -		printf("MLS not yet implemented\n");
> > > -		exit(1);
> > > +		fprintf(fout, "sensitivity s0;\n");
> > > +		fprintf(fout, "sensitivity s1;\n");
> > > +		fprintf(fout, "dominance { s0 s1 }\n");
> > > +		fprintf(fout, "category c0;\n");
> > > +		fprintf(fout, "category c1;\n");
> > > +		fprintf(fout, "level s0:c0.c1;\n");
> > > +		fprintf(fout, "level s1:c0.c1;\n");
> > > +#define SYSTEMLOW "s0"
> > > +#define SYSTEMHIGH "s1:c0.c1"
> > > +		for (i = 0; secclass_map[i].name; i++) {
> > > +			struct security_class_mapping *map = &secclass_map[i];
> > > +
> > > +			fprintf(fout, "mlsconstrain %s {\n", map->name);
> > > +			for (j = 0; map->perms[j]; j++)
> > > +				fprintf(fout, "\t%s\n", map->perms[j]);
> > > +			/*
> > > +			 * This requires all subjects and objects to be
> > > +			 * single-level (l2 eq h2), and that the subject
> > > +			 * level dominate the object level (h1 dom h2)
> > > +			 * in order to have any permissions to it.
> > > +			 */
> > > +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
> > > +		}
> > >   	}
> > >   	/* types, roles, and allows */
> > > @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
> > >   	for (i = 0; secclass_map[i].name; i++)
> > >   		fprintf(fout, "allow base_t base_t:%s *;\n",
> > >   			secclass_map[i].name);
> > > -	fprintf(fout, "user user_u roles { base_r };\n");
> > > -	fprintf(fout, "\n");
> > > +	fprintf(fout, "user user_u roles { base_r }");
> > > +	if (mls)
> > > +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
> > > +			SYSTEMLOW, SYSTEMHIGH);
> > > +	fprintf(fout, ";\n");
> > > +
> > > +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
> > > +#define OBJUSERROLETYPE "user_u:object_r:base_t"
> > >   	/* default sids */
> > >   	for (i = 1; i < initial_sid_to_string_len; i++)
> > > -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
> > > +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
> > > +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
> > >   	fprintf(fout, "\n");
> > > -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
> > > +#define FS_USE(behavior, fstype)			    \
> > > +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
> > > +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
> > > +
> > > +	/*
> > > +	 * Filesystems whose inode labels can be fetched via getxattr.
> > > +	 */
> > > +#ifdef CONFIG_EXT2_FS_SECURITY
> > > +	FS_USE("xattr", "ext2");
> > > +#endif
> > > +#ifdef CONFIG_EXT3_FS_SECURITY
> > > +	FS_USE("xattr", "ext3");
> > > +#endif
> > > +#ifdef CONFIG_EXT4_FS_SECURITY
> > > +	FS_USE("xattr", "ext4");
> > > +#endif
> > > +#ifdef CONFIG_JFS_SECURITY
> > > +	FS_USE("xattr", "jfs");
> > > +#endif
> > > +#ifdef CONFIG_REISERFS_FS_SECURITY
> > > +	FS_USE("xattr", "reiserfs");
> > > +#endif
> > > +#ifdef CONFIG_JFFS2_FS_SECURITY
> > > +	FS_USE("xattr", "jffs2");
> > > +#endif
> > > +#ifdef CONFIG_XFS_FS
> > > +	FS_USE("xattr", "xfs");
> > > +#endif
> > > +#ifdef CONFIG_GFS2_FS
> > > +	FS_USE("xattr", "gfs2");
> > > +#endif
> > > +#ifdef CONFIG_BTRFS_FS
> > > +	FS_USE("xattr", "btrfs");
> > > +#endif
> > > +#ifdef CONFIG_F2FS_FS_SECURITY
> > > +	FS_USE("xattr", "f2fs");
> > > +#endif
> > > +#ifdef CONFIG_OCFS2_FS
> > > +	FS_USE("xattr", "ocsfs2");
> > > +#endif
> > > +#ifdef CONFIG_OVERLAY_FS
> > > +	FS_USE("xattr", "overlay");
> > > +#endif
> > > +#ifdef CONFIG_SQUASHFS_XATTR
> > > +	FS_USE("xattr", "squashfs");
> > > +#endif
> > > +
> > > +	/*
> > > +	 * Filesystems whose inodes are labeled from allocating task.
> > > +	 */
> > > +	FS_USE("task", "pipefs");
> > > +	FS_USE("task", "sockfs");
> > > -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
> > > +	/*
> > > +	 * Filesystems whose inode labels are computed from both
> > > +	 * the allocating task and the superblock label.
> > > +	 */
> > > +#ifdef CONFIG_UNIX98_PTYS
> > > +	FS_USE("trans", "devpts");
> > > +#endif
> > > +#ifdef CONFIG_HUGETLBFS
> > > +	FS_USE("trans", "hugetlbfs");
> > > +#endif
> > > +#ifdef CONFIG_TMPFS
> > > +	FS_USE("trans", "tmpfs");
> > > +#endif
> > > +#ifdef CONFIG_DEVTMPFS
> > > +	FS_USE("trans", "devtmpfs");
> > > +#endif
> > > +#ifdef CONFIG_POSIX_MQUEUE
> > > +	FS_USE("trans", "mqueue");
> > > +#endif
> > > -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
> > > -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
> > > +#define GENFSCON(fstype, prefix)			     \
> > > +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
> > > +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
> > > -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
> > > +	/*
> > > +	 * Filesystems whose inodes are labeled from path prefix match
> > > +	 * relative to the filesystem root.  Depending on the filesystem,
> > > +	 * only a single label for all inodes may be supported.  Here
> > > +	 * we list the filesystem types for which per-file labeling is
> > > +	 * supported using genfscon; any other filesystem type can also
> > > +	 * be added by only with a single entry for all of its inodes.
> > > +	 */
> > > +#ifdef CONFIG_PROC_FS
> > > +	GENFSCON("proc", "/");
> > > +#endif
> > > +#ifdef CONFIG_SECURITY_SELINUX
> > > +	GENFSCON("selinuxfs", "/");
> > > +#endif
> > > +#ifdef CONFIG_SYSFS
> > > +	GENFSCON("sysfs", "/");
> > > +#endif
> > > +#ifdef CONFIG_DEBUG_FS
> > > +	GENFSCON("debugfs", "/");
> > > +#endif
> > > +#ifdef CONFIG_TRACING
> > > +	GENFSCON("tracefs", "/");
> > > +#endif
> > > +#ifdef CONFIG_PSTORE
> > > +	GENFSCON("pstore", "/");
> > > +#endif
> > > +	GENFSCON("cgroup", "/");
> > > +	GENFSCON("cgroup2", "/");
> > >   	fclose(fout);
> > > @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
> > >   		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
> > >   		usage(argv[0]);
> > >   	}
> > > -	fprintf(fout, "/ user_u:base_r:base_t\n");
> > > -	fprintf(fout, "/.* user_u:base_r:base_t\n");
> > > +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> > > +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> > >   	fclose(fout);
> > >   	return 0;
> > > -- 
> > > 2.20.1
> > > 
> > 
>
Dominick Grift Feb. 21, 2019, 8:56 p.m. UTC | #8
On Thu, Feb 21, 2019 at 03:28:37PM -0500, Stephen Smalley wrote:
> On 2/21/19 2:44 PM, Dominick Grift wrote:
> > On Thu, Feb 21, 2019 at 02:34:38PM -0500, Stephen Smalley wrote:
> > > On 2/21/19 1:42 PM, Stephen Smalley wrote:
> > > > Derived in part from a patch by Dominick Grift.
> > > > 
> > > > The MDP example no longer works on modern systems.  Fix it.
> > > > While we are at it, add MLS support and enable it.
> > > > 
> > > > NB This still does not work on systems using dbus-daemon instead of
> > > > dbus-broker because dbus-daemon does not yet gracefully handle unknown
> > > > classes/permissions.  This is a deficiency in libselinux's
> > > > selinux_set_mapping() interface and underlying implementation,
> > > > which was never fully updated to deal with unknown classes/permissions
> > > > unlike the kernel.  Programs that instead use selinux_check_access()
> > > > like dbus-broker do not have this problem.
> > > 
> > > We could perhaps avoid this problem by having mdp always include at least a
> > > core set of userspace classes/permissions in the policy it generates.  We
> > > could also fix libselinux but that won't help on any existing distro.
> > > 
> > > > 
> > > > Other known issues:
> > > > - Not everything appears to be relabeled, so some files are left with invalid
> > > > contexts and remapped to the unlabeled SID/context.
> > > 
> > > This appears to be partly due to overuse of <<none>> in file_contexts (.fc)
> > > files.  That excludes those parts of the filesystem from being relabeled at
> > > all.  This was used to exclude pseudo filesystems (obsoleted by seclabel
> > > mount option detection) or runtime directories/files whose labels were
> > > derived from the creating process and couldn't be statically specified by
> > > file_contexts.  To get my system back into working order even with targeted
> > > policy, I had to strip all <<none>> entries out of my file_contexts* files
> > > and then run setfiles -F with the list of filesystem mounts to relabel.
> > > Otherwise, I'd have files left in the old contexts and the system wouldn't
> > > even come up to user login, even if permissive.
> > 
> > What <<none>> spec(s) in fedora would be so important that it causes the system to not come up to user login, even in permissive?
> > Does the unlabeled isid not address these particular scenario's? and why not?
> 
> Yes, I don't fully understand it myself; I just know that certain services
> won't start successfully and it never reaches the point where I can login
> locally or remotely.  But stripping the <<none>> entries and running
> setfiles -F did fix it for me.  NB This was for converting back from mdp to
> the Fedora targeted policy.  It wouldn't be an issue for converting to mdp
> since that file_contexts has no <<none>> entries and has a default match for
> /.*.

I am going on a limb here so bear with me but; I suspect that it was not the <<none>> that "did" it. I think it might have been the additional setfiles -F that did it.
I think the services did not come up because systemd was not able to compute its context from /sbin/init.
If the above is actually the case then my question is:
Why can't systemd compute its context from /sbin/init by relying on the unlabeled isid. I mean if /sbin/init was mislabeled. then the unlabeled isid should have kicked in. So why was systemd unable to use that to compute its context?

> 
> Maybe it is a case of processes with CAP_MAC_ADMIN fetching the raw context
> (which is invalid under the current policy) and then trying to feed them
> back to the kernel via a selinuxfs interface, e.g. security_compute_create()
> or similar.  The kernel would reject those.
> 
> > 
> > I am testing the patch now here (but in my scenario its a very minimal fedora with dssp2-standard policy)
> > 
> > > 
> > > FWIW, Android policy doesn't use <<none>> at all.  But they also don't have
> > > a /.* or equivalent entry as a default match, so anything not covered by a
> > > more specific match is likewise not labeled. seapp_contexts handles the more
> > > dynamic aspect of app directory labeling for Android.
> > > 
> > > The other problem case for relabeling is the mount point directories, which
> > > requires unmounting them all and relabeling them if we care. Otherwise
> > > they'll just get the unlabeled context and as long as we allow mounting on
> > > that, it should be ok.
> > > 
> > > > - X will fail due to lack of a x_contexts file
> > > > - libvirtd will fail due to lack of a virtual_domain_context file
> > > 
> > > We could easily add these to the mdp policy.
> > > 
> > > > - crond reports an error with "No security context"
> > > 
> > > This is probably due to the lack of a contexts/default_contexts or any
> > > contexts/users/ files in the dummy policy.
> > > 
> > > > 
> > > > Changes to mdp:
> > > > Add support for devtmpfs, required by modern Linux distributions.
> > > > Add MLS support, with sample sensitivities, categories, and constraints.
> > > > Generate fs_use and genfscon rules based on kernel configuration.
> > > > Update list of filesystem types for fs_use and genfscon rules.
> > > > Use object_r for object contexts.
> > > > 
> > > > Changes to install_policy.sh:
> > > > Bail immediately on any errors.
> > > > Provide more helpful error messages when unable to find userspace tools.
> > > > Refuse to run if SELinux is already enabled.
> > > > Unconditionally move aside /etc/selinux/config and create a new one.
> > > > Build policy with -U allow so that userspace object managers do not break.
> > > > Build policy with MLS enabled by default.
> > > > Add default seusers mapping and failsafe context for use by
> > > > pam_selinux / libselinux.
> > > > Set to permissive mode rather than enforcing to permit initial autorelabel.
> > > > Update the list of filesystem types to be relabeled.
> > > > Create /.autorelabel to trigger an autorelabel on reboot.
> > > > Drop broken attempt to relabel the /dev mountpoint directory.
> > > > 
> > > > Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> > > > ---
> > > >    scripts/selinux/install_policy.sh |  82 ++++++++-------
> > > >    scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
> > > >    2 files changed, 183 insertions(+), 63 deletions(-)
> > > > 
> > > > diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
> > > > index 0b86c47baf7d..09eab4d0da5c 100755
> > > > --- a/scripts/selinux/install_policy.sh
> > > > +++ b/scripts/selinux/install_policy.sh
> > > > @@ -1,30 +1,51 @@
> > > >    #!/bin/sh
> > > >    # SPDX-License-Identifier: GPL-2.0
> > > > +set -e
> > > >    if [ `id -u` -ne 0 ]; then
> > > >    	echo "$0: must be root to install the selinux policy"
> > > >    	exit 1
> > > >    fi
> > > > +
> > > >    SF=`which setfiles`
> > > >    if [ $? -eq 1 ]; then
> > > > -	if [ -f /sbin/setfiles ]; then
> > > > -		SF="/usr/setfiles"
> > > > -	else
> > > > -		echo "no selinux tools installed: setfiles"
> > > > -		exit 1
> > > > -	fi
> > > > +	echo "Could not find setfiles"
> > > > +	echo "Do you have policycoreutils installed?"
> > > > +	exit 1
> > > >    fi
> > > > -cd mdp
> > > > -
> > > >    CP=`which checkpolicy`
> > > > +if [ $? -eq 1 ]; then
> > > > +	echo "Could not find checkpolicy"
> > > > +	echo "Do you have checkpolicy installed?"
> > > > +	exit 1
> > > > +fi
> > > >    VERS=`$CP -V | awk '{print $1}'`
> > > > -./mdp policy.conf file_contexts
> > > > -$CP -o policy.$VERS policy.conf
> > > > +ENABLED=`which selinuxenabled`
> > > > +if [ $? -eq 1 ]; then
> > > > +	echo "Could not find selinuxenabled"
> > > > +	echo "Do you have libselinux-utils installed?"
> > > > +	exit 1
> > > > +fi
> > > > +
> > > > +if selinuxenabled; then
> > > > +    echo "SELinux is already enabled"
> > > > +    echo "This prevents safely relabeling all files."
> > > > +    echo "Boot with selinux=0 on the kernel command-line or"
> > > > +    echo "SELINUX=disabled in /etc/selinux/config."
> > > > +    exit 1
> > > > +fi
> > > > +
> > > > +cd mdp
> > > > +./mdp -m policy.conf file_contexts
> > > > +$CP -U allow -M -o policy.$VERS policy.conf
> > > >    mkdir -p /etc/selinux/dummy/policy
> > > >    mkdir -p /etc/selinux/dummy/contexts/files
> > > > +echo "__default__:user_u" > /etc/selinux/dummy/seusers
> > > > +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
> > > > +
> > > >    cp file_contexts /etc/selinux/dummy/contexts/files
> > > >    cp dbus_contexts /etc/selinux/dummy/contexts
> > > >    cp policy.$VERS /etc/selinux/dummy/policy
> > > > @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
> > > >    if [ ! -d /etc/selinux ]; then
> > > >    	mkdir -p /etc/selinux
> > > >    fi
> > > > -if [ ! -f /etc/selinux/config ]; then
> > > > -	cat > /etc/selinux/config << EOF
> > > > -SELINUX=enforcing
> > > > +if [ -f /etc/selinux/config ]; then
> > > > +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
> > > > +    mv /etc/selinux/config /etc/selinux/config.bak
> > > > +fi
> > > > +echo "Creating new /etc/selinux/config for dummy policy."
> > > > +cat > /etc/selinux/config << EOF
> > > > +SELINUX=permissive
> > > >    SELINUXTYPE=dummy
> > > >    EOF
> > > > -else
> > > > -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
> > > > -	if [ "eq$TYPE" != "eqdummy" ]; then
> > > > -		selinuxenabled
> > > > -		if [ $? -eq 0 ]; then
> > > > -			echo "SELinux already enabled with a non-dummy policy."
> > > > -			echo "Exiting.  Please install policy by hand if that"
> > > > -			echo "is what you REALLY want."
> > > > -			exit 1
> > > > -		fi
> > > > -		mv /etc/selinux/config /etc/selinux/config.mdpbak
> > > > -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
> > > > -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
> > > > -	fi
> > > > -fi
> > > >    cd /etc/selinux/dummy/contexts/files
> > > > -$SF file_contexts /
> > > > +$SF -F file_contexts /
> > > > -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
> > > > -$SF file_contexts $mounts
> > > > +mounts=`cat /proc/$$/mounts | \
> > > > +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
> > > > +	awk '{ print $2 '}`
> > > > +$SF -F file_contexts $mounts
> > > > -
> > > > -dodev=`cat /proc/$$/mounts | grep "/dev "`
> > > > -if [ "eq$dodev" != "eq" ]; then
> > > > -	mount --move /dev /mnt
> > > > -	$SF file_contexts /dev
> > > > -	mount --move /mnt /dev
> > > > -fi
> > > > +touch /.autorelabel
> > > > diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
> > > > index 073fe7537f6c..daad333c7252 100644
> > > > --- a/scripts/selinux/mdp/mdp.c
> > > > +++ b/scripts/selinux/mdp/mdp.c
> > > > @@ -33,6 +33,7 @@
> > > >    #include <unistd.h>
> > > >    #include <string.h>
> > > >    #include <sys/socket.h>
> > > > +#include <linux/kconfig.h>
> > > >    static void usage(char *name)
> > > >    {
> > > > @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
> > > >    	}
> > > >    	fprintf(fout, "\n");
> > > > -	/* NOW PRINT OUT MLS STUFF */
> > > > +	/* print out mls declarations and constraints */
> > > >    	if (mls) {
> > > > -		printf("MLS not yet implemented\n");
> > > > -		exit(1);
> > > > +		fprintf(fout, "sensitivity s0;\n");
> > > > +		fprintf(fout, "sensitivity s1;\n");
> > > > +		fprintf(fout, "dominance { s0 s1 }\n");
> > > > +		fprintf(fout, "category c0;\n");
> > > > +		fprintf(fout, "category c1;\n");
> > > > +		fprintf(fout, "level s0:c0.c1;\n");
> > > > +		fprintf(fout, "level s1:c0.c1;\n");
> > > > +#define SYSTEMLOW "s0"
> > > > +#define SYSTEMHIGH "s1:c0.c1"
> > > > +		for (i = 0; secclass_map[i].name; i++) {
> > > > +			struct security_class_mapping *map = &secclass_map[i];
> > > > +
> > > > +			fprintf(fout, "mlsconstrain %s {\n", map->name);
> > > > +			for (j = 0; map->perms[j]; j++)
> > > > +				fprintf(fout, "\t%s\n", map->perms[j]);
> > > > +			/*
> > > > +			 * This requires all subjects and objects to be
> > > > +			 * single-level (l2 eq h2), and that the subject
> > > > +			 * level dominate the object level (h1 dom h2)
> > > > +			 * in order to have any permissions to it.
> > > > +			 */
> > > > +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
> > > > +		}
> > > >    	}
> > > >    	/* types, roles, and allows */
> > > > @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
> > > >    	for (i = 0; secclass_map[i].name; i++)
> > > >    		fprintf(fout, "allow base_t base_t:%s *;\n",
> > > >    			secclass_map[i].name);
> > > > -	fprintf(fout, "user user_u roles { base_r };\n");
> > > > -	fprintf(fout, "\n");
> > > > +	fprintf(fout, "user user_u roles { base_r }");
> > > > +	if (mls)
> > > > +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
> > > > +			SYSTEMLOW, SYSTEMHIGH);
> > > > +	fprintf(fout, ";\n");
> > > > +
> > > > +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
> > > > +#define OBJUSERROLETYPE "user_u:object_r:base_t"
> > > >    	/* default sids */
> > > >    	for (i = 1; i < initial_sid_to_string_len; i++)
> > > > -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
> > > > +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
> > > > +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
> > > >    	fprintf(fout, "\n");
> > > > -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
> > > > +#define FS_USE(behavior, fstype)			    \
> > > > +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
> > > > +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
> > > > +
> > > > +	/*
> > > > +	 * Filesystems whose inode labels can be fetched via getxattr.
> > > > +	 */
> > > > +#ifdef CONFIG_EXT2_FS_SECURITY
> > > > +	FS_USE("xattr", "ext2");
> > > > +#endif
> > > > +#ifdef CONFIG_EXT3_FS_SECURITY
> > > > +	FS_USE("xattr", "ext3");
> > > > +#endif
> > > > +#ifdef CONFIG_EXT4_FS_SECURITY
> > > > +	FS_USE("xattr", "ext4");
> > > > +#endif
> > > > +#ifdef CONFIG_JFS_SECURITY
> > > > +	FS_USE("xattr", "jfs");
> > > > +#endif
> > > > +#ifdef CONFIG_REISERFS_FS_SECURITY
> > > > +	FS_USE("xattr", "reiserfs");
> > > > +#endif
> > > > +#ifdef CONFIG_JFFS2_FS_SECURITY
> > > > +	FS_USE("xattr", "jffs2");
> > > > +#endif
> > > > +#ifdef CONFIG_XFS_FS
> > > > +	FS_USE("xattr", "xfs");
> > > > +#endif
> > > > +#ifdef CONFIG_GFS2_FS
> > > > +	FS_USE("xattr", "gfs2");
> > > > +#endif
> > > > +#ifdef CONFIG_BTRFS_FS
> > > > +	FS_USE("xattr", "btrfs");
> > > > +#endif
> > > > +#ifdef CONFIG_F2FS_FS_SECURITY
> > > > +	FS_USE("xattr", "f2fs");
> > > > +#endif
> > > > +#ifdef CONFIG_OCFS2_FS
> > > > +	FS_USE("xattr", "ocsfs2");
> > > > +#endif
> > > > +#ifdef CONFIG_OVERLAY_FS
> > > > +	FS_USE("xattr", "overlay");
> > > > +#endif
> > > > +#ifdef CONFIG_SQUASHFS_XATTR
> > > > +	FS_USE("xattr", "squashfs");
> > > > +#endif
> > > > +
> > > > +	/*
> > > > +	 * Filesystems whose inodes are labeled from allocating task.
> > > > +	 */
> > > > +	FS_USE("task", "pipefs");
> > > > +	FS_USE("task", "sockfs");
> > > > -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
> > > > +	/*
> > > > +	 * Filesystems whose inode labels are computed from both
> > > > +	 * the allocating task and the superblock label.
> > > > +	 */
> > > > +#ifdef CONFIG_UNIX98_PTYS
> > > > +	FS_USE("trans", "devpts");
> > > > +#endif
> > > > +#ifdef CONFIG_HUGETLBFS
> > > > +	FS_USE("trans", "hugetlbfs");
> > > > +#endif
> > > > +#ifdef CONFIG_TMPFS
> > > > +	FS_USE("trans", "tmpfs");
> > > > +#endif
> > > > +#ifdef CONFIG_DEVTMPFS
> > > > +	FS_USE("trans", "devtmpfs");
> > > > +#endif
> > > > +#ifdef CONFIG_POSIX_MQUEUE
> > > > +	FS_USE("trans", "mqueue");
> > > > +#endif
> > > > -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
> > > > -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
> > > > +#define GENFSCON(fstype, prefix)			     \
> > > > +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
> > > > +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
> > > > -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
> > > > +	/*
> > > > +	 * Filesystems whose inodes are labeled from path prefix match
> > > > +	 * relative to the filesystem root.  Depending on the filesystem,
> > > > +	 * only a single label for all inodes may be supported.  Here
> > > > +	 * we list the filesystem types for which per-file labeling is
> > > > +	 * supported using genfscon; any other filesystem type can also
> > > > +	 * be added by only with a single entry for all of its inodes.
> > > > +	 */
> > > > +#ifdef CONFIG_PROC_FS
> > > > +	GENFSCON("proc", "/");
> > > > +#endif
> > > > +#ifdef CONFIG_SECURITY_SELINUX
> > > > +	GENFSCON("selinuxfs", "/");
> > > > +#endif
> > > > +#ifdef CONFIG_SYSFS
> > > > +	GENFSCON("sysfs", "/");
> > > > +#endif
> > > > +#ifdef CONFIG_DEBUG_FS
> > > > +	GENFSCON("debugfs", "/");
> > > > +#endif
> > > > +#ifdef CONFIG_TRACING
> > > > +	GENFSCON("tracefs", "/");
> > > > +#endif
> > > > +#ifdef CONFIG_PSTORE
> > > > +	GENFSCON("pstore", "/");
> > > > +#endif
> > > > +	GENFSCON("cgroup", "/");
> > > > +	GENFSCON("cgroup2", "/");
> > > >    	fclose(fout);
> > > > @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
> > > >    		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
> > > >    		usage(argv[0]);
> > > >    	}
> > > > -	fprintf(fout, "/ user_u:base_r:base_t\n");
> > > > -	fprintf(fout, "/.* user_u:base_r:base_t\n");
> > > > +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> > > > +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
> > > >    	fclose(fout);
> > > >    	return 0;
> > > > 
> > > 
> > 
>
Stephen Smalley Feb. 22, 2019, 3:13 p.m. UTC | #9
On 2/21/19 3:56 PM, Dominick Grift wrote:
> On Thu, Feb 21, 2019 at 03:28:37PM -0500, Stephen Smalley wrote:
>> On 2/21/19 2:44 PM, Dominick Grift wrote:
>>> On Thu, Feb 21, 2019 at 02:34:38PM -0500, Stephen Smalley wrote:
>>>> On 2/21/19 1:42 PM, Stephen Smalley wrote:
>>>>> Derived in part from a patch by Dominick Grift.
>>>>>
>>>>> The MDP example no longer works on modern systems.  Fix it.
>>>>> While we are at it, add MLS support and enable it.
>>>>>
>>>>> NB This still does not work on systems using dbus-daemon instead of
>>>>> dbus-broker because dbus-daemon does not yet gracefully handle unknown
>>>>> classes/permissions.  This is a deficiency in libselinux's
>>>>> selinux_set_mapping() interface and underlying implementation,
>>>>> which was never fully updated to deal with unknown classes/permissions
>>>>> unlike the kernel.  Programs that instead use selinux_check_access()
>>>>> like dbus-broker do not have this problem.
>>>>
>>>> We could perhaps avoid this problem by having mdp always include at least a
>>>> core set of userspace classes/permissions in the policy it generates.  We
>>>> could also fix libselinux but that won't help on any existing distro.
>>>>
>>>>>
>>>>> Other known issues:
>>>>> - Not everything appears to be relabeled, so some files are left with invalid
>>>>> contexts and remapped to the unlabeled SID/context.
>>>>
>>>> This appears to be partly due to overuse of <<none>> in file_contexts (.fc)
>>>> files.  That excludes those parts of the filesystem from being relabeled at
>>>> all.  This was used to exclude pseudo filesystems (obsoleted by seclabel
>>>> mount option detection) or runtime directories/files whose labels were
>>>> derived from the creating process and couldn't be statically specified by
>>>> file_contexts.  To get my system back into working order even with targeted
>>>> policy, I had to strip all <<none>> entries out of my file_contexts* files
>>>> and then run setfiles -F with the list of filesystem mounts to relabel.
>>>> Otherwise, I'd have files left in the old contexts and the system wouldn't
>>>> even come up to user login, even if permissive.
>>>
>>> What <<none>> spec(s) in fedora would be so important that it causes the system to not come up to user login, even in permissive?
>>> Does the unlabeled isid not address these particular scenario's? and why not?
>>
>> Yes, I don't fully understand it myself; I just know that certain services
>> won't start successfully and it never reaches the point where I can login
>> locally or remotely.  But stripping the <<none>> entries and running
>> setfiles -F did fix it for me.  NB This was for converting back from mdp to
>> the Fedora targeted policy.  It wouldn't be an issue for converting to mdp
>> since that file_contexts has no <<none>> entries and has a default match for
>> /.*.
> 
> I am going on a limb here so bear with me but; I suspect that it was not the <<none>> that "did" it. I think it might have been the additional setfiles -F that did it.
> I think the services did not come up because systemd was not able to compute its context from /sbin/init.
> If the above is actually the case then my question is:
> Why can't systemd compute its context from /sbin/init by relying on the unlabeled isid. I mean if /sbin/init was mislabeled. then the unlabeled isid should have kicked in. So why was systemd unable to use that to compute its context?

Yes, I think you are correct about the cause.  It appears that systemd 
fetches the context of its executable via getfilecon_raw() -> getxattr() 
and then calls security_compute_create() with that as the 2nd argument. 
At that point systemd is still running in kernel_t, which is allowed all 
capabilities including mac_admin.  Hence, the getfilecon_raw() returns 
the actual on-disk xattr value even if it is not a valid context rather 
than remapping it to the unlabeled context.  Then the 
security_compute_create() call fails since the 2nd argument is not a 
valid context and we don't allow even mac_admin callers to pass invalid 
contexts to selinuxfs interfaces; that is only for getting/setting 
non-host policy contexts on files via getxattr/setxattr and 
/proc/self/attr/fscreate.  Ways to resolve:

1) Remove mac_admin permission from kernel_t (and really anything except 
for domains that specifically need to set unknown contexts, e.g. for 
creating distro images with policies that differ from the host).  Then 
getfilecon_raw() would return the unlabeled sid context and 
security_compute_create() should just end up returning the 1st context 
i.e. the kernel context (no transition defined on unlabeled).

-or-

2) Allowing passing invalid contexts to selinuxfs from mac_admin 
callers, remap internally to unlabeled context.  Then the 
security_compute_create() call wouldn't have failed.  We didn't want to 
do that because we wanted even mac_admin callers to be able to validate 
contexts via security_check_context() aka /sys/fs/selinux/context.

-or-

3) Manually fix the label on the systemd binary before rebooting.

> 
>>
>> Maybe it is a case of processes with CAP_MAC_ADMIN fetching the raw context
>> (which is invalid under the current policy) and then trying to feed them
>> back to the kernel via a selinuxfs interface, e.g. security_compute_create()
>> or similar.  The kernel would reject those.
>>
>>>
>>> I am testing the patch now here (but in my scenario its a very minimal fedora with dssp2-standard policy)
>>>
>>>>
>>>> FWIW, Android policy doesn't use <<none>> at all.  But they also don't have
>>>> a /.* or equivalent entry as a default match, so anything not covered by a
>>>> more specific match is likewise not labeled. seapp_contexts handles the more
>>>> dynamic aspect of app directory labeling for Android.
>>>>
>>>> The other problem case for relabeling is the mount point directories, which
>>>> requires unmounting them all and relabeling them if we care. Otherwise
>>>> they'll just get the unlabeled context and as long as we allow mounting on
>>>> that, it should be ok.
>>>>
>>>>> - X will fail due to lack of a x_contexts file
>>>>> - libvirtd will fail due to lack of a virtual_domain_context file
>>>>
>>>> We could easily add these to the mdp policy.
>>>>
>>>>> - crond reports an error with "No security context"
>>>>
>>>> This is probably due to the lack of a contexts/default_contexts or any
>>>> contexts/users/ files in the dummy policy.
>>>>
>>>>>
>>>>> Changes to mdp:
>>>>> Add support for devtmpfs, required by modern Linux distributions.
>>>>> Add MLS support, with sample sensitivities, categories, and constraints.
>>>>> Generate fs_use and genfscon rules based on kernel configuration.
>>>>> Update list of filesystem types for fs_use and genfscon rules.
>>>>> Use object_r for object contexts.
>>>>>
>>>>> Changes to install_policy.sh:
>>>>> Bail immediately on any errors.
>>>>> Provide more helpful error messages when unable to find userspace tools.
>>>>> Refuse to run if SELinux is already enabled.
>>>>> Unconditionally move aside /etc/selinux/config and create a new one.
>>>>> Build policy with -U allow so that userspace object managers do not break.
>>>>> Build policy with MLS enabled by default.
>>>>> Add default seusers mapping and failsafe context for use by
>>>>> pam_selinux / libselinux.
>>>>> Set to permissive mode rather than enforcing to permit initial autorelabel.
>>>>> Update the list of filesystem types to be relabeled.
>>>>> Create /.autorelabel to trigger an autorelabel on reboot.
>>>>> Drop broken attempt to relabel the /dev mountpoint directory.
>>>>>
>>>>> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
>>>>> ---
>>>>>     scripts/selinux/install_policy.sh |  82 ++++++++-------
>>>>>     scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
>>>>>     2 files changed, 183 insertions(+), 63 deletions(-)
>>>>>
>>>>> diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
>>>>> index 0b86c47baf7d..09eab4d0da5c 100755
>>>>> --- a/scripts/selinux/install_policy.sh
>>>>> +++ b/scripts/selinux/install_policy.sh
>>>>> @@ -1,30 +1,51 @@
>>>>>     #!/bin/sh
>>>>>     # SPDX-License-Identifier: GPL-2.0
>>>>> +set -e
>>>>>     if [ `id -u` -ne 0 ]; then
>>>>>     	echo "$0: must be root to install the selinux policy"
>>>>>     	exit 1
>>>>>     fi
>>>>> +
>>>>>     SF=`which setfiles`
>>>>>     if [ $? -eq 1 ]; then
>>>>> -	if [ -f /sbin/setfiles ]; then
>>>>> -		SF="/usr/setfiles"
>>>>> -	else
>>>>> -		echo "no selinux tools installed: setfiles"
>>>>> -		exit 1
>>>>> -	fi
>>>>> +	echo "Could not find setfiles"
>>>>> +	echo "Do you have policycoreutils installed?"
>>>>> +	exit 1
>>>>>     fi
>>>>> -cd mdp
>>>>> -
>>>>>     CP=`which checkpolicy`
>>>>> +if [ $? -eq 1 ]; then
>>>>> +	echo "Could not find checkpolicy"
>>>>> +	echo "Do you have checkpolicy installed?"
>>>>> +	exit 1
>>>>> +fi
>>>>>     VERS=`$CP -V | awk '{print $1}'`
>>>>> -./mdp policy.conf file_contexts
>>>>> -$CP -o policy.$VERS policy.conf
>>>>> +ENABLED=`which selinuxenabled`
>>>>> +if [ $? -eq 1 ]; then
>>>>> +	echo "Could not find selinuxenabled"
>>>>> +	echo "Do you have libselinux-utils installed?"
>>>>> +	exit 1
>>>>> +fi
>>>>> +
>>>>> +if selinuxenabled; then
>>>>> +    echo "SELinux is already enabled"
>>>>> +    echo "This prevents safely relabeling all files."
>>>>> +    echo "Boot with selinux=0 on the kernel command-line or"
>>>>> +    echo "SELINUX=disabled in /etc/selinux/config."
>>>>> +    exit 1
>>>>> +fi
>>>>> +
>>>>> +cd mdp
>>>>> +./mdp -m policy.conf file_contexts
>>>>> +$CP -U allow -M -o policy.$VERS policy.conf
>>>>>     mkdir -p /etc/selinux/dummy/policy
>>>>>     mkdir -p /etc/selinux/dummy/contexts/files
>>>>> +echo "__default__:user_u" > /etc/selinux/dummy/seusers
>>>>> +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
>>>>> +
>>>>>     cp file_contexts /etc/selinux/dummy/contexts/files
>>>>>     cp dbus_contexts /etc/selinux/dummy/contexts
>>>>>     cp policy.$VERS /etc/selinux/dummy/policy
>>>>> @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
>>>>>     if [ ! -d /etc/selinux ]; then
>>>>>     	mkdir -p /etc/selinux
>>>>>     fi
>>>>> -if [ ! -f /etc/selinux/config ]; then
>>>>> -	cat > /etc/selinux/config << EOF
>>>>> -SELINUX=enforcing
>>>>> +if [ -f /etc/selinux/config ]; then
>>>>> +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
>>>>> +    mv /etc/selinux/config /etc/selinux/config.bak
>>>>> +fi
>>>>> +echo "Creating new /etc/selinux/config for dummy policy."
>>>>> +cat > /etc/selinux/config << EOF
>>>>> +SELINUX=permissive
>>>>>     SELINUXTYPE=dummy
>>>>>     EOF
>>>>> -else
>>>>> -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
>>>>> -	if [ "eq$TYPE" != "eqdummy" ]; then
>>>>> -		selinuxenabled
>>>>> -		if [ $? -eq 0 ]; then
>>>>> -			echo "SELinux already enabled with a non-dummy policy."
>>>>> -			echo "Exiting.  Please install policy by hand if that"
>>>>> -			echo "is what you REALLY want."
>>>>> -			exit 1
>>>>> -		fi
>>>>> -		mv /etc/selinux/config /etc/selinux/config.mdpbak
>>>>> -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
>>>>> -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
>>>>> -	fi
>>>>> -fi
>>>>>     cd /etc/selinux/dummy/contexts/files
>>>>> -$SF file_contexts /
>>>>> +$SF -F file_contexts /
>>>>> -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
>>>>> -$SF file_contexts $mounts
>>>>> +mounts=`cat /proc/$$/mounts | \
>>>>> +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
>>>>> +	awk '{ print $2 '}`
>>>>> +$SF -F file_contexts $mounts
>>>>> -
>>>>> -dodev=`cat /proc/$$/mounts | grep "/dev "`
>>>>> -if [ "eq$dodev" != "eq" ]; then
>>>>> -	mount --move /dev /mnt
>>>>> -	$SF file_contexts /dev
>>>>> -	mount --move /mnt /dev
>>>>> -fi
>>>>> +touch /.autorelabel
>>>>> diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
>>>>> index 073fe7537f6c..daad333c7252 100644
>>>>> --- a/scripts/selinux/mdp/mdp.c
>>>>> +++ b/scripts/selinux/mdp/mdp.c
>>>>> @@ -33,6 +33,7 @@
>>>>>     #include <unistd.h>
>>>>>     #include <string.h>
>>>>>     #include <sys/socket.h>
>>>>> +#include <linux/kconfig.h>
>>>>>     static void usage(char *name)
>>>>>     {
>>>>> @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
>>>>>     	}
>>>>>     	fprintf(fout, "\n");
>>>>> -	/* NOW PRINT OUT MLS STUFF */
>>>>> +	/* print out mls declarations and constraints */
>>>>>     	if (mls) {
>>>>> -		printf("MLS not yet implemented\n");
>>>>> -		exit(1);
>>>>> +		fprintf(fout, "sensitivity s0;\n");
>>>>> +		fprintf(fout, "sensitivity s1;\n");
>>>>> +		fprintf(fout, "dominance { s0 s1 }\n");
>>>>> +		fprintf(fout, "category c0;\n");
>>>>> +		fprintf(fout, "category c1;\n");
>>>>> +		fprintf(fout, "level s0:c0.c1;\n");
>>>>> +		fprintf(fout, "level s1:c0.c1;\n");
>>>>> +#define SYSTEMLOW "s0"
>>>>> +#define SYSTEMHIGH "s1:c0.c1"
>>>>> +		for (i = 0; secclass_map[i].name; i++) {
>>>>> +			struct security_class_mapping *map = &secclass_map[i];
>>>>> +
>>>>> +			fprintf(fout, "mlsconstrain %s {\n", map->name);
>>>>> +			for (j = 0; map->perms[j]; j++)
>>>>> +				fprintf(fout, "\t%s\n", map->perms[j]);
>>>>> +			/*
>>>>> +			 * This requires all subjects and objects to be
>>>>> +			 * single-level (l2 eq h2), and that the subject
>>>>> +			 * level dominate the object level (h1 dom h2)
>>>>> +			 * in order to have any permissions to it.
>>>>> +			 */
>>>>> +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
>>>>> +		}
>>>>>     	}
>>>>>     	/* types, roles, and allows */
>>>>> @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
>>>>>     	for (i = 0; secclass_map[i].name; i++)
>>>>>     		fprintf(fout, "allow base_t base_t:%s *;\n",
>>>>>     			secclass_map[i].name);
>>>>> -	fprintf(fout, "user user_u roles { base_r };\n");
>>>>> -	fprintf(fout, "\n");
>>>>> +	fprintf(fout, "user user_u roles { base_r }");
>>>>> +	if (mls)
>>>>> +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
>>>>> +			SYSTEMLOW, SYSTEMHIGH);
>>>>> +	fprintf(fout, ";\n");
>>>>> +
>>>>> +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
>>>>> +#define OBJUSERROLETYPE "user_u:object_r:base_t"
>>>>>     	/* default sids */
>>>>>     	for (i = 1; i < initial_sid_to_string_len; i++)
>>>>> -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
>>>>> +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
>>>>> +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
>>>>>     	fprintf(fout, "\n");
>>>>> -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
>>>>> +#define FS_USE(behavior, fstype)			    \
>>>>> +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
>>>>> +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
>>>>> +
>>>>> +	/*
>>>>> +	 * Filesystems whose inode labels can be fetched via getxattr.
>>>>> +	 */
>>>>> +#ifdef CONFIG_EXT2_FS_SECURITY
>>>>> +	FS_USE("xattr", "ext2");
>>>>> +#endif
>>>>> +#ifdef CONFIG_EXT3_FS_SECURITY
>>>>> +	FS_USE("xattr", "ext3");
>>>>> +#endif
>>>>> +#ifdef CONFIG_EXT4_FS_SECURITY
>>>>> +	FS_USE("xattr", "ext4");
>>>>> +#endif
>>>>> +#ifdef CONFIG_JFS_SECURITY
>>>>> +	FS_USE("xattr", "jfs");
>>>>> +#endif
>>>>> +#ifdef CONFIG_REISERFS_FS_SECURITY
>>>>> +	FS_USE("xattr", "reiserfs");
>>>>> +#endif
>>>>> +#ifdef CONFIG_JFFS2_FS_SECURITY
>>>>> +	FS_USE("xattr", "jffs2");
>>>>> +#endif
>>>>> +#ifdef CONFIG_XFS_FS
>>>>> +	FS_USE("xattr", "xfs");
>>>>> +#endif
>>>>> +#ifdef CONFIG_GFS2_FS
>>>>> +	FS_USE("xattr", "gfs2");
>>>>> +#endif
>>>>> +#ifdef CONFIG_BTRFS_FS
>>>>> +	FS_USE("xattr", "btrfs");
>>>>> +#endif
>>>>> +#ifdef CONFIG_F2FS_FS_SECURITY
>>>>> +	FS_USE("xattr", "f2fs");
>>>>> +#endif
>>>>> +#ifdef CONFIG_OCFS2_FS
>>>>> +	FS_USE("xattr", "ocsfs2");
>>>>> +#endif
>>>>> +#ifdef CONFIG_OVERLAY_FS
>>>>> +	FS_USE("xattr", "overlay");
>>>>> +#endif
>>>>> +#ifdef CONFIG_SQUASHFS_XATTR
>>>>> +	FS_USE("xattr", "squashfs");
>>>>> +#endif
>>>>> +
>>>>> +	/*
>>>>> +	 * Filesystems whose inodes are labeled from allocating task.
>>>>> +	 */
>>>>> +	FS_USE("task", "pipefs");
>>>>> +	FS_USE("task", "sockfs");
>>>>> -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
>>>>> +	/*
>>>>> +	 * Filesystems whose inode labels are computed from both
>>>>> +	 * the allocating task and the superblock label.
>>>>> +	 */
>>>>> +#ifdef CONFIG_UNIX98_PTYS
>>>>> +	FS_USE("trans", "devpts");
>>>>> +#endif
>>>>> +#ifdef CONFIG_HUGETLBFS
>>>>> +	FS_USE("trans", "hugetlbfs");
>>>>> +#endif
>>>>> +#ifdef CONFIG_TMPFS
>>>>> +	FS_USE("trans", "tmpfs");
>>>>> +#endif
>>>>> +#ifdef CONFIG_DEVTMPFS
>>>>> +	FS_USE("trans", "devtmpfs");
>>>>> +#endif
>>>>> +#ifdef CONFIG_POSIX_MQUEUE
>>>>> +	FS_USE("trans", "mqueue");
>>>>> +#endif
>>>>> -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
>>>>> -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
>>>>> +#define GENFSCON(fstype, prefix)			     \
>>>>> +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
>>>>> +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
>>>>> -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
>>>>> +	/*
>>>>> +	 * Filesystems whose inodes are labeled from path prefix match
>>>>> +	 * relative to the filesystem root.  Depending on the filesystem,
>>>>> +	 * only a single label for all inodes may be supported.  Here
>>>>> +	 * we list the filesystem types for which per-file labeling is
>>>>> +	 * supported using genfscon; any other filesystem type can also
>>>>> +	 * be added by only with a single entry for all of its inodes.
>>>>> +	 */
>>>>> +#ifdef CONFIG_PROC_FS
>>>>> +	GENFSCON("proc", "/");
>>>>> +#endif
>>>>> +#ifdef CONFIG_SECURITY_SELINUX
>>>>> +	GENFSCON("selinuxfs", "/");
>>>>> +#endif
>>>>> +#ifdef CONFIG_SYSFS
>>>>> +	GENFSCON("sysfs", "/");
>>>>> +#endif
>>>>> +#ifdef CONFIG_DEBUG_FS
>>>>> +	GENFSCON("debugfs", "/");
>>>>> +#endif
>>>>> +#ifdef CONFIG_TRACING
>>>>> +	GENFSCON("tracefs", "/");
>>>>> +#endif
>>>>> +#ifdef CONFIG_PSTORE
>>>>> +	GENFSCON("pstore", "/");
>>>>> +#endif
>>>>> +	GENFSCON("cgroup", "/");
>>>>> +	GENFSCON("cgroup2", "/");
>>>>>     	fclose(fout);
>>>>> @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
>>>>>     		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
>>>>>     		usage(argv[0]);
>>>>>     	}
>>>>> -	fprintf(fout, "/ user_u:base_r:base_t\n");
>>>>> -	fprintf(fout, "/.* user_u:base_r:base_t\n");
>>>>> +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>>>> +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>>>>     	fclose(fout);
>>>>>     	return 0;
>>>>>
>>>>
>>>
>>
>
Dac Override Feb. 22, 2019, 3:35 p.m. UTC | #10
Stephen Smalley <sds@tycho.nsa.gov> writes:

> On 2/21/19 3:56 PM, Dominick Grift wrote:
>> On Thu, Feb 21, 2019 at 03:28:37PM -0500, Stephen Smalley wrote:
>>> On 2/21/19 2:44 PM, Dominick Grift wrote:
>>>> On Thu, Feb 21, 2019 at 02:34:38PM -0500, Stephen Smalley wrote:
>>>>> On 2/21/19 1:42 PM, Stephen Smalley wrote:
>>>>>> Derived in part from a patch by Dominick Grift.
>>>>>>
>>>>>> The MDP example no longer works on modern systems.  Fix it.
>>>>>> While we are at it, add MLS support and enable it.
>>>>>>
>>>>>> NB This still does not work on systems using dbus-daemon instead of
>>>>>> dbus-broker because dbus-daemon does not yet gracefully handle unknown
>>>>>> classes/permissions.  This is a deficiency in libselinux's
>>>>>> selinux_set_mapping() interface and underlying implementation,
>>>>>> which was never fully updated to deal with unknown classes/permissions
>>>>>> unlike the kernel.  Programs that instead use selinux_check_access()
>>>>>> like dbus-broker do not have this problem.
>>>>>
>>>>> We could perhaps avoid this problem by having mdp always include at least a
>>>>> core set of userspace classes/permissions in the policy it generates.  We
>>>>> could also fix libselinux but that won't help on any existing distro.
>>>>>
>>>>>>
>>>>>> Other known issues:
>>>>>> - Not everything appears to be relabeled, so some files are left with invalid
>>>>>> contexts and remapped to the unlabeled SID/context.
>>>>>
>>>>> This appears to be partly due to overuse of <<none>> in file_contexts (.fc)
>>>>> files.  That excludes those parts of the filesystem from being relabeled at
>>>>> all.  This was used to exclude pseudo filesystems (obsoleted by seclabel
>>>>> mount option detection) or runtime directories/files whose labels were
>>>>> derived from the creating process and couldn't be statically specified by
>>>>> file_contexts.  To get my system back into working order even with targeted
>>>>> policy, I had to strip all <<none>> entries out of my file_contexts* files
>>>>> and then run setfiles -F with the list of filesystem mounts to relabel.
>>>>> Otherwise, I'd have files left in the old contexts and the system wouldn't
>>>>> even come up to user login, even if permissive.
>>>>
>>>> What <<none>> spec(s) in fedora would be so important that it causes the system to not come up to user login, even in permissive?
>>>> Does the unlabeled isid not address these particular scenario's? and why not?
>>>
>>> Yes, I don't fully understand it myself; I just know that certain services
>>> won't start successfully and it never reaches the point where I can login
>>> locally or remotely.  But stripping the <<none>> entries and running
>>> setfiles -F did fix it for me.  NB This was for converting back from mdp to
>>> the Fedora targeted policy.  It wouldn't be an issue for converting to mdp
>>> since that file_contexts has no <<none>> entries and has a default match for
>>> /.*.
>>
>> I am going on a limb here so bear with me but; I suspect that it was
> not the <<none>> that "did" it. I think it might have been the
> additional setfiles -F that did it.
>> I think the services did not come up because systemd was not able to compute its context from /sbin/init.
>> If the above is actually the case then my question is:
>> Why can't systemd compute its context from /sbin/init by relying on
> the unlabeled isid. I mean if /sbin/init was mislabeled. then the
> unlabeled isid should have kicked in. So why was systemd unable to use
> that to compute its context?
>
> Yes, I think you are correct about the cause.  It appears that systemd
> fetches the context of its executable via getfilecon_raw() ->
> getxattr() and then calls security_compute_create() with that as the
> 2nd argument. At that point systemd is still running in kernel_t,
> which is allowed all capabilities including mac_admin.  Hence, the
> getfilecon_raw() returns the actual on-disk xattr value even if it is
> not a valid context rather than remapping it to the unlabeled context.
> Then the security_compute_create() call fails since the 2nd argument
> is not a valid context and we don't allow even mac_admin callers to
> pass invalid contexts to selinuxfs interfaces; that is only for
> getting/setting non-host policy contexts on files via
> getxattr/setxattr and /proc/self/attr/fscreate.  Ways to resolve:
>
> 1) Remove mac_admin permission from kernel_t (and really anything
> except for domains that specifically need to set unknown contexts,
> e.g. for creating distro images with policies that differ from the
> host).  Then getfilecon_raw() would return the unlabeled sid context
> and security_compute_create() should just end up returning the 1st
> context i.e. the kernel context (no transition defined on unlabeled).

This would not solve it for me because I saw it when i moved from
dssp2-standard to dummy (so systemd was running in base_t via the kernel
isid already i suppose, and well, base_t is unconfined)

dssp2-standard does not do mac_admin:

# sesearch -A -c capability2 -p mac_admin | wc -l
0

>
> -or-
>
> 2) Allowing passing invalid contexts to selinuxfs from mac_admin
> callers, remap internally to unlabeled context.  Then the
> security_compute_create() call wouldn't have failed.  We didn't want
> to do that because we wanted even mac_admin callers to be able to
> validate contexts via security_check_context() aka
> /sys/fs/selinux/context.
>

I do not feel qualified to judge this option

> -or-
>
> 3) Manually fix the label on the systemd binary before rebooting.
>

Generally the procedure is and was that if you change policy. you
autorelabel in permissive mode. I am not 100% sure but I suspect that if
you do that consistently, that things should work out. Maybe the autorelabel solution
in fedora and systemd systems in general should be scrutinized some more
to see if that is an area that can be improved.

>>
>>>
>>> Maybe it is a case of processes with CAP_MAC_ADMIN fetching the raw context
>>> (which is invalid under the current policy) and then trying to feed them
>>> back to the kernel via a selinuxfs interface, e.g. security_compute_create()
>>> or similar.  The kernel would reject those.
>>>
>>>>
>>>> I am testing the patch now here (but in my scenario its a very minimal fedora with dssp2-standard policy)
>>>>
>>>>>
>>>>> FWIW, Android policy doesn't use <<none>> at all.  But they also don't have
>>>>> a /.* or equivalent entry as a default match, so anything not covered by a
>>>>> more specific match is likewise not labeled. seapp_contexts handles the more
>>>>> dynamic aspect of app directory labeling for Android.
>>>>>
>>>>> The other problem case for relabeling is the mount point directories, which
>>>>> requires unmounting them all and relabeling them if we care. Otherwise
>>>>> they'll just get the unlabeled context and as long as we allow mounting on
>>>>> that, it should be ok.
>>>>>
>>>>>> - X will fail due to lack of a x_contexts file
>>>>>> - libvirtd will fail due to lack of a virtual_domain_context file
>>>>>
>>>>> We could easily add these to the mdp policy.
>>>>>
>>>>>> - crond reports an error with "No security context"
>>>>>
>>>>> This is probably due to the lack of a contexts/default_contexts or any
>>>>> contexts/users/ files in the dummy policy.
>>>>>
>>>>>>
>>>>>> Changes to mdp:
>>>>>> Add support for devtmpfs, required by modern Linux distributions.
>>>>>> Add MLS support, with sample sensitivities, categories, and constraints.
>>>>>> Generate fs_use and genfscon rules based on kernel configuration.
>>>>>> Update list of filesystem types for fs_use and genfscon rules.
>>>>>> Use object_r for object contexts.
>>>>>>
>>>>>> Changes to install_policy.sh:
>>>>>> Bail immediately on any errors.
>>>>>> Provide more helpful error messages when unable to find userspace tools.
>>>>>> Refuse to run if SELinux is already enabled.
>>>>>> Unconditionally move aside /etc/selinux/config and create a new one.
>>>>>> Build policy with -U allow so that userspace object managers do not break.
>>>>>> Build policy with MLS enabled by default.
>>>>>> Add default seusers mapping and failsafe context for use by
>>>>>> pam_selinux / libselinux.
>>>>>> Set to permissive mode rather than enforcing to permit initial autorelabel.
>>>>>> Update the list of filesystem types to be relabeled.
>>>>>> Create /.autorelabel to trigger an autorelabel on reboot.
>>>>>> Drop broken attempt to relabel the /dev mountpoint directory.
>>>>>>
>>>>>> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
>>>>>> ---
>>>>>>     scripts/selinux/install_policy.sh |  82 ++++++++-------
>>>>>>     scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
>>>>>>     2 files changed, 183 insertions(+), 63 deletions(-)
>>>>>>
>>>>>> diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
>>>>>> index 0b86c47baf7d..09eab4d0da5c 100755
>>>>>> --- a/scripts/selinux/install_policy.sh
>>>>>> +++ b/scripts/selinux/install_policy.sh
>>>>>> @@ -1,30 +1,51 @@
>>>>>>     #!/bin/sh
>>>>>>     # SPDX-License-Identifier: GPL-2.0
>>>>>> +set -e
>>>>>>     if [ `id -u` -ne 0 ]; then
>>>>>>     	echo "$0: must be root to install the selinux policy"
>>>>>>     	exit 1
>>>>>>     fi
>>>>>> +
>>>>>>     SF=`which setfiles`
>>>>>>     if [ $? -eq 1 ]; then
>>>>>> -	if [ -f /sbin/setfiles ]; then
>>>>>> -		SF="/usr/setfiles"
>>>>>> -	else
>>>>>> -		echo "no selinux tools installed: setfiles"
>>>>>> -		exit 1
>>>>>> -	fi
>>>>>> +	echo "Could not find setfiles"
>>>>>> +	echo "Do you have policycoreutils installed?"
>>>>>> +	exit 1
>>>>>>     fi
>>>>>> -cd mdp
>>>>>> -
>>>>>>     CP=`which checkpolicy`
>>>>>> +if [ $? -eq 1 ]; then
>>>>>> +	echo "Could not find checkpolicy"
>>>>>> +	echo "Do you have checkpolicy installed?"
>>>>>> +	exit 1
>>>>>> +fi
>>>>>>     VERS=`$CP -V | awk '{print $1}'`
>>>>>> -./mdp policy.conf file_contexts
>>>>>> -$CP -o policy.$VERS policy.conf
>>>>>> +ENABLED=`which selinuxenabled`
>>>>>> +if [ $? -eq 1 ]; then
>>>>>> +	echo "Could not find selinuxenabled"
>>>>>> +	echo "Do you have libselinux-utils installed?"
>>>>>> +	exit 1
>>>>>> +fi
>>>>>> +
>>>>>> +if selinuxenabled; then
>>>>>> +    echo "SELinux is already enabled"
>>>>>> +    echo "This prevents safely relabeling all files."
>>>>>> +    echo "Boot with selinux=0 on the kernel command-line or"
>>>>>> +    echo "SELINUX=disabled in /etc/selinux/config."
>>>>>> +    exit 1
>>>>>> +fi
>>>>>> +
>>>>>> +cd mdp
>>>>>> +./mdp -m policy.conf file_contexts
>>>>>> +$CP -U allow -M -o policy.$VERS policy.conf
>>>>>>     mkdir -p /etc/selinux/dummy/policy
>>>>>>     mkdir -p /etc/selinux/dummy/contexts/files
>>>>>> +echo "__default__:user_u" > /etc/selinux/dummy/seusers
>>>>>> +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
>>>>>> +
>>>>>>     cp file_contexts /etc/selinux/dummy/contexts/files
>>>>>>     cp dbus_contexts /etc/selinux/dummy/contexts
>>>>>>     cp policy.$VERS /etc/selinux/dummy/policy
>>>>>> @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
>>>>>>     if [ ! -d /etc/selinux ]; then
>>>>>>     	mkdir -p /etc/selinux
>>>>>>     fi
>>>>>> -if [ ! -f /etc/selinux/config ]; then
>>>>>> -	cat > /etc/selinux/config << EOF
>>>>>> -SELINUX=enforcing
>>>>>> +if [ -f /etc/selinux/config ]; then
>>>>>> +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
>>>>>> +    mv /etc/selinux/config /etc/selinux/config.bak
>>>>>> +fi
>>>>>> +echo "Creating new /etc/selinux/config for dummy policy."
>>>>>> +cat > /etc/selinux/config << EOF
>>>>>> +SELINUX=permissive
>>>>>>     SELINUXTYPE=dummy
>>>>>>     EOF
>>>>>> -else
>>>>>> -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
>>>>>> -	if [ "eq$TYPE" != "eqdummy" ]; then
>>>>>> -		selinuxenabled
>>>>>> -		if [ $? -eq 0 ]; then
>>>>>> -			echo "SELinux already enabled with a non-dummy policy."
>>>>>> -			echo "Exiting.  Please install policy by hand if that"
>>>>>> -			echo "is what you REALLY want."
>>>>>> -			exit 1
>>>>>> -		fi
>>>>>> -		mv /etc/selinux/config /etc/selinux/config.mdpbak
>>>>>> -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
>>>>>> -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
>>>>>> -	fi
>>>>>> -fi
>>>>>>     cd /etc/selinux/dummy/contexts/files
>>>>>> -$SF file_contexts /
>>>>>> +$SF -F file_contexts /
>>>>>> -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
>>>>>> -$SF file_contexts $mounts
>>>>>> +mounts=`cat /proc/$$/mounts | \
>>>>>> +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
>>>>>> +	awk '{ print $2 '}`
>>>>>> +$SF -F file_contexts $mounts
>>>>>> -
>>>>>> -dodev=`cat /proc/$$/mounts | grep "/dev "`
>>>>>> -if [ "eq$dodev" != "eq" ]; then
>>>>>> -	mount --move /dev /mnt
>>>>>> -	$SF file_contexts /dev
>>>>>> -	mount --move /mnt /dev
>>>>>> -fi
>>>>>> +touch /.autorelabel
>>>>>> diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
>>>>>> index 073fe7537f6c..daad333c7252 100644
>>>>>> --- a/scripts/selinux/mdp/mdp.c
>>>>>> +++ b/scripts/selinux/mdp/mdp.c
>>>>>> @@ -33,6 +33,7 @@
>>>>>>     #include <unistd.h>
>>>>>>     #include <string.h>
>>>>>>     #include <sys/socket.h>
>>>>>> +#include <linux/kconfig.h>
>>>>>>     static void usage(char *name)
>>>>>>     {
>>>>>> @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
>>>>>>     	}
>>>>>>     	fprintf(fout, "\n");
>>>>>> -	/* NOW PRINT OUT MLS STUFF */
>>>>>> +	/* print out mls declarations and constraints */
>>>>>>     	if (mls) {
>>>>>> -		printf("MLS not yet implemented\n");
>>>>>> -		exit(1);
>>>>>> +		fprintf(fout, "sensitivity s0;\n");
>>>>>> +		fprintf(fout, "sensitivity s1;\n");
>>>>>> +		fprintf(fout, "dominance { s0 s1 }\n");
>>>>>> +		fprintf(fout, "category c0;\n");
>>>>>> +		fprintf(fout, "category c1;\n");
>>>>>> +		fprintf(fout, "level s0:c0.c1;\n");
>>>>>> +		fprintf(fout, "level s1:c0.c1;\n");
>>>>>> +#define SYSTEMLOW "s0"
>>>>>> +#define SYSTEMHIGH "s1:c0.c1"
>>>>>> +		for (i = 0; secclass_map[i].name; i++) {
>>>>>> +			struct security_class_mapping *map = &secclass_map[i];
>>>>>> +
>>>>>> +			fprintf(fout, "mlsconstrain %s {\n", map->name);
>>>>>> +			for (j = 0; map->perms[j]; j++)
>>>>>> +				fprintf(fout, "\t%s\n", map->perms[j]);
>>>>>> +			/*
>>>>>> +			 * This requires all subjects and objects to be
>>>>>> +			 * single-level (l2 eq h2), and that the subject
>>>>>> +			 * level dominate the object level (h1 dom h2)
>>>>>> +			 * in order to have any permissions to it.
>>>>>> +			 */
>>>>>> +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
>>>>>> +		}
>>>>>>     	}
>>>>>>     	/* types, roles, and allows */
>>>>>> @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
>>>>>>     	for (i = 0; secclass_map[i].name; i++)
>>>>>>     		fprintf(fout, "allow base_t base_t:%s *;\n",
>>>>>>     			secclass_map[i].name);
>>>>>> -	fprintf(fout, "user user_u roles { base_r };\n");
>>>>>> -	fprintf(fout, "\n");
>>>>>> +	fprintf(fout, "user user_u roles { base_r }");
>>>>>> +	if (mls)
>>>>>> +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
>>>>>> +			SYSTEMLOW, SYSTEMHIGH);
>>>>>> +	fprintf(fout, ";\n");
>>>>>> +
>>>>>> +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
>>>>>> +#define OBJUSERROLETYPE "user_u:object_r:base_t"
>>>>>>     	/* default sids */
>>>>>>     	for (i = 1; i < initial_sid_to_string_len; i++)
>>>>>> -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
>>>>>> +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
>>>>>> +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
>>>>>>     	fprintf(fout, "\n");
>>>>>> -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
>>>>>> +#define FS_USE(behavior, fstype)			    \
>>>>>> +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
>>>>>> +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Filesystems whose inode labels can be fetched via getxattr.
>>>>>> +	 */
>>>>>> +#ifdef CONFIG_EXT2_FS_SECURITY
>>>>>> +	FS_USE("xattr", "ext2");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_EXT3_FS_SECURITY
>>>>>> +	FS_USE("xattr", "ext3");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_EXT4_FS_SECURITY
>>>>>> +	FS_USE("xattr", "ext4");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_JFS_SECURITY
>>>>>> +	FS_USE("xattr", "jfs");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_REISERFS_FS_SECURITY
>>>>>> +	FS_USE("xattr", "reiserfs");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_JFFS2_FS_SECURITY
>>>>>> +	FS_USE("xattr", "jffs2");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_XFS_FS
>>>>>> +	FS_USE("xattr", "xfs");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_GFS2_FS
>>>>>> +	FS_USE("xattr", "gfs2");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_BTRFS_FS
>>>>>> +	FS_USE("xattr", "btrfs");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_F2FS_FS_SECURITY
>>>>>> +	FS_USE("xattr", "f2fs");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_OCFS2_FS
>>>>>> +	FS_USE("xattr", "ocsfs2");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_OVERLAY_FS
>>>>>> +	FS_USE("xattr", "overlay");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_SQUASHFS_XATTR
>>>>>> +	FS_USE("xattr", "squashfs");
>>>>>> +#endif
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Filesystems whose inodes are labeled from allocating task.
>>>>>> +	 */
>>>>>> +	FS_USE("task", "pipefs");
>>>>>> +	FS_USE("task", "sockfs");
>>>>>> -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
>>>>>> +	/*
>>>>>> +	 * Filesystems whose inode labels are computed from both
>>>>>> +	 * the allocating task and the superblock label.
>>>>>> +	 */
>>>>>> +#ifdef CONFIG_UNIX98_PTYS
>>>>>> +	FS_USE("trans", "devpts");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_HUGETLBFS
>>>>>> +	FS_USE("trans", "hugetlbfs");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_TMPFS
>>>>>> +	FS_USE("trans", "tmpfs");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_DEVTMPFS
>>>>>> +	FS_USE("trans", "devtmpfs");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_POSIX_MQUEUE
>>>>>> +	FS_USE("trans", "mqueue");
>>>>>> +#endif
>>>>>> -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
>>>>>> -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
>>>>>> +#define GENFSCON(fstype, prefix)			     \
>>>>>> +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
>>>>>> +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
>>>>>> -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
>>>>>> +	/*
>>>>>> +	 * Filesystems whose inodes are labeled from path prefix match
>>>>>> +	 * relative to the filesystem root.  Depending on the filesystem,
>>>>>> +	 * only a single label for all inodes may be supported.  Here
>>>>>> +	 * we list the filesystem types for which per-file labeling is
>>>>>> +	 * supported using genfscon; any other filesystem type can also
>>>>>> +	 * be added by only with a single entry for all of its inodes.
>>>>>> +	 */
>>>>>> +#ifdef CONFIG_PROC_FS
>>>>>> +	GENFSCON("proc", "/");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_SECURITY_SELINUX
>>>>>> +	GENFSCON("selinuxfs", "/");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_SYSFS
>>>>>> +	GENFSCON("sysfs", "/");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_DEBUG_FS
>>>>>> +	GENFSCON("debugfs", "/");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_TRACING
>>>>>> +	GENFSCON("tracefs", "/");
>>>>>> +#endif
>>>>>> +#ifdef CONFIG_PSTORE
>>>>>> +	GENFSCON("pstore", "/");
>>>>>> +#endif
>>>>>> +	GENFSCON("cgroup", "/");
>>>>>> +	GENFSCON("cgroup2", "/");
>>>>>>     	fclose(fout);
>>>>>> @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
>>>>>>     		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
>>>>>>     		usage(argv[0]);
>>>>>>     	}
>>>>>> -	fprintf(fout, "/ user_u:base_r:base_t\n");
>>>>>> -	fprintf(fout, "/.* user_u:base_r:base_t\n");
>>>>>> +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>>>>> +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>>>>>     	fclose(fout);
>>>>>>     	return 0;
>>>>>>
>>>>>
>>>>
>>>
>>
>
Stephen Smalley Feb. 22, 2019, 3:46 p.m. UTC | #11
On 2/22/19 10:35 AM, Dominick Grift wrote:
> Stephen Smalley <sds@tycho.nsa.gov> writes:
> 
>> On 2/21/19 3:56 PM, Dominick Grift wrote:
>>> On Thu, Feb 21, 2019 at 03:28:37PM -0500, Stephen Smalley wrote:
>>>> On 2/21/19 2:44 PM, Dominick Grift wrote:
>>>>> On Thu, Feb 21, 2019 at 02:34:38PM -0500, Stephen Smalley wrote:
>>>>>> On 2/21/19 1:42 PM, Stephen Smalley wrote:
>>>>>>> Derived in part from a patch by Dominick Grift.
>>>>>>>
>>>>>>> The MDP example no longer works on modern systems.  Fix it.
>>>>>>> While we are at it, add MLS support and enable it.
>>>>>>>
>>>>>>> NB This still does not work on systems using dbus-daemon instead of
>>>>>>> dbus-broker because dbus-daemon does not yet gracefully handle unknown
>>>>>>> classes/permissions.  This is a deficiency in libselinux's
>>>>>>> selinux_set_mapping() interface and underlying implementation,
>>>>>>> which was never fully updated to deal with unknown classes/permissions
>>>>>>> unlike the kernel.  Programs that instead use selinux_check_access()
>>>>>>> like dbus-broker do not have this problem.
>>>>>>
>>>>>> We could perhaps avoid this problem by having mdp always include at least a
>>>>>> core set of userspace classes/permissions in the policy it generates.  We
>>>>>> could also fix libselinux but that won't help on any existing distro.
>>>>>>
>>>>>>>
>>>>>>> Other known issues:
>>>>>>> - Not everything appears to be relabeled, so some files are left with invalid
>>>>>>> contexts and remapped to the unlabeled SID/context.
>>>>>>
>>>>>> This appears to be partly due to overuse of <<none>> in file_contexts (.fc)
>>>>>> files.  That excludes those parts of the filesystem from being relabeled at
>>>>>> all.  This was used to exclude pseudo filesystems (obsoleted by seclabel
>>>>>> mount option detection) or runtime directories/files whose labels were
>>>>>> derived from the creating process and couldn't be statically specified by
>>>>>> file_contexts.  To get my system back into working order even with targeted
>>>>>> policy, I had to strip all <<none>> entries out of my file_contexts* files
>>>>>> and then run setfiles -F with the list of filesystem mounts to relabel.
>>>>>> Otherwise, I'd have files left in the old contexts and the system wouldn't
>>>>>> even come up to user login, even if permissive.
>>>>>
>>>>> What <<none>> spec(s) in fedora would be so important that it causes the system to not come up to user login, even in permissive?
>>>>> Does the unlabeled isid not address these particular scenario's? and why not?
>>>>
>>>> Yes, I don't fully understand it myself; I just know that certain services
>>>> won't start successfully and it never reaches the point where I can login
>>>> locally or remotely.  But stripping the <<none>> entries and running
>>>> setfiles -F did fix it for me.  NB This was for converting back from mdp to
>>>> the Fedora targeted policy.  It wouldn't be an issue for converting to mdp
>>>> since that file_contexts has no <<none>> entries and has a default match for
>>>> /.*.
>>>
>>> I am going on a limb here so bear with me but; I suspect that it was
>> not the <<none>> that "did" it. I think it might have been the
>> additional setfiles -F that did it.
>>> I think the services did not come up because systemd was not able to compute its context from /sbin/init.
>>> If the above is actually the case then my question is:
>>> Why can't systemd compute its context from /sbin/init by relying on
>> the unlabeled isid. I mean if /sbin/init was mislabeled. then the
>> unlabeled isid should have kicked in. So why was systemd unable to use
>> that to compute its context?
>>
>> Yes, I think you are correct about the cause.  It appears that systemd
>> fetches the context of its executable via getfilecon_raw() ->
>> getxattr() and then calls security_compute_create() with that as the
>> 2nd argument. At that point systemd is still running in kernel_t,
>> which is allowed all capabilities including mac_admin.  Hence, the
>> getfilecon_raw() returns the actual on-disk xattr value even if it is
>> not a valid context rather than remapping it to the unlabeled context.
>> Then the security_compute_create() call fails since the 2nd argument
>> is not a valid context and we don't allow even mac_admin callers to
>> pass invalid contexts to selinuxfs interfaces; that is only for
>> getting/setting non-host policy contexts on files via
>> getxattr/setxattr and /proc/self/attr/fscreate.  Ways to resolve:
>>
>> 1) Remove mac_admin permission from kernel_t (and really anything
>> except for domains that specifically need to set unknown contexts,
>> e.g. for creating distro images with policies that differ from the
>> host).  Then getfilecon_raw() would return the unlabeled sid context
>> and security_compute_create() should just end up returning the 1st
>> context i.e. the kernel context (no transition defined on unlabeled).
> 
> This would not solve it for me because I saw it when i moved from
> dssp2-standard to dummy (so systemd was running in base_t via the kernel
> isid already i suppose, and well, base_t is unconfined)
> 
> dssp2-standard does not do mac_admin:
> 
> # sesearch -A -c capability2 -p mac_admin | wc -l
> 0
> 
>>
>> -or-
>>
>> 2) Allowing passing invalid contexts to selinuxfs from mac_admin
>> callers, remap internally to unlabeled context.  Then the
>> security_compute_create() call wouldn't have failed.  We didn't want
>> to do that because we wanted even mac_admin callers to be able to
>> validate contexts via security_check_context() aka
>> /sys/fs/selinux/context.
>>
> 
> I do not feel qualified to judge this option
> 
>> -or-
>>
>> 3) Manually fix the label on the systemd binary before rebooting.
>>
> 
> Generally the procedure is and was that if you change policy. you
> autorelabel in permissive mode. I am not 100% sure but I suspect that if
> you do that consistently, that things should work out. Maybe the autorelabel solution
> in fedora and systemd systems in general should be scrutinized some more
> to see if that is an area that can be improved.

Unfortunately autorelabel in permissive didn't appear to resolve it for 
me.  I had to boot with SELinux disabled and run setfiles by hand to fix it.

> 
>>>
>>>>
>>>> Maybe it is a case of processes with CAP_MAC_ADMIN fetching the raw context
>>>> (which is invalid under the current policy) and then trying to feed them
>>>> back to the kernel via a selinuxfs interface, e.g. security_compute_create()
>>>> or similar.  The kernel would reject those.
>>>>
>>>>>
>>>>> I am testing the patch now here (but in my scenario its a very minimal fedora with dssp2-standard policy)
>>>>>
>>>>>>
>>>>>> FWIW, Android policy doesn't use <<none>> at all.  But they also don't have
>>>>>> a /.* or equivalent entry as a default match, so anything not covered by a
>>>>>> more specific match is likewise not labeled. seapp_contexts handles the more
>>>>>> dynamic aspect of app directory labeling for Android.
>>>>>>
>>>>>> The other problem case for relabeling is the mount point directories, which
>>>>>> requires unmounting them all and relabeling them if we care. Otherwise
>>>>>> they'll just get the unlabeled context and as long as we allow mounting on
>>>>>> that, it should be ok.
>>>>>>
>>>>>>> - X will fail due to lack of a x_contexts file
>>>>>>> - libvirtd will fail due to lack of a virtual_domain_context file
>>>>>>
>>>>>> We could easily add these to the mdp policy.
>>>>>>
>>>>>>> - crond reports an error with "No security context"
>>>>>>
>>>>>> This is probably due to the lack of a contexts/default_contexts or any
>>>>>> contexts/users/ files in the dummy policy.
>>>>>>
>>>>>>>
>>>>>>> Changes to mdp:
>>>>>>> Add support for devtmpfs, required by modern Linux distributions.
>>>>>>> Add MLS support, with sample sensitivities, categories, and constraints.
>>>>>>> Generate fs_use and genfscon rules based on kernel configuration.
>>>>>>> Update list of filesystem types for fs_use and genfscon rules.
>>>>>>> Use object_r for object contexts.
>>>>>>>
>>>>>>> Changes to install_policy.sh:
>>>>>>> Bail immediately on any errors.
>>>>>>> Provide more helpful error messages when unable to find userspace tools.
>>>>>>> Refuse to run if SELinux is already enabled.
>>>>>>> Unconditionally move aside /etc/selinux/config and create a new one.
>>>>>>> Build policy with -U allow so that userspace object managers do not break.
>>>>>>> Build policy with MLS enabled by default.
>>>>>>> Add default seusers mapping and failsafe context for use by
>>>>>>> pam_selinux / libselinux.
>>>>>>> Set to permissive mode rather than enforcing to permit initial autorelabel.
>>>>>>> Update the list of filesystem types to be relabeled.
>>>>>>> Create /.autorelabel to trigger an autorelabel on reboot.
>>>>>>> Drop broken attempt to relabel the /dev mountpoint directory.
>>>>>>>
>>>>>>> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
>>>>>>> ---
>>>>>>>      scripts/selinux/install_policy.sh |  82 ++++++++-------
>>>>>>>      scripts/selinux/mdp/mdp.c         | 164 +++++++++++++++++++++++++-----
>>>>>>>      2 files changed, 183 insertions(+), 63 deletions(-)
>>>>>>>
>>>>>>> diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
>>>>>>> index 0b86c47baf7d..09eab4d0da5c 100755
>>>>>>> --- a/scripts/selinux/install_policy.sh
>>>>>>> +++ b/scripts/selinux/install_policy.sh
>>>>>>> @@ -1,30 +1,51 @@
>>>>>>>      #!/bin/sh
>>>>>>>      # SPDX-License-Identifier: GPL-2.0
>>>>>>> +set -e
>>>>>>>      if [ `id -u` -ne 0 ]; then
>>>>>>>      	echo "$0: must be root to install the selinux policy"
>>>>>>>      	exit 1
>>>>>>>      fi
>>>>>>> +
>>>>>>>      SF=`which setfiles`
>>>>>>>      if [ $? -eq 1 ]; then
>>>>>>> -	if [ -f /sbin/setfiles ]; then
>>>>>>> -		SF="/usr/setfiles"
>>>>>>> -	else
>>>>>>> -		echo "no selinux tools installed: setfiles"
>>>>>>> -		exit 1
>>>>>>> -	fi
>>>>>>> +	echo "Could not find setfiles"
>>>>>>> +	echo "Do you have policycoreutils installed?"
>>>>>>> +	exit 1
>>>>>>>      fi
>>>>>>> -cd mdp
>>>>>>> -
>>>>>>>      CP=`which checkpolicy`
>>>>>>> +if [ $? -eq 1 ]; then
>>>>>>> +	echo "Could not find checkpolicy"
>>>>>>> +	echo "Do you have checkpolicy installed?"
>>>>>>> +	exit 1
>>>>>>> +fi
>>>>>>>      VERS=`$CP -V | awk '{print $1}'`
>>>>>>> -./mdp policy.conf file_contexts
>>>>>>> -$CP -o policy.$VERS policy.conf
>>>>>>> +ENABLED=`which selinuxenabled`
>>>>>>> +if [ $? -eq 1 ]; then
>>>>>>> +	echo "Could not find selinuxenabled"
>>>>>>> +	echo "Do you have libselinux-utils installed?"
>>>>>>> +	exit 1
>>>>>>> +fi
>>>>>>> +
>>>>>>> +if selinuxenabled; then
>>>>>>> +    echo "SELinux is already enabled"
>>>>>>> +    echo "This prevents safely relabeling all files."
>>>>>>> +    echo "Boot with selinux=0 on the kernel command-line or"
>>>>>>> +    echo "SELINUX=disabled in /etc/selinux/config."
>>>>>>> +    exit 1
>>>>>>> +fi
>>>>>>> +
>>>>>>> +cd mdp
>>>>>>> +./mdp -m policy.conf file_contexts
>>>>>>> +$CP -U allow -M -o policy.$VERS policy.conf
>>>>>>>      mkdir -p /etc/selinux/dummy/policy
>>>>>>>      mkdir -p /etc/selinux/dummy/contexts/files
>>>>>>> +echo "__default__:user_u" > /etc/selinux/dummy/seusers
>>>>>>> +echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
>>>>>>> +
>>>>>>>      cp file_contexts /etc/selinux/dummy/contexts/files
>>>>>>>      cp dbus_contexts /etc/selinux/dummy/contexts
>>>>>>>      cp policy.$VERS /etc/selinux/dummy/policy
>>>>>>> @@ -33,37 +54,22 @@ FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
>>>>>>>      if [ ! -d /etc/selinux ]; then
>>>>>>>      	mkdir -p /etc/selinux
>>>>>>>      fi
>>>>>>> -if [ ! -f /etc/selinux/config ]; then
>>>>>>> -	cat > /etc/selinux/config << EOF
>>>>>>> -SELINUX=enforcing
>>>>>>> +if [ -f /etc/selinux/config ]; then
>>>>>>> +    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
>>>>>>> +    mv /etc/selinux/config /etc/selinux/config.bak
>>>>>>> +fi
>>>>>>> +echo "Creating new /etc/selinux/config for dummy policy."
>>>>>>> +cat > /etc/selinux/config << EOF
>>>>>>> +SELINUX=permissive
>>>>>>>      SELINUXTYPE=dummy
>>>>>>>      EOF
>>>>>>> -else
>>>>>>> -	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
>>>>>>> -	if [ "eq$TYPE" != "eqdummy" ]; then
>>>>>>> -		selinuxenabled
>>>>>>> -		if [ $? -eq 0 ]; then
>>>>>>> -			echo "SELinux already enabled with a non-dummy policy."
>>>>>>> -			echo "Exiting.  Please install policy by hand if that"
>>>>>>> -			echo "is what you REALLY want."
>>>>>>> -			exit 1
>>>>>>> -		fi
>>>>>>> -		mv /etc/selinux/config /etc/selinux/config.mdpbak
>>>>>>> -		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
>>>>>>> -		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
>>>>>>> -	fi
>>>>>>> -fi
>>>>>>>      cd /etc/selinux/dummy/contexts/files
>>>>>>> -$SF file_contexts /
>>>>>>> +$SF -F file_contexts /
>>>>>>> -mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
>>>>>>> -$SF file_contexts $mounts
>>>>>>> +mounts=`cat /proc/$$/mounts | \
>>>>>>> +	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
>>>>>>> +	awk '{ print $2 '}`
>>>>>>> +$SF -F file_contexts $mounts
>>>>>>> -
>>>>>>> -dodev=`cat /proc/$$/mounts | grep "/dev "`
>>>>>>> -if [ "eq$dodev" != "eq" ]; then
>>>>>>> -	mount --move /dev /mnt
>>>>>>> -	$SF file_contexts /dev
>>>>>>> -	mount --move /mnt /dev
>>>>>>> -fi
>>>>>>> +touch /.autorelabel
>>>>>>> diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
>>>>>>> index 073fe7537f6c..daad333c7252 100644
>>>>>>> --- a/scripts/selinux/mdp/mdp.c
>>>>>>> +++ b/scripts/selinux/mdp/mdp.c
>>>>>>> @@ -33,6 +33,7 @@
>>>>>>>      #include <unistd.h>
>>>>>>>      #include <string.h>
>>>>>>>      #include <sys/socket.h>
>>>>>>> +#include <linux/kconfig.h>
>>>>>>>      static void usage(char *name)
>>>>>>>      {
>>>>>>> @@ -95,10 +96,31 @@ int main(int argc, char *argv[])
>>>>>>>      	}
>>>>>>>      	fprintf(fout, "\n");
>>>>>>> -	/* NOW PRINT OUT MLS STUFF */
>>>>>>> +	/* print out mls declarations and constraints */
>>>>>>>      	if (mls) {
>>>>>>> -		printf("MLS not yet implemented\n");
>>>>>>> -		exit(1);
>>>>>>> +		fprintf(fout, "sensitivity s0;\n");
>>>>>>> +		fprintf(fout, "sensitivity s1;\n");
>>>>>>> +		fprintf(fout, "dominance { s0 s1 }\n");
>>>>>>> +		fprintf(fout, "category c0;\n");
>>>>>>> +		fprintf(fout, "category c1;\n");
>>>>>>> +		fprintf(fout, "level s0:c0.c1;\n");
>>>>>>> +		fprintf(fout, "level s1:c0.c1;\n");
>>>>>>> +#define SYSTEMLOW "s0"
>>>>>>> +#define SYSTEMHIGH "s1:c0.c1"
>>>>>>> +		for (i = 0; secclass_map[i].name; i++) {
>>>>>>> +			struct security_class_mapping *map = &secclass_map[i];
>>>>>>> +
>>>>>>> +			fprintf(fout, "mlsconstrain %s {\n", map->name);
>>>>>>> +			for (j = 0; map->perms[j]; j++)
>>>>>>> +				fprintf(fout, "\t%s\n", map->perms[j]);
>>>>>>> +			/*
>>>>>>> +			 * This requires all subjects and objects to be
>>>>>>> +			 * single-level (l2 eq h2), and that the subject
>>>>>>> +			 * level dominate the object level (h1 dom h2)
>>>>>>> +			 * in order to have any permissions to it.
>>>>>>> +			 */
>>>>>>> +			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
>>>>>>> +		}
>>>>>>>      	}
>>>>>>>      	/* types, roles, and allows */
>>>>>>> @@ -108,34 +130,126 @@ int main(int argc, char *argv[])
>>>>>>>      	for (i = 0; secclass_map[i].name; i++)
>>>>>>>      		fprintf(fout, "allow base_t base_t:%s *;\n",
>>>>>>>      			secclass_map[i].name);
>>>>>>> -	fprintf(fout, "user user_u roles { base_r };\n");
>>>>>>> -	fprintf(fout, "\n");
>>>>>>> +	fprintf(fout, "user user_u roles { base_r }");
>>>>>>> +	if (mls)
>>>>>>> +		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
>>>>>>> +			SYSTEMLOW, SYSTEMHIGH);
>>>>>>> +	fprintf(fout, ";\n");
>>>>>>> +
>>>>>>> +#define SUBJUSERROLETYPE "user_u:base_r:base_t"
>>>>>>> +#define OBJUSERROLETYPE "user_u:object_r:base_t"
>>>>>>>      	/* default sids */
>>>>>>>      	for (i = 1; i < initial_sid_to_string_len; i++)
>>>>>>> -		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
>>>>>>> +		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
>>>>>>> +			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
>>>>>>>      	fprintf(fout, "\n");
>>>>>>> -	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
>>>>>>> +#define FS_USE(behavior, fstype)			    \
>>>>>>> +	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
>>>>>>> +		behavior, fstype, mls ? ":" SYSTEMLOW : "")
>>>>>>> +
>>>>>>> +	/*
>>>>>>> +	 * Filesystems whose inode labels can be fetched via getxattr.
>>>>>>> +	 */
>>>>>>> +#ifdef CONFIG_EXT2_FS_SECURITY
>>>>>>> +	FS_USE("xattr", "ext2");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_EXT3_FS_SECURITY
>>>>>>> +	FS_USE("xattr", "ext3");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_EXT4_FS_SECURITY
>>>>>>> +	FS_USE("xattr", "ext4");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_JFS_SECURITY
>>>>>>> +	FS_USE("xattr", "jfs");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_REISERFS_FS_SECURITY
>>>>>>> +	FS_USE("xattr", "reiserfs");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_JFFS2_FS_SECURITY
>>>>>>> +	FS_USE("xattr", "jffs2");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_XFS_FS
>>>>>>> +	FS_USE("xattr", "xfs");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_GFS2_FS
>>>>>>> +	FS_USE("xattr", "gfs2");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_BTRFS_FS
>>>>>>> +	FS_USE("xattr", "btrfs");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_F2FS_FS_SECURITY
>>>>>>> +	FS_USE("xattr", "f2fs");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_OCFS2_FS
>>>>>>> +	FS_USE("xattr", "ocsfs2");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_OVERLAY_FS
>>>>>>> +	FS_USE("xattr", "overlay");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_SQUASHFS_XATTR
>>>>>>> +	FS_USE("xattr", "squashfs");
>>>>>>> +#endif
>>>>>>> +
>>>>>>> +	/*
>>>>>>> +	 * Filesystems whose inodes are labeled from allocating task.
>>>>>>> +	 */
>>>>>>> +	FS_USE("task", "pipefs");
>>>>>>> +	FS_USE("task", "sockfs");
>>>>>>> -	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
>>>>>>> +	/*
>>>>>>> +	 * Filesystems whose inode labels are computed from both
>>>>>>> +	 * the allocating task and the superblock label.
>>>>>>> +	 */
>>>>>>> +#ifdef CONFIG_UNIX98_PTYS
>>>>>>> +	FS_USE("trans", "devpts");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_HUGETLBFS
>>>>>>> +	FS_USE("trans", "hugetlbfs");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_TMPFS
>>>>>>> +	FS_USE("trans", "tmpfs");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_DEVTMPFS
>>>>>>> +	FS_USE("trans", "devtmpfs");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_POSIX_MQUEUE
>>>>>>> +	FS_USE("trans", "mqueue");
>>>>>>> +#endif
>>>>>>> -	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
>>>>>>> -	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
>>>>>>> +#define GENFSCON(fstype, prefix)			     \
>>>>>>> +	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
>>>>>>> +		fstype, prefix, mls ? ":" SYSTEMLOW : "")
>>>>>>> -	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
>>>>>>> +	/*
>>>>>>> +	 * Filesystems whose inodes are labeled from path prefix match
>>>>>>> +	 * relative to the filesystem root.  Depending on the filesystem,
>>>>>>> +	 * only a single label for all inodes may be supported.  Here
>>>>>>> +	 * we list the filesystem types for which per-file labeling is
>>>>>>> +	 * supported using genfscon; any other filesystem type can also
>>>>>>> +	 * be added by only with a single entry for all of its inodes.
>>>>>>> +	 */
>>>>>>> +#ifdef CONFIG_PROC_FS
>>>>>>> +	GENFSCON("proc", "/");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_SECURITY_SELINUX
>>>>>>> +	GENFSCON("selinuxfs", "/");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_SYSFS
>>>>>>> +	GENFSCON("sysfs", "/");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_DEBUG_FS
>>>>>>> +	GENFSCON("debugfs", "/");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_TRACING
>>>>>>> +	GENFSCON("tracefs", "/");
>>>>>>> +#endif
>>>>>>> +#ifdef CONFIG_PSTORE
>>>>>>> +	GENFSCON("pstore", "/");
>>>>>>> +#endif
>>>>>>> +	GENFSCON("cgroup", "/");
>>>>>>> +	GENFSCON("cgroup2", "/");
>>>>>>>      	fclose(fout);
>>>>>>> @@ -144,8 +258,8 @@ int main(int argc, char *argv[])
>>>>>>>      		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
>>>>>>>      		usage(argv[0]);
>>>>>>>      	}
>>>>>>> -	fprintf(fout, "/ user_u:base_r:base_t\n");
>>>>>>> -	fprintf(fout, "/.* user_u:base_r:base_t\n");
>>>>>>> +	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>>>>>> +	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
>>>>>>>      	fclose(fout);
>>>>>>>      	return 0;
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
diff mbox series

Patch

diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
index 0b86c47baf7d..09eab4d0da5c 100755
--- a/scripts/selinux/install_policy.sh
+++ b/scripts/selinux/install_policy.sh
@@ -1,30 +1,51 @@ 
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
+set -e
 if [ `id -u` -ne 0 ]; then
 	echo "$0: must be root to install the selinux policy"
 	exit 1
 fi
+
 SF=`which setfiles`
 if [ $? -eq 1 ]; then
-	if [ -f /sbin/setfiles ]; then
-		SF="/usr/setfiles"
-	else
-		echo "no selinux tools installed: setfiles"
-		exit 1
-	fi
+	echo "Could not find setfiles"
+	echo "Do you have policycoreutils installed?"
+	exit 1
 fi
 
-cd mdp
-
 CP=`which checkpolicy`
+if [ $? -eq 1 ]; then
+	echo "Could not find checkpolicy"
+	echo "Do you have checkpolicy installed?"
+	exit 1
+fi
 VERS=`$CP -V | awk '{print $1}'`
 
-./mdp policy.conf file_contexts
-$CP -o policy.$VERS policy.conf
+ENABLED=`which selinuxenabled`
+if [ $? -eq 1 ]; then
+	echo "Could not find selinuxenabled"
+	echo "Do you have libselinux-utils installed?"
+	exit 1
+fi
+
+if selinuxenabled; then
+    echo "SELinux is already enabled"
+    echo "This prevents safely relabeling all files."
+    echo "Boot with selinux=0 on the kernel command-line or"
+    echo "SELINUX=disabled in /etc/selinux/config."
+    exit 1
+fi
+
+cd mdp
+./mdp -m policy.conf file_contexts
+$CP -U allow -M -o policy.$VERS policy.conf
 
 mkdir -p /etc/selinux/dummy/policy
 mkdir -p /etc/selinux/dummy/contexts/files
 
+echo "__default__:user_u" > /etc/selinux/dummy/seusers
+echo "base_r:base_t" > /etc/selinux/dummy/contexts/failsafe_context
+
 cp file_contexts /etc/selinux/dummy/contexts/files
 cp dbus_contexts /etc/selinux/dummy/contexts
 cp policy.$VERS /etc/selinux/dummy/policy
@@ -33,37 +54,22 @@  FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
 if [ ! -d /etc/selinux ]; then
 	mkdir -p /etc/selinux
 fi
-if [ ! -f /etc/selinux/config ]; then
-	cat > /etc/selinux/config << EOF
-SELINUX=enforcing
+if [ -f /etc/selinux/config ]; then
+    echo "/etc/selinux/config exists, moving to /etc/selinux/config.bak."
+    mv /etc/selinux/config /etc/selinux/config.bak
+fi
+echo "Creating new /etc/selinux/config for dummy policy."
+cat > /etc/selinux/config << EOF
+SELINUX=permissive
 SELINUXTYPE=dummy
 EOF
-else
-	TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
-	if [ "eq$TYPE" != "eqdummy" ]; then
-		selinuxenabled
-		if [ $? -eq 0 ]; then
-			echo "SELinux already enabled with a non-dummy policy."
-			echo "Exiting.  Please install policy by hand if that"
-			echo "is what you REALLY want."
-			exit 1
-		fi
-		mv /etc/selinux/config /etc/selinux/config.mdpbak
-		grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
-		echo "SELINUXTYPE=dummy" >> /etc/selinux/config
-	fi
-fi
 
 cd /etc/selinux/dummy/contexts/files
-$SF file_contexts /
+$SF -F file_contexts /
 
-mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
-$SF file_contexts $mounts
+mounts=`cat /proc/$$/mounts | \
+	egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
+	awk '{ print $2 '}`
+$SF -F file_contexts $mounts
 
-
-dodev=`cat /proc/$$/mounts | grep "/dev "`
-if [ "eq$dodev" != "eq" ]; then
-	mount --move /dev /mnt
-	$SF file_contexts /dev
-	mount --move /mnt /dev
-fi
+touch /.autorelabel
diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
index 073fe7537f6c..daad333c7252 100644
--- a/scripts/selinux/mdp/mdp.c
+++ b/scripts/selinux/mdp/mdp.c
@@ -33,6 +33,7 @@ 
 #include <unistd.h>
 #include <string.h>
 #include <sys/socket.h>
+#include <linux/kconfig.h>
 
 static void usage(char *name)
 {
@@ -95,10 +96,31 @@  int main(int argc, char *argv[])
 	}
 	fprintf(fout, "\n");
 
-	/* NOW PRINT OUT MLS STUFF */
+	/* print out mls declarations and constraints */
 	if (mls) {
-		printf("MLS not yet implemented\n");
-		exit(1);
+		fprintf(fout, "sensitivity s0;\n");
+		fprintf(fout, "sensitivity s1;\n");
+		fprintf(fout, "dominance { s0 s1 }\n");
+		fprintf(fout, "category c0;\n");
+		fprintf(fout, "category c1;\n");
+		fprintf(fout, "level s0:c0.c1;\n");
+		fprintf(fout, "level s1:c0.c1;\n");
+#define SYSTEMLOW "s0"
+#define SYSTEMHIGH "s1:c0.c1"
+		for (i = 0; secclass_map[i].name; i++) {
+			struct security_class_mapping *map = &secclass_map[i];
+
+			fprintf(fout, "mlsconstrain %s {\n", map->name);
+			for (j = 0; map->perms[j]; j++)
+				fprintf(fout, "\t%s\n", map->perms[j]);
+			/*
+			 * This requires all subjects and objects to be
+			 * single-level (l2 eq h2), and that the subject
+			 * level dominate the object level (h1 dom h2)
+			 * in order to have any permissions to it.
+			 */
+			fprintf(fout, "} (l2 eq h2 and h1 dom h2);\n\n");
+		}
 	}
 
 	/* types, roles, and allows */
@@ -108,34 +130,126 @@  int main(int argc, char *argv[])
 	for (i = 0; secclass_map[i].name; i++)
 		fprintf(fout, "allow base_t base_t:%s *;\n",
 			secclass_map[i].name);
-	fprintf(fout, "user user_u roles { base_r };\n");
-	fprintf(fout, "\n");
+	fprintf(fout, "user user_u roles { base_r }");
+	if (mls)
+		fprintf(fout, " level %s range %s - %s", SYSTEMLOW,
+			SYSTEMLOW, SYSTEMHIGH);
+	fprintf(fout, ";\n");
+
+#define SUBJUSERROLETYPE "user_u:base_r:base_t"
+#define OBJUSERROLETYPE "user_u:object_r:base_t"
 
 	/* default sids */
 	for (i = 1; i < initial_sid_to_string_len; i++)
-		fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
+		fprintf(fout, "sid %s " SUBJUSERROLETYPE "%s\n",
+			initial_sid_to_string[i], mls ? ":" SYSTEMLOW : "");
 	fprintf(fout, "\n");
 
-	fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
+#define FS_USE(behavior, fstype)			    \
+	fprintf(fout, "fs_use_%s %s " OBJUSERROLETYPE "%s;\n", \
+		behavior, fstype, mls ? ":" SYSTEMLOW : "")
+
+	/*
+	 * Filesystems whose inode labels can be fetched via getxattr.
+	 */
+#ifdef CONFIG_EXT2_FS_SECURITY
+	FS_USE("xattr", "ext2");
+#endif
+#ifdef CONFIG_EXT3_FS_SECURITY
+	FS_USE("xattr", "ext3");
+#endif
+#ifdef CONFIG_EXT4_FS_SECURITY
+	FS_USE("xattr", "ext4");
+#endif
+#ifdef CONFIG_JFS_SECURITY
+	FS_USE("xattr", "jfs");
+#endif
+#ifdef CONFIG_REISERFS_FS_SECURITY
+	FS_USE("xattr", "reiserfs");
+#endif
+#ifdef CONFIG_JFFS2_FS_SECURITY
+	FS_USE("xattr", "jffs2");
+#endif
+#ifdef CONFIG_XFS_FS
+	FS_USE("xattr", "xfs");
+#endif
+#ifdef CONFIG_GFS2_FS
+	FS_USE("xattr", "gfs2");
+#endif
+#ifdef CONFIG_BTRFS_FS
+	FS_USE("xattr", "btrfs");
+#endif
+#ifdef CONFIG_F2FS_FS_SECURITY
+	FS_USE("xattr", "f2fs");
+#endif
+#ifdef CONFIG_OCFS2_FS
+	FS_USE("xattr", "ocsfs2");
+#endif
+#ifdef CONFIG_OVERLAY_FS
+	FS_USE("xattr", "overlay");
+#endif
+#ifdef CONFIG_SQUASHFS_XATTR
+	FS_USE("xattr", "squashfs");
+#endif
+
+	/*
+	 * Filesystems whose inodes are labeled from allocating task.
+	 */
+	FS_USE("task", "pipefs");
+	FS_USE("task", "sockfs");
 
-	fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
+	/*
+	 * Filesystems whose inode labels are computed from both
+	 * the allocating task and the superblock label.
+	 */
+#ifdef CONFIG_UNIX98_PTYS
+	FS_USE("trans", "devpts");
+#endif
+#ifdef CONFIG_HUGETLBFS
+	FS_USE("trans", "hugetlbfs");
+#endif
+#ifdef CONFIG_TMPFS
+	FS_USE("trans", "tmpfs");
+#endif
+#ifdef CONFIG_DEVTMPFS
+	FS_USE("trans", "devtmpfs");
+#endif
+#ifdef CONFIG_POSIX_MQUEUE
+	FS_USE("trans", "mqueue");
+#endif
 
-	fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
-	fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
+#define GENFSCON(fstype, prefix)			     \
+	fprintf(fout, "genfscon %s %s " OBJUSERROLETYPE "%s\n", \
+		fstype, prefix, mls ? ":" SYSTEMLOW : "")
 
-	fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
+	/*
+	 * Filesystems whose inodes are labeled from path prefix match
+	 * relative to the filesystem root.  Depending on the filesystem,
+	 * only a single label for all inodes may be supported.  Here
+	 * we list the filesystem types for which per-file labeling is
+	 * supported using genfscon; any other filesystem type can also
+	 * be added by only with a single entry for all of its inodes.
+	 */
+#ifdef CONFIG_PROC_FS
+	GENFSCON("proc", "/");
+#endif
+#ifdef CONFIG_SECURITY_SELINUX
+	GENFSCON("selinuxfs", "/");
+#endif
+#ifdef CONFIG_SYSFS
+	GENFSCON("sysfs", "/");
+#endif
+#ifdef CONFIG_DEBUG_FS
+	GENFSCON("debugfs", "/");
+#endif
+#ifdef CONFIG_TRACING
+	GENFSCON("tracefs", "/");
+#endif
+#ifdef CONFIG_PSTORE
+	GENFSCON("pstore", "/");
+#endif
+	GENFSCON("cgroup", "/");
+	GENFSCON("cgroup2", "/");
 
 	fclose(fout);
 
@@ -144,8 +258,8 @@  int main(int argc, char *argv[])
 		printf("Wrote policy, but cannot open %s for writing\n", ctxout);
 		usage(argv[0]);
 	}
-	fprintf(fout, "/ user_u:base_r:base_t\n");
-	fprintf(fout, "/.* user_u:base_r:base_t\n");
+	fprintf(fout, "/ " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
+	fprintf(fout, "/.* " OBJUSERROLETYPE "%s\n", mls ? ":" SYSTEMLOW : "");
 	fclose(fout);
 
 	return 0;