if (!kstrtoul(str, 0, &checkreqprot)) { if (checkreqprot)
pr_err("SELinux: checkreqprot set to 1 via kernel parameter. This is no longer supported.\n");
} return 1;
}
__setup("checkreqprot=", checkreqprot_setup);
/** * selinux_secmark_enabled - Check to see if SECMARK is currently enabled * * Description: * This function checks the SECMARK reference counter to see if any SECMARK * targets are currently configured, if the reference counter is greater than * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is * enabled, false (0) if SECMARK is disabled. If the always_check_network * policy capability is enabled, SECMARK is always considered enabled. *
*/ staticint selinux_secmark_enabled(void)
{ return (selinux_policycap_alwaysnetwork() ||
atomic_read(&selinux_secmark_refcount));
}
/** * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled * * Description: * This function checks if NetLabel or labeled IPSEC is enabled. Returns true * (1) if any are enabled or false (0) if neither are enabled. If the * always_check_network policy capability is enabled, peer labeling * is always considered enabled. *
*/ staticint selinux_peerlbl_enabled(void)
{ return (selinux_policycap_alwaysnetwork() ||
netlbl_enabled() || selinux_xfrm_enabled());
}
/* * Try reloading inode security labels that have been marked as invalid. The * @may_sleep parameter indicates when sleeping and thus reloading labels is * allowed; when set to false, returns -ECHILD when the label is * invalid. The @dentry parameter should be set to a dentry of the inode.
*/ staticint __inode_security_revalidate(struct inode *inode, struct dentry *dentry, bool may_sleep)
{ if (!selinux_initialized()) return 0;
if (may_sleep)
might_sleep(); else return -ECHILD;
/* * Check to ensure that an inode's SELinux state is valid and try * reloading the inode security label if necessary. This will fail if * @dentry is NULL and no dentry for this inode can be found; in that * case, continue using the old label.
*/
inode_doinit_with_dentry(inode, dentry); return 0;
}
/* check below is racy, but revalidate will recheck with lock held */ if (data_race(likely(isec->initialized == LABEL_INITIALIZED))) return isec;
rc = __inode_security_revalidate(inode, NULL, !rcu); if (rc) return ERR_PTR(rc); return isec;
}
/* * Get the security label of an inode.
*/ staticinlinestruct inode_security_struct *inode_security(struct inode *inode)
{ struct inode_security_struct *isec = selinux_inode(inode);
/* check below is racy, but revalidate will recheck with lock held */ if (data_race(likely(isec->initialized == LABEL_INITIALIZED))) return isec;
__inode_security_revalidate(inode, NULL, true); return isec;
}
/* * Get the security label of a dentry's backing inode.
*/ staticinlinestruct inode_security_struct *backing_inode_security(struct dentry *dentry)
{ struct inode *inode = d_backing_inode(dentry); struct inode_security_struct *isec = selinux_inode(inode);
/* check below is racy, but revalidate will recheck with lock held */ if (data_race(likely(isec->initialized == LABEL_INITIALIZED))) return isec;
__inode_security_revalidate(inode, dentry, true); return isec;
}
if (!isec) return;
sbsec = selinux_superblock(inode->i_sb); /* * As not all inode security structures are in a list, we check for * empty list outside of the lock to make sure that we won't waste * time taking a lock doing nothing. * * The list_del_init() function can be safely called more than once. * It should not be possible for this function to be called with * concurrent list_add(), but for better safety against future changes * in the code, we use list_empty_careful() here.
*/ if (!list_empty_careful(&isec->list)) {
spin_lock(&sbsec->isec_lock);
list_del_init(&isec->list);
spin_unlock(&sbsec->isec_lock);
}
}
staticint match_opt_prefix(char *s, int l, char **arg)
{ unsignedint i;
for (i = 0; i < ARRAY_SIZE(tokens); i++) {
size_t len = tokens[i].len; if (len > l || memcmp(s, tokens[i].name, len)) continue; if (tokens[i].has_arg) { if (len == l || s[len] != '=') continue;
*arg = s + len + 1;
} elseif (len != l) continue; return tokens[i].opt;
} return Opt_error;
}
#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
/* * Make sure that the xattr handler exists and that no * error other than -ENODATA is returned by getxattr on * the root directory. -ENODATA is ok, as this may be * the first boot of the SELinux kernel before we have * assigned xattr values to the filesystem.
*/ if (!(root_inode->i_opflags & IOP_XATTR)) {
pr_warn("SELinux: (dev %s, type %s) has no xattr support\n",
sb->s_id, sb->s_type->name); goto fallback;
}
rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0); if (rc < 0 && rc != -ENODATA) { if (rc == -EOPNOTSUPP) {
pr_warn("SELinux: (dev %s, type %s) has no security xattr handler\n",
sb->s_id, sb->s_type->name); goto fallback;
} else {
pr_warn("SELinux: (dev %s, type %s) getxattr errno %d\n",
sb->s_id, sb->s_type->name, -rc); return rc;
}
} return 0;
fallback: /* No xattr support - try to fallback to genfs if possible. */
rc = security_genfs_sid(sb->s_type->name, "/",
SECCLASS_DIR, &sid); if (rc) return -EOPNOTSUPP;
pr_warn("SELinux: (dev %s, type %s) falling back to genfs\n",
sb->s_id, sb->s_type->name);
sbsec->behavior = SECURITY_FS_USE_GENFS;
sbsec->sid = sid; return 0;
}
if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
rc = sb_check_xattr_support(sb); if (rc) return rc;
}
sbsec->flags |= SE_SBINITIALIZED;
/* * Explicitly set or clear SBLABEL_MNT. It's not sufficient to simply * leave the flag untouched because sb_clone_mnt_opts might be handing * us a superblock that needs the flag to be cleared.
*/ if (selinux_is_sblabel_mnt(sb))
sbsec->flags |= SBLABEL_MNT; else
sbsec->flags &= ~SBLABEL_MNT;
/* Initialize the root inode. */
rc = inode_doinit_with_dentry(root_inode, root);
/* Initialize any other inodes associated with the superblock, e.g. inodes created prior to initial policy load or inodes created during get_sb by a pseudo filesystem that directly
populates itself. */
spin_lock(&sbsec->isec_lock); while (!list_empty(&sbsec->isec_head)) { struct inode_security_struct *isec =
list_first_entry(&sbsec->isec_head, struct inode_security_struct, list); struct inode *inode = isec->inode;
list_del_init(&isec->list);
spin_unlock(&sbsec->isec_lock);
inode = igrab(inode); if (inode) { if (!IS_PRIVATE(inode))
inode_doinit_with_dentry(inode, NULL);
iput(inode);
}
spin_lock(&sbsec->isec_lock);
}
spin_unlock(&sbsec->isec_lock); return rc;
}
/* check if the old mount command had the same options */ if (sbsec->flags & SE_SBINITIALIZED) if (!(sbsec->flags & flag) ||
(old_sid != new_sid)) return 1;
/* check if we were passed the same options twice, * aka someone passed context=a,context=b
*/ if (!(sbsec->flags & SE_SBINITIALIZED)) if (mnt_flags & flag) return 1; return 0;
}
/* * Allow filesystems with binary mount data to explicitly set mount point * labeling information.
*/ staticint selinux_set_mnt_opts(struct super_block *sb, void *mnt_opts, unsignedlong kern_flags, unsignedlong *set_kern_flags)
{ conststruct cred *cred = current_cred(); struct superblock_security_struct *sbsec = selinux_superblock(sb); struct dentry *root = sb->s_root; struct selinux_mnt_opts *opts = mnt_opts; struct inode_security_struct *root_isec;
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
u32 defcontext_sid = 0; int rc = 0;
/* * Specifying internal flags without providing a place to * place the results is not allowed
*/ if (kern_flags && !set_kern_flags) return -EINVAL;
mutex_lock(&sbsec->lock);
if (!selinux_initialized()) { if (!opts) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security
server is ready to handle calls. */ if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
sbsec->flags |= SE_SBNATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
} goto out;
}
rc = -EINVAL;
pr_warn("SELinux: Unable to set superblock options " "before the security server is initialized\n"); goto out;
}
/* * Binary mount data FS will come through this function twice. Once * from an explicit call and once from the generic calls from the vfs. * Since the generic VFS calls will not contain any security mount data * we need to skip the double mount verification. * * This does open a hole in which we will not notice if the first * mount using this sb set explicit options and a second mount using * this sb does not set any security options. (The first options * will be used for both mounts)
*/ if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
&& !opts) goto out;
/* * parse the mount options, check if they are valid sids. * also check if someone is trying to mount the same sb more * than once with different security options.
*/ if (opts) { if (opts->fscontext_sid) {
fscontext_sid = opts->fscontext_sid; if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
fscontext_sid)) goto out_double_mount;
sbsec->flags |= FSCONTEXT_MNT;
} if (opts->context_sid) {
context_sid = opts->context_sid; if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
context_sid)) goto out_double_mount;
sbsec->flags |= CONTEXT_MNT;
} if (opts->rootcontext_sid) {
rootcontext_sid = opts->rootcontext_sid; if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
rootcontext_sid)) goto out_double_mount;
sbsec->flags |= ROOTCONTEXT_MNT;
} if (opts->defcontext_sid) {
defcontext_sid = opts->defcontext_sid; if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
defcontext_sid)) goto out_double_mount;
sbsec->flags |= DEFCONTEXT_MNT;
}
}
if (sbsec->flags & SE_SBINITIALIZED) { /* previously mounted with options, but not on this attempt? */ if ((sbsec->flags & SE_MNTMASK) && !opts) goto out_double_mount;
rc = 0; goto out;
}
if (strcmp(sb->s_type->name, "proc") == 0)
sbsec->flags |= SE_SBPROC | SE_SBGENFS;
if (!sbsec->behavior) { /* * Determine the labeling behavior to use for this * filesystem type.
*/
rc = security_fs_use(sb); if (rc) {
pr_warn("%s: security_fs_use(%s) returned %d\n",
__func__, sb->s_type->name, rc); goto out;
}
}
/* * If this is a user namespace mount and the filesystem type is not * explicitly whitelisted, then no contexts are allowed on the command * line and security labels must be ignored.
*/ if (sb->s_user_ns != &init_user_ns &&
strcmp(sb->s_type->name, "tmpfs") &&
strcmp(sb->s_type->name, "ramfs") &&
strcmp(sb->s_type->name, "devpts") &&
strcmp(sb->s_type->name, "overlay")) { if (context_sid || fscontext_sid || rootcontext_sid ||
defcontext_sid) {
rc = -EACCES; goto out;
} if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
rc = security_transition_sid(current_sid(),
current_sid(),
SECCLASS_FILE, NULL,
&sbsec->mntpoint_sid); if (rc) goto out;
} goto out_set_opts;
}
/* sets the context of the superblock for the fs being mounted. */ if (fscontext_sid) {
rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); if (rc) goto out;
sbsec->sid = fscontext_sid;
}
/* * Switch to using mount point labeling behavior. * sets the label used on all file below the mountpoint, and will set * the superblock context if not already set.
*/ if (sbsec->flags & SE_SBNATIVE) { /* * This means we are initializing a superblock that has been * mounted before the SELinux was initialized and the * filesystem requested native labeling. We had already * returned SECURITY_LSM_NATIVE_LABELS in *set_kern_flags * in the original mount attempt, so now we just need to set * the SECURITY_FS_USE_NATIVE behavior.
*/
sbsec->behavior = SECURITY_FS_USE_NATIVE;
} elseif (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
sbsec->behavior = SECURITY_FS_USE_NATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
}
if (context_sid) { if (!fscontext_sid) {
rc = may_context_mount_sb_relabel(context_sid, sbsec,
cred); if (rc) goto out;
sbsec->sid = context_sid;
} else {
rc = may_context_mount_inode_relabel(context_sid, sbsec,
cred); if (rc) goto out;
} if (!rootcontext_sid)
rootcontext_sid = context_sid;
int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT); int set_context = (oldsbsec->flags & CONTEXT_MNT); int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
/* * Specifying internal flags without providing a place to * place the results is not allowed.
*/ if (kern_flags && !set_kern_flags) return -EINVAL;
mutex_lock(&newsbsec->lock);
/* * if the parent was able to be mounted it clearly had no special lsm * mount options. thus we can safely deal with this superblock later
*/ if (!selinux_initialized()) { if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
newsbsec->flags |= SE_SBNATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
} goto out;
}
/* how can we clone if the old one wasn't set up?? */
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
/* if fs is reusing a sb, make sure that the contexts match */ if (newsbsec->flags & SE_SBINITIALIZED) {
mutex_unlock(&newsbsec->lock); if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; return selinux_cmp_sb_context(oldsb, newsb);
}
/* * NOTE: the caller is responsible for freeing the memory even if on error.
*/ staticint selinux_add_opt(int token, constchar *s, void **mnt_opts)
{ struct selinux_mnt_opts *opts = *mnt_opts;
u32 *dst_sid; int rc;
if (token == Opt_seclabel) /* eaten and completely ignored */ return 0; if (!s) return -EINVAL;
if (!selinux_initialized()) {
pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n"); return -EINVAL;
}
if (!opts) {
opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return -ENOMEM;
*mnt_opts = opts;
}
switch (token) { case Opt_context: if (opts->context_sid || opts->defcontext_sid) goto err;
dst_sid = &opts->context_sid; break; case Opt_fscontext: if (opts->fscontext_sid) goto err;
dst_sid = &opts->fscontext_sid; break; case Opt_rootcontext: if (opts->rootcontext_sid) goto err;
dst_sid = &opts->rootcontext_sid; break; case Opt_defcontext: if (opts->context_sid || opts->defcontext_sid) goto err;
dst_sid = &opts->defcontext_sid; break; default:
WARN_ON(1); return -EINVAL;
}
rc = security_context_str_to_sid(s, dst_sid, GFP_KERNEL); if (rc)
pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
s, rc); return rc;
staticinline u16 socket_type_to_security_class(int family, int type, int protocol)
{ bool extsockclass = selinux_policycap_extsockclass();
switch (family) { case PF_UNIX: switch (type) { case SOCK_STREAM: case SOCK_SEQPACKET: return SECCLASS_UNIX_STREAM_SOCKET; case SOCK_DGRAM: case SOCK_RAW: return SECCLASS_UNIX_DGRAM_SOCKET;
} break; case PF_INET: case PF_INET6: switch (type) { case SOCK_STREAM: case SOCK_SEQPACKET: if (default_protocol_stream(protocol)) return SECCLASS_TCP_SOCKET; elseif (extsockclass && protocol == IPPROTO_SCTP) return SECCLASS_SCTP_SOCKET; else return SECCLASS_RAWIP_SOCKET; case SOCK_DGRAM: if (default_protocol_dgram(protocol)) return SECCLASS_UDP_SOCKET; elseif (extsockclass && (protocol == IPPROTO_ICMP ||
protocol == IPPROTO_ICMPV6)) return SECCLASS_ICMP_SOCKET; else return SECCLASS_RAWIP_SOCKET; default: return SECCLASS_RAWIP_SOCKET;
} break; case PF_NETLINK: switch (protocol) { case NETLINK_ROUTE: return SECCLASS_NETLINK_ROUTE_SOCKET; case NETLINK_SOCK_DIAG: return SECCLASS_NETLINK_TCPDIAG_SOCKET; case NETLINK_NFLOG: return SECCLASS_NETLINK_NFLOG_SOCKET; case NETLINK_XFRM: return SECCLASS_NETLINK_XFRM_SOCKET; case NETLINK_SELINUX: return SECCLASS_NETLINK_SELINUX_SOCKET; case NETLINK_ISCSI: return SECCLASS_NETLINK_ISCSI_SOCKET; case NETLINK_AUDIT: return SECCLASS_NETLINK_AUDIT_SOCKET; case NETLINK_FIB_LOOKUP: return SECCLASS_NETLINK_FIB_LOOKUP_SOCKET; case NETLINK_CONNECTOR: return SECCLASS_NETLINK_CONNECTOR_SOCKET; case NETLINK_NETFILTER: return SECCLASS_NETLINK_NETFILTER_SOCKET; case NETLINK_DNRTMSG: return SECCLASS_NETLINK_DNRT_SOCKET; case NETLINK_KOBJECT_UEVENT: return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET; case NETLINK_GENERIC: return SECCLASS_NETLINK_GENERIC_SOCKET; case NETLINK_SCSITRANSPORT: return SECCLASS_NETLINK_SCSITRANSPORT_SOCKET; case NETLINK_RDMA: return SECCLASS_NETLINK_RDMA_SOCKET; case NETLINK_CRYPTO: return SECCLASS_NETLINK_CRYPTO_SOCKET; default: return SECCLASS_NETLINK_SOCKET;
} case PF_PACKET: return SECCLASS_PACKET_SOCKET; case PF_KEY: return SECCLASS_KEY_SOCKET; case PF_APPLETALK: return SECCLASS_APPLETALK_SOCKET;
}
if (extsockclass) { switch (family) { case PF_AX25: return SECCLASS_AX25_SOCKET; case PF_IPX: return SECCLASS_IPX_SOCKET; case PF_NETROM: return SECCLASS_NETROM_SOCKET; case PF_ATMPVC: return SECCLASS_ATMPVC_SOCKET; case PF_X25: return SECCLASS_X25_SOCKET; case PF_ROSE: return SECCLASS_ROSE_SOCKET; case PF_DECnet: return SECCLASS_DECNET_SOCKET; case PF_ATMSVC: return SECCLASS_ATMSVC_SOCKET; case PF_RDS: return SECCLASS_RDS_SOCKET; case PF_IRDA: return SECCLASS_IRDA_SOCKET; case PF_PPPOX: return SECCLASS_PPPOX_SOCKET; case PF_LLC: return SECCLASS_LLC_SOCKET; case PF_CAN: return SECCLASS_CAN_SOCKET; case PF_TIPC: return SECCLASS_TIPC_SOCKET; case PF_BLUETOOTH: return SECCLASS_BLUETOOTH_SOCKET; case PF_IUCV: return SECCLASS_IUCV_SOCKET; case PF_RXRPC: return SECCLASS_RXRPC_SOCKET; case PF_ISDN: return SECCLASS_ISDN_SOCKET; case PF_PHONET: return SECCLASS_PHONET_SOCKET; case PF_IEEE802154: return SECCLASS_IEEE802154_SOCKET; case PF_CAIF: return SECCLASS_CAIF_SOCKET; case PF_ALG: return SECCLASS_ALG_SOCKET; case PF_NFC: return SECCLASS_NFC_SOCKET; case PF_VSOCK: return SECCLASS_VSOCK_SOCKET; case PF_KCM: return SECCLASS_KCM_SOCKET; case PF_QIPCRTR: return SECCLASS_QIPCRTR_SOCKET; case PF_SMC: return SECCLASS_SMC_SOCKET; case PF_XDP: return SECCLASS_XDP_SOCKET; case PF_MCTP: return SECCLASS_MCTP_SOCKET; #if PF_MAX > 46 #errorNew address family defined, please update this function. #endif
}
}
buffer = (char *)__get_free_page(GFP_KERNEL); if (!buffer) return -ENOMEM;
path = dentry_path_raw(dentry, buffer, PAGE_SIZE); if (IS_ERR(path))
rc = PTR_ERR(path); else { if (flags & SE_SBPROC) { /* each process gets a /proc/PID/ entry. Strip off the * PID part to get a valid selinux labeling.
* e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ while (path[1] >= '0' && path[1] <= '9') {
path[1] = '/';
path++;
}
}
rc = security_genfs_sid(sb->s_type->name,
path, tclass, sid); if (rc == -ENOENT) { /* No match in policy, mark as unlabeled. */
*sid = SECINITSID_UNLABELED;
rc = 0;
}
}
free_page((unsignedlong)buffer); return rc;
}
if (rc == -EINVAL) {
pr_notice_ratelimited("SELinux: inode=%lu on dev=%s was found to have an invalid context=%s. This indicates you may need to relabel the inode or the filesystem in question.\n",
ino, dev, context);
} else {
pr_warn("SELinux: %s: context_to_sid(%s) returned %d for dev=%s ino=%ld\n",
__func__, context, -rc, dev, ino);
}
}
kfree(context); return 0;
}
/* The inode's security attributes must be initialized before first use. */ staticint inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
{ struct superblock_security_struct *sbsec = NULL; struct inode_security_struct *isec = selinux_inode(inode);
u32 task_sid, sid = 0;
u16 sclass; struct dentry *dentry; int rc = 0;
if (isec->initialized == LABEL_INITIALIZED) return 0;
spin_lock(&isec->lock); if (isec->initialized == LABEL_INITIALIZED) goto out_unlock;
if (isec->sclass == SECCLASS_FILE)
isec->sclass = inode_mode_to_security_class(inode->i_mode);
sbsec = selinux_superblock(inode->i_sb); if (!(sbsec->flags & SE_SBINITIALIZED)) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security
server is ready to handle calls. */
spin_lock(&sbsec->isec_lock); if (list_empty(&isec->list))
list_add(&isec->list, &sbsec->isec_head);
spin_unlock(&sbsec->isec_lock); goto out_unlock;
}
switch (sbsec->behavior) { /* * In case of SECURITY_FS_USE_NATIVE we need to re-fetch the labels * via xattr when called from delayed_superblock_init().
*/ case SECURITY_FS_USE_NATIVE: case SECURITY_FS_USE_XATTR: if (!(inode->i_opflags & IOP_XATTR)) {
sid = sbsec->def_sid; break;
} /* Need a dentry, since the xattr API requires one.
Life would be simpler if we could just pass the inode. */ if (opt_dentry) { /* Called from d_instantiate or d_splice_alias. */
dentry = dget(opt_dentry);
} else { /* * Called from selinux_complete_init, try to find a dentry. * Some filesystems really want a connected one, so try * that first. We could split SECURITY_FS_USE_XATTR in * two, depending upon that...
*/
dentry = d_find_alias(inode); if (!dentry)
dentry = d_find_any_alias(inode);
} if (!dentry) { /* * this is can be hit on boot when a file is accessed * before the policy is loaded. When we load policy we * may find inodes that have no dentry on the * sbsec->isec_head list. No reason to complain as these * will get fixed up the next time we go through * inode_doinit with a dentry, before these inodes could * be used again by userspace.
*/ goto out_invalid;
}
rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid,
&sid);
dput(dentry); if (rc) goto out; break; case SECURITY_FS_USE_TASK:
sid = task_sid; break; case SECURITY_FS_USE_TRANS: /* Default to the fs SID. */
sid = sbsec->sid;
/* Try to obtain a transition SID. */
rc = security_transition_sid(task_sid, sid,
sclass, NULL, &sid); if (rc) goto out; break; case SECURITY_FS_USE_MNTPOINT:
sid = sbsec->mntpoint_sid; break; default: /* Default to the fs superblock SID. */
sid = sbsec->sid;
if ((sbsec->flags & SE_SBGENFS) &&
(!S_ISLNK(inode->i_mode) ||
selinux_policycap_genfs_seclabel_symlinks())) { /* We must have a dentry to determine the label on
* procfs inodes */ if (opt_dentry) { /* Called from d_instantiate or
* d_splice_alias. */
dentry = dget(opt_dentry);
} else { /* Called from selinux_complete_init, try to * find a dentry. Some filesystems really want * a connected one, so try that first.
*/
dentry = d_find_alias(inode); if (!dentry)
dentry = d_find_any_alias(inode);
} /* * This can be hit on boot when a file is accessed * before the policy is loaded. When we load policy we * may find inodes that have no dentry on the * sbsec->isec_head list. No reason to complain as * these will get fixed up the next time we go through * inode_doinit() with a dentry, before these inodes * could be used again by userspace.
*/ if (!dentry) goto out_invalid;
rc = selinux_genfs_get_sid(dentry, sclass,
sbsec->flags, &sid); if (rc) {
dput(dentry); goto out;
}
/* Convert a Linux signal to an access vector. */ staticinline u32 signal_to_av(int sig)
{
u32 perm = 0;
switch (sig) { case SIGCHLD: /* Commonly granted from child to parent. */
perm = PROCESS__SIGCHLD; break; case SIGKILL: /* Cannot be caught or ignored */
perm = PROCESS__SIGKILL; break; case SIGSTOP: /* Cannot be caught or ignored */
perm = PROCESS__SIGSTOP; break; default: /* All other signals. */
perm = PROCESS__SIGNAL; break;
}
/* Check whether a task has a particular permission to an inode. The 'adp' parameter is optional and allows other audit
data to be passed (e.g. the dentry). */ staticint inode_has_perm(conststruct cred *cred, struct inode *inode,
u32 perms, struct common_audit_data *adp)
{ struct inode_security_struct *isec;
u32 sid;
/* Same as inode_has_perm, but pass explicit audit data containing the dentry to help the auditing code to more easily generate the
pathname if needed. */ staticinlineint dentry_has_perm(conststruct cred *cred, struct dentry *dentry,
u32 av)
{ struct common_audit_data ad; struct inode *inode = d_backing_inode(dentry); struct inode_security_struct *isec = selinux_inode(inode);
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry; /* check below is racy, but revalidate will recheck with lock held */ if (data_race(unlikely(isec->initialized != LABEL_INITIALIZED)))
__inode_security_revalidate(inode, dentry, true); return inode_has_perm(cred, inode, av, &ad);
}
/* Same as inode_has_perm, but pass explicit audit data containing the path to help the auditing code to more easily generate the
pathname if needed. */ staticinlineint path_has_perm(conststruct cred *cred, conststruct path *path,
u32 av)
{ struct common_audit_data ad; struct inode *inode = d_backing_inode(path->dentry); struct inode_security_struct *isec = selinux_inode(inode);
ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = *path; /* check below is racy, but revalidate will recheck with lock held */ if (data_race(unlikely(isec->initialized != LABEL_INITIALIZED)))
__inode_security_revalidate(inode, path->dentry, true); return inode_has_perm(cred, inode, av, &ad);
}
/* Same as path_has_perm, but uses the inode from the file struct. */ staticinlineint file_path_has_perm(conststruct cred *cred, struct file *file,
u32 av)
{ struct common_audit_data ad;
/* Check whether a task can use an open file descriptor to access an inode in a given way. Check access to the descriptor itself, and then use dentry_has_perm to check a particular permission to the file. Access to the descriptor is implicitly granted if it has the same SID as the process. If av is zero, then access to the file is not checked, e.g. for cases
where only the descriptor is affected like seek. */ staticint file_has_perm(conststruct cred *cred, struct file *file,
u32 av)
{ struct file_security_struct *fsec = selinux_file(file); struct inode *inode = file_inode(file); struct common_audit_data ad;
u32 sid = cred_sid(cred); int rc;
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad); if (rc) goto out;
}
/* Convert a Linux mode and permission mask to an access vector. */ staticinline u32 file_mask_to_av(int mode, int mask)
{
u32 av = 0;
if (!S_ISDIR(mode)) { if (mask & MAY_EXEC)
av |= FILE__EXECUTE; if (mask & MAY_READ)
av |= FILE__READ;
if (mask & MAY_APPEND)
av |= FILE__APPEND; elseif (mask & MAY_WRITE)
av |= FILE__WRITE;
} else { if (mask & MAY_EXEC)
av |= DIR__SEARCH; if (mask & MAY_WRITE)
av |= DIR__WRITE; if (mask & MAY_READ)
av |= DIR__READ;
}
return av;
}
/* Convert a Linux file to an access vector. */ staticinline u32 file_to_av(conststruct file *file)
{
u32 av = 0;
if (file->f_mode & FMODE_READ)
av |= FILE__READ; if (file->f_mode & FMODE_WRITE) { if (file->f_flags & O_APPEND)
av |= FILE__APPEND; else
av |= FILE__WRITE;
} if (!av) { /* * Special file opened with flags 3 for ioctl-only use.
*/
av = FILE__IOCTL;
}
return av;
}
/* * Convert a file to an access vector and include the correct * open permission.
*/ staticinline u32 open_file_to_av(struct file *file)
{
u32 av = file_to_av(file); struct inode *inode = file_inode(file);
if (selinux_policycap_openperm() &&
inode->i_sb->s_magic != SOCKFS_MAGIC)
av |= FILE__OPEN;
/* * (This comment used to live with the selinux_task_setuid hook, * which was removed). * * Since setuid only affects the current process, and since the SELinux * controls are not based on the Linux identity attributes, SELinux does not * need to control this operation. However, SELinux does control the use of * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
*/
staticint selinux_quotactl(int cmds, int type, int id, conststruct super_block *sb)
{ conststruct cred *cred = current_cred(); int rc = 0;
if (!sb) return 0;
switch (cmds) { case Q_SYNC: case Q_QUOTAON: case Q_QUOTAOFF: case Q_SETINFO: case Q_SETQUOTA: case Q_XQUOTAOFF: case Q_XQUOTAON: case Q_XSETQLIM:
rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL); break; case Q_GETFMT: case Q_GETINFO: case Q_GETQUOTA: case Q_XGETQUOTA: case Q_XGETQSTAT: case Q_XGETQSTATV: case Q_XGETNEXTQUOTA:
rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL); break; default:
rc = 0; /* let the kernel handle invalid cmds */ break;
} return rc;
}
staticint selinux_syslog(int type)
{ switch (type) { case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ return avc_has_perm(current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL); case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ /* Set level of messages printed to console */ case SYSLOG_ACTION_CONSOLE_LEVEL: return avc_has_perm(current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
NULL);
} /* All other syslog types */ return avc_has_perm(current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
}
/* * Check permission for allocating a new virtual mapping. Returns * 0 if permission is granted, negative error code if not. * * Do not audit the selinux permission check, as this is applied to all * processes that allocate mappings.
*/ staticint selinux_vm_enough_memory(struct mm_struct *mm, long pages)
{ return cred_has_capability(current_cred(), CAP_SYS_ADMIN,
CAP_OPT_NOAUDIT, true);
}
rcu_read_lock();
tracer = ptrace_parent(current); if (tracer)
sid = task_sid_obj(tracer);
rcu_read_unlock();
return sid;
}
staticint check_nnp_nosuid(conststruct linux_binprm *bprm, conststruct task_security_struct *old_tsec, conststruct task_security_struct *new_tsec)
{ int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS); int nosuid = !mnt_may_suid(bprm->file->f_path.mnt); int rc;
u32 av;
if (!nnp && !nosuid) return 0; /* neither NNP nor nosuid */
if (new_tsec->sid == old_tsec->sid) return 0; /* No change in credentials */
/* * If the policy enables the nnp_nosuid_transition policy capability, * then we permit transitions under NNP or nosuid if the * policy allows the corresponding permission between * the old and new contexts.
*/ if (selinux_policycap_nnp_nosuid_transition()) {
av = 0; if (nnp)
av |= PROCESS2__NNP_TRANSITION; if (nosuid)
av |= PROCESS2__NOSUID_TRANSITION;
rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS2, av, NULL); if (!rc) return 0;
}
/* * We also permit NNP or nosuid transitions to bounded SIDs, * i.e. SIDs that are guaranteed to only be allowed a subset * of the permissions of the current SID.
*/
rc = security_bounded_transition(old_tsec->sid,
new_tsec->sid); if (!rc) return 0;
/* * On failure, preserve the errno values for NNP vs nosuid. * NNP: Operation not permitted for caller. * nosuid: Permission denied to file.
*/ if (nnp) return -EPERM; return -EACCES;
}
/* Default to the current task SID. */
new_tsec->sid = old_tsec->sid;
new_tsec->osid = old_tsec->sid;
/* Reset fs, key, and sock SIDs on execve. */
new_tsec->create_sid = 0;
new_tsec->keycreate_sid = 0;
new_tsec->sockcreate_sid = 0;
/* * Before policy is loaded, label any task outside kernel space * as SECINITSID_INIT, so that any userspace tasks surviving from * early boot end up with a label different from SECINITSID_KERNEL * (if the policy chooses to set SECINITSID_INIT != SECINITSID_KERNEL).
*/ if (!selinux_initialized()) {
new_tsec->sid = SECINITSID_INIT; /* also clear the exec_sid just in case */
new_tsec->exec_sid = 0; return 0;
}
if (old_tsec->exec_sid) {
new_tsec->sid = old_tsec->exec_sid; /* Reset exec SID on execve. */
new_tsec->exec_sid = 0;
/* Fail on NNP or nosuid if not an allowed transition. */
rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); if (rc) return rc;
} else { /* Check for a default transition on this program. */
rc = security_transition_sid(old_tsec->sid,
isec->sid, SECCLASS_PROCESS, NULL,
&new_tsec->sid); if (rc) return rc;
/* * Fallback to old SID on NNP or nosuid if not an allowed * transition.
*/
rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); if (rc)
new_tsec->sid = old_tsec->sid;
}
/* Check for shared state */ if (bprm->unsafe & LSM_UNSAFE_SHARE) {
rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__SHARE,
NULL); if (rc) return -EPERM;
}
/* Make sure that anyone attempting to ptrace over a task that
* changes its SID has the appropriate permit */ if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
u32 ptsid = ptrace_parent_sid(); if (ptsid != 0) {
rc = avc_has_perm(ptsid, new_tsec->sid,
SECCLASS_PROCESS,
PROCESS__PTRACE, NULL); if (rc) return -EPERM;
}
}
/* Clear any possibly unsafe personality bits on exec: */
bprm->per_clear |= PER_CLEAR_ON_SETID;
/* Enable secure mode for SIDs transitions unless the noatsecure permission is granted between
the two SIDs, i.e. ahp returns 0. */
rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__NOATSECURE,
NULL);
bprm->secureexec |= !!rc;
}
tty = get_current_tty(); if (tty) {
spin_lock(&tty->files_lock); if (!list_empty(&tty->tty_files)) { struct tty_file_private *file_priv;
/* Revalidate access to controlling tty. Use file_path_has_perm on the tty path directly rather than using file_has_perm, as this particular open file may belong to another process and we are
only interested in the inode-based check here. */
file_priv = list_first_entry(&tty->tty_files, struct tty_file_private, list);
file = file_priv->file; if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE))
drop_tty = 1;
}
spin_unlock(&tty->files_lock);
tty_kref_put(tty);
} /* Reset controlling tty. */ if (drop_tty)
no_tty();
/* Revalidate access to inherited open files. */
n = iterate_fd(files, 0, match_file, cred); if (!n) /* none found? */ return;
devnull = dentry_open(&selinux_null, O_RDWR, cred); if (IS_ERR(devnull))
devnull = NULL; /* replace all the matching ones with this */ do {
replace_fd(n - 1, devnull, 0);
} while ((n = iterate_fd(files, n, match_file, cred)) != 0); if (devnull)
fput(devnull);
}
/* * Prepare a process for imminent new credential changes due to exec
*/ staticvoid selinux_bprm_committing_creds(conststruct linux_binprm *bprm)
{ struct task_security_struct *new_tsec; struct rlimit *rlim, *initrlim; int rc, i;
new_tsec = selinux_cred(bprm->cred); if (new_tsec->sid == new_tsec->osid) return;
/* Close files for which the new task SID is not authorized. */
flush_unauthorized_files(bprm->cred, current->files);
/* Always clear parent death signal on SID transitions. */
current->pdeath_signal = 0;
/* Check whether the new SID can inherit resource limits from the old * SID. If not, reset all soft limits to the lower of the current * task's hard limit and the init task's soft limit. * * Note that the setting of hard limits (even to lower them) can be * controlled by the setrlimit check. The inclusion of the init task's * soft limit into the computation is to avoid resetting soft limits * higher than the default soft limit for cases where the default is * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
*/
rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
PROCESS__RLIMITINH, NULL); if (rc) { /* protect against do_prlimit() */
task_lock(current); for (i = 0; i < RLIM_NLIMITS; i++) {
rlim = current->signal->rlim + i;
initrlim = init_task.signal->rlim + i;
rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
}
task_unlock(current); if (IS_ENABLED(CONFIG_POSIX_TIMERS))
update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
}
}
/* * Clean up the process immediately after the installation of new credentials * due to exec
*/ staticvoid selinux_bprm_committed_creds(conststruct linux_binprm *bprm)
{ conststruct task_security_struct *tsec = selinux_cred(current_cred());
u32 osid, sid; int rc;
osid = tsec->osid;
sid = tsec->sid;
if (sid == osid) return;
/* Check whether the new SID can inherit signal state from the old SID. * If not, clear itimers to avoid subsequent signal generation and * flush and unblock signals. * * This must occur _after_ the task SID has been updated so that any * kill done after the flush will be checked against the new SID.
*/
rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); if (rc) {
clear_itimer();
/* Wake up the parent if it is waiting so that it can recheck
* wait permission to the new task SID. */
read_lock(&tasklist_lock);
__wake_up_parent(current, unrcu_pointer(current->real_parent));
read_unlock(&tasklist_lock);
}
/* * Superblock not initialized (i.e. no options) - reject if any * options specified, otherwise accept.
*/ if (!(sbsec->flags & SE_SBINITIALIZED)) return opts ? 1 : 0;
/* * Superblock initialized and no options specified - reject if * superblock has any options set, otherwise accept.
*/ if (!opts) return (sbsec->flags & SE_MNTMASK) ? 1 : 0;
if (opts->fscontext_sid) { if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
opts->fscontext_sid)) return 1;
} if (opts->context_sid) { if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
opts->context_sid)) return 1;
} if (opts->rootcontext_sid) { struct inode_security_struct *root_isec;
root_isec = backing_inode_security(sb->s_root); if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
opts->rootcontext_sid)) return 1;
} if (opts->defcontext_sid) { if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
opts->defcontext_sid)) return 1;
} return 0;
}
/* * Ensure that fc->security remains NULL when no options are set * as expected by selinux_set_mnt_opts().
*/ if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT))) return 0;
opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return -ENOMEM;
if (sbsec->flags & FSCONTEXT_MNT)
opts->fscontext_sid = sbsec->sid; if (sbsec->flags & CONTEXT_MNT)
opts->context_sid = sbsec->mntpoint_sid; if (sbsec->flags & DEFCONTEXT_MNT)
opts->defcontext_sid = sbsec->def_sid;
fc->security = opts; return 0;
}
isec->initialized = LABEL_INITIALIZED; /* * Now that we've initialized security, check whether we're * allowed to actually create this type of anonymous inode.
*/
/** * task_avdcache_reset - Reset the task's AVD cache * @tsec: the task's security state * * Clear the task's AVD cache in @tsec and reset it to the current policy's * and task's info.
*/ staticinlinevoid task_avdcache_reset(struct task_security_struct *tsec)
{
memset(&tsec->avdcache.dir, 0, sizeof(tsec->avdcache.dir));
tsec->avdcache.sid = tsec->sid;
tsec->avdcache.seqno = avc_policy_seqno();
tsec->avdcache.dir_spot = TSEC_AVDC_DIR_SIZE - 1;
}
/** * task_avdcache_search - Search the task's AVD cache * @tsec: the task's security state * @isec: the inode to search for in the cache * @avdc: matching avd cache entry returned to the caller * * Search @tsec for a AVD cache entry that matches @isec and return it to the * caller via @avdc. Returns 0 if a match is found, negative values otherwise.
*/ staticinlineint task_avdcache_search(struct task_security_struct *tsec, struct inode_security_struct *isec, struct avdc_entry **avdc)
{ int orig, iter;
/* focused on path walk optimization, only cache directories */ if (isec->sclass != SECCLASS_DIR) return -ENOENT;
orig = iter = tsec->avdcache.dir_spot; do { if (tsec->avdcache.dir[iter].isid == isec->sid) { /* cache hit */
tsec->avdcache.dir_spot = iter;
*avdc = &tsec->avdcache.dir[iter]; return 0;
}
iter = (iter - 1) & (TSEC_AVDC_DIR_SIZE - 1);
} while (iter != orig);
return -ENOENT;
}
/** * task_avdcache_update - Update the task's AVD cache * @tsec: the task's security state * @isec: the inode associated with the cache entry * @avd: the AVD to cache * @audited: the permission audit bitmask to cache * * Update the AVD cache in @tsec with the @avdc and @audited info associated * with @isec.
*/ staticinlinevoid task_avdcache_update(struct task_security_struct *tsec, struct inode_security_struct *isec, struct av_decision *avd,
u32 audited)
{ int spot;
/* focused on path walk optimization, only cache directories */ if (isec->sclass != SECCLASS_DIR) return;
/** * selinux_inode_permission - Check if the current task can access an inode * @inode: the inode that is being accessed * @requested: the accesses being requested * * Check if the current task is allowed to access @inode according to * @requested. Returns 0 if allowed, negative values otherwise.
*/ staticint selinux_inode_permission(struct inode *inode, int requested)
{ int mask;
u32 perms; struct task_security_struct *tsec; struct inode_security_struct *isec; struct avdc_entry *avdc; int rc, rc2;
u32 audited, denied;
/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ if (ia_valid & ATTR_FORCE) {
ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
ATTR_FORCE); if (!ia_valid) return 0;
}
if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts)) returnfalse; if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true)) returnfalse; returntrue;
}
/** * selinux_inode_xattr_skipcap - Skip the xattr capability checks? * @name: name of the xattr * * Returns 1 to indicate that SELinux "owns" the access control rights to xattrs * named @name; the LSM layer should avoid enforcing any traditional * capability based access controls on this xattr. Returns 0 to indicate that * SELinux does not "own" the access control rights to xattrs named @name and is * deferring to the LSM layer for further access controls, including capability * based controls.
*/ staticint selinux_inode_xattr_skipcap(constchar *name)
{ /* require capability check if not a selinux xattr */ return !strcmp(name, XATTR_NAME_SELINUX);
}
/* if not a selinux xattr, only check the ordinary setattr perm */ if (strcmp(name, XATTR_NAME_SELINUX)) return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
if (!selinux_initialized()) return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM);
sbsec = selinux_superblock(inode->i_sb); if (!(sbsec->flags & SBLABEL_MNT)) return -EOPNOTSUPP;
if (!inode_owner_or_capable(idmap, inode)) return -EPERM;
if (strcmp(name, XATTR_NAME_SELINUX)) { /* Not an attribute we recognize, so nothing to do. */ return;
}
if (!selinux_initialized()) { /* If we haven't even been initialized, then we can't validate * against a policy, so leave the label as invalid. It may * resolve to a valid label on the next revalidation try if * we've since initialized.
*/ return;
}
rc = security_context_to_sid_force(value, size,
&newsid); if (rc) {
pr_err("SELinux: unable to map context to SID" "for (%s, %lu), rc=%d\n",
inode->i_sb->s_id, inode->i_ino, -rc); return;
}
staticint selinux_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry, constchar *name)
{ /* if not a selinux xattr, only check the ordinary setattr perm */ if (strcmp(name, XATTR_NAME_SELINUX)) return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
if (!selinux_initialized()) return 0;
/* No one is allowed to remove a SELinux security label.
You can change the label, but all data must be labeled. */ return -EACCES;
}
/* * Set permission needed based on the type of mark being set. * Performs an additional check for sb watches.
*/ switch (obj_type) { case FSNOTIFY_OBJ_TYPE_VFSMOUNT:
perm = FILE__WATCH_MOUNT; break; case FSNOTIFY_OBJ_TYPE_SB:
perm = FILE__WATCH_SB;
ret = superblock_has_perm(current_cred(), path->dentry->d_sb,
FILESYSTEM__WATCH, &ad); if (ret) return ret; break; case FSNOTIFY_OBJ_TYPE_INODE:
perm = FILE__WATCH; break; case FSNOTIFY_OBJ_TYPE_MNTNS:
perm = FILE__WATCH_MOUNTNS; break; default: return -EINVAL;
}
/* blocking watches require the file:watch_with_perm permission */ if (mask & (ALL_FSNOTIFY_PERM_EVENTS))
perm |= FILE__WATCH_WITH_PERM;
/* watches on read-like events need the file:watch_reads permission */ if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_PRE_ACCESS |
FS_CLOSE_NOWRITE))
perm |= FILE__WATCH_READS;
/* * Copy the inode security context value to the user. * * Permission check is handled by selinux_inode_getxattr hook.
*/ staticint selinux_inode_getsecurity(struct mnt_idmap *idmap, struct inode *inode, constchar *name, void **buffer, bool alloc)
{
u32 size; int error; char *context = NULL; struct inode_security_struct *isec;
/* * If we're not initialized yet, then we can't validate contexts, so * just let vfs_getxattr fall back to using the on-disk xattr.
*/ if (!selinux_initialized() ||
strcmp(name, XATTR_SELINUX_SUFFIX)) return -EOPNOTSUPP;
/* * If the caller has CAP_MAC_ADMIN, then get the raw context * value even if it is not defined by current policy; otherwise, * use the in-core value under current policy. * Use the non-auditing forms of the permission checks since * getxattr may be called by unprivileged processes commonly * and lack of permission just means that we fall back to the * in-core context value, not a denial.
*/
isec = inode_security(inode); if (has_cap_mac_admin(false))
error = security_sid_to_context_force(isec->sid, &context,
&size); else
error = security_sid_to_context(isec->sid,
&context, &size); if (error) return error;
error = size; if (alloc) {
*buffer = context; goto out_nofree;
}
kfree(context);
out_nofree: return error;
}
if (new_creds == NULL) {
new_creds = prepare_creds(); if (!new_creds) return -ENOMEM;
}
tsec = selinux_cred(new_creds); /* Get label from overlay inode and set it in create_sid */
selinux_inode_getlsmprop(d_inode(src), &prop);
tsec->create_sid = prop.selinux.secid;
*new = new_creds; return 0;
}
staticint selinux_inode_copy_up_xattr(struct dentry *dentry, constchar *name)
{ /* The copy_up hook above sets the initial context on an inode, but we * don't then want to overwrite it by blindly copying all the lower * xattrs up. Instead, filter out SELinux-related xattrs following * policy load.
*/ if (selinux_initialized() && !strcmp(name, XATTR_NAME_SELINUX)) return -ECANCELED; /* Discard */ /* * Any other attribute apart from SELINUX is not claimed, supported * by selinux.
*/ return -EOPNOTSUPP;
}
switch (cmd) { case FIONREAD: case FIBMAP: case FIGETBSZ: case FS_IOC_GETFLAGS: case FS_IOC_GETVERSION:
error = file_has_perm(cred, file, FILE__GETATTR); break;
case FS_IOC_SETFLAGS: case FS_IOC_SETVERSION:
error = file_has_perm(cred, file, FILE__SETATTR); break;
/* sys_ioctl() checks */ case FIONBIO: case FIOASYNC:
error = file_has_perm(cred, file, 0); break;
case KDSKBENT: case KDSKBSENT:
error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
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.
*/ default:
error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
} return error;
}
staticint selinux_file_ioctl_compat(struct file *file, unsignedint cmd, unsignedlong arg)
{ /* * If we are in a 64-bit kernel running 32-bit userspace, we need to * make sure we don't compare 32-bit flags to 64-bit flags.
*/ switch (cmd) { case FS_IOC32_GETFLAGS:
cmd = FS_IOC_GETFLAGS; break; case FS_IOC32_SETFLAGS:
cmd = FS_IOC_SETFLAGS; break; case FS_IOC32_GETVERSION:
cmd = FS_IOC_GETVERSION; break; case FS_IOC32_SETVERSION:
cmd = FS_IOC_SETVERSION; break; default: break;
}
if (default_noexec &&
(prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) ||
(!shared && (prot & PROT_WRITE)))) { /* * We are making executable an anonymous mapping or a * private file mapping that will also be writable. * This has an additional check.
*/
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECMEM, NULL); if (rc) goto error;
}
if (file) { /* read access is always possible with a mapping */
u32 av = FILE__READ;
/* write access only matters if the mapping is shared */ if (shared && (prot & PROT_WRITE))
av |= FILE__WRITE;
if (prot & PROT_EXEC)
av |= FILE__EXECUTE;
return file_has_perm(cred, file, av);
}
error: return rc;
}
staticint selinux_mmap_addr(unsignedlong addr)
{ int rc = 0;
if (default_noexec &&
(prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { int rc = 0; /* * We don't use the vma_is_initial_heap() helper as it has * a history of problems and is currently broken on systems * where there is no heap, e.g. brk == start_brk. Before * replacing the conditional below with vma_is_initial_heap(), * or something similar, please ensure that the logic is the * same as what we have below or you have tested every possible * corner case you can think to test.
*/ if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL);
} elseif (!vma->vm_file && (vma_is_initial_stack(vma) ||
vma_is_stack_for_current(vma))) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECSTACK, NULL);
} elseif (vma->vm_file && vma->anon_vma) { /* * We are making executable a file mapping that has * had some COW done. Since pages might have been * written, check ability to execute the possibly * modified content. This typically should only * occur for text relocations.
*/
rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
} if (rc) return rc;
}
switch (cmd) { case F_SETFL: if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
err = file_has_perm(cred, file, FILE__WRITE); break;
}
fallthrough; case F_SETOWN: case F_SETSIG: case F_GETFL: case F_GETOWN: case F_GETSIG: case F_GETOWNER_UIDS: /* Just check FD__USE permission */
err = file_has_perm(cred, file, 0); break; case F_GETLK: case F_SETLK: case F_SETLKW: case F_OFD_GETLK: case F_OFD_SETLK: case F_OFD_SETLKW: #if BITS_PER_LONG == 32 case F_GETLK64: case F_SETLK64: case F_SETLKW64: #endif
err = file_has_perm(cred, file, FILE__LOCK); break;
}
fsec = selinux_file(file);
isec = inode_security(file_inode(file)); /* * Save inode label and policy sequence number * at open-time so that selinux_file_permission * can determine whether revalidation is necessary. * Task label is already saved in the file security * struct as its SID.
*/
fsec->isid = isec->sid;
fsec->pseqno = avc_policy_seqno(); /* * Since the inode label or policy seqno may have changed * between the selinux_inode_permission check and the saving * of state above, recheck that access is still permitted. * Otherwise, access might never be revalidated against the * new inode label or new policy. * This check is not redundant - do not remove.
*/ return file_path_has_perm(file->f_cred, file, open_file_to_av(file));
}
/* * prepare a new set of credentials for modification
*/ staticint selinux_cred_prepare(struct cred *new, conststruct cred *old,
gfp_t gfp)
{ conststruct task_security_struct *old_tsec = selinux_cred(old); struct task_security_struct *tsec = selinux_cred(new);
*tsec = *old_tsec; return 0;
}
/* * transfer the SELinux data to a blank set of creds
*/ staticvoid selinux_cred_transfer(struct cred *new, conststruct cred *old)
{ conststruct task_security_struct *old_tsec = selinux_cred(old); struct task_security_struct *tsec = selinux_cred(new);
/* * set the security data for a kernel service * - all the creation contexts are set to unlabelled
*/ staticint selinux_kernel_act_as(struct cred *new, u32 secid)
{ struct task_security_struct *tsec = selinux_cred(new);
u32 sid = current_sid(); int ret;
/* * set the file creation context in a security record to the same as the * objective context of the specified inode
*/ staticint selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
{ struct inode_security_struct *isec = inode_security(inode); struct task_security_struct *tsec = selinux_cred(new);
u32 sid = current_sid(); int ret;
ret = avc_has_perm(sid, isec->sid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__CREATE_FILES_AS,
NULL);
if (ret == 0)
tsec->create_sid = isec->sid; return ret;
}
if (!flags) return 0; if (flags & LSM_PRLIMIT_WRITE)
av |= PROCESS__SETRLIMIT; if (flags & LSM_PRLIMIT_READ)
av |= PROCESS__GETRLIMIT; return avc_has_perm(cred_sid(cred), cred_sid(tcred),
SECCLASS_PROCESS, av, NULL);
}
/* Control the ability to change the hard limit (whether lowering or raising it), so that the hard limit can later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */ if (old_rlim->rlim_max != new_rlim->rlim_max) return avc_has_perm(current_sid(), task_sid_obj(p),
SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
parse_error:
pr_warn( "SELinux: failure in selinux_parse_skb()," " unable to parse packet\n"); return ret;
okay: if (_addrp)
*_addrp = addrp; return 0;
}
/** * selinux_skb_peerlbl_sid - Determine the peer label of a packet * @skb: the packet * @family: protocol family * @sid: the packet's peer label SID * * Description: * Check the various different forms of network peer labeling and determine * the peer label/SID for the packet; most of the magic actually occurs in * the security server function security_net_peersid_cmp(). The function * returns zero if the value in @sid is valid (although it may be SECSID_NULL) * or -EACCES if @sid is invalid due to inconsistencies with the different * peer labels. *
*/ staticint selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
{ int err;
u32 xfrm_sid;
u32 nlbl_sid;
u32 nlbl_type;
err = selinux_xfrm_skb_sid(skb, &xfrm_sid); if (unlikely(err)) return -EACCES;
err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); if (unlikely(err)) return -EACCES;
err = security_net_peersid_resolve(nlbl_sid,
nlbl_type, xfrm_sid, sid); if (unlikely(err)) {
pr_warn( "SELinux: failure in selinux_skb_peerlbl_sid()," " unable to determine packet's peer label\n"); return -EACCES;
}
return 0;
}
/** * selinux_conn_sid - Determine the child socket label for a connection * @sk_sid: the parent socket's SID * @skb_sid: the packet's SID * @conn_sid: the resulting connection SID * * If @skb_sid is valid then the user:role:type information from @sk_sid is * combined with the MLS information from @skb_sid in order to create * @conn_sid. If @skb_sid is not valid then @conn_sid is simply a copy * of @sk_sid. Returns zero on success, negative values on failure. *
*/ staticint selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
{ int err = 0;
staticbool sock_skip_has_perm(u32 sid)
{ if (sid == SECINITSID_KERNEL) returntrue;
/* * Before POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT, sockets that * inherited the kernel context from early boot used to be skipped * here, so preserve that behavior unless the capability is set. * * By setting the capability the policy signals that it is ready * for this quirk to be fixed. Note that sockets created by a kernel * thread or a usermode helper executed without a transition will * still be skipped in this check regardless of the policycap * setting.
*/ if (!selinux_policycap_userspace_initial_context() &&
sid == SECINITSID_INIT) returntrue; returnfalse;
}
if (sock->sk) {
sksec = selinux_sock(sock->sk);
sksec->sclass = sclass;
sksec->sid = sid; /* Allows detection of the first association on this socket */ if (sksec->sclass == SECCLASS_SCTP_SOCKET)
sksec->sctp_assoc_state = SCTP_ASSOC_UNSET;
/* Range of port numbers used to automatically bind. Need to determine whether we should perform a name_bind
permission check between the socket and the port number. */
err = sock_has_perm(sk, SOCKET__BIND); if (err) goto out;
/* If PF_INET or PF_INET6, check name_bind permission for the port. */
family = sk->sk_family; if (family == PF_INET || family == PF_INET6) { char *addrp; struct common_audit_data ad; struct lsm_network_audit net = {0,}; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL;
u16 family_sa; unsignedshort snum;
u32 sid, node_perm;
/* * sctp_bindx(3) calls via selinux_sctp_bind_connect() * that validates multiple binding addresses. Because of this * need to check address->sa_family as it is possible to have * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
*/ if (addrlen < offsetofend(struct sockaddr, sa_family)) return -EINVAL;
family_sa = address->sa_family; switch (family_sa) { case AF_UNSPEC: case AF_INET: if (addrlen < sizeof(struct sockaddr_in)) return -EINVAL;
addr4 = (struct sockaddr_in *)address; if (family_sa == AF_UNSPEC) { if (family == PF_INET6) { /* Length check from inet6_bind_sk() */ if (addrlen < SIN6_LEN_RFC2133) return -EINVAL; /* Family check from __inet6_bind() */ goto err_af;
} /* see __inet_bind(), we only want to allow * AF_UNSPEC if the address is INADDR_ANY
*/ if (addr4->sin_addr.s_addr != htonl(INADDR_ANY)) goto err_af;
family_sa = AF_INET;
}
snum = ntohs(addr4->sin_port);
addrp = (char *)&addr4->sin_addr.s_addr; break; case AF_INET6: if (addrlen < SIN6_LEN_RFC2133) return -EINVAL;
addr6 = (struct sockaddr_in6 *)address;
snum = ntohs(addr6->sin6_port);
addrp = (char *)&addr6->sin6_addr.s6_addr; break; default: goto err_af;
}
/* This supports connect(2) and SCTP connect services such as sctp_connectx(3) * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst
*/ staticint selinux_socket_connect_helper(struct socket *sock, struct sockaddr *address, int addrlen)
{ struct sock *sk = sock->sk; struct sk_security_struct *sksec = selinux_sock(sk); int err;
err = sock_has_perm(sk, SOCKET__CONNECT); if (err) return err; if (addrlen < offsetofend(struct sockaddr, sa_family)) return -EINVAL;
/* connect(AF_UNSPEC) has special handling, as it is a documented * way to disconnect the socket
*/ if (address->sa_family == AF_UNSPEC) return 0;
/* * If a TCP or SCTP socket, check name_connect permission * for the port.
*/ if (sksec->sclass == SECCLASS_TCP_SOCKET ||
sksec->sclass == SECCLASS_SCTP_SOCKET) { struct common_audit_data ad; struct lsm_network_audit net = {0,}; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; unsignedshort snum;
u32 sid, perm;
/* sctp_connectx(3) calls via selinux_sctp_bind_connect() * that validates multiple connect addresses. Because of this * need to check address->sa_family as it is possible to have * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
*/ switch (address->sa_family) { case AF_INET:
addr4 = (struct sockaddr_in *)address; if (addrlen < sizeof(struct sockaddr_in)) return -EINVAL;
snum = ntohs(addr4->sin_port); break; case AF_INET6:
addr6 = (struct sockaddr_in6 *)address; if (addrlen < SIN6_LEN_RFC2133) return -EINVAL;
snum = ntohs(addr6->sin6_port); break; default: /* Note that SCTP services expect -EINVAL, whereas * others expect -EAFNOSUPPORT.
*/ if (sksec->sclass == SECCLASS_SCTP_SOCKET) return -EINVAL; else return -EAFNOSUPPORT;
}
err = sel_netport_sid(sk->sk_protocol, snum, &sid); if (err) return err;
switch (sksec->sclass) { case SECCLASS_TCP_SOCKET:
perm = TCP_SOCKET__NAME_CONNECT; break; case SECCLASS_SCTP_SOCKET:
perm = SCTP_SOCKET__NAME_CONNECT; break;
}
if (family != PF_INET && family != PF_INET6) return 0;
/* Handle mapped IPv4 packets arriving via IPv6 sockets */ if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
family = PF_INET;
/* If any sort of compatibility mode is enabled then handoff processing * to the selinux_sock_rcv_skb_compat() function to deal with the * special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */ if (!selinux_policycap_netpeer()) return selinux_sock_rcv_skb_compat(sk, skb, family);
/* * Determines peer_secid for the asoc and updates socket's peer label * if it's the first association on the socket.
*/ staticint selinux_sctp_process_new_assoc(struct sctp_association *asoc, struct sk_buff *skb)
{ struct sock *sk = asoc->base.sk;
u16 family = sk->sk_family; struct sk_security_struct *sksec = selinux_sock(sk); struct common_audit_data ad; struct lsm_network_audit net; int err;
/* handle mapped IPv4 packets arriving via IPv6 sockets */ if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
family = PF_INET;
if (selinux_peerlbl_enabled()) {
asoc->peer_secid = SECSID_NULL;
/* This will return peer_sid = SECSID_NULL if there are * no peer labels, see security_net_peersid_resolve().
*/
err = selinux_skb_peerlbl_sid(skb, family, &asoc->peer_secid); if (err) return err;
if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
sksec->sctp_assoc_state = SCTP_ASSOC_SET;
/* Here as first association on socket. As the peer SID * was allowed by peer recv (and the netif/node checks), * then it is approved by policy and used as the primary * peer SID for getpeercon(3).
*/
sksec->peer_sid = asoc->peer_secid;
} elseif (sksec->peer_sid != asoc->peer_secid) { /* Other association peer SIDs are checked to enforce * consistency among the peer SIDs.
*/
ad_net_init_from_sk(&ad, &net, asoc->base.sk);
err = avc_has_perm(sksec->peer_sid, asoc->peer_secid,
sksec->sclass, SCTP_SOCKET__ASSOCIATION,
&ad); if (err) return err;
} return 0;
}
/* Called whenever SCTP receives an INIT or COOKIE ECHO chunk. This * happens on an incoming connect(2), sctp_connectx(3) or * sctp_sendmsg(3) (with no association already present).
*/ staticint selinux_sctp_assoc_request(struct sctp_association *asoc, struct sk_buff *skb)
{ struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
u32 conn_sid; int err;
if (!selinux_policycap_extsockclass()) return 0;
err = selinux_sctp_process_new_assoc(asoc, skb); if (err) return err;
/* Compute the MLS component for the connection and store * the information in asoc. This will be used by SCTP TCP type * sockets and peeled off connections as they cause a new * socket to be generated. selinux_sctp_sk_clone() will then * plug this into the new socket.
*/
err = selinux_conn_sid(sksec->sid, asoc->peer_secid, &conn_sid); if (err) return err;
asoc->secid = conn_sid;
/* Set any NetLabel labels including CIPSO/CALIPSO options. */ return selinux_netlbl_sctp_assoc_request(asoc, skb);
}
/* Called when SCTP receives a COOKIE ACK chunk as the final * response to an association request (initited by us).
*/ staticint selinux_sctp_assoc_established(struct sctp_association *asoc, struct sk_buff *skb)
{ struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
if (!selinux_policycap_extsockclass()) return 0;
/* Inherit secid from the parent socket - this will be picked up * by selinux_sctp_sk_clone() if the association gets peeled off * into a new socket.
*/
asoc->secid = sksec->sid;
/* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting * based on their @optname.
*/ staticint selinux_sctp_bind_connect(struct sock *sk, int optname, struct sockaddr *address, int addrlen)
{ int len, err = 0, walk_size = 0; void *addr_buf; struct sockaddr *addr; struct socket *sock;
if (!selinux_policycap_extsockclass()) return 0;
/* Process one or more addresses that may be IPv4 or IPv6 */
sock = sk->sk_socket;
addr_buf = address;
while (walk_size < addrlen) { if (walk_size + sizeof(sa_family_t) > addrlen) return -EINVAL;
addr = addr_buf; switch (addr->sa_family) { case AF_UNSPEC: case AF_INET:
len = sizeof(struct sockaddr_in); break; case AF_INET6:
len = sizeof(struct sockaddr_in6); break; default: return -EINVAL;
}
if (walk_size + len > addrlen) return -EINVAL;
err = -EINVAL; switch (optname) { /* Bind checks */ case SCTP_PRIMARY_ADDR: case SCTP_SET_PEER_PRIMARY_ADDR: case SCTP_SOCKOPT_BINDX_ADD:
err = selinux_socket_bind(sock, addr, len); break; /* Connect checks */ case SCTP_SOCKOPT_CONNECTX: case SCTP_PARAM_SET_PRIMARY: case SCTP_PARAM_ADD_IP: case SCTP_SENDMSG_CONNECT:
err = selinux_socket_connect_helper(sock, addr, len); if (err) return err;
/* As selinux_sctp_bind_connect() is called by the * SCTP protocol layer, the socket is already locked, * therefore selinux_netlbl_socket_connect_locked() * is called here. The situations handled are: * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2), * whenever a new IP address is added or when a new * primary address is selected. * Note that an SCTP connect(2) call happens before * the SCTP protocol layer and is handled via * selinux_socket_connect().
*/
err = selinux_netlbl_socket_connect_locked(sk, addr); break;
}
if (err) return err;
addr_buf += len;
walk_size += len;
}
return 0;
}
/* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */ staticvoid selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk, struct sock *newsk)
{ struct sk_security_struct *sksec = selinux_sock(sk); struct sk_security_struct *newsksec = selinux_sock(newsk);
/* If policy does not support SECCLASS_SCTP_SOCKET then call * the non-sctp clone version.
*/ if (!selinux_policycap_extsockclass()) return selinux_sk_clone_security(sk, newsk);
/* replace the existing subflow label deleting the existing one * and re-recreating a new label using the updated context
*/
selinux_netlbl_sk_security_free(ssksec); return selinux_netlbl_socket_post_create(ssk, ssk->sk_family);
}
newsksec->sid = req->secid;
newsksec->peer_sid = req->peer_secid; /* NOTE: Ideally, we should also get the isec->sid for the new socket in sync, but we don't have the isec available yet. So we will wait until sock_graft to do it, by which
time it will have been created and available. */
/* We don't need to take any sort of lock here as we are the only
* thread with access to newsksec */
selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
}
/* we aren't taking into account the "sockcreate" SID since the socket * that is being created here is not a socket in the traditional sense, * instead it is a private sock, accessible only to the kernel, and * representing a wide range of network traffic spanning multiple * connections unlike traditional sockets - check the TUN driver to
* get a better understanding of why this socket is special */
/* we don't currently perform any NetLabel based labeling here and it * isn't clear that we would want to do so anyway; while we could apply * labeling without the support of the TUN user the resulting labeled * traffic from the other end of the connection would almost certainly * cause confusion to the TUN user that had no idea network labeling
* protocols were being used */
if (secmark_active) if (avc_has_perm(peer_sid, skb->secmark,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) return NF_DROP;
if (netlbl_enabled()) /* we do this in the FORWARD path and not the POST_ROUTING * path because we want to make sure we apply the necessary * labeling before IPsec is applied so we can leverage AH
* protection */ if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) return NF_DROP;
/* we do this in the LOCAL_OUT path and not the POST_ROUTING path * because we want to make sure we apply the necessary labeling
* before IPsec is applied so we can leverage AH protection */
sk = sk_to_full_sk(skb->sk); if (sk) { struct sk_security_struct *sksec;
if (sk_listener(sk)) /* if the socket is the listening state then this * packet is a SYN-ACK packet which means it needs to * be labeled based on the connection/request_sock and * not the parent socket. unfortunately, we can't * lookup the request_sock yet as it isn't queued on * the parent socket until after the SYN-ACK is sent. * the "solution" is to simply pass the packet as-is * as any IP option based labeling should be copied * from the initial connection request (in the IP * layer). it is far from ideal, but until we get a * security label in the packet itself this is the
* best we can do. */ return NF_ACCEPT;
/* standard practice, label using the parent socket */
sksec = selinux_sock(sk);
sid = sksec->sid;
} else
sid = SECINITSID_KERNEL; if (selinux_netlbl_skbuff_setsid(skb, state->pf, sid) != 0) return NF_DROP;
/* If any sort of compatibility mode is enabled then handoff processing * to the selinux_ip_postroute_compat() function to deal with the * special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */ if (!selinux_policycap_netpeer()) return selinux_ip_postroute_compat(skb, state);
#ifdef CONFIG_XFRM /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec * packet transformation so allow the packet to pass without any checks * since we'll have another chance to perform access control checks * when the packet is on it's final way out. * NOTE: there appear to be some IPv6 multicast cases where skb->dst * is NULL, in this case go ahead and apply access control. * NOTE: if this is a local socket (skb->sk != NULL) that is in the * TCP listening state we cannot wait until the XFRM processing * is done as we will miss out on the SA label if we do; * unfortunately, this means more work, but it is only once per
* connection. */ if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
!(sk && sk_listener(sk))) return NF_ACCEPT; #endif
family = state->pf; if (sk == NULL) { /* Without an associated socket the packet is either coming * from the kernel or it is being forwarded; check the packet * to determine which and if the packet is being forwarded
* query the packet directly to determine the security label. */ if (skb->skb_iif) {
secmark_perm = PACKET__FORWARD_OUT; if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) return NF_DROP;
} else {
secmark_perm = PACKET__SEND;
peer_sid = SECINITSID_KERNEL;
}
} elseif (sk_listener(sk)) { /* Locally generated packet but the associated socket is in the * listening state which means this is a SYN-ACK packet. In * this particular case the correct security label is assigned * to the connection/request_sock but unfortunately we can't * query the request_sock as it isn't queued on the parent * socket until after the SYN-ACK packet is sent; the only * viable choice is to regenerate the label like we do in * selinux_inet_conn_request(). See also selinux_ip_output()
* for similar problems. */
u32 skb_sid; struct sk_security_struct *sksec;
sksec = selinux_sock(sk); if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) return NF_DROP; /* At this point, if the returned skb peerlbl is SECSID_NULL * and the packet has been through at least one XFRM * transformation then we must be dealing with the "final" * form of labeled IPsec packet; since we've already applied * all of our access controls on this packet we can safely
* pass the packet. */ if (skb_sid == SECSID_NULL) { switch (family) { case PF_INET: if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) return NF_ACCEPT; break; case PF_INET6: if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) return NF_ACCEPT; break; default: return NF_DROP_ERR(-ECONNREFUSED);
}
} if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid)) return NF_DROP;
secmark_perm = PACKET__SEND;
} else { /* Locally generated packet, fetch the security label from the
* associated socket. */ struct sk_security_struct *sksec = selinux_sock(sk);
peer_sid = sksec->sid;
secmark_perm = PACKET__SEND;
}
while (data_len >= nlmsg_total_size(0)) {
nlh = (struct nlmsghdr *)data;
/* NOTE: the nlmsg_len field isn't reliably set by some netlink * users which means we can't reject skb's with bogus * length fields; our solution is to follow what * netlink_rcv_skb() does and simply skip processing at * messages with length fields that are clearly junk
*/ if (nlh->nlmsg_len < NLMSG_HDRLEN || nlh->nlmsg_len > data_len) return 0;
/* move to the next message after applying netlink padding */
msg_len = NLMSG_ALIGN(nlh->nlmsg_len); if (msg_len >= data_len) return 0;
data_len -= msg_len;
data += msg_len;
}
staticint selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
{
u32 perms;
switch (cmd) { case IPC_INFO: case MSG_INFO: /* No specific object, just general system-wide information. */ return avc_has_perm(current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case IPC_STAT: case MSG_STAT: case MSG_STAT_ANY:
perms = MSGQ__GETATTR | MSGQ__ASSOCIATE; break; case IPC_SET:
perms = MSGQ__SETATTR; break; case IPC_RMID:
perms = MSGQ__DESTROY; break; default: return 0;
}
/* * First time through, need to assign label to the message
*/ if (msec->sid == SECINITSID_UNLABELED) { /* * Compute new sid based on current process and * message queue this message will be stored in
*/
rc = security_transition_sid(sid, isec->sid,
SECCLASS_MSG, NULL, &msec->sid); if (rc) return rc;
}
/* Can this process write to the queue? */
rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
MSGQ__WRITE, &ad); if (!rc) /* Can this process send the message */
rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
MSG__SEND, &ad); if (!rc) /* Can the message be put in the queue? */
rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ENQUEUE, &ad);
return rc;
}
staticint selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg, struct task_struct *target, long type, int mode)
{ struct ipc_security_struct *isec; struct msg_security_struct *msec; struct common_audit_data ad;
u32 sid = task_sid_obj(target); int rc;
/* Note, at this point, shp is locked down */ staticint selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
{
u32 perms;
switch (cmd) { case IPC_INFO: case SHM_INFO: /* No specific object, just general system-wide information. */ return avc_has_perm(current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case IPC_STAT: case SHM_STAT: case SHM_STAT_ANY:
perms = SHM__GETATTR | SHM__ASSOCIATE; break; case IPC_SET:
perms = SHM__SETATTR; break; case SHM_LOCK: case SHM_UNLOCK:
perms = SHM__LOCK; break; case IPC_RMID:
perms = SHM__DESTROY; break; default: return 0;
}
/* Note, at this point, sma is locked down */ staticint selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
{ int err;
u32 perms;
switch (cmd) { case IPC_INFO: case SEM_INFO: /* No specific object, just general system-wide information. */ return avc_has_perm(current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case GETPID: case GETNCNT: case GETZCNT:
perms = SEM__GETATTR; break; case GETVAL: case GETALL:
perms = SEM__READ; break; case SETVAL: case SETALL:
perms = SEM__WRITE; break; case IPC_RMID:
perms = SEM__DESTROY; break; case IPC_SET:
perms = SEM__SETATTR; break; case IPC_STAT: case SEM_STAT: case SEM_STAT_ANY:
perms = SEM__GETATTR | SEM__ASSOCIATE; break; default: return 0;
}
/* * Basic control over ability to set these attributes at all.
*/ switch (attr) { case LSM_ATTR_EXEC:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETEXEC, NULL); break; case LSM_ATTR_FSCREATE:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETFSCREATE, NULL); break; case LSM_ATTR_KEYCREATE:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETKEYCREATE, NULL); break; case LSM_ATTR_SOCKCREATE:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETSOCKCREATE, NULL); break; case LSM_ATTR_CURRENT:
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETCURRENT, NULL); break; default:
error = -EOPNOTSUPP; break;
} if (error) return error;
/* Obtain a SID for the context, if one was specified. */ if (size && str[0] && str[0] != '\n') { if (str[size-1] == '\n') {
str[size-1] = 0;
size--;
}
error = security_context_to_sid(value, size,
&sid, GFP_KERNEL); if (error == -EINVAL && attr == LSM_ATTR_FSCREATE) { if (!has_cap_mac_admin(true)) { struct audit_buffer *ab;
size_t audit_size;
/* We strip a nul only if it is at the end, * otherwise the context contains a nul and
* we should audit that */ if (str[size - 1] == '\0')
audit_size = size - 1; else
audit_size = size;
ab = audit_log_start(audit_context(),
GFP_ATOMIC,
AUDIT_SELINUX_ERR); if (!ab) return error;
audit_log_format(ab, "op=fscreate invalid_context=");
audit_log_n_untrustedstring(ab, value,
audit_size);
audit_log_end(ab);
/* Permission checking based on the specified context is performed during the actual operation (execve, open/mkdir/...), when we know the full context of the operation. See selinux_bprm_creds_for_exec for the execve checks and may_create for the file creation checks. The
operation will then fail if the context is not permitted. */
tsec = selinux_cred(new); if (attr == LSM_ATTR_EXEC) {
tsec->exec_sid = sid;
} elseif (attr == LSM_ATTR_FSCREATE) {
tsec->create_sid = sid;
} elseif (attr == LSM_ATTR_KEYCREATE) { if (sid) {
error = avc_has_perm(mysid, sid,
SECCLASS_KEY, KEY__CREATE, NULL); if (error) goto abort_change;
}
tsec->keycreate_sid = sid;
} elseif (attr == LSM_ATTR_SOCKCREATE) {
tsec->sockcreate_sid = sid;
} elseif (attr == LSM_ATTR_CURRENT) {
error = -EINVAL; if (sid == 0) goto abort_change;
if (!current_is_single_threaded()) {
error = security_bounded_transition(tsec->sid, sid); if (error) goto abort_change;
}
/* Check permissions for the transition. */
error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
PROCESS__DYNTRANSITION, NULL); if (error) goto abort_change;
/* Check for ptracing, and update the task SID if ok.
Otherwise, leave SID unchanged and fail. */
ptsid = ptrace_parent_sid(); if (ptsid != 0) {
error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
PROCESS__PTRACE, NULL); if (error) goto abort_change;
}
/** * selinux_getselfattr - Get SELinux current task attributes * @attr: the requested attribute * @ctx: buffer to receive the result * @size: buffer size (input), buffer size used (output) * @flags: unused * * Fill the passed user space @ctx with the details of the requested * attribute. * * Returns the number of attributes on success, an error code otherwise. * There will only ever be one attribute.
*/ staticint selinux_getselfattr(unsignedint attr, struct lsm_ctx __user *ctx,
u32 *size, u32 flags)
{ int rc; char *val = NULL; int val_len;
#ifdef CONFIG_BPF_SYSCALL staticint selinux_bpf(int cmd, union bpf_attr *attr, unsignedint size, bool kernel)
{
u32 sid = current_sid(); int ret;
switch (cmd) { case BPF_MAP_CREATE:
ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
NULL); break; case BPF_PROG_LOAD:
ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
NULL); break; default:
ret = 0; break;
}
return ret;
}
static u32 bpf_map_fmode_to_av(fmode_t fmode)
{
u32 av = 0;
if (fmode & FMODE_READ)
av |= BPF__MAP_READ; if (fmode & FMODE_WRITE)
av |= BPF__MAP_WRITE; return av;
}
/* This function will check the file pass through unix socket or binder to see * if it is a bpf related object. And apply corresponding checks on the bpf * object based on the type. The bpf maps and programs, not like other files and * socket, are using a shared anonymous inode inside the kernel as their inode. * So checking that inode cannot identify if the process have privilege to * access the bpf object and that's why we have to add this additional check in * selinux_file_receive and selinux_binder_transfer_files.
*/ staticint bpf_fd_pass(conststruct file *file, u32 sid)
{ struct bpf_security_struct *bpfsec; struct bpf_prog *prog; struct bpf_map *map; int ret;
if (file->f_op == &bpf_map_fops) {
map = file->private_data;
bpfsec = map->security;
ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(file->f_mode), NULL); if (ret) return ret;
} elseif (file->f_op == &bpf_prog_fops) {
prog = file->private_data;
bpfsec = prog->aux->security;
ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL); if (ret) return ret;
} return 0;
}
#ifdef CONFIG_IO_URING /** * selinux_uring_override_creds - check the requested cred override * @new: the target creds * * Check to see if the current task is allowed to override it's credentials * to service an io_uring operation.
*/ staticint selinux_uring_override_creds(conststruct cred *new)
{ return avc_has_perm(current_sid(), cred_sid(new),
SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL);
}
/** * selinux_uring_sqpoll - check if a io_uring polling thread can be created * * Check to see if the current task is allowed to create a new io_uring * kernel polling thread.
*/ staticint selinux_uring_sqpoll(void)
{
u32 sid = current_sid();
/** * selinux_uring_cmd - check if IORING_OP_URING_CMD is allowed * @ioucmd: the io_uring command structure * * Check to see if the current domain is allowed to execute an * IORING_OP_URING_CMD against the device/file specified in @ioucmd. *
*/ staticint selinux_uring_cmd(struct io_uring_cmd *ioucmd)
{ struct file *file = ioucmd->file; struct inode *inode = file_inode(file); struct inode_security_struct *isec = selinux_inode(inode); struct common_audit_data ad;
/** * selinux_uring_allowed - check if io_uring_setup() can be called * * Check to see if the current task is allowed to call io_uring_setup().
*/ staticint selinux_uring_allowed(void)
{
u32 sid = current_sid();
/* * IMPORTANT NOTE: When adding new hooks, please be careful to keep this order: * 1. any hooks that don't belong to (2.) or (3.) below, * 2. hooks that both access structures allocated by other hooks, and allocate * structures that can be later accessed by other hooks (mostly "cloning" * hooks), * 3. hooks that only allocate structures that can be later accessed by other * hooks ("allocating" hooks). * * Please follow block comment delimiters in the list to keep this order.
*/ staticstruct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file),
/* Set up any superblocks initialized prior to the policy load. */
pr_debug("SELinux: Setting up existing superblocks.\n");
iterate_supers(delayed_superblock_init, NULL);
}
/* SELinux requires early initialization in order to label
all processes and objects when they are created. */
DEFINE_LSM(selinux) = {
.name = "selinux",
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &selinux_enabled_boot,
.blobs = &selinux_blob_sizes,
.init = selinux_init,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.