Skip to content

Commit 15d937d

Browse files
author
Miklos Szeredi
committed
fuse: add request extension
Will need to add supplementary groups to create messages, so add the general concept of a request extension. A request extension is appended to the end of the main request. It has a header indicating the size and type of the extension. The create security context (fuse_secctx_*) is similar to the generic request extension, so include that as well in a backward compatible manner. Add the total extension length to the request header. The offset of the extension block within the request can be calculated by: inh->len - inh->total_extlen * 8 Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 1b929c0 commit 15d937d

File tree

4 files changed

+71
-31
lines changed

4 files changed

+71
-31
lines changed

fs/fuse/dev.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@ static void fuse_args_to_req(struct fuse_req *req, struct fuse_args *args)
476476
req->in.h.opcode = args->opcode;
477477
req->in.h.nodeid = args->nodeid;
478478
req->args = args;
479+
if (args->is_ext)
480+
req->in.h.total_extlen = args->in_args[args->ext_idx].size / 8;
479481
if (args->end)
480482
__set_bit(FR_ASYNC, &req->flags);
481483
}

fs/fuse/dir.c

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
466466
}
467467

468468
static int get_security_context(struct dentry *entry, umode_t mode,
469-
void **security_ctx, u32 *security_ctxlen)
469+
struct fuse_in_arg *ext)
470470
{
471471
struct fuse_secctx *fctx;
472472
struct fuse_secctx_header *header;
@@ -513,14 +513,42 @@ static int get_security_context(struct dentry *entry, umode_t mode,
513513

514514
memcpy(ptr, ctx, ctxlen);
515515
}
516-
*security_ctxlen = total_len;
517-
*security_ctx = header;
516+
ext->size = total_len;
517+
ext->value = header;
518518
err = 0;
519519
out_err:
520520
kfree(ctx);
521521
return err;
522522
}
523523

524+
static int get_create_ext(struct fuse_args *args, struct dentry *dentry,
525+
umode_t mode)
526+
{
527+
struct fuse_conn *fc = get_fuse_conn_super(dentry->d_sb);
528+
struct fuse_in_arg ext = { .size = 0, .value = NULL };
529+
int err = 0;
530+
531+
if (fc->init_security)
532+
err = get_security_context(dentry, mode, &ext);
533+
534+
if (!err && ext.size) {
535+
WARN_ON(args->in_numargs >= ARRAY_SIZE(args->in_args));
536+
args->is_ext = true;
537+
args->ext_idx = args->in_numargs++;
538+
args->in_args[args->ext_idx] = ext;
539+
} else {
540+
kfree(ext.value);
541+
}
542+
543+
return err;
544+
}
545+
546+
static void free_ext_value(struct fuse_args *args)
547+
{
548+
if (args->is_ext)
549+
kfree(args->in_args[args->ext_idx].value);
550+
}
551+
524552
/*
525553
* Atomic create+open operation
526554
*
@@ -541,8 +569,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
541569
struct fuse_entry_out outentry;
542570
struct fuse_inode *fi;
543571
struct fuse_file *ff;
544-
void *security_ctx = NULL;
545-
u32 security_ctxlen;
546572
bool trunc = flags & O_TRUNC;
547573

548574
/* Userspace expects S_IFREG in create mode */
@@ -586,19 +612,12 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
586612
args.out_args[1].size = sizeof(outopen);
587613
args.out_args[1].value = &outopen;
588614

589-
if (fm->fc->init_security) {
590-
err = get_security_context(entry, mode, &security_ctx,
591-
&security_ctxlen);
592-
if (err)
593-
goto out_put_forget_req;
594-
595-
args.in_numargs = 3;
596-
args.in_args[2].size = security_ctxlen;
597-
args.in_args[2].value = security_ctx;
598-
}
615+
err = get_create_ext(&args, entry, mode);
616+
if (err)
617+
goto out_put_forget_req;
599618

600619
err = fuse_simple_request(fm, &args);
601-
kfree(security_ctx);
620+
free_ext_value(&args);
602621
if (err)
603622
goto out_free_ff;
604623

