habanalabs/gaudi: add missing handling of NIC related events
[linux-2.6-microblaze.git] / fs / fuse / dir.c
index 0654bfe..656e921 100644 (file)
@@ -17,6 +17,9 @@
 #include <linux/xattr.h>
 #include <linux/iversion.h>
 #include <linux/posix_acl.h>
+#include <linux/security.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
 
 static void fuse_advise_use_readdirplus(struct inode *dir)
 {
@@ -456,6 +459,62 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
        return ERR_PTR(err);
 }
 
+static int get_security_context(struct dentry *entry, umode_t mode,
+                               void **security_ctx, u32 *security_ctxlen)
+{
+       struct fuse_secctx *fctx;
+       struct fuse_secctx_header *header;
+       void *ctx = NULL, *ptr;
+       u32 ctxlen, total_len = sizeof(*header);
+       int err, nr_ctx = 0;
+       const char *name;
+       size_t namelen;
+
+       err = security_dentry_init_security(entry, mode, &entry->d_name,
+                                           &name, &ctx, &ctxlen);
+       if (err) {
+               if (err != -EOPNOTSUPP)
+                       goto out_err;
+               /* No LSM is supporting this security hook. Ignore error */
+               ctxlen = 0;
+               ctx = NULL;
+       }
+
+       if (ctxlen) {
+               nr_ctx = 1;
+               namelen = strlen(name) + 1;
+               err = -EIO;
+               if (WARN_ON(namelen > XATTR_NAME_MAX + 1 || ctxlen > S32_MAX))
+                       goto out_err;
+               total_len += FUSE_REC_ALIGN(sizeof(*fctx) + namelen + ctxlen);
+       }
+
+       err = -ENOMEM;
+       header = ptr = kzalloc(total_len, GFP_KERNEL);
+       if (!ptr)
+               goto out_err;
+
+       header->nr_secctx = nr_ctx;
+       header->size = total_len;
+       ptr += sizeof(*header);
+       if (nr_ctx) {
+               fctx = ptr;
+               fctx->size = ctxlen;
+               ptr += sizeof(*fctx);
+
+               strcpy(ptr, name);
+               ptr += namelen;
+
+               memcpy(ptr, ctx, ctxlen);
+       }
+       *security_ctxlen = total_len;
+       *security_ctx = header;
+       err = 0;
+out_err:
+       kfree(ctx);
+       return err;
+}
+
 /*
  * Atomic create+open operation
  *
@@ -476,6 +535,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
        struct fuse_entry_out outentry;
        struct fuse_inode *fi;
        struct fuse_file *ff;
+       void *security_ctx = NULL;
+       u32 security_ctxlen;
 
        /* Userspace expects S_IFREG in create mode */
        BUG_ON((mode & S_IFMT) != S_IFREG);
@@ -517,7 +578,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
        args.out_args[0].value = &outentry;
        args.out_args[1].size = sizeof(outopen);
        args.out_args[1].value = &outopen;
+
+       if (fm->fc->init_security) {
+               err = get_security_context(entry, mode, &security_ctx,
+                                          &security_ctxlen);
+               if (err)
+                       goto out_put_forget_req;
+
+               args.in_numargs = 3;
+               args.in_args[2].size = security_ctxlen;
+               args.in_args[2].value = security_ctx;
+       }
+
        err = fuse_simple_request(fm, &args);
+       kfree(security_ctx);
        if (err)
                goto out_free_ff;
 
@@ -620,6 +694,8 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
        struct dentry *d;
        int err;
        struct fuse_forget_link *forget;
+       void *security_ctx = NULL;
+       u32 security_ctxlen;
 
        if (fuse_is_bad(dir))
                return -EIO;
@@ -633,7 +709,22 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
        args->out_numargs = 1;
        args->out_args[0].size = sizeof(outarg);
        args->out_args[0].value = &outarg;
+
+       if (fm->fc->init_security && args->opcode != FUSE_LINK) {
+               err = get_security_context(entry, mode, &security_ctx,
+                                          &security_ctxlen);
+               if (err)
+                       goto out_put_forget_req;
+
+               BUG_ON(args->in_numargs != 2);
+
+               args->in_numargs = 3;
+               args->in_args[2].size = security_ctxlen;
+               args->in_args[2].value = security_ctx;
+       }
+
        err = fuse_simple_request(fm, args);
+       kfree(security_ctx);
        if (err)
                goto out_put_forget_req;