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...