@@ -705,8 +724,6 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
705724
struct dentry *d;
706725
int err;
707726
struct fuse_forget_link *forget;
708-
void *security_ctx = NULL;
709-
u32 security_ctxlen;
710727

711728
if (fuse_is_bad(dir))
712729
return -EIO;
@@ -721,21 +738,14 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
721738
args->out_args[0].size = sizeof(outarg);
722739
args->out_args[0].value = &outarg;
723740

724-
if (fm->fc->init_security && args->opcode != FUSE_LINK) {
725-
err = get_security_context(entry, mode, &security_ctx,
726-
&security_ctxlen);
741+
if (args->opcode != FUSE_LINK) {
742+
err = get_create_ext(args, entry, mode);
727743
if (err)
728744
goto out_put_forget_req;
729-
730-
BUG_ON(args->in_numargs != 2);
731-
732-
args->in_numargs = 3;
733-
args->in_args[2].size = security_ctxlen;
734-
args->in_args[2].value = security_ctx;
735745
}
736746

737747
err = fuse_simple_request(fm, args);
738-
kfree(security_ctx);
748+
free_ext_value(args);
739749
if (err)
740750
goto out_put_forget_req;
741751

fs/fuse/fuse_i.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,9 @@ struct fuse_page_desc {
249249
struct fuse_args {
250250
uint64_t nodeid;
251251
uint32_t opcode;
252-
unsigned short in_numargs;
253-
unsigned short out_numargs;
252+
uint8_t in_numargs;
253+
uint8_t out_numargs;
254+
uint8_t ext_idx;
254255
bool force:1;
255256
bool noreply:1;
256257
bool nocreds:1;
@@ -261,6 +262,7 @@ struct fuse_args {
261262
bool page_zeroing:1;
262263
bool page_replace:1;
263264
bool may_block:1;
265+
bool is_ext:1;
264266
struct fuse_in_arg in_args[3];
265267
struct fuse_arg out_args[2];
266268
void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error);

include/uapi/linux/fuse.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@
201201
* 7.38
202202
* - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry
203203
* - add FOPEN_PARALLEL_DIRECT_WRITES
204+
* - add total_extlen to fuse_in_header
205+
* - add FUSE_MAX_NR_SECCTX
206+
* - add extension header
204207
*/
205208

206209
#ifndef _LINUX_FUSE_H
@@ -503,6 +506,15 @@ struct fuse_file_lock {
503506
*/
504507
#define FUSE_EXPIRE_ONLY (1 << 0)
505508

509+
/**
510+
* extension type
511+
* FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx
512+
*/
513+
enum fuse_ext_type {
514+
/* Types 0..31 are reserved for fuse_secctx_header */
515+
FUSE_MAX_NR_SECCTX = 31,
516+
};
517+
506518
enum fuse_opcode {
507519
FUSE_LOOKUP = 1,
508520
FUSE_FORGET = 2, /* no reply */
@@ -886,7 +898,8 @@ struct fuse_in_header {
886898
uint32_t uid;
887899
uint32_t gid;
888900
uint32_t pid;
889-
uint32_t padding;
901+
uint16_t total_extlen; /* length of extensions in 8byte units */
902+
uint16_t padding;
890903
};
891904

892905
struct fuse_out_header {
@@ -1047,4 +1060,17 @@ struct fuse_secctx_header {
10471060
uint32_t nr_secctx;
10481061
};
10491062

1063+
/**
1064+
* struct fuse_ext_header - extension header
1065+
* @size: total size of this extension including this header
1066+
* @type: type of extension
1067+
*
1068+
* This is made compatible with fuse_secctx_header by using type values >
1069+
* FUSE_MAX_NR_SECCTX
1070+
*/
1071+
struct fuse_ext_header {
1072+
uint32_t size;
1073+
uint32_t type;
1074+
};
1075+
10501076
#endif /* _LINUX_FUSE_H */

0 commit comments

Comments
 (0)