Skip to content

Commit 8a018eb

Browse files
Qian CaiAl Viro
authored andcommitted
pipe: Fix memory leaks in create_pipe_files()
Calling pipe2() with O_NOTIFICATION_PIPE could results in memory leaks unless watch_queue_init() is successful. In case of watch_queue_init() failure in pipe2() we are left with inode and pipe_inode_info instances that need to be freed. That failure exit has been introduced in commit c73be61 ("pipe: Add general notification queue support") and its handling should've been identical to nearby treatment of alloc_file_pseudo() failures - it is dealing with the same situation. As it is, the mainline kernel leaks in that case. Another problem is that CONFIG_WATCH_QUEUE and !CONFIG_WATCH_QUEUE cases are treated differently (and the former leaks just pipe_inode_info, the latter - both pipe_inode_info and inode). Fixed by providing a dummy wacth_queue_init() in !CONFIG_WATCH_QUEUE case and by having failures of wacth_queue_init() handled the same way we handle alloc_file_pseudo() ones. Fixes: c73be61 ("pipe: Add general notification queue support") Signed-off-by: Qian Cai <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 933a375 commit 8a018eb

File tree

2 files changed

+11
-6
lines changed

2 files changed

+11
-6
lines changed

fs/pipe.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -913,19 +913,18 @@ int create_pipe_files(struct file **res, int flags)
913913
{
914914
struct inode *inode = get_pipe_inode();
915915
struct file *f;
916+
int error;
916917

917918
if (!inode)
918919
return -ENFILE;
919920

920921
if (flags & O_NOTIFICATION_PIPE) {
921-
#ifdef CONFIG_WATCH_QUEUE
922-
if (watch_queue_init(inode->i_pipe) < 0) {
922+
error = watch_queue_init(inode->i_pipe);
923+
if (error) {
924+
free_pipe_info(inode->i_pipe);
923925
iput(inode);
924-
return -ENOMEM;
926+
return error;
925927
}
926-
#else
927-
return -ENOPKG;
928-
#endif
929928
}
930929

931930
f = alloc_file_pseudo(inode, pipe_mnt, "",

include/linux/watch_queue.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ static inline void remove_watch_list(struct watch_list *wlist, u64 id)
122122
*/
123123
#define watch_sizeof(STRUCT) (sizeof(STRUCT) << WATCH_INFO_LENGTH__SHIFT)
124124

125+
#else
126+
static inline int watch_queue_init(struct pipe_inode_info *pipe)
127+
{
128+
return -ENOPKG;
129+
}
130+
125131
#endif
126132

127133
#endif /* _LINUX_WATCH_QUEUE_H */

0 commit comments

Comments
 (0)