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
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet)
¤
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.