Helo again. I need to get back to this issue, we still don't have a fix for socketpair() and UDS sockets.
I was wondering if the fix i posted is ok (apart from the variables beeing named inode), as you can see this fields in the structure are initialized in smack_sk_alloc_security (to cover those sockets that won't be connected like those created by socketpair() ) and in smack_unix_stream_connect() for all other situations. Do you have some other ideas about this issue, maybe there could be a more generic way to fix this in smack ? I was also wondering about a situation were a descriptor to a socket would be passed around more then once from a process to process, in the end it could actually end up in the original sending process, should we somehow take into account the path such a descriptor would take in the process tree ? bes regards On 09/25/2015 09:09 PM, Casey Schaufler wrote: > On 9/23/2015 7:07 AM, Stephen Smalley wrote: >> On 09/23/2015 05:00 AM, Roman Kubiak wrote: >>> We found a lot of scenarios where the smack_file_receive() function might >>> fail >>> >>> 1) for pipes a different patch is needed for the function to work >>> (otherwise all pipe descriptors >>> get the "_" label), patch below: >>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c >>> index a143328..0ebfb07 100644 >>> --- a/security/smack/smack_lsm.c >>> +++ b/security/smack/smack_lsm.c >>> @@ -3099,6 +3099,9 @@ static void smack_d_instantiate(struct dentry >>> *opt_dentry, struct inode *inode) >>> */ >>> isp->smk_inode = smk_of_current(); >>> break; >>> + case PIPEFS_MAGIC: >>> + isp->smk_inode = smk_of_current(); >>> + break; >> We have the equivalent of this in SELinux already, by way of specifying >> fs_use_task for pipefs in policy and the SECURITY_FS_USE_TASK case in >> selinux inode_doinit_with_dentry(). > > This looks like a fix regardless of the file_receive issue. > >> >>> default: >>> isp->smk_inode = sbsp->smk_root; >>> break; >>> >>> 2) for sockets it's a complicated issue with connected/unconnected sockets, >>> also connected means they might be server/client sockets (those with >>> accept/listen and those with only connect), socketpair is another issue. I >>> tried to cover at least one case, where the descriptor is a connected UDS >>> socket (it has a peer), patch below: >> I don't understand the issue here; for SELinux, we just always call >> file_has_perm() in selinux_file_receive(), and it does not matter >> whether the open file refers to a file, a pipe, a socket, or whatever. > > There's a difference in how SELinux and Smack treat socket based > communications. I won't try to describe exactly how SELinux does > it, because I always get it wrong. Smack treats the communication > as a write operation from the sending process to the receiving > process. The information about Smack label of the receiving process > is stored in the socket structure (which is not itself an object in > the Smack model) and the check is made against that. The Smack label > attached to a UDS inode is not relevant. If the file structure for > a UDS lacks an inode it shouldn't matter at all to Smack. > > For file_receive of a UDS what matters is whether the receiving > process can write to the process at the other end. That has nothing > to do with the inode. > > >> If the open file refers to a socket, whether connected, unconnected, >> local, network, or whatever, that socket has an associated inode that >> was created when the socket was created (and that typically has the same >> label as the process that created the socket), and I can check whether >> the current process (the recipient) is allowed to read and write to >> sockets with that label. > > But Smack doesn't really care about the inode. The UDS file system > object is not interesting to Smack. > >> If you want to permit that, then you can allow it via a rule. If not, >> then don't. What's the problem? You don't need to replicate the actual >> checking that gets done on socket send at this point. You are just >> checking whether the recipient can use the socket at all, not whether it >> can talk to the peer. That should get mediated at send time. > > The check is to see if using the descriptor as is would violate > the system policy. If the receiving process does not have write > access to the process on the far end it shouldn't be using the > descriptor. Unless, of course, the intent is to pass access to > the receiving process that it shouldn't have. Fred being able > to write to Wilma and Betty shouldn't allow Fred to give Wilma > the right to write to Betty. > >> >>> diff --git a/security/smack/smack.h b/security/smack/smack.h >>> index 67ccb7b..7b1fbad 100644 >>> --- a/security/smack/smack.h >>> +++ b/security/smack/smack.h >>> @@ -79,9 +79,11 @@ struct superblock_smack { >>> }; >>> >>> struct socket_smack { >>> - struct smack_known *smk_out; /* outbound label */ >>> - struct smack_known *smk_in; /* inbound label */ >>> - struct smack_known *smk_packet; /* TCP peer label */ >>> + struct smack_known *smk_out; /* outbound label */ >>> + struct smack_known *smk_in; /* inbound label */ >>> + struct smack_known *smk_packet; /* TCP peer label */ >>> + struct smack_known *smk_inode_out; >>> + struct smack_known *smk_inode_in; >>> }; > > This does not look at all right to me. You should never need to > look at the inode for a UDS. > >>> >>> /* >>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c >>> index db46ddb..4d55b6b 100644 >>> --- a/security/smack/smack_lsm.c >>> +++ b/security/smack/smack_lsm.c >>> @@ -34,6 +34,7 @@ >>> #include <net/cipso_ipv4.h> >>> #include <net/ip.h> >>> #include <net/ipv6.h> >>> +#include <net/af_unix.h> >>> #include <linux/audit.h> >>> #include <linux/magic.h> >>> #include <linux/dcache.h> >>> @@ -202,6 +203,73 @@ static int smk_bu_credfile(const struct cred *cred, >>> struct file *file, >>> #endif >>> >>> /** >>> + * Helper function when a descriptor passed in a socket >>> + * is a socket >>> + */ >>> +static int smk_socket_receive(struct socket *socket, struct smk_audit_info >>> *ad) >>> +{ >>> + int rc = -EACCES; >>> + struct socket_smack *ssk; >>> + struct socket_smack *psk = NULL; >>> + struct sock *sk = socket->sk; >>> + struct sock *peer_sock; >>> + struct task_smack *tsp; >>> + >>> + lock_sock(socket->sk); >>> + >>> + /* >>> + * Check if this is a AF_UNIX connected socket >>> + */ >>> + if (socket->state == SS_CONNECTED && sk->sk_family == PF_LOCAL) { >>> + peer_sock = unix_peer_get(socket->sk); >>> + >>> + if (peer_sock != NULL) { >>> + psk = peer_sock->sk_security; >>> + if (psk->smk_inode_in != NULL >>> + && psk->smk_inode_out != NULL) { >>> + ssk = psk; >>> + } else { >>> + ssk = socket->sk->sk_security; >>> + } >>> + } else { >>> + /* >>> + * This should never happen >>> + * a connected socket without >>> + * a peer ?? >>> + */ >>> + release_sock(socket->sk); >>> + return -EACCES; >>> + } >>> + >>> + if (!smack_privileged(CAP_MAC_OVERRIDE)) { >>> + tsp = current_security(); >>> + >>> + rc = smk_access(tsp->smk_task, >>> + ssk->smk_inode_in, >>> + MAY_WRITE, ad); >>> + rc = smk_bu_note("UDS fd receive", >>> + tsp->smk_task, >>> + ssk->smk_inode_in, >>> + MAY_WRITE, rc); >>> + >>> + if (rc == 0) { >>> + rc = smk_access(ssk->smk_inode_out, >>> + tsp->smk_task, >>> + MAY_WRITE, ad); >>> + rc = smk_bu_note("UDS fd receive", >>> + ssk->smk_inode_out, >>> + tsp->smk_task, >>> + MAY_WRITE, rc); >>> + } >>> + } >>> + } >>> + >>> + release_sock(socket->sk); >>> + >>> + return rc; >>> +} >>> + >>> +/** >>> * smk_fetch - Fetch the smack label from a file. >>> * @name: type of the label (attribute) >>> * @ip: a pointer to the inode >>> @@ -1638,9 +1706,19 @@ static int smack_file_receive(struct file *file) >>> int may = 0; >>> struct smk_audit_info ad; >>> struct inode *inode = file_inode(file); >>> + struct socket *socket; >>> >>> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); >>> smk_ad_setfield_u_fs_path(&ad, file->f_path); >>> + >>> + if (unlikely(S_ISSOCK(inode->i_mode))) { >>> + socket = SOCKET_I(inode); >>> + >>> + if (socket != NULL) >>> + return smk_socket_receive(socket, &ad); >>> + else >>> + return -EACCES; >>> + } >>> /* >>> * This code relies on bitmasks. >>> */ >>> @@ -2078,6 +2156,8 @@ static int smack_sk_alloc_security(struct sock *sk, >>> int family, gfp_t gfp_flags) >>> ssp->smk_in = skp; >>> ssp->smk_out = skp; >>> ssp->smk_packet = NULL; >>> + ssp->smk_inode_out = skp; >>> + ssp->smk_inode_in = skp; >>> >>> sk->sk_security = ssp; >>> >>> @@ -3341,13 +3421,14 @@ static int smack_unix_stream_connect(struct sock >>> *sock, >>> MAY_WRITE, rc); >>> } >>> } >>> - >>> /* >>> * Cross reference the peer labels for SO_PEERSEC. >>> */ >>> if (rc == 0) { >>> nsp->smk_packet = ssp->smk_out; >>> ssp->smk_packet = osp->smk_out; >>> + nsp->smk_inode_in = osp->smk_in; >>> + nsp->smk_inode_out = osp->smk_out; >>> } >>> >>> return rc; >>> >>> 3) We don't know what to do with unconnected sockets, we don't know what to >>> do with network sockets (foreign peer on different machines), we don't know >>> what to do if the descriptor is passed between multiple processes, and >>> might end back in the originating process >>> >>> I can send those patches to the list if they look ok, however they only >>> cover those two cases mentioned above. >>> >>> best regards >>> Roman Kubiak >>> >>> On 09/18/2015 06:46 PM, Stephen Smalley wrote: >>>> On 09/18/2015 12:15 PM, Casey Schaufler wrote: >>>>> On 9/17/2015 6:38 AM, Stephen Smalley wrote: >>>>>> On 09/16/2015 05:14 PM, Casey Schaufler wrote: >>>>>>> On 9/9/2015 3:46 AM, Roman Kubiak wrote: >>>>>>>> Helo (sorry for the long topic but it's hard to describe the problem >>>>>>>> in short). >>>>>>>> >>>>>>>> The situation is as follows >>>>>>>> >>>>>>>> - create a socket connection between two processes (unix socket) >>>>>>>> - one of the processes creates a socketpair >>>>>>>> - this process sends one of the descriptors created by socketpair >>>>>>>> to the other process >>>>>>>> - the socket gets received by the other process >>>>>>>> >>>>>>>> Now the problem is that we can't label the sockets as if they were >>>>>>>> connected, >>>>>>>> connect() is never called on them, and the proper LSM functios don't >>>>>>>> get called. >>>>>>>> So when the LSM hook for file_receive gets called, all the security >>>>>>>> fields in >>>>>>>> the sockets are NULL. >>>>>>> The problem here for Smack, which I assume is the LSM in question, >>>>>>> is that the receive check is being done against the file_inode() >>>>>>> of the file, and that makes no sense at all for the spawn of socketpair. >>>>>>> This came about as part of a global change to the use of the f_security >>>>>>> blob in Smack. The smack_file_receive check was changed to use the >>>>>>> file_inode(), and shouldn't have been. The fix is: >>>>>>> >>>>>>> replace: >>>>>>> struct inode *inode = file_inode(file); >>>>>>> with: >>>>>>> struct smack_known *skp = (struct smack_known >>>>>>> *)file->f_security; >>>>>>> >>>>>>> replace: >>>>>>> rc = smk_curacc(smk_of_inode(inode), may, &ad); >>>>>>> with: >>>>>>> rc = smk_curacc(skp, may, &ad); >>>>>>> >>>>>>> Give that a try and if you like the results, submit a patch. >>>>>>> If you don't like the results, let me know why. >>>>>> With that change, you'll be checking read/write to the label of the >>>>>> process that opened the file, not to the label of the file (inode) >>>>>> itself. I doubt that is what you want to do. >>>>> You're correct for the case where "file" refers to a file. >>>>> The suggested change should only apply to the case where "file" >>>>> refers to UDS. A correct patch has to take the difference into >>>>> account. >>>>> >>>>> I'll blame my error on jet lag this once. >>>> It should make no difference; your current smack_file_receive() logic >>>> should work as is for both regular files and UDS. >>>> >>>> The only issue here AFAICS is SO_PEERSEC support on socketpair()-created >>>> sockets. >>>> >>>> >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe >>>> linux-security-module" in >>>> the body of a message to majord...@vger.kernel.org >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>> >> -- >> To unsubscribe from this list: send the line "unsubscribe >> linux-security-module" in >> the body of a message to majord...@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > > -- -------------- Roman Kubiak -------------- -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html