staticint match_opt_prefix(char *s, int l, char **arg)
{ int i;
for (i = 0; i < ARRAY_SIZE(smk_mount_opts); i++) {
size_t len = smk_mount_opts[i].len; if (len > l || memcmp(s, smk_mount_opts[i].name, len)) continue; if (len == l || s[len] != '=') continue;
*arg = s + len + 1; return smk_mount_opts[i].opt;
} return Opt_error;
}
/** *smack_shm_associate-Smackaccesscheckforshm *@isp:theobject *@shmflg:accessrequested * *Returns0ifcurrenthastherequestedaccess,errorcodeotherwise
*/ staticint smack_shm_associate(struct kern_ipc_perm *isp, int shmflg)
{ int may;
may = smack_flags_to_may(shmflg); return smk_curacc_shm(isp, may);
}
/** *smack_shm_shmctl-Smackaccesscheckforshm *@isp:theobject *@cmd:whatitwantstodo * *Returns0ifcurrenthastherequestedaccess,errorcodeotherwise
*/ staticint smack_shm_shmctl(struct kern_ipc_perm *isp, int cmd)
{ int may;
switch (cmd) { case IPC_STAT: case SHM_STAT: case SHM_STAT_ANY:
may = MAY_READ; break; case IPC_SET: case SHM_LOCK: case SHM_UNLOCK: case IPC_RMID:
may = MAY_READWRITE; break; case IPC_INFO: case SHM_INFO: /* *Systemlevelinformation.
*/ return0; default: return -EINVAL;
} return smk_curacc_shm(isp, may);
}
/** *smack_shm_shmat-Smackaccessforshmat *@isp:theobject *@shmaddr:unused *@shmflg:accessrequested * *Returns0ifcurrenthastherequestedaccess,errorcodeotherwise
*/ staticint smack_shm_shmat(struct kern_ipc_perm *isp, char __user *shmaddr, int shmflg)
{ int may;
may = smack_flags_to_may(shmflg); return smk_curacc_shm(isp, may);
}
/**
* smack_sem_associate - Smack access check for sem
* @isp: the object
* @semflg: access requested
*
* Returns 0if current has the requested access, error code otherwise
*/
static int smack_sem_associate(struct kern_ipc_perm *isp, int semflg)
{
int may;
may = smack_flags_to_may(semflg); return smk_curacc_sem(isp, may);
}
/**
* smack_sem_semctl - Smack access check for sem
* @isp: the object
* @cmd: what it wants to do
*
* Returns 0if current has the requested access, error code otherwise
*/
static int smack_sem_semctl(struct kern_ipc_perm *isp, int cmd)
{
int may;
switch (cmd) { case GETPID: case GETNCNT: case GETZCNT: case GETVAL: case GETALL: case IPC_STAT: case SEM_STAT: case SEM_STAT_ANY:
may = MAY_READ;
break; case SETVAL: case SETALL: case IPC_RMID: case IPC_SET:
may = MAY_READWRITE;
break; case IPC_INFO: case SEM_INFO:
/*
* System level information
*/ return0;
default: return -EINVAL;
}
return smk_curacc_sem(isp, may);
}
/**
* smack_sem_semop - Smack checks of semaphore operations
* @isp: the object
* @sops: unused
* @nsops: unused
* @alter: unused
*
* Treated as read and write in allcases.
*
* Returns 0if access is allowed, error code otherwise
*/
static int smack_sem_semop(struct kern_ipc_perm *isp, struct sembuf *sops,
unsigned nsops, int alter)
{ return smk_curacc_sem(isp, MAY_READWRITE);
}
/**
* smk_curacc_msq : helper to checkif current has access on msq
* @isp : the msq
* @access : access requested
*
* return0if current has access, error otherwise
*/
static int smk_curacc_msq(struct kern_ipc_perm *isp, int access)
{
struct smack_known *msp = smack_of_ipc(isp);
struct smk_audit_info ad;
int rc;
/**
* smack_msg_queue_associate - Smack access check for msg_queue
* @isp: the object
* @msqflg: access requested
*
* Returns 0if current has the requested access, error code otherwise
*/
static int smack_msg_queue_associate(struct kern_ipc_perm *isp, int msqflg)
{
int may;
may = smack_flags_to_may(msqflg); return smk_curacc_msq(isp, may);
}
/**
* smack_msg_queue_msgctl - Smack access check for msg_queue
* @isp: the object
* @cmd: what it wants to do
*
* Returns 0if current has the requested access, error code otherwise
*/
static int smack_msg_queue_msgctl(struct kern_ipc_perm *isp, int cmd)
{
int may;
switch (cmd) { case IPC_STAT: case MSG_STAT: case MSG_STAT_ANY:
may = MAY_READ;
break; case IPC_SET: case IPC_RMID:
may = MAY_READWRITE;
break; case IPC_INFO: case MSG_INFO:
/*
* System level information
*/ return0;
default: return -EINVAL;
}
return smk_curacc_msq(isp, may);
}
/**
* smack_msg_queue_msgsnd - Smack access check for msg_queue
* @isp: the object
* @msg: unused
* @msqflg: access requested
*
* Returns 0if current has the requested access, error code otherwise
*/
static int smack_msg_queue_msgsnd(struct kern_ipc_perm *isp, struct msg_msg *msg,
int msqflg)
{
int may;
may = smack_flags_to_may(msqflg); return smk_curacc_msq(isp, may);
}
/**
* smack_msg_queue_msgrcv - Smack access check for msg_queue
* @isp: the object
* @msg: unused
* @target: unused
* @type: unused
* @mode: unused
*
* Returns 0if current has read and write access, error code otherwise
*/
static int smack_msg_queue_msgrcv(struct kern_ipc_perm *isp,
struct msg_msg *msg,
struct task_struct *target, long type,
int mode)
{ return smk_curacc_msq(isp, MAY_READWRITE);
}
/**
* smack_ipc_permission - Smack access for ipc_permission()
* @ipp: the object permissions
* @flag: access requested
*
* Returns 0if current has read and write access, error code otherwise
*/
static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
{
struct smack_known **blob = smack_ipc(ipp);
struct smack_known *iskp = *blob;
int may = smack_flags_to_may(flag);
struct smk_audit_info ad;
int rc;
/**
* smack_ipc_getlsmprop - Extract smack security data
* @ipp: the object permissions
* @prop: where result will be saved
*/
static void smack_ipc_getlsmprop(struct kern_ipc_perm *ipp, struct lsm_prop *prop)
{
struct smack_known **iskpp = smack_ipc(ipp);
prop->smack.skp = *iskpp;
}
/**
* smack_d_instantiate - Make sure the blob is correct on an inode
* @opt_dentry: dentry where inode will be attached
* @inode: the object
*
* Set the inode's security blob if it hasn't been done already.
*/
static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
{
struct super_block *sbp;
struct superblock_smack *sbsp;
struct inode_smack *isp;
struct smack_known *skp;
struct smack_known *ckp = smk_of_current();
struct smack_known *final;
char trattr[TRANS_TRUE_SIZE];
int transflag = 0;
int rc;
struct dentry *dp;
if (inode == NULL) return;
isp = smack_inode(inode);
/*
* If the inode is already instantiated
* take the quick way out
*/ if (isp->smk_flags & SMK_INODE_INSTANT) return;
sbp = inode->i_sb;
sbsp = smack_superblock(sbp);
/*
* We're going to use the superblock default label
* if there's no label on the file.
*/
final = sbsp->smk_default;
/*
* If this is the root inode the superblock
* may be in the process of initialization.
* If that is the case use the root value out
* of the superblock.
*/ if (opt_dentry->d_parent == opt_dentry) {
switch (sbp->s_magic) { case CGROUP_SUPER_MAGIC: case CGROUP2_SUPER_MAGIC:
/*
* The cgroup filesystem is never mounted,
* so there's no opportunity to set the mount
* options.
*/
sbsp->smk_root = &smack_known_star;
sbsp->smk_default = &smack_known_star;
isp->smk_inode = sbsp->smk_root;
break; case TMPFS_MAGIC:
/*
* What about shmem/tmpfs anonymous files with dentry
* obtained from d_alloc_pseudo()?
*/
isp->smk_inode = smk_of_current();
break; case PIPEFS_MAGIC:
isp->smk_inode = smk_of_current();
break; case SOCKFS_MAGIC:
/*
* Socket access is controlled by the socket
* structures associated with the task involved.
*/
isp->smk_inode = &smack_known_star;
break;
default:
isp->smk_inode = sbsp->smk_root;
break;
}
isp->smk_flags |= SMK_INODE_INSTANT; return;
}
/*
* This is pretty hackish.
* Casey says that we shouldn't have to do
* file system specific code, but it does help
* with keeping it simple.
*/
switch (sbp->s_magic) { case SMACK_MAGIC: case CGROUP_SUPER_MAGIC: case CGROUP2_SUPER_MAGIC:
/*
* Casey says that it's a little embarrassing
* that the smack file system doesn't do
* extended attributes.
*
* Cgroupfs is special
*/
final = &smack_known_star;
break; case DEVPTS_SUPER_MAGIC:
/*
* devpts seems content with the label of the task.
* Programs that change smack have to treat the
* pty with respect.
*/
final = ckp;
break; case PROC_SUPER_MAGIC:
/*
* Casey says procfs appears not to care.
* The superblock default suffices.
*/
break; case TMPFS_MAGIC:
/*
* Device labels should come from the filesystem,
* but watch out, because they're volitile,
* getting recreated on every reboot.
*/
final = &smack_known_star;
/*
* If a smack value has been set we want to use it,
* but since tmpfs isn't giving us the opportunity
* to set mount options simulate setting the
* superblock default.
*/
fallthrough;
default:
/*
* This isn't an understood special case.
* Get the value from the xattr.
*/
/*
* UNIX domain sockets use lower level socket data.
*/ if (S_ISSOCK(inode->i_mode)) {
final = &smack_known_star;
break;
}
/*
* No xattr support means, alas, no SMACK label.
* Use the aforeapplied default.
* It would be curious if the label of the task
* does not match that assigned.
*/ if (!(inode->i_opflags & IOP_XATTR))
break;
/*
* Get the dentry for xattr.
*/
dp = dget(opt_dentry);
skp = smk_fetch(XATTR_NAME_SMACK, inode, dp); if (!IS_ERR_OR_NULL(skp))
final = skp;
/*
* Transmuting directory
*/ if (S_ISDIR(inode->i_mode)) {
/*
* If this is a new directory and the label was
* transmuted when the inode was initialized
* set the transmute attribute on the directory
* and mark the inode.
*
* If there is a transmute attribute on the
* directory mark the inode.
*/
rc = __vfs_getxattr(dp, inode,
XATTR_NAME_SMACKTRANSMUTE, trattr,
TRANS_TRUE_SIZE); if (rc >= 0 && strncmp(trattr, TRANS_TRUE,
TRANS_TRUE_SIZE) != 0)
rc = -EINVAL; if (rc >= 0)
transflag = SMK_INODE_TRANSMUTE;
}
/*
* Don't let the exec or mmap label be "*" or "@".
*/
skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); if (IS_ERR(skp) || skp == &smack_known_star ||
skp == &smack_known_web)
skp = NULL;
isp->smk_task = skp;
/**
* smack_getselfattr - Smack current process attribute
* @attr: which attribute to fetch
* @ctx: buffer to receive the result
* @size: available size in, actual size out
* @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.
*/
static int smack_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
u32 *size, u32 flags)
{
int rc;
struct smack_known *skp;
/**
* smack_getprocattr - Smack process attribute access
* @p: the object task
* @name: the name of the attribute in /proc/.../attr
* @value: where to put the result
*
* Places a copy of the task Smack into value
*
* Returns the length of the smack label or an error code
*/
static int smack_getprocattr(struct task_struct *p, const char *name, char **value)
{
struct smack_known *skp = smk_of_task_struct_obj(p);
char *cp;
int slen;
if (strcmp(name, "current") != 0) return -EINVAL;
cp = kstrdup(skp->smk_known, GFP_KERNEL); if (cp == NULL) return -ENOMEM;
slen = strlen(cp);
*value = cp; return slen;
}
/**
* do_setattr - Smack process attribute setting
* @attr: the ID of the attribute
* @value: the value to set
* @size: the size of the value
*
* Sets the Smack value of the task. Only setting self
* is permitted and only with privilege
*
* Returns the length of the smack label or an error code
*/
static int do_setattr(u64 attr, void *value, size_t size)
{
struct task_smack *tsp = smack_cred(current_cred());
struct cred *new;
struct smack_known *skp;
struct smack_known_list_elem *sklep;
int rc;
if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel)) return -EPERM;
skp = smk_import_entry(value, size); if (IS_ERR(skp)) return PTR_ERR(skp);
/*
* No process is ever allowed the web ("@") label
* and the star ("*") label.
*/ if (skp == &smack_known_web || skp == &smack_known_star) return -EINVAL;
if (!smack_privileged(CAP_MAC_ADMIN)) {
rc = -EPERM;
list_for_each_entry(sklep, &tsp->smk_relabel, list) if (sklep->smk_label == skp) {
rc = 0;
break;
} if (rc) return rc;
}
new = prepare_creds(); if (new == NULL) return -ENOMEM;
tsp = smack_cred(new);
tsp->smk_task = skp;
/*
* process can change its label only once
*/
smk_destroy_label_list(&tsp->smk_relabel);
commit_creds(new); return size;
}
/**
* smack_setselfattr - Set a Smack process attribute
* @attr: which attribute to set
* @ctx: buffer containing the data
* @size: size of @ctx
* @flags: unused
*
* Fill the passed user space @ctx with the details of the requested
* attribute.
*
* Returns 0 on success, an error code otherwise.
*/
static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
u32 size, u32 flags)
{
int rc;
/**
* smack_setprocattr - Smack process attribute setting
* @name: the name of the attribute in /proc/.../attr
* @value: the value to set
* @size: the size of the value
*
* Sets the Smack value of the task. Only setting self
* is permitted and only with privilege
*
* Returns the length of the smack label or an error code
*/
static int smack_setprocattr(const char *name, void *value, size_t size)
{
int attr = lsm_name_to_attr(name);
/**
* smack_unix_may_send - Smack access on UDS
* @sock: one socket
* @other: the other socket
*
* Return0if a subject with the smack of sock could access
* an object with the smack of other, otherwise an error code
*/
static int smack_unix_may_send(struct socket *sock, struct socket *other)
{
struct socket_smack *ssp = smack_sock(sock->sk);
struct socket_smack *osp = smack_sock(other->sk);
struct smk_audit_info ad;
int rc;
/**
* smack_socket_sendmsg - Smack check based on destination host
* @sock: the socket
* @msg: the message
* @size: the size of the message
*
* Return0if the current subject can write to the destination host.
* For IPv4 this is only a question if the destination is a single label host.
* For IPv6 this is a check against the label of the port.
*/
static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size)
{
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
#if IS_ENABLED(CONFIG_IPV6)
struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
#endif
#ifdef SMACK_IPV6_SECMARK_LABELING
struct socket_smack *ssp = smack_sock(sock->sk);
struct smack_known *rsp;
#endif
int rc = 0;
/*
* Perfectly reasonable for this to be NULL
*/ if (sip == NULL) return0;
/**
* smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack
* @sap: netlabel secattr
* @ssp: socket security information
*
* Returns a pointer to a Smack label entry found on the label list.
*/
static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
struct socket_smack *ssp)
{
struct smack_known *skp;
int found = 0;
int acat;
int kcat;
/*
* Netlabel found it in the cache.
*/ if ((sap->flags & NETLBL_SECATTR_CACHE) != 0) return (struct smack_known *)sap->cache->data;
if ((sap->flags & NETLBL_SECATTR_SECID) != 0)
/*
* Looks like a fallback, which gives us a secid.
*/ return smack_from_secid(sap->attr.secid);
if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
/*
* Looks like a CIPSO packet.
* If there are flags but no level netlabel isn't
* behaving the way we expect it to.
*
* Look it up in the label table
* Without guidance regarding the smack value
* for the packet fall back on the network
* ambient value.
*/
rcu_read_lock();
list_for_each_entry_rcu(skp, &smack_known_list, list) { if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl)
continue;
/*
* Compare the catsets. Use the netlbl APIs.
*/ if ((sap->flags & NETLBL_SECATTR_MLS_CAT) == 0) { if ((skp->smk_netlabel.flags &
NETLBL_SECATTR_MLS_CAT) == 0)
found = 1;
break;
}
for (acat = -1, kcat = -1; acat == kcat; ) {
acat = netlbl_catmap_walk(sap->attr.mls.cat,
acat + 1);
kcat = netlbl_catmap_walk(
skp->smk_netlabel.attr.mls.cat,
kcat + 1); if (acat < 0 || kcat < 0)
break;
} if (acat == kcat) {
found = 1;
break;
}
}
rcu_read_unlock();
if (found) return skp;
if (ssp != NULL && ssp->smk_in == &smack_known_star) return &smack_known_web; return &smack_known_star;
}
/*
* Without guidance regarding the smack value
* for the packet fall back on the network
* ambient value.
*/ return smack_net_ambient;
}
#if IS_ENABLED(CONFIG_IPV6)
static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
{
u8 nexthdr;
int offset;
int proto = -EINVAL;
struct ipv6hdr _ipv6h;
struct ipv6hdr *ip6;
__be16 frag_off;
struct tcphdr _tcph, *th;
struct udphdr _udph, *uh;
proto = nexthdr;
switch (proto) { case IPPROTO_TCP:
th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); if (th != NULL)
sip->sin6_port = th->source;
break; case IPPROTO_UDP: case IPPROTO_UDPLITE:
uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); if (uh != NULL)
sip->sin6_port = uh->source;
break;
} return proto;
}
#endif /* CONFIG_IPV6 */
/**
* smack_from_skb - Smack data from the secmark in an skb
* @skb: packet
*
* Returns smack_known of the secmark or NULL if that won't work.
*/
#ifdef CONFIG_NETWORK_SECMARK
static struct smack_known *smack_from_skb(struct sk_buff *skb)
{ if (skb == NULL || skb->secmark == 0) return NULL;
/**
* smack_from_netlbl - Smack data from the IP options in an skb
* @sk: socket data came in on
* @family: address family
* @skb: packet
*
* Find the Smack label in the IP options. If it hasn't been
* added to the netlabel cache, add it here.
*
* Returns smack_known of the IP options or NULL if that won't work.
*/
static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
struct sk_buff *skb)
{
struct netlbl_lsm_secattr secattr;
struct socket_smack *ssp = NULL;
struct smack_known *skp = NULL;
netlbl_secattr_init(&secattr);
if (sk)
ssp = smack_sock(sk);
if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) {
skp = smack_from_secattr(&secattr, ssp); if (secattr.flags & NETLBL_SECATTR_CACHEABLE)
netlbl_cache_add(skb, family, &skp->smk_netlabel);
}
netlbl_secattr_destroy(&secattr);
return skp;
}
/**
* smack_socket_sock_rcv_skb - Smack packet delivery access check
* @sk: socket
* @skb: packet
*
* Returns 0if the packet should be delivered, an error code otherwise
*/
static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
struct socket_smack *ssp = smack_sock(sk);
struct smack_known *skp = NULL;
int rc = 0;
struct smk_audit_info ad;
u16 family = sk->sk_family;
#ifdef CONFIG_AUDIT
struct lsm_network_audit net;
#endif
#if IS_ENABLED(CONFIG_IPV6)
struct sockaddr_in6 sadd;
int proto;
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
family = PF_INET;
#endif /* CONFIG_IPV6 */
switch (family) { case PF_INET:
/*
* If there is a secmark use it rather than the CIPSO label.
* If there is no secmark fall back to CIPSO.
* The secmark is assumed to reflect policy better.
*/
skp = smack_from_skb(skb); if (skp == NULL) {
skp = smack_from_netlbl(sk, family, skb); if (skp == NULL)
skp = smack_net_ambient;
}
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
ad.a.u.net->family = family;
ad.a.u.net->netif = skb->skb_iif;
ipv4_skb_to_auditdata(skb, &ad.a, NULL);
#endif
/*
* Receiving a packet requires that the other end
* be able to write here. Read access is not required.
* This is the simplest possible security model
* for networking.
*/
rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
MAY_WRITE, rc); if (rc != 0)
netlbl_skbuff_err(skb, family, rc, 0);
break;
#if IS_ENABLED(CONFIG_IPV6) case PF_INET6:
proto = smk_skb_to_addr_ipv6(skb, &sadd); if (proto != IPPROTO_UDP && proto != IPPROTO_UDPLITE &&
proto != IPPROTO_TCP)
break;
#ifdef SMACK_IPV6_SECMARK_LABELING
skp = smack_from_skb(skb); if (skp == NULL) { if (smk_ipv6_localhost(&sadd))
break;
skp = smack_ipv6host_label(&sadd); if (skp == NULL)
skp = smack_net_ambient;
}
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
ad.a.u.net->family = family;
ad.a.u.net->netif = skb->skb_iif;
ipv6_skb_to_auditdata(skb, &ad.a, NULL);
#endif /* CONFIG_AUDIT */
rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in,
MAY_WRITE, rc);
#endif /* SMACK_IPV6_SECMARK_LABELING */
#ifdef SMACK_IPV6_PORT_LABELING
rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
#endif /* SMACK_IPV6_PORT_LABELING */ if (rc != 0)
icmpv6_send(skb, ICMPV6_DEST_UNREACH,
ICMPV6_ADM_PROHIBITED, 0);
break;
#endif /* CONFIG_IPV6 */
}
return rc;
}
/**
* smack_socket_getpeersec_stream - pull in packet label
* @sock: the socket
* @optval: user's destination
* @optlen: size thereof
* @len: max thereof
*
* returns zero on success, an error code otherwise
*/
static int smack_socket_getpeersec_stream(struct socket *sock,
sockptr_t optval, sockptr_t optlen,
unsigned int len)
{
struct socket_smack *ssp;
char *rcp = "";
u32 slen = 1;
int rc = 0;
if (copy_to_sockptr(optval, rcp, slen))
rc = -EFAULT;
out_len: if (copy_to_sockptr(optlen, &slen, sizeof(slen)))
rc = -EFAULT; return rc;
}
/**
* smack_socket_getpeersec_dgram - pull in packet label
* @sock: the peer socket
* @skb: packet data
* @secid: pointer to where to put the secid of the packet
*
* Sets the netlabel socket state on sk from parent
*/
static int smack_socket_getpeersec_dgram(struct socket *sock,
struct sk_buff *skb, u32 *secid)
{
struct socket_smack *ssp = NULL;
struct smack_known *skp;
struct sock *sk = NULL;
int family = PF_UNSPEC;
u32 s = 0; /* 0 is the invalid secid */
if (skb != NULL) { if (skb->protocol == htons(ETH_P_IP))
family = PF_INET;
#if IS_ENABLED(CONFIG_IPV6) elseif (skb->protocol == htons(ETH_P_IPV6))
family = PF_INET6;
#endif /* CONFIG_IPV6 */
} if (family == PF_UNSPEC && sock != NULL)
family = sock->sk->sk_family;
switch (family) { case PF_UNIX:
ssp = smack_sock(sock->sk);
s = ssp->smk_out->smk_secid;
break; case PF_INET:
skp = smack_from_skb(skb); if (skp) {
s = skp->smk_secid;
break;
}
/*
* Translate what netlabel gave us.
*/ if (sock != NULL)
sk = sock->sk;
skp = smack_from_netlbl(sk, family, skb); if (skp != NULL)
s = skp->smk_secid;
break; case PF_INET6:
#ifdef SMACK_IPV6_SECMARK_LABELING
skp = smack_from_skb(skb); if (skp)
s = skp->smk_secid;
#endif
break;
}
*secid = s; if (s == 0) return -EINVAL; return0;
}
/**
* smack_inet_conn_request - Smack access check on connect
* @sk: socket involved
* @skb: packet
* @req: unused
*
* Returns 0if a task with the packet label could write to
* the socket, otherwise an error code
*/
static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
u16 family = sk->sk_family;
struct smack_known *skp;
struct socket_smack *ssp = smack_sock(sk);
struct sockaddr_in addr;
struct iphdr *hdr;
struct smack_known *hskp;
int rc;
struct smk_audit_info ad;
#ifdef CONFIG_AUDIT
struct lsm_network_audit net;
#endif
#if IS_ENABLED(CONFIG_IPV6) if (family == PF_INET6) {
/*
* Handle mapped IPv4 packets arriving
* via IPv6 sockets. Don't set up netlabel
* processing on IPv6.
*/ if (skb->protocol == htons(ETH_P_IP))
family = PF_INET; else return0;
}
#endif /* CONFIG_IPV6 */
/*
* If there is a secmark use it rather than the CIPSO label.
* If there is no secmark fall back to CIPSO.
* The secmark is assumed to reflect policy better.
*/
skp = smack_from_skb(skb); if (skp == NULL) {
skp = smack_from_netlbl(sk, family, skb); if (skp == NULL)
skp = &smack_known_huh;
}
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
ad.a.u.net->family = family;
ad.a.u.net->netif = skb->skb_iif;
ipv4_skb_to_auditdata(skb, &ad.a, NULL);
#endif
/*
* Receiving a packet requires that the other end be able to write
* here. Read access is not required.
*/
rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc); if (rc != 0) return rc;
/*
* Save the peer's label in the request_sock so we can later setup
* smk_packet in the child socket so that SO_PEERCRED can report it.
*/
req->peer_secid = skp->smk_secid;
/*
* We need to decideif we want to label the incoming connection here
* if we do we only need to label the request_sock and the stack will
* propagate the wire-label to the sock when it is created.
*/
hdr = ip_hdr(skb);
addr.sin_addr.s_addr = hdr->saddr;
rcu_read_lock();
hskp = smack_ipv4host_label(&addr);
rcu_read_unlock();
if (hskp == NULL)
rc = netlbl_req_setattr(req, &ssp->smk_out->smk_netlabel); else
netlbl_req_delattr(req);
return rc;
}
/**
* smack_inet_csk_clone - Copy the connection information to the new socket
* @sk: the new socket
* @req: the connection's request_sock
*
* Transfer the connection's peer label to the newly created socket.
*/
static void smack_inet_csk_clone(struct sock *sk,
const struct request_sock *req)
{
struct socket_smack *ssp = smack_sock(sk);
struct smack_known *skp;
/*
* Key management security hooks
*
* Casey has not tested key support very heavily.
* The permission check is most likely too restrictive.
* If you care about keys please have a look.
*/
#ifdef CONFIG_KEYS
/**
* smack_key_alloc - Set the key security blob
* @key: object
* @cred: the credentials to use
* @flags: unused
*
* No allocation required
*
* Returns 0
*/
static int smack_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
struct smack_known **blob = smack_key(key);
struct smack_known *skp = smk_of_task(smack_cred(cred));
*blob = skp; return0;
}
/**
* smack_key_permission - Smack access on a key
* @key_ref: gets to the object
* @cred: the credentials to use
* @need_perm: requested key permission
*
* Return0if the task has read and write to the object,
* an error code otherwise
*/
static int smack_key_permission(key_ref_t key_ref,
const struct cred *cred,
enum key_need_perm need_perm)
{
struct smack_known **blob;
struct smack_known *skp;
struct key *keyp;
struct smk_audit_info ad;
struct smack_known *tkp = smk_of_task(smack_cred(cred));
int request = 0;
int rc;
/*
* Validate requested permissions
*/
switch (need_perm) { case KEY_NEED_READ: case KEY_NEED_SEARCH: case KEY_NEED_VIEW:
request |= MAY_READ;
break; case KEY_NEED_WRITE: case KEY_NEED_LINK: case KEY_NEED_SETATTR:
request |= MAY_WRITE;
break; case KEY_NEED_UNSPECIFIED: case KEY_NEED_UNLINK: case KEY_SYSADMIN_OVERRIDE: case KEY_AUTHTOKEN_OVERRIDE: case KEY_DEFER_PERM_CHECK: return0;
default: return -EINVAL;
}
keyp = key_ref_to_ptr(key_ref); if (keyp == NULL) return -EINVAL;
/*
* If the key hasn't been initialized give it access so that
* it may do so.
*/
blob = smack_key(keyp);
skp = *blob; if (skp == NULL) return0;
/*
* This should not occur
*/ if (tkp == NULL) return -EACCES;
/*
* smack_key_getsecurity - Smack label tagging the key
* @key points to the key to be queried
* @_buffer points to a pointer that should be set to point to the
* resulting string (if no label or an error occurs).
* Return the length of the string (including terminating NUL) or -ve if
* an error.
* May also return0 (and a NULL buffer pointer) if there is no label.
*/
static int smack_key_getsecurity(struct key *key, char **_buffer)
{
struct smack_known **blob = smack_key(key);
struct smack_known *skp = *blob;
size_t length;
char *copy;
#ifdef CONFIG_KEY_NOTIFICATIONS
/**
* smack_watch_key - Smack access to watch a key for notifications.
* @key: The key to be watched
*
* Return0if the @watch->cred has permission to read from the key object and
* an error otherwise.
*/
static int smack_watch_key(struct key *key)
{
struct smk_audit_info ad;
struct smack_known *tkp = smk_of_current();
struct smack_known **blob = smack_key(key);
int rc;
/*
* This should not occur
*/ if (tkp == NULL) return -EACCES;
if (smack_privileged_cred(CAP_MAC_OVERRIDE, current_cred())) return0;
#ifdef CONFIG_WATCH_QUEUE
/**
* smack_post_notification - Smack access to post a notification to a queue
* @w_cred: The credentials of the watcher.
* @cred: The credentials of the event source (may be NULL).
* @n: The notification message to be posted.
*/
static int smack_post_notification(const struct cred *w_cred,
const struct cred *cred,
struct watch_notification *n)
{
struct smk_audit_info ad;
struct smack_known *subj, *obj;
int rc;
/* Always let maintenance notifications through. */ if (n->type == WATCH_TYPE_META) return0;
if (!cred) return0;
subj = smk_of_task(smack_cred(cred));
obj = smk_of_task(smack_cred(w_cred));
/*
* Smack Audit hooks
*
* Audit requires a unique representation of each Smack specific
* rule. This unique representation is used to distinguish the
* object to be audited from remaining kernel objects and also
* works as a glue between the audit hooks.
*
* Since repository entries are added but never deleted, we'll use
* the smack_known label address related to the given audit rule as
* the needed unique representation. This also better fits the smack
* model where nearly everything is a label.
*/
#ifdef CONFIG_AUDIT
/**
* smack_audit_rule_init - Initialize a smack audit rule
* @field: audit rule fields given from user-space (audit.h)
* @op: required testing operator (=, !=, >, <, ...)
* @rulestr: smack label to be audited
* @vrule: pointer to save our own audit rule representation
* @gfp: type of the memory for the allocation
*
* Prepare to audit caseswhere (@field @op @rulestr) is true.
* The label to be audited is created if necessary.
*/
static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
gfp_t gfp)
{
struct smack_known *skp;
char **rule = (char **)vrule;
*rule = NULL;
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) return -EINVAL;
if (op != Audit_equal && op != Audit_not_equal) return -EINVAL;
skp = smk_import_entry(rulestr, 0); if (IS_ERR(skp)) return PTR_ERR(skp);
*rule = skp->smk_known;
return0;
}
/**
* smack_audit_rule_known - Distinguish Smack audit rules
* @krule: rule of interest, in Audit kernel representation format
*
* This is used to filter Smack rules from remaining Audit ones.
* If it's proved that this rule belongs to us, the
* audit_rule_match hook will be called to do the final judgement.
*/
static int smack_audit_rule_known(struct audit_krule *krule)
{
struct audit_field *f;
int i;
for (i = 0; i < krule->field_count; i++) {
f = &krule->fields[i];
if (f->type == AUDIT_SUBJ_USER || f->type == AUDIT_OBJ_USER) return1;
}
return0;
}
/**
* smack_audit_rule_match - Audit given object ?
* @prop: security id for identifying the object to test
* @field: audit rule flags given from user-space
* @op: required testing operator
* @vrule: smack internal rule presentation
*
* The core Audit hook. It's used to take the decision of
* whether to audit or not to audit a given object.
*/
static int smack_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op,
void *vrule)
{
struct smack_known *skp = prop->smack.skp;
char *rule = vrule;
if (unlikely(!rule)) {
WARN_ONCE(1, "Smack: missing rule\n"); return -ENOENT;
}
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) return0;
/*
* No need to do string comparisons. If a match occurs,
* both pointers will point to the same smack_known
* label.
*/ if (op == Audit_equal) return (rule == skp->smk_known); if (op == Audit_not_equal) return (rule != skp->smk_known);
return0;
}
/*
* There is no need for a smack_audit_rule_free hook.
* No memory was allocated.
*/
#endif /* CONFIG_AUDIT */
/**
* smack_ismaclabel - checkif xattr @name references a smack MAC label
* @name: Full xattr name to check.
*/
static int smack_ismaclabel(const char *name)
{ return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
}
/**
* smack_to_secctx - fill a lsm_context
* @skp: Smack label
* @cp: destination
*
* Fill the passed @cp and return the length of the string
*/
static int smack_to_secctx(struct smack_known *skp, struct lsm_context *cp)
{
int len = strlen(skp->smk_known);
/**
* smack_secid_to_secctx - return the smack label for a secid
* @secid: incoming integer
* @cp: destination
*
* Exists for networking code.
*/
static int smack_secid_to_secctx(u32 secid, struct lsm_context *cp)
{ return smack_to_secctx(smack_from_secid(secid), cp);
}
/**
* smack_lsmprop_to_secctx - return the smack label
* @prop: includes incoming Smack data
* @cp: destination
*
* Exists for audit code.
*/
static int smack_lsmprop_to_secctx(struct lsm_prop *prop,
struct lsm_context *cp)
{ return smack_to_secctx(prop->smack.skp, cp);
}
/**
* smack_secctx_to_secid - return the secid for a smack label
* @secdata: smack label
* @seclen: how long result is
* @secid: outgoing integer
*
* Exists for audit and networking code.
*/
static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
struct smack_known *skp = smk_find_entry(secdata);
/*
* There used to be a smack_release_secctx hook
* that did nothing back when hooks were in a vector.
* Now that there's a list such a hook adds cost.
*/
if (new_creds == NULL) {
new_creds = prepare_creds(); if (new_creds == NULL) return -ENOMEM;
}
tsp = smack_cred(new_creds);
/*
* Get label from overlay inode and set it in create_sid
*/
isp = smack_inode(d_inode(dentry));
skp = isp->smk_inode;
tsp->smk_task = skp;
*new = new_creds; return0;
}
static int smack_inode_copy_up_xattr(struct dentry *src, const char *name)
{
/*
* Return -ECANCELED if this is the smack access Smack attribute.
*/ if (!strcmp(name, XATTR_NAME_SMACK)) return -ECANCELED;
/*
* Use the process credential unless all of
* the transmuting criteria are met
*/
ntsp->smk_task = otsp->smk_task;
/*
* the attribute of the containing directory
*/
isp = smack_inode(d_inode(dentry->d_parent));
if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
rcu_read_lock();
may = smk_access_entry(otsp->smk_task->smk_known,
isp->smk_inode->smk_known,
&otsp->smk_task->smk_rules);
rcu_read_unlock();
/*
* If the directory is transmuting and the rule
* providing access is transmuting use the containing
* directory label instead of the process label.
*/ if (may > 0 && (may & MAY_TRANSMUTE)) {
ntsp->smk_task = isp->smk_inode;
ntsp->smk_transmuted = ntsp->smk_task;
}
} return0;
}
#ifdef CONFIG_IO_URING
/**
* smack_uring_override_creds - Is io_uring cred override allowed?
* @new: the target creds
*
* Check to see if the current task is allowed to override it's credentials
* to service an io_uring operation.
*/
static int smack_uring_override_creds(const struct cred *new)
{
struct task_smack *tsp = smack_cred(current_cred());
struct task_smack *nsp = smack_cred(new);
/*
* Allow the degenerate casewhere the new Smack value is
* the same as the current Smack value.
*/ if (tsp->smk_task == nsp->smk_task) return0;
if (smack_privileged_cred(CAP_MAC_OVERRIDE, current_cred())) return0;
return -EPERM;
}
/**
* smack_uring_sqpoll - checkif 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.
*/
static int smack_uring_sqpoll(void)
{ if (smack_privileged_cred(CAP_MAC_ADMIN, current_cred())) return0;
return -EPERM;
}
/**
* smack_uring_cmd - check on file operations for io_uring
* @ioucmd: the command in question
*
* Make a best guess about whether a io_uring "command" should
* be allowed. Use the same logic used for determining if the
* file could be opened for read in the absence of better criteria.
*/
static int smack_uring_cmd(struct io_uring_cmd *ioucmd)
{
struct file *file = ioucmd->file;
struct smk_audit_info ad;
struct task_smack *tsp;
struct inode *inode;
int rc;
/* initialize the smack_known_list */
init_smack_known_list();
return0;
}
/*
* Smack requires early initialization in order to label
* all processes and objects when they are created.
*/
DEFINE_LSM(smack) = {
.name = "smack",
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.blobs = &smack_blob_sizes,
.init = smack_init,
};
Messung V0.5 in Prozent
¤ 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.0.157Bemerkung:
¤
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.