]>
Commit | Line | Data |
---|---|---|
52761858 SL |
1 | From d081712cdf4b7a4274fb883bac202ddb596238c2 Mon Sep 17 00:00:00 2001 |
2 | From: Sasha Levin <sashal@kernel.org> | |
3 | Date: Mon, 29 Nov 2021 22:15:32 +0200 | |
4 | Subject: fanotify: use helpers to parcel fanotify_info buffer | |
5 | ||
6 | From: Amir Goldstein <amir73il@gmail.com> | |
7 | ||
8 | [ Upstream commit 1a9515ac9e55e68d733bab81bd408463ab1e25b1 ] | |
9 | ||
10 | fanotify_info buffer is parceled into variable sized records, so the | |
11 | records must be written in order: dir_fh, file_fh, name. | |
12 | ||
13 | Use helpers to assert that order and make fanotify_alloc_name_event() | |
14 | a bit more generic to allow empty dir_fh record and to allow expanding | |
15 | to more records (i.e. name2) soon. | |
16 | ||
17 | Link: https://lore.kernel.org/r/20211129201537.1932819-7-amir73il@gmail.com | |
18 | Signed-off-by: Amir Goldstein <amir73il@gmail.com> | |
19 | Signed-off-by: Jan Kara <jack@suse.cz> | |
20 | Signed-off-by: Chuck Lever <chuck.lever@oracle.com> | |
21 | --- | |
22 | fs/notify/fanotify/fanotify.c | 35 +++++++++++++++++++---------------- | |
23 | fs/notify/fanotify/fanotify.h | 20 ++++++++++++++++++++ | |
24 | 2 files changed, 39 insertions(+), 16 deletions(-) | |
25 | ||
26 | diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c | |
27 | index ffad224be0149..2b13c79cebc62 100644 | |
28 | --- a/fs/notify/fanotify/fanotify.c | |
29 | +++ b/fs/notify/fanotify/fanotify.c | |
30 | @@ -576,7 +576,7 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id, | |
31 | return &ffe->fae; | |
32 | } | |
33 | ||
34 | -static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, | |
35 | +static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, | |
36 | __kernel_fsid_t *fsid, | |
37 | const struct qstr *name, | |
38 | struct inode *child, | |
39 | @@ -586,15 +586,17 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, | |
40 | struct fanotify_name_event *fne; | |
41 | struct fanotify_info *info; | |
42 | struct fanotify_fh *dfh, *ffh; | |
43 | - unsigned int dir_fh_len = fanotify_encode_fh_len(id); | |
44 | + unsigned int dir_fh_len = fanotify_encode_fh_len(dir); | |
45 | unsigned int child_fh_len = fanotify_encode_fh_len(child); | |
46 | - unsigned int size; | |
47 | + unsigned long name_len = name ? name->len : 0; | |
48 | + unsigned int len, size; | |
49 | ||
50 | - size = sizeof(*fne) + FANOTIFY_FH_HDR_LEN + dir_fh_len; | |
51 | + /* Reserve terminating null byte even for empty name */ | |
52 | + size = sizeof(*fne) + name_len + 1; | |
53 | + if (dir_fh_len) | |
54 | + size += FANOTIFY_FH_HDR_LEN + dir_fh_len; | |
55 | if (child_fh_len) | |
56 | size += FANOTIFY_FH_HDR_LEN + child_fh_len; | |
57 | - if (name) | |
58 | - size += name->len + 1; | |
59 | fne = kmalloc(size, gfp); | |
60 | if (!fne) | |
61 | return NULL; | |
62 | @@ -604,22 +606,23 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, | |
63 | *hash ^= fanotify_hash_fsid(fsid); | |
64 | info = &fne->info; | |
65 | fanotify_info_init(info); | |
66 | - dfh = fanotify_info_dir_fh(info); | |
67 | - info->dir_fh_totlen = fanotify_encode_fh(dfh, id, dir_fh_len, hash, 0); | |
68 | + if (dir_fh_len) { | |
69 | + dfh = fanotify_info_dir_fh(info); | |
70 | + len = fanotify_encode_fh(dfh, dir, dir_fh_len, hash, 0); | |
71 | + fanotify_info_set_dir_fh(info, len); | |
72 | + } | |
73 | if (child_fh_len) { | |
74 | ffh = fanotify_info_file_fh(info); | |
75 | - info->file_fh_totlen = fanotify_encode_fh(ffh, child, | |
76 | - child_fh_len, hash, 0); | |
77 | + len = fanotify_encode_fh(ffh, child, child_fh_len, hash, 0); | |
78 | + fanotify_info_set_file_fh(info, len); | |
79 | } | |
80 | - if (name) { | |
81 | - long salt = name->len; | |
82 | - | |
83 | + if (name_len) { | |
84 | fanotify_info_copy_name(info, name); | |
85 | - *hash ^= full_name_hash((void *)salt, name->name, name->len); | |
86 | + *hash ^= full_name_hash((void *)name_len, name->name, name_len); | |
87 | } | |
88 | ||
89 | - pr_debug("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", | |
90 | - __func__, id->i_ino, size, dir_fh_len, child_fh_len, | |
91 | + pr_debug("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", | |
92 | + __func__, size, dir_fh_len, child_fh_len, | |
93 | info->name_len, info->name_len, fanotify_info_name(info)); | |
94 | ||
95 | return &fne->fae; | |
96 | diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h | |
97 | index dd23ba659e76b..7ac6f9f1e4148 100644 | |
98 | --- a/fs/notify/fanotify/fanotify.h | |
99 | +++ b/fs/notify/fanotify/fanotify.h | |
100 | @@ -138,6 +138,26 @@ static inline void fanotify_info_init(struct fanotify_info *info) | |
101 | info->name_len = 0; | |
102 | } | |
103 | ||
104 | +/* These set/copy helpers MUST be called by order */ | |
105 | +static inline void fanotify_info_set_dir_fh(struct fanotify_info *info, | |
106 | + unsigned int totlen) | |
107 | +{ | |
108 | + if (WARN_ON_ONCE(info->file_fh_totlen > 0) || | |
109 | + WARN_ON_ONCE(info->name_len > 0)) | |
110 | + return; | |
111 | + | |
112 | + info->dir_fh_totlen = totlen; | |
113 | +} | |
114 | + | |
115 | +static inline void fanotify_info_set_file_fh(struct fanotify_info *info, | |
116 | + unsigned int totlen) | |
117 | +{ | |
118 | + if (WARN_ON_ONCE(info->name_len > 0)) | |
119 | + return; | |
120 | + | |
121 | + info->file_fh_totlen = totlen; | |
122 | +} | |
123 | + | |
124 | static inline void fanotify_info_copy_name(struct fanotify_info *info, | |
125 | const struct qstr *name) | |
126 | { | |
127 | -- | |
128 | 2.43.0 | |
129 |