Re: [RFC] call_with_creds()
From: Al Viro
Date: Wed Jul 18 2018 - 15:46:45 EST
On Wed, Jul 18, 2018 at 11:19:18AM -0700, Linus Torvalds wrote:
> On Wed, Jul 18, 2018 at 11:13 AM Al Viro <viro@xxxxxxxxxxxxxxxxxx> wrote:
> >
> > Linus, David - do you have any objections to the above?
>
> I damn well do.
>
> I explained earlier why it's wrong and fragile, and why it can just
> cause the *reverse* security problem if you do it wrong. So now you
> take a subtle bug, and make it even more subtle, and encourage people
> to do this known-broken model of using creds at IO time.
>
> No.
>
> Some debugging option to just clear current->creds entirely and catch
> mis-uses, sure. But saying "we have shit buggy garbage in random write
> functions, so we'll just paper over it"? No.
Huh? Nevermind ->write(), what about open()? Here's a specific question
Miklos brought when I suggested to get rid of that override:
/*
* These allocate and release file read/write context information.
*/
int nfs_open(struct inode *inode, struct file *filp)
{
struct nfs_open_context *ctx;
ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode, filp);
struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
fmode_t f_mode,
struct file *filp)
{
struct nfs_open_context *ctx;
struct rpc_cred *cred = rpc_lookup_cred();
struct rpc_cred *rpc_lookup_cred(void)
{
return rpcauth_lookupcred(&generic_auth, 0);
struct rpc_cred *
rpcauth_lookupcred(struct rpc_auth *auth, int flags)
{
struct auth_cred acred;
struct rpc_cred *ret;
const struct cred *cred = current_cred();
How should we bring the cred passed to do_dentry_open() where open() has been
called to rpcauth_lookupcred() where we end up looking for rpc_cred by what
should've been the cred passed to do_dentry_open() and is, instead, current_cred()?
We can pass filp->f_cred to rpc_lookup_cred() variant that gets it as an explicit
argument and feed it down to rpcauth_lookupcred() variant that does the same.
We can basically ignore the ->f_cred here. Or we can get current_cred() equal
to ->f_cred for the duration of open().
I'd probably prefer the first variant, but the last part of the question Miklos
asked
> Okay, so ->open() is a file op, and file ops should use file->f_cred,
> but how are we going to enforce this?
is not trivial - how do we find the places where that kind of thing happens and
what do we do in the meanwhile? I don't see any quick answers - any suggestions
would be very welcome. It's not just direct current_cred() callers; that stuff
gets called deep in call chains. And lifting it all the way up means a lot of
methods that need to get an explicit struct cred * argument. Are you OK with
going in that direction?
I'm honestly not sure - it's not an attempt to maneuver you into changing your
policy re ->write(). Do we care about ->f_cred at all and if we do, how do we
get it consistent across the filesystems? I'd buy "it's a weird and obscure thing"
for overlayfs, but that example is on NFS...
We definitely do have bugs in that area - consider e.g.
static int ecryptfs_threadfn(void *ignored)
{
set_freezable();
while (1) {
struct ecryptfs_open_req *req;
wait_event_freezable(
ecryptfs_kthread_ctl.wait,
(!list_empty(&ecryptfs_kthread_ctl.req_list)
|| kthread_should_stop()));
mutex_lock(&ecryptfs_kthread_ctl.mux);
if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
mutex_unlock(&ecryptfs_kthread_ctl.mux);
goto out;
}
while (!list_empty(&ecryptfs_kthread_ctl.req_list)) {
req = list_first_entry(&ecryptfs_kthread_ctl.req_list,
struct ecryptfs_open_req,
kthread_ctl_list);
list_del(&req->kthread_ctl_list);
*req->lower_file = dentry_open(&req->path,
(O_RDWR | O_LARGEFILE), current_cred());
complete(&req->done);
}
mutex_unlock(&ecryptfs_kthread_ctl.mux);
}
out:
return 0;
}
It's a kernel thread, so current_cred() looks bogus...