selinux: allow FIOCLEX and FIONCLEX with policy capability
authorRichard Haines <richard_c_haines@btinternet.com>
Fri, 25 Feb 2022 17:54:38 +0000 (17:54 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 8 Apr 2022 12:23:55 +0000 (14:23 +0200)
[ Upstream commit 65881e1db4e948614d9eb195b8e1197339822949 ]

These ioctls are equivalent to fcntl(fd, F_SETFD, flags), which SELinux
always allows too.  Furthermore, a failed FIOCLEX could result in a file
descriptor being leaked to a process that should not have access to it.

As this patch removes access controls, a policy capability needs to be
enabled in policy to always allow these ioctls.

Based-on-patch-by: Demi Marie Obenour <demiobenour@gmail.com>
Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
[PM: subject line tweak]
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
security/selinux/hooks.c
security/selinux/include/policycap.h
security/selinux/include/policycap_names.h
security/selinux/include/security.h

index 9a89e456d3789591c0643b7af181bde92733a5a8..9ce029b2f22678228084d37a5130c6159d12783d 100644 (file)
@@ -3795,6 +3795,12 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
                                            CAP_OPT_NONE, true);
                break;
 
+       case FIOCLEX:
+       case FIONCLEX:
+               if (!selinux_policycap_ioctl_skip_cloexec())
+                       error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
+               break;
+
        /* default case assumes that the command will go
         * to the file's ioctl() function.
         */
index 2ec038efbb03cc53d4e2c5780641f213dadd9894..a9e572ca4fd96d00ea26c917c25f6c91d552475f 100644 (file)
@@ -11,6 +11,7 @@ enum {
        POLICYDB_CAPABILITY_CGROUPSECLABEL,
        POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
        POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS,
+       POLICYDB_CAPABILITY_IOCTL_SKIP_CLOEXEC,
        __POLICYDB_CAPABILITY_MAX
 };
 #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
index b89289f092c938ede5c28b293cfb3f51e7d3979c..ebd64afe1defd13dfb20fd9f9fd05c54f61f218f 100644 (file)
@@ -12,7 +12,8 @@ const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
        "always_check_network",
        "cgroup_seclabel",
        "nnp_nosuid_transition",
-       "genfs_seclabel_symlinks"
+       "genfs_seclabel_symlinks",
+       "ioctl_skip_cloexec"
 };
 
 #endif /* _SELINUX_POLICYCAP_NAMES_H_ */
index ac0ece01305a65744af9a619bc3fb5afed7cfde2..c0d966020ebdd5a66bdd99e43f3aa61e147d231d 100644 (file)
@@ -219,6 +219,13 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
        return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]);
 }
 
+static inline bool selinux_policycap_ioctl_skip_cloexec(void)
+{
+       struct selinux_state *state = &selinux_state;
+
+       return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_IOCTL_SKIP_CLOEXEC]);
+}
+
 struct selinux_policy_convert_data;
 
 struct selinux_load_state {