Commit 1a9515ac authored by Amir Goldstein's avatar Amir Goldstein Committed by Jan Kara

fanotify: use helpers to parcel fanotify_info buffer

fanotify_info buffer is parceled into variable sized records, so the
records must be written in order: dir_fh, file_fh, name.

Use helpers to assert that order and make fanotify_alloc_name_event()
a bit more generic to allow empty dir_fh record and to allow expanding
to more records (i.e. name2) soon.

Link: https://lore.kernel.org/r/20211129201537.1932819-7-amir73il@gmail.comSigned-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 2d9374f0
...@@ -576,7 +576,7 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id, ...@@ -576,7 +576,7 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id,
return &ffe->fae; return &ffe->fae;
} }
static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
__kernel_fsid_t *fsid, __kernel_fsid_t *fsid,
const struct qstr *name, const struct qstr *name,
struct inode *child, struct inode *child,
...@@ -586,15 +586,17 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, ...@@ -586,15 +586,17 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
struct fanotify_name_event *fne; struct fanotify_name_event *fne;
struct fanotify_info *info; struct fanotify_info *info;
struct fanotify_fh *dfh, *ffh; struct fanotify_fh *dfh, *ffh;
unsigned int dir_fh_len = fanotify_encode_fh_len(id); unsigned int dir_fh_len = fanotify_encode_fh_len(dir);
unsigned int child_fh_len = fanotify_encode_fh_len(child); unsigned int child_fh_len = fanotify_encode_fh_len(child);
unsigned int size; unsigned long name_len = name ? name->len : 0;
unsigned int len, size;
size = sizeof(*fne) + FANOTIFY_FH_HDR_LEN + dir_fh_len; /* Reserve terminating null byte even for empty name */
size = sizeof(*fne) + name_len + 1;
if (dir_fh_len)
size += FANOTIFY_FH_HDR_LEN + dir_fh_len;
if (child_fh_len) if (child_fh_len)
size += FANOTIFY_FH_HDR_LEN + child_fh_len; size += FANOTIFY_FH_HDR_LEN + child_fh_len;
if (name)
size += name->len + 1;
fne = kmalloc(size, gfp); fne = kmalloc(size, gfp);
if (!fne) if (!fne)
return NULL; return NULL;
...@@ -604,22 +606,23 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, ...@@ -604,22 +606,23 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
*hash ^= fanotify_hash_fsid(fsid); *hash ^= fanotify_hash_fsid(fsid);
info = &fne->info; info = &fne->info;
fanotify_info_init(info); fanotify_info_init(info);
dfh = fanotify_info_dir_fh(info); if (dir_fh_len) {
info->dir_fh_totlen = fanotify_encode_fh(dfh, id, dir_fh_len, hash, 0); dfh = fanotify_info_dir_fh(info);
len = fanotify_encode_fh(dfh, dir, dir_fh_len, hash, 0);
fanotify_info_set_dir_fh(info, len);
}
if (child_fh_len) { if (child_fh_len) {
ffh = fanotify_info_file_fh(info); ffh = fanotify_info_file_fh(info);
info->file_fh_totlen = fanotify_encode_fh(ffh, child, len = fanotify_encode_fh(ffh, child, child_fh_len, hash, 0);
child_fh_len, hash, 0); fanotify_info_set_file_fh(info, len);
} }
if (name) { if (name_len) {
long salt = name->len;
fanotify_info_copy_name(info, name); fanotify_info_copy_name(info, name);
*hash ^= full_name_hash((void *)salt, name->name, name->len); *hash ^= full_name_hash((void *)name_len, name->name, name_len);
} }
pr_debug("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", pr_debug("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n",
__func__, id->i_ino, size, dir_fh_len, child_fh_len, __func__, size, dir_fh_len, child_fh_len,
info->name_len, info->name_len, fanotify_info_name(info)); info->name_len, info->name_len, fanotify_info_name(info));
return &fne->fae; return &fne->fae;
......
...@@ -138,6 +138,26 @@ static inline void fanotify_info_init(struct fanotify_info *info) ...@@ -138,6 +138,26 @@ static inline void fanotify_info_init(struct fanotify_info *info)
info->name_len = 0; info->name_len = 0;
} }
/* These set/copy helpers MUST be called by order */
static inline void fanotify_info_set_dir_fh(struct fanotify_info *info,
unsigned int totlen)
{
if (WARN_ON_ONCE(info->file_fh_totlen > 0) ||
WARN_ON_ONCE(info->name_len > 0))
return;
info->dir_fh_totlen = totlen;
}
static inline void fanotify_info_set_file_fh(struct fanotify_info *info,
unsigned int totlen)
{
if (WARN_ON_ONCE(info->name_len > 0))
return;
info->file_fh_totlen = totlen;
}
static inline void fanotify_info_copy_name(struct fanotify_info *info, static inline void fanotify_info_copy_name(struct fanotify_info *info,
const struct qstr *name) const struct qstr *name)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment