cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fanotify.h (14022B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2#include <linux/fsnotify_backend.h>
      3#include <linux/path.h>
      4#include <linux/slab.h>
      5#include <linux/exportfs.h>
      6#include <linux/hashtable.h>
      7
      8extern struct kmem_cache *fanotify_mark_cache;
      9extern struct kmem_cache *fanotify_fid_event_cachep;
     10extern struct kmem_cache *fanotify_path_event_cachep;
     11extern struct kmem_cache *fanotify_perm_event_cachep;
     12
     13/* Possible states of the permission event */
     14enum {
     15	FAN_EVENT_INIT,
     16	FAN_EVENT_REPORTED,
     17	FAN_EVENT_ANSWERED,
     18	FAN_EVENT_CANCELED,
     19};
     20
     21/*
     22 * 3 dwords are sufficient for most local fs (64bit ino, 32bit generation).
     23 * fh buf should be dword aligned. On 64bit arch, the ext_buf pointer is
     24 * stored in either the first or last 2 dwords.
     25 */
     26#define FANOTIFY_INLINE_FH_LEN	(3 << 2)
     27#define FANOTIFY_FH_HDR_LEN	offsetof(struct fanotify_fh, buf)
     28
     29/* Fixed size struct for file handle */
     30struct fanotify_fh {
     31	u8 type;
     32	u8 len;
     33#define FANOTIFY_FH_FLAG_EXT_BUF 1
     34	u8 flags;
     35	u8 pad;
     36	unsigned char buf[];
     37} __aligned(4);
     38
     39/* Variable size struct for dir file handle + child file handle + name */
     40struct fanotify_info {
     41	/* size of dir_fh/file_fh including fanotify_fh hdr size */
     42	u8 dir_fh_totlen;
     43	u8 dir2_fh_totlen;
     44	u8 file_fh_totlen;
     45	u8 name_len;
     46	u8 name2_len;
     47	u8 pad[3];
     48	unsigned char buf[];
     49	/*
     50	 * (struct fanotify_fh) dir_fh starts at buf[0]
     51	 * (optional) dir2_fh starts at buf[dir_fh_totlen]
     52	 * (optional) file_fh starts at buf[dir_fh_totlen + dir2_fh_totlen]
     53	 * name starts at buf[dir_fh_totlen + dir2_fh_totlen + file_fh_totlen]
     54	 * ...
     55	 */
     56#define FANOTIFY_DIR_FH_SIZE(info)	((info)->dir_fh_totlen)
     57#define FANOTIFY_DIR2_FH_SIZE(info)	((info)->dir2_fh_totlen)
     58#define FANOTIFY_FILE_FH_SIZE(info)	((info)->file_fh_totlen)
     59#define FANOTIFY_NAME_SIZE(info)	((info)->name_len + 1)
     60#define FANOTIFY_NAME2_SIZE(info)	((info)->name2_len + 1)
     61
     62#define FANOTIFY_DIR_FH_OFFSET(info)	0
     63#define FANOTIFY_DIR2_FH_OFFSET(info) \
     64	(FANOTIFY_DIR_FH_OFFSET(info) + FANOTIFY_DIR_FH_SIZE(info))
     65#define FANOTIFY_FILE_FH_OFFSET(info) \
     66	(FANOTIFY_DIR2_FH_OFFSET(info) + FANOTIFY_DIR2_FH_SIZE(info))
     67#define FANOTIFY_NAME_OFFSET(info) \
     68	(FANOTIFY_FILE_FH_OFFSET(info) + FANOTIFY_FILE_FH_SIZE(info))
     69#define FANOTIFY_NAME2_OFFSET(info) \
     70	(FANOTIFY_NAME_OFFSET(info) + FANOTIFY_NAME_SIZE(info))
     71
     72#define FANOTIFY_DIR_FH_BUF(info) \
     73	((info)->buf + FANOTIFY_DIR_FH_OFFSET(info))
     74#define FANOTIFY_DIR2_FH_BUF(info) \
     75	((info)->buf + FANOTIFY_DIR2_FH_OFFSET(info))
     76#define FANOTIFY_FILE_FH_BUF(info) \
     77	((info)->buf + FANOTIFY_FILE_FH_OFFSET(info))
     78#define FANOTIFY_NAME_BUF(info) \
     79	((info)->buf + FANOTIFY_NAME_OFFSET(info))
     80#define FANOTIFY_NAME2_BUF(info) \
     81	((info)->buf + FANOTIFY_NAME2_OFFSET(info))
     82} __aligned(4);
     83
     84static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh)
     85{
     86	return (fh->flags & FANOTIFY_FH_FLAG_EXT_BUF);
     87}
     88
     89static inline char **fanotify_fh_ext_buf_ptr(struct fanotify_fh *fh)
     90{
     91	BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN % 4);
     92	BUILD_BUG_ON(__alignof__(char *) - 4 + sizeof(char *) >
     93		     FANOTIFY_INLINE_FH_LEN);
     94	return (char **)ALIGN((unsigned long)(fh->buf), __alignof__(char *));
     95}
     96
     97static inline void *fanotify_fh_ext_buf(struct fanotify_fh *fh)
     98{
     99	return *fanotify_fh_ext_buf_ptr(fh);
    100}
    101
    102static inline void *fanotify_fh_buf(struct fanotify_fh *fh)
    103{
    104	return fanotify_fh_has_ext_buf(fh) ? fanotify_fh_ext_buf(fh) : fh->buf;
    105}
    106
    107static inline int fanotify_info_dir_fh_len(struct fanotify_info *info)
    108{
    109	if (!info->dir_fh_totlen ||
    110	    WARN_ON_ONCE(info->dir_fh_totlen < FANOTIFY_FH_HDR_LEN))
    111		return 0;
    112
    113	return info->dir_fh_totlen - FANOTIFY_FH_HDR_LEN;
    114}
    115
    116static inline struct fanotify_fh *fanotify_info_dir_fh(struct fanotify_info *info)
    117{
    118	BUILD_BUG_ON(offsetof(struct fanotify_info, buf) % 4);
    119
    120	return (struct fanotify_fh *)FANOTIFY_DIR_FH_BUF(info);
    121}
    122
    123static inline int fanotify_info_dir2_fh_len(struct fanotify_info *info)
    124{
    125	if (!info->dir2_fh_totlen ||
    126	    WARN_ON_ONCE(info->dir2_fh_totlen < FANOTIFY_FH_HDR_LEN))
    127		return 0;
    128
    129	return info->dir2_fh_totlen - FANOTIFY_FH_HDR_LEN;
    130}
    131
    132static inline struct fanotify_fh *fanotify_info_dir2_fh(struct fanotify_info *info)
    133{
    134	return (struct fanotify_fh *)FANOTIFY_DIR2_FH_BUF(info);
    135}
    136
    137static inline int fanotify_info_file_fh_len(struct fanotify_info *info)
    138{
    139	if (!info->file_fh_totlen ||
    140	    WARN_ON_ONCE(info->file_fh_totlen < FANOTIFY_FH_HDR_LEN))
    141		return 0;
    142
    143	return info->file_fh_totlen - FANOTIFY_FH_HDR_LEN;
    144}
    145
    146static inline struct fanotify_fh *fanotify_info_file_fh(struct fanotify_info *info)
    147{
    148	return (struct fanotify_fh *)FANOTIFY_FILE_FH_BUF(info);
    149}
    150
    151static inline char *fanotify_info_name(struct fanotify_info *info)
    152{
    153	if (!info->name_len)
    154		return NULL;
    155
    156	return FANOTIFY_NAME_BUF(info);
    157}
    158
    159static inline char *fanotify_info_name2(struct fanotify_info *info)
    160{
    161	if (!info->name2_len)
    162		return NULL;
    163
    164	return FANOTIFY_NAME2_BUF(info);
    165}
    166
    167static inline void fanotify_info_init(struct fanotify_info *info)
    168{
    169	BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN + MAX_HANDLE_SZ > U8_MAX);
    170	BUILD_BUG_ON(NAME_MAX > U8_MAX);
    171
    172	info->dir_fh_totlen = 0;
    173	info->dir2_fh_totlen = 0;
    174	info->file_fh_totlen = 0;
    175	info->name_len = 0;
    176	info->name2_len = 0;
    177}
    178
    179/* These set/copy helpers MUST be called by order */
    180static inline void fanotify_info_set_dir_fh(struct fanotify_info *info,
    181					    unsigned int totlen)
    182{
    183	if (WARN_ON_ONCE(info->dir2_fh_totlen > 0) ||
    184	    WARN_ON_ONCE(info->file_fh_totlen > 0) ||
    185	    WARN_ON_ONCE(info->name_len > 0) ||
    186	    WARN_ON_ONCE(info->name2_len > 0))
    187		return;
    188
    189	info->dir_fh_totlen = totlen;
    190}
    191
    192static inline void fanotify_info_set_dir2_fh(struct fanotify_info *info,
    193					     unsigned int totlen)
    194{
    195	if (WARN_ON_ONCE(info->file_fh_totlen > 0) ||
    196	    WARN_ON_ONCE(info->name_len > 0) ||
    197	    WARN_ON_ONCE(info->name2_len > 0))
    198		return;
    199
    200	info->dir2_fh_totlen = totlen;
    201}
    202
    203static inline void fanotify_info_set_file_fh(struct fanotify_info *info,
    204					     unsigned int totlen)
    205{
    206	if (WARN_ON_ONCE(info->name_len > 0) ||
    207	    WARN_ON_ONCE(info->name2_len > 0))
    208		return;
    209
    210	info->file_fh_totlen = totlen;
    211}
    212
    213static inline void fanotify_info_copy_name(struct fanotify_info *info,
    214					   const struct qstr *name)
    215{
    216	if (WARN_ON_ONCE(name->len > NAME_MAX) ||
    217	    WARN_ON_ONCE(info->name2_len > 0))
    218		return;
    219
    220	info->name_len = name->len;
    221	strcpy(fanotify_info_name(info), name->name);
    222}
    223
    224static inline void fanotify_info_copy_name2(struct fanotify_info *info,
    225					    const struct qstr *name)
    226{
    227	if (WARN_ON_ONCE(name->len > NAME_MAX))
    228		return;
    229
    230	info->name2_len = name->len;
    231	strcpy(fanotify_info_name2(info), name->name);
    232}
    233
    234/*
    235 * Common structure for fanotify events. Concrete structs are allocated in
    236 * fanotify_handle_event() and freed when the information is retrieved by
    237 * userspace. The type of event determines how it was allocated, how it will
    238 * be freed and which concrete struct it may be cast to.
    239 */
    240enum fanotify_event_type {
    241	FANOTIFY_EVENT_TYPE_FID, /* fixed length */
    242	FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */
    243	FANOTIFY_EVENT_TYPE_PATH,
    244	FANOTIFY_EVENT_TYPE_PATH_PERM,
    245	FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */
    246	FANOTIFY_EVENT_TYPE_FS_ERROR, /* struct fanotify_error_event */
    247	__FANOTIFY_EVENT_TYPE_NUM
    248};
    249
    250#define FANOTIFY_EVENT_TYPE_BITS \
    251	(ilog2(__FANOTIFY_EVENT_TYPE_NUM - 1) + 1)
    252#define FANOTIFY_EVENT_HASH_BITS \
    253	(32 - FANOTIFY_EVENT_TYPE_BITS)
    254
    255struct fanotify_event {
    256	struct fsnotify_event fse;
    257	struct hlist_node merge_list;	/* List for hashed merge */
    258	u32 mask;
    259	struct {
    260		unsigned int type : FANOTIFY_EVENT_TYPE_BITS;
    261		unsigned int hash : FANOTIFY_EVENT_HASH_BITS;
    262	};
    263	struct pid *pid;
    264};
    265
    266static inline void fanotify_init_event(struct fanotify_event *event,
    267				       unsigned int hash, u32 mask)
    268{
    269	fsnotify_init_event(&event->fse);
    270	INIT_HLIST_NODE(&event->merge_list);
    271	event->hash = hash;
    272	event->mask = mask;
    273	event->pid = NULL;
    274}
    275
    276#define FANOTIFY_INLINE_FH(name, size)					\
    277struct {								\
    278	struct fanotify_fh (name);					\
    279	/* Space for object_fh.buf[] - access with fanotify_fh_buf() */	\
    280	unsigned char _inline_fh_buf[(size)];				\
    281}
    282
    283struct fanotify_fid_event {
    284	struct fanotify_event fae;
    285	__kernel_fsid_t fsid;
    286
    287	FANOTIFY_INLINE_FH(object_fh, FANOTIFY_INLINE_FH_LEN);
    288};
    289
    290static inline struct fanotify_fid_event *
    291FANOTIFY_FE(struct fanotify_event *event)
    292{
    293	return container_of(event, struct fanotify_fid_event, fae);
    294}
    295
    296struct fanotify_name_event {
    297	struct fanotify_event fae;
    298	__kernel_fsid_t fsid;
    299	struct fanotify_info info;
    300};
    301
    302static inline struct fanotify_name_event *
    303FANOTIFY_NE(struct fanotify_event *event)
    304{
    305	return container_of(event, struct fanotify_name_event, fae);
    306}
    307
    308struct fanotify_error_event {
    309	struct fanotify_event fae;
    310	s32 error; /* Error reported by the Filesystem. */
    311	u32 err_count; /* Suppressed errors count */
    312
    313	__kernel_fsid_t fsid; /* FSID this error refers to. */
    314
    315	FANOTIFY_INLINE_FH(object_fh, MAX_HANDLE_SZ);
    316};
    317
    318static inline struct fanotify_error_event *
    319FANOTIFY_EE(struct fanotify_event *event)
    320{
    321	return container_of(event, struct fanotify_error_event, fae);
    322}
    323
    324static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event)
    325{
    326	if (event->type == FANOTIFY_EVENT_TYPE_FID)
    327		return &FANOTIFY_FE(event)->fsid;
    328	else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
    329		return &FANOTIFY_NE(event)->fsid;
    330	else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR)
    331		return &FANOTIFY_EE(event)->fsid;
    332	else
    333		return NULL;
    334}
    335
    336static inline struct fanotify_fh *fanotify_event_object_fh(
    337						struct fanotify_event *event)
    338{
    339	if (event->type == FANOTIFY_EVENT_TYPE_FID)
    340		return &FANOTIFY_FE(event)->object_fh;
    341	else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
    342		return fanotify_info_file_fh(&FANOTIFY_NE(event)->info);
    343	else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR)
    344		return &FANOTIFY_EE(event)->object_fh;
    345	else
    346		return NULL;
    347}
    348
    349static inline struct fanotify_info *fanotify_event_info(
    350						struct fanotify_event *event)
    351{
    352	if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
    353		return &FANOTIFY_NE(event)->info;
    354	else
    355		return NULL;
    356}
    357
    358static inline int fanotify_event_object_fh_len(struct fanotify_event *event)
    359{
    360	struct fanotify_info *info = fanotify_event_info(event);
    361	struct fanotify_fh *fh = fanotify_event_object_fh(event);
    362
    363	if (info)
    364		return info->file_fh_totlen ? fh->len : 0;
    365	else
    366		return fh ? fh->len : 0;
    367}
    368
    369static inline int fanotify_event_dir_fh_len(struct fanotify_event *event)
    370{
    371	struct fanotify_info *info = fanotify_event_info(event);
    372
    373	return info ? fanotify_info_dir_fh_len(info) : 0;
    374}
    375
    376static inline int fanotify_event_dir2_fh_len(struct fanotify_event *event)
    377{
    378	struct fanotify_info *info = fanotify_event_info(event);
    379
    380	return info ? fanotify_info_dir2_fh_len(info) : 0;
    381}
    382
    383static inline bool fanotify_event_has_object_fh(struct fanotify_event *event)
    384{
    385	/* For error events, even zeroed fh are reported. */
    386	if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR)
    387		return true;
    388	return fanotify_event_object_fh_len(event) > 0;
    389}
    390
    391static inline bool fanotify_event_has_dir_fh(struct fanotify_event *event)
    392{
    393	return fanotify_event_dir_fh_len(event) > 0;
    394}
    395
    396static inline bool fanotify_event_has_dir2_fh(struct fanotify_event *event)
    397{
    398	return fanotify_event_dir2_fh_len(event) > 0;
    399}
    400
    401static inline bool fanotify_event_has_any_dir_fh(struct fanotify_event *event)
    402{
    403	return fanotify_event_has_dir_fh(event) ||
    404		fanotify_event_has_dir2_fh(event);
    405}
    406
    407struct fanotify_path_event {
    408	struct fanotify_event fae;
    409	struct path path;
    410};
    411
    412static inline struct fanotify_path_event *
    413FANOTIFY_PE(struct fanotify_event *event)
    414{
    415	return container_of(event, struct fanotify_path_event, fae);
    416}
    417
    418/*
    419 * Structure for permission fanotify events. It gets allocated and freed in
    420 * fanotify_handle_event() since we wait there for user response. When the
    421 * information is retrieved by userspace the structure is moved from
    422 * group->notification_list to group->fanotify_data.access_list to wait for
    423 * user response.
    424 */
    425struct fanotify_perm_event {
    426	struct fanotify_event fae;
    427	struct path path;
    428	unsigned short response;	/* userspace answer to the event */
    429	unsigned short state;		/* state of the event */
    430	int fd;		/* fd we passed to userspace for this event */
    431};
    432
    433static inline struct fanotify_perm_event *
    434FANOTIFY_PERM(struct fanotify_event *event)
    435{
    436	return container_of(event, struct fanotify_perm_event, fae);
    437}
    438
    439static inline bool fanotify_is_perm_event(u32 mask)
    440{
    441	return IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS) &&
    442		mask & FANOTIFY_PERM_EVENTS;
    443}
    444
    445static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)
    446{
    447	return container_of(fse, struct fanotify_event, fse);
    448}
    449
    450static inline bool fanotify_is_error_event(u32 mask)
    451{
    452	return mask & FAN_FS_ERROR;
    453}
    454
    455static inline bool fanotify_event_has_path(struct fanotify_event *event)
    456{
    457	return event->type == FANOTIFY_EVENT_TYPE_PATH ||
    458		event->type == FANOTIFY_EVENT_TYPE_PATH_PERM;
    459}
    460
    461static inline struct path *fanotify_event_path(struct fanotify_event *event)
    462{
    463	if (event->type == FANOTIFY_EVENT_TYPE_PATH)
    464		return &FANOTIFY_PE(event)->path;
    465	else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM)
    466		return &FANOTIFY_PERM(event)->path;
    467	else
    468		return NULL;
    469}
    470
    471/*
    472 * Use 128 size hash table to speed up events merge.
    473 */
    474#define FANOTIFY_HTABLE_BITS	(7)
    475#define FANOTIFY_HTABLE_SIZE	(1 << FANOTIFY_HTABLE_BITS)
    476#define FANOTIFY_HTABLE_MASK	(FANOTIFY_HTABLE_SIZE - 1)
    477
    478/*
    479 * Permission events and overflow event do not get merged - don't hash them.
    480 */
    481static inline bool fanotify_is_hashed_event(u32 mask)
    482{
    483	return !(fanotify_is_perm_event(mask) ||
    484		 fsnotify_is_overflow_event(mask));
    485}
    486
    487static inline unsigned int fanotify_event_hash_bucket(
    488						struct fsnotify_group *group,
    489						struct fanotify_event *event)
    490{
    491	return event->hash & FANOTIFY_HTABLE_MASK;
    492}
    493
    494static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)
    495{
    496	unsigned int mflags = 0;
    497
    498	if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
    499		mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
    500	if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)
    501		mflags |= FAN_MARK_EVICTABLE;
    502
    503	return mflags;
    504}