ceph: fscrypt_auth handling for ceph
[linux-block.git] / fs / ceph / crypto.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/ceph/ceph_debug.h>
3 #include <linux/xattr.h>
4 #include <linux/fscrypt.h>
5
6 #include "super.h"
7 #include "crypto.h"
8
9 static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t len)
10 {
11         struct ceph_inode_info *ci = ceph_inode(inode);
12         struct ceph_fscrypt_auth *cfa = (struct ceph_fscrypt_auth *)ci->fscrypt_auth;
13         u32 ctxlen;
14
15         /* Non existent or too short? */
16         if (!cfa || (ci->fscrypt_auth_len < (offsetof(struct ceph_fscrypt_auth, cfa_blob) + 1)))
17                 return -ENOBUFS;
18
19         /* Some format we don't recognize? */
20         if (le32_to_cpu(cfa->cfa_version) != CEPH_FSCRYPT_AUTH_VERSION)
21                 return -ENOBUFS;
22
23         ctxlen = le32_to_cpu(cfa->cfa_blob_len);
24         if (len < ctxlen)
25                 return -ERANGE;
26
27         memcpy(ctx, cfa->cfa_blob, ctxlen);
28         return ctxlen;
29 }
30
31 static int ceph_crypt_set_context(struct inode *inode, const void *ctx,
32                                   size_t len, void *fs_data)
33 {
34         int ret;
35         struct iattr attr = { };
36         struct ceph_iattr cia = { };
37         struct ceph_fscrypt_auth *cfa;
38
39         WARN_ON_ONCE(fs_data);
40
41         if (len > FSCRYPT_SET_CONTEXT_MAX_SIZE)
42                 return -EINVAL;
43
44         cfa = kzalloc(sizeof(*cfa), GFP_KERNEL);
45         if (!cfa)
46                 return -ENOMEM;
47
48         cfa->cfa_version = cpu_to_le32(CEPH_FSCRYPT_AUTH_VERSION);
49         cfa->cfa_blob_len = cpu_to_le32(len);
50         memcpy(cfa->cfa_blob, ctx, len);
51
52         cia.fscrypt_auth = cfa;
53
54         ret = __ceph_setattr(inode, &attr, &cia);
55         if (ret == 0)
56                 inode_set_flags(inode, S_ENCRYPTED, S_ENCRYPTED);
57         kfree(cia.fscrypt_auth);
58         return ret;
59 }
60
61 static bool ceph_crypt_empty_dir(struct inode *inode)
62 {
63         struct ceph_inode_info *ci = ceph_inode(inode);
64
65         return ci->i_rsubdirs + ci->i_rfiles == 1;
66 }
67
68 static struct fscrypt_operations ceph_fscrypt_ops = {
69         .get_context            = ceph_crypt_get_context,
70         .set_context            = ceph_crypt_set_context,
71         .empty_dir              = ceph_crypt_empty_dir,
72 };
73
74 void ceph_fscrypt_set_ops(struct super_block *sb)
75 {
76         fscrypt_set_ops(sb, &ceph_fscrypt_ops);
77 }