Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fuse: Fail all requests with invalid uids or gids

Upon a cursory examinination the uid and gid of a fuse request are
necessary for correct operation. Failing a fuse request where those
values are not reliable seems a straight forward and reliable means of
ensuring that fuse requests with bad data are not sent or processed.

In most cases the vfs will avoid actions it suspects will cause
an inode write back of an inode with an invalid uid or gid. But that does
not map precisely to what fuse is doing, so test for this and solve
this at the fuse level as well.

Performing this work in fuse_req_init_context is cheap as the code is
already performing the translation here and only needs to check the
result of the translation to see if things are not representable in
a form the fuse server can handle.

[SzM] Don't zero the context for the nofail case, just keep using the
munging version (makes sense for debugging and doesn't hurt).

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>

authored by

Eric W. Biederman and committed by
Miklos Szeredi
c9582eb0 dbf107b2

+13 -9
+13 -9
fs/fuse/dev.c
··· 112 112 refcount_dec(&req->count); 113 113 } 114 114 115 - static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req) 116 - { 117 - req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid()); 118 - req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid()); 119 - req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); 120 - } 121 - 122 115 void fuse_set_initialized(struct fuse_conn *fc) 123 116 { 124 117 /* Make sure stores before this are seen on another CPU */ ··· 156 163 goto out; 157 164 } 158 165 159 - fuse_req_init_context(fc, req); 166 + req->in.h.uid = from_kuid(&init_user_ns, current_fsuid()); 167 + req->in.h.gid = from_kgid(&init_user_ns, current_fsgid()); 168 + req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); 169 + 160 170 __set_bit(FR_WAITING, &req->flags); 161 171 if (for_background) 162 172 __set_bit(FR_BACKGROUND, &req->flags); 163 173 174 + if (unlikely(req->in.h.uid == ((uid_t)-1) || 175 + req->in.h.gid == ((gid_t)-1))) { 176 + fuse_put_request(fc, req); 177 + return ERR_PTR(-EOVERFLOW); 178 + } 164 179 return req; 165 180 166 181 out: ··· 257 256 if (!req) 258 257 req = get_reserved_req(fc, file); 259 258 260 - fuse_req_init_context(fc, req); 259 + req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid()); 260 + req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid()); 261 + req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); 262 + 261 263 __set_bit(FR_WAITING, &req->flags); 262 264 __clear_bit(FR_BACKGROUND, &req->flags); 263 265 return req;