Skip to content

Commit deefa7f

Browse files
committed
fs: Add receive_fd() wrapper for __receive_fd()
For both pidfd and seccomp, the __user pointer is not used. Update __receive_fd() to make writing to ufd optional via a NULL check. However, for the receive_fd_user() wrapper, ufd is NULL checked so an -EFAULT can be returned to avoid changing the SCM_RIGHTS interface behavior. Add new wrapper receive_fd() for pidfd and seccomp that does not use the ufd argument. For the new helper, the allocated fd needs to be returned on success. Update the existing callers to handle it. Cc: Alexander Viro <[email protected]> Cc: [email protected] Reviewed-by: Sargun Dhillon <[email protected]> Acked-by: Christian Brauner <[email protected]> Signed-off-by: Kees Cook <[email protected]>
1 parent 6659061 commit deefa7f

File tree

4 files changed

+19
-9
lines changed

4 files changed

+19
-9
lines changed

fs/file.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -944,12 +944,13 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
944944
* @o_flags: the O_* flags to apply to the new fd entry
945945
*
946946
* Installs a received file into the file descriptor table, with appropriate
947-
* checks and count updates. Writes the fd number to userspace.
947+
* checks and count updates. Optionally writes the fd number to userspace, if
948+
* @ufd is non-NULL.
948949
*
949950
* This helper handles its own reference counting of the incoming
950951
* struct file.
951952
*
952-
* Returns -ve on error.
953+
* Returns newly install fd or -ve on error.
953954
*/
954955
int __receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
955956
{
@@ -964,16 +965,18 @@ int __receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
964965
if (new_fd < 0)
965966
return new_fd;
966967

967-
error = put_user(new_fd, ufd);
968-
if (error) {
969-
put_unused_fd(new_fd);
970-
return error;
968+
if (ufd) {
969+
error = put_user(new_fd, ufd);
970+
if (error) {
971+
put_unused_fd(new_fd);
972+
return error;
973+
}
971974
}
972975

973976
/* Bump the sock usage counts, if any. */
974977
__receive_sock(file);
975978
fd_install(new_fd, get_file(file));
976-
return 0;
979+
return new_fd;
977980
}
978981

979982
static int ksys_dup3(unsigned int oldfd, unsigned int newfd, int flags)

include/linux/file.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/compiler.h>
1010
#include <linux/types.h>
1111
#include <linux/posix_types.h>
12+
#include <linux/errno.h>
1213

1314
struct file;
1415

@@ -96,8 +97,14 @@ extern int __receive_fd(struct file *file, int __user *ufd,
9697
static inline int receive_fd_user(struct file *file, int __user *ufd,
9798
unsigned int o_flags)
9899
{
100+
if (ufd == NULL)
101+
return -EFAULT;
99102
return __receive_fd(file, ufd, o_flags);
100103
}
104+
static inline int receive_fd(struct file *file, unsigned int o_flags)
105+
{
106+
return __receive_fd(file, NULL, o_flags);
107+
}
101108

102109
extern void flush_delayed_fput(void);
103110
extern void __fput_sync(struct file *);

net/compat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
299299

300300
for (i = 0; i < fdmax; i++) {
301301
err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags);
302-
if (err)
302+
if (err < 0)
303303
break;
304304
}
305305

net/core/scm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
307307

308308
for (i = 0; i < fdmax; i++) {
309309
err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags);
310-
if (err)
310+
if (err < 0)
311311
break;
312312
}
313313

0 commit comments

Comments
 (0)