Skip to content

Commit aa16880

Browse files
mihalicynMiklos Szeredi
authored andcommitted
fuse: add basic infrastructure to support idmappings
Add some preparational changes in fuse_get_req/fuse_force_creds to handle idmappings. Miklos suggested [1], [2] to change the meaning of in.h.uid/in.h.gid fields when daemon declares support for idmapped mounts. In a new semantic, we fill uid/gid values in fuse header with a id-mapped caller uid/gid (for requests which create new inodes), for all the rest cases we just send -1 to userspace. No functional changes intended. Link: https://lore.kernel.org/all/CAJfpegsVY97_5mHSc06mSw79FehFWtoXT=hhTUK_E-Yhr7OAuQ@mail.gmail.com/ [1] Link: https://lore.kernel.org/all/CAJfpegtHQsEUuFq1k4ZbTD3E1h-GsrN3PWyv7X8cg6sfU_W2Yw@mail.gmail.com/ [2] Signed-off-by: Alexander Mikhalitsyn <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 2097154 commit aa16880

File tree

3 files changed

+41
-12
lines changed

3 files changed

+41
-12
lines changed

fs/fuse/dev.c

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ static void fuse_drop_waiting(struct fuse_conn *fc)
108108

109109
static void fuse_put_request(struct fuse_req *req);
110110

111-
static struct fuse_req *fuse_get_req(struct fuse_mount *fm, bool for_background)
111+
static struct fuse_req *fuse_get_req(struct mnt_idmap *idmap,
112+
struct fuse_mount *fm,
113+
bool for_background)
112114
{
113115
struct fuse_conn *fc = fm->fc;
114116
struct fuse_req *req;
@@ -140,19 +142,37 @@ static struct fuse_req *fuse_get_req(struct fuse_mount *fm, bool for_background)
140142
goto out;
141143
}
142144

143-
req->in.h.uid = from_kuid(fc->user_ns, current_fsuid());
144-
req->in.h.gid = from_kgid(fc->user_ns, current_fsgid());
145145
req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
146146

147147
__set_bit(FR_WAITING, &req->flags);
148148
if (for_background)
149149
__set_bit(FR_BACKGROUND, &req->flags);
150150

151-
if (unlikely(req->in.h.uid == ((uid_t)-1) ||
152-
req->in.h.gid == ((gid_t)-1))) {
153-
fuse_put_request(req);
154-
return ERR_PTR(-EOVERFLOW);
151+
if ((fm->sb->s_iflags & SB_I_NOIDMAP) || idmap) {
152+
kuid_t idmapped_fsuid;
153+
kgid_t idmapped_fsgid;
154+
155+
/*
156+
* Note, that when
157+
* (fm->sb->s_iflags & SB_I_NOIDMAP) is true, then
158+
* (idmap == &nop_mnt_idmap) is always true and therefore,
159+
* mapped_fsuid(idmap, fc->user_ns) == current_fsuid().
160+
*/
161+
idmapped_fsuid = idmap ? mapped_fsuid(idmap, fc->user_ns) : current_fsuid();
162+
idmapped_fsgid = idmap ? mapped_fsgid(idmap, fc->user_ns) : current_fsgid();
163+
req->in.h.uid = from_kuid(fc->user_ns, idmapped_fsuid);
164+
req->in.h.gid = from_kgid(fc->user_ns, idmapped_fsgid);
165+
166+
if (unlikely(req->in.h.uid == ((uid_t)-1) ||
167+
req->in.h.gid == ((gid_t)-1))) {
168+
fuse_put_request(req);
169+
return ERR_PTR(-EOVERFLOW);
170+
}
171+
} else {
172+
req->in.h.uid = FUSE_INVALID_UIDGID;
173+
req->in.h.gid = FUSE_INVALID_UIDGID;
155174
}
175+
156176
return req;
157177

158178
out:
@@ -497,8 +517,14 @@ static void fuse_force_creds(struct fuse_req *req)
497517
{
498518
struct fuse_conn *fc = req->fm->fc;
499519

500-
req->in.h.uid = from_kuid_munged(fc->user_ns, current_fsuid());
501-
req->in.h.gid = from_kgid_munged(fc->user_ns, current_fsgid());
520+
if (req->fm->sb->s_iflags & SB_I_NOIDMAP) {
521+
req->in.h.uid = from_kuid_munged(fc->user_ns, current_fsuid());
522+
req->in.h.gid = from_kgid_munged(fc->user_ns, current_fsgid());
523+
} else {
524+
req->in.h.uid = FUSE_INVALID_UIDGID;
525+
req->in.h.gid = FUSE_INVALID_UIDGID;
526+
}
527+
502528
req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
503529
}
504530

@@ -530,7 +556,7 @@ ssize_t fuse_simple_request(struct fuse_mount *fm, struct fuse_args *args)
530556
__set_bit(FR_FORCE, &req->flags);
531557
} else {
532558
WARN_ON(args->nocreds);
533-
req = fuse_get_req(fm, false);
559+
req = fuse_get_req(NULL, fm, false);
534560
if (IS_ERR(req))
535561
return PTR_ERR(req);
536562
}
@@ -591,7 +617,7 @@ int fuse_simple_background(struct fuse_mount *fm, struct fuse_args *args,
591617
__set_bit(FR_BACKGROUND, &req->flags);
592618
} else {
593619
WARN_ON(args->nocreds);
594-
req = fuse_get_req(fm, true);
620+
req = fuse_get_req(NULL, fm, true);
595621
if (IS_ERR(req))
596622
return PTR_ERR(req);
597623
}
@@ -613,7 +639,7 @@ static int fuse_simple_notify_reply(struct fuse_mount *fm,
613639
struct fuse_req *req;
614640
struct fuse_iqueue *fiq = &fm->fc->iq;
615641

616-
req = fuse_get_req(fm, false);
642+
req = fuse_get_req(NULL, fm, false);
617643
if (IS_ERR(req))
618644
return PTR_ERR(req);
619645

fs/fuse/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,7 @@ static void fuse_sb_defaults(struct super_block *sb)
15721572
sb->s_time_gran = 1;
15731573
sb->s_export_op = &fuse_export_operations;
15741574
sb->s_iflags |= SB_I_IMA_UNVERIFIABLE_SIGNATURE;
1575+
sb->s_iflags |= SB_I_NOIDMAP;
15751576
if (sb->s_user_ns != &init_user_ns)
15761577
sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER;
15771578
sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION);

include/uapi/linux/fuse.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,8 @@ struct fuse_fallocate_in {
984984
*/
985985
#define FUSE_UNIQUE_RESEND (1ULL << 63)
986986

987+
#define FUSE_INVALID_UIDGID ((uint32_t)(-1))
988+
987989
struct fuse_in_header {
988990
uint32_t len;
989991
uint32_t opcode;

0 commit comments

Comments
 (0)