mirror of https://github.com/torvalds/linux.git
vfs-6.19-rc1.fd_prepare.fs
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCaSmOZwAKCRCRxhvAZXjc
op0AAP4oNVJkFyvgKoPos5K2EGFB8M7merGhpYtsOoeg8UK6OwD/UySQErHsXQDR
sUDDa5uFOhfrkcfM8REtAN4wF8p5qAc=
=QgFD
-----END PGP SIGNATURE-----
Merge tag 'vfs-6.19-rc1.fd_prepare.fs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull fd prepare updates from Christian Brauner:
"This adds the FD_ADD() and FD_PREPARE() primitive. They simplify the
common pattern of get_unused_fd_flags() + create file + fd_install()
that is used extensively throughout the kernel and currently requires
cumbersome cleanup paths.
FD_ADD() - For simple cases where a file is installed immediately:
fd = FD_ADD(O_CLOEXEC, vfio_device_open_file(device));
if (fd < 0)
vfio_device_put_registration(device);
return fd;
FD_PREPARE() - For cases requiring access to the fd or file, or
additional work before publishing:
FD_PREPARE(fdf, O_CLOEXEC, sync_file->file);
if (fdf.err) {
fput(sync_file->file);
return fdf.err;
}
data.fence = fd_prepare_fd(fdf);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
return fd_publish(fdf);
The primitives are centered around struct fd_prepare. FD_PREPARE()
encapsulates all allocation and cleanup logic and must be followed by
a call to fd_publish() which associates the fd with the file and
installs it into the caller's fdtable. If fd_publish() isn't called,
both are deallocated automatically. FD_ADD() is a shorthand that does
fd_publish() immediately and never exposes the struct to the caller.
I've implemented this in a way that it's compatible with the cleanup
infrastructure while also being usable separately. IOW, it's centered
around struct fd_prepare which is aliased to class_fd_prepare_t and so
we can make use of all the basica guard infrastructure"
* tag 'vfs-6.19-rc1.fd_prepare.fs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (42 commits)
io_uring: convert io_create_mock_file() to FD_PREPARE()
file: convert replace_fd() to FD_PREPARE()
vfio: convert vfio_group_ioctl_get_device_fd() to FD_ADD()
tty: convert ptm_open_peer() to FD_ADD()
ntsync: convert ntsync_obj_get_fd() to FD_PREPARE()
media: convert media_request_alloc() to FD_PREPARE()
hv: convert mshv_ioctl_create_partition() to FD_ADD()
gpio: convert linehandle_create() to FD_PREPARE()
pseries: port papr_rtas_setup_file_interface() to FD_ADD()
pseries: convert papr_platform_dump_create_handle() to FD_ADD()
spufs: convert spufs_gang_open() to FD_PREPARE()
papr-hvpipe: convert papr_hvpipe_dev_create_handle() to FD_PREPARE()
spufs: convert spufs_context_open() to FD_PREPARE()
net/socket: convert __sys_accept4_file() to FD_ADD()
net/socket: convert sock_map_fd() to FD_ADD()
net/kcm: convert kcm_ioctl() to FD_PREPARE()
net/handshake: convert handshake_nl_accept_doit() to FD_PREPARE()
secretmem: convert memfd_secret() to FD_ADD()
memfd: convert memfd_create() to FD_ADD()
bpf: convert bpf_token_create() to FD_PREPARE()
...
This commit is contained in:
commit
1b5dd29869
|
|
@ -267,22 +267,11 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
|
||||||
|
|
||||||
static int spufs_context_open(const struct path *path)
|
static int spufs_context_open(const struct path *path)
|
||||||
{
|
{
|
||||||
int ret;
|
FD_PREPARE(fdf, 0, dentry_open(path, O_RDONLY, current_cred()));
|
||||||
struct file *filp;
|
if (fdf.err)
|
||||||
|
return fdf.err;
|
||||||
ret = get_unused_fd_flags(0);
|
fd_prepare_file(fdf)->f_op = &spufs_context_fops;
|
||||||
if (ret < 0)
|
return fd_publish(fdf);
|
||||||
return ret;
|
|
||||||
|
|
||||||
filp = dentry_open(path, O_RDONLY, current_cred());
|
|
||||||
if (IS_ERR(filp)) {
|
|
||||||
put_unused_fd(ret);
|
|
||||||
return PTR_ERR(filp);
|
|
||||||
}
|
|
||||||
|
|
||||||
filp->f_op = &spufs_context_fops;
|
|
||||||
fd_install(ret, filp);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spu_context *
|
static struct spu_context *
|
||||||
|
|
@ -508,26 +497,15 @@ static const struct file_operations spufs_gang_fops = {
|
||||||
|
|
||||||
static int spufs_gang_open(const struct path *path)
|
static int spufs_gang_open(const struct path *path)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
struct file *filp;
|
|
||||||
|
|
||||||
ret = get_unused_fd_flags(0);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get references for dget and mntget, will be released
|
* get references for dget and mntget, will be released
|
||||||
* in error path of *_open().
|
* in error path of *_open().
|
||||||
*/
|
*/
|
||||||
filp = dentry_open(path, O_RDONLY, current_cred());
|
FD_PREPARE(fdf, 0, dentry_open(path, O_RDONLY, current_cred()));
|
||||||
if (IS_ERR(filp)) {
|
if (fdf.err)
|
||||||
put_unused_fd(ret);
|
return fdf.err;
|
||||||
return PTR_ERR(filp);
|
fd_prepare_file(fdf)->f_op = &spufs_gang_fops;
|
||||||
}
|
return fd_publish(fdf);
|
||||||
|
|
||||||
filp->f_op = &spufs_gang_fops;
|
|
||||||
fd_install(ret, filp);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spufs_create_gang(struct inode *inode,
|
static int spufs_create_gang(struct inode *inode,
|
||||||
|
|
|
||||||
|
|
@ -479,10 +479,7 @@ static const struct file_operations papr_hvpipe_handle_ops = {
|
||||||
|
|
||||||
static int papr_hvpipe_dev_create_handle(u32 srcID)
|
static int papr_hvpipe_dev_create_handle(u32 srcID)
|
||||||
{
|
{
|
||||||
struct hvpipe_source_info *src_info;
|
struct hvpipe_source_info *src_info __free(kfree) = NULL;
|
||||||
struct file *file;
|
|
||||||
long err;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
spin_lock(&hvpipe_src_list_lock);
|
spin_lock(&hvpipe_src_list_lock);
|
||||||
/*
|
/*
|
||||||
|
|
@ -506,20 +503,13 @@ static int papr_hvpipe_dev_create_handle(u32 srcID)
|
||||||
src_info->tsk = current;
|
src_info->tsk = current;
|
||||||
init_waitqueue_head(&src_info->recv_wqh);
|
init_waitqueue_head(&src_info->recv_wqh);
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
|
FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
|
||||||
if (fd < 0) {
|
anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
|
||||||
err = fd;
|
(void *)src_info, O_RDWR));
|
||||||
goto free_buf;
|
if (fdf.err)
|
||||||
}
|
return fdf.err;
|
||||||
|
|
||||||
file = anon_inode_getfile("[papr-hvpipe]",
|
|
||||||
&papr_hvpipe_handle_ops, (void *)src_info,
|
|
||||||
O_RDWR);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
err = PTR_ERR(file);
|
|
||||||
goto free_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
retain_and_null_ptr(src_info);
|
||||||
spin_lock(&hvpipe_src_list_lock);
|
spin_lock(&hvpipe_src_list_lock);
|
||||||
/*
|
/*
|
||||||
* If two processes are executing ioctl() for the same
|
* If two processes are executing ioctl() for the same
|
||||||
|
|
@ -528,22 +518,11 @@ static int papr_hvpipe_dev_create_handle(u32 srcID)
|
||||||
*/
|
*/
|
||||||
if (hvpipe_find_source(srcID)) {
|
if (hvpipe_find_source(srcID)) {
|
||||||
spin_unlock(&hvpipe_src_list_lock);
|
spin_unlock(&hvpipe_src_list_lock);
|
||||||
err = -EALREADY;
|
return -EALREADY;
|
||||||
goto free_file;
|
|
||||||
}
|
}
|
||||||
list_add(&src_info->list, &hvpipe_src_list);
|
list_add(&src_info->list, &hvpipe_src_list);
|
||||||
spin_unlock(&hvpipe_src_list_lock);
|
spin_unlock(&hvpipe_src_list_lock);
|
||||||
|
return fd_publish(fdf);
|
||||||
fd_install(fd, file);
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
free_file:
|
|
||||||
fput(file);
|
|
||||||
free_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
free_buf:
|
|
||||||
kfree(src_info);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -303,8 +303,6 @@ static long papr_platform_dump_create_handle(u64 dump_tag)
|
||||||
{
|
{
|
||||||
struct ibm_platform_dump_params *params;
|
struct ibm_platform_dump_params *params;
|
||||||
u64 param_dump_tag;
|
u64 param_dump_tag;
|
||||||
struct file *file;
|
|
||||||
long err;
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -334,34 +332,22 @@ static long papr_platform_dump_create_handle(u64 dump_tag)
|
||||||
params->dump_tag_lo = (u32)(dump_tag & 0x00000000ffffffffULL);
|
params->dump_tag_lo = (u32)(dump_tag & 0x00000000ffffffffULL);
|
||||||
params->status = RTAS_IBM_PLATFORM_DUMP_START;
|
params->status = RTAS_IBM_PLATFORM_DUMP_START;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
|
fd = FD_ADD(O_RDONLY | O_CLOEXEC,
|
||||||
|
anon_inode_getfile_fmode("[papr-platform-dump]",
|
||||||
|
&papr_platform_dump_handle_ops,
|
||||||
|
(void *)params, O_RDONLY,
|
||||||
|
FMODE_LSEEK | FMODE_PREAD));
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
err = fd;
|
rtas_work_area_free(params->work_area);
|
||||||
goto free_area;
|
kfree(params);
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
file = anon_inode_getfile_fmode("[papr-platform-dump]",
|
|
||||||
&papr_platform_dump_handle_ops,
|
|
||||||
(void *)params, O_RDONLY,
|
|
||||||
FMODE_LSEEK | FMODE_PREAD);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
err = PTR_ERR(file);
|
|
||||||
goto put_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, file);
|
|
||||||
|
|
||||||
list_add(¶ms->list, &platform_dump_list);
|
list_add(¶ms->list, &platform_dump_list);
|
||||||
|
|
||||||
pr_info("%s (%d) initiated platform dump for dump tag %llu\n",
|
pr_info("%s (%d) initiated platform dump for dump tag %llu\n",
|
||||||
current->comm, current->pid, dump_tag);
|
current->comm, current->pid, dump_tag);
|
||||||
return fd;
|
return fd;
|
||||||
put_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
free_area:
|
|
||||||
rtas_work_area_free(params->work_area);
|
|
||||||
kfree(params);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -205,35 +205,18 @@ long papr_rtas_setup_file_interface(struct papr_rtas_sequence *seq,
|
||||||
char *name)
|
char *name)
|
||||||
{
|
{
|
||||||
const struct papr_rtas_blob *blob;
|
const struct papr_rtas_blob *blob;
|
||||||
struct file *file;
|
|
||||||
long ret;
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
blob = papr_rtas_retrieve(seq);
|
blob = papr_rtas_retrieve(seq);
|
||||||
if (IS_ERR(blob))
|
if (IS_ERR(blob))
|
||||||
return PTR_ERR(blob);
|
return PTR_ERR(blob);
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
|
fd = FD_ADD(O_RDONLY | O_CLOEXEC,
|
||||||
if (fd < 0) {
|
anon_inode_getfile_fmode(name, fops, (void *)blob, O_RDONLY,
|
||||||
ret = fd;
|
FMODE_LSEEK | FMODE_PREAD));
|
||||||
goto free_blob;
|
if (fd < 0)
|
||||||
}
|
papr_rtas_blob_free(blob);
|
||||||
|
|
||||||
file = anon_inode_getfile_fmode(name, fops, (void *)blob,
|
|
||||||
O_RDONLY, FMODE_LSEEK | FMODE_PREAD);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
ret = PTR_ERR(file);
|
|
||||||
goto put_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, file);
|
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
put_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
free_blob:
|
|
||||||
papr_rtas_blob_free(blob);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -768,18 +768,10 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_export, "DMA_BUF");
|
||||||
*/
|
*/
|
||||||
int dma_buf_fd(struct dma_buf *dmabuf, int flags)
|
int dma_buf_fd(struct dma_buf *dmabuf, int flags)
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (!dmabuf || !dmabuf->file)
|
if (!dmabuf || !dmabuf->file)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(flags);
|
return FD_ADD(flags, dmabuf->file);
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
fd_install(fd, dmabuf->file);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF");
|
EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -298,12 +298,13 @@ static const struct file_operations linehandle_fileops = {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DEFINE_FREE(linehandle_free, struct linehandle_state *, if (!IS_ERR_OR_NULL(_T)) linehandle_free(_T))
|
||||||
|
|
||||||
static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||||
{
|
{
|
||||||
struct gpiohandle_request handlereq;
|
struct gpiohandle_request handlereq;
|
||||||
struct linehandle_state *lh;
|
struct linehandle_state *lh __free(linehandle_free) = NULL;
|
||||||
struct file *file;
|
int i, ret;
|
||||||
int fd, i, ret;
|
|
||||||
u32 lflags;
|
u32 lflags;
|
||||||
|
|
||||||
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
|
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
|
||||||
|
|
@ -327,10 +328,8 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||||
lh->label = kstrndup(handlereq.consumer_label,
|
lh->label = kstrndup(handlereq.consumer_label,
|
||||||
sizeof(handlereq.consumer_label) - 1,
|
sizeof(handlereq.consumer_label) - 1,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!lh->label) {
|
if (!lh->label)
|
||||||
ret = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out_free_lh;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lh->num_descs = handlereq.lines;
|
lh->num_descs = handlereq.lines;
|
||||||
|
|
@ -340,20 +339,18 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||||
u32 offset = handlereq.lineoffsets[i];
|
u32 offset = handlereq.lineoffsets[i];
|
||||||
struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
|
struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
|
||||||
|
|
||||||
if (IS_ERR(desc)) {
|
if (IS_ERR(desc))
|
||||||
ret = PTR_ERR(desc);
|
return PTR_ERR(desc);
|
||||||
goto out_free_lh;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gpiod_request_user(desc, lh->label);
|
ret = gpiod_request_user(desc, lh->label);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_free_lh;
|
return ret;
|
||||||
lh->descs[i] = desc;
|
lh->descs[i] = desc;
|
||||||
linehandle_flags_to_desc_flags(handlereq.flags, &desc->flags);
|
linehandle_flags_to_desc_flags(handlereq.flags, &desc->flags);
|
||||||
|
|
||||||
ret = gpiod_set_transitory(desc, false);
|
ret = gpiod_set_transitory(desc, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_free_lh;
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lines have to be requested explicitly for input
|
* Lines have to be requested explicitly for input
|
||||||
|
|
@ -364,11 +361,11 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||||
|
|
||||||
ret = gpiod_direction_output_nonotify(desc, val);
|
ret = gpiod_direction_output_nonotify(desc, val);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_free_lh;
|
return ret;
|
||||||
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
|
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
|
||||||
ret = gpiod_direction_input_nonotify(desc);
|
ret = gpiod_direction_input_nonotify(desc);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_free_lh;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
|
gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
|
||||||
|
|
@ -377,44 +374,23 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||||
offset);
|
offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
|
FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
|
||||||
if (fd < 0) {
|
anon_inode_getfile("gpio-linehandle", &linehandle_fileops,
|
||||||
ret = fd;
|
lh, O_RDONLY | O_CLOEXEC));
|
||||||
goto out_free_lh;
|
if (fdf.err)
|
||||||
}
|
return fdf.err;
|
||||||
|
retain_and_null_ptr(lh);
|
||||||
|
|
||||||
file = anon_inode_getfile("gpio-linehandle",
|
handlereq.fd = fd_prepare_fd(fdf);
|
||||||
&linehandle_fileops,
|
if (copy_to_user(ip, &handlereq, sizeof(handlereq)))
|
||||||
lh,
|
|
||||||
O_RDONLY | O_CLOEXEC);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
ret = PTR_ERR(file);
|
|
||||||
goto out_put_unused_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
handlereq.fd = fd;
|
|
||||||
if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
|
|
||||||
/*
|
|
||||||
* fput() will trigger the release() callback, so do not go onto
|
|
||||||
* the regular error cleanup path here.
|
|
||||||
*/
|
|
||||||
fput(file);
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, file);
|
fd_publish(fdf);
|
||||||
|
|
||||||
dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
|
dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
|
||||||
lh->num_descs);
|
lh->num_descs);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_put_unused_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
out_free_lh:
|
|
||||||
linehandle_free(lh);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_GPIO_CDEV_V1 */
|
#endif /* CONFIG_GPIO_CDEV_V1 */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1870,8 +1870,6 @@ mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev)
|
||||||
struct hv_partition_creation_properties creation_properties = {};
|
struct hv_partition_creation_properties creation_properties = {};
|
||||||
union hv_partition_isolation_properties isolation_properties = {};
|
union hv_partition_isolation_properties isolation_properties = {};
|
||||||
struct mshv_partition *partition;
|
struct mshv_partition *partition;
|
||||||
struct file *file;
|
|
||||||
int fd;
|
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
if (copy_from_user(&args, user_arg, sizeof(args)))
|
if (copy_from_user(&args, user_arg, sizeof(args)))
|
||||||
|
|
@ -1938,29 +1936,13 @@ mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev)
|
||||||
goto delete_partition;
|
goto delete_partition;
|
||||||
|
|
||||||
ret = mshv_init_async_handler(partition);
|
ret = mshv_init_async_handler(partition);
|
||||||
if (ret)
|
if (!ret) {
|
||||||
goto remove_partition;
|
ret = FD_ADD(O_CLOEXEC, anon_inode_getfile("mshv_partition",
|
||||||
|
&mshv_partition_fops,
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
partition, O_RDWR));
|
||||||
if (fd < 0) {
|
if (ret >= 0)
|
||||||
ret = fd;
|
return ret;
|
||||||
goto remove_partition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file = anon_inode_getfile("mshv_partition", &mshv_partition_fops,
|
|
||||||
partition, O_RDWR);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
ret = PTR_ERR(file);
|
|
||||||
goto put_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, file);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
put_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
remove_partition:
|
|
||||||
remove_partition(partition);
|
remove_partition(partition);
|
||||||
delete_partition:
|
delete_partition:
|
||||||
hv_call_delete_partition(partition->pt_id);
|
hv_call_delete_partition(partition->pt_id);
|
||||||
|
|
|
||||||
|
|
@ -282,8 +282,6 @@ EXPORT_SYMBOL_GPL(media_request_get_by_fd);
|
||||||
int media_request_alloc(struct media_device *mdev, int *alloc_fd)
|
int media_request_alloc(struct media_device *mdev, int *alloc_fd)
|
||||||
{
|
{
|
||||||
struct media_request *req;
|
struct media_request *req;
|
||||||
struct file *filp;
|
|
||||||
int fd;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Either both are NULL or both are non-NULL */
|
/* Either both are NULL or both are non-NULL */
|
||||||
|
|
@ -297,19 +295,6 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd)
|
||||||
if (!req)
|
if (!req)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
|
||||||
if (fd < 0) {
|
|
||||||
ret = fd;
|
|
||||||
goto err_free_req;
|
|
||||||
}
|
|
||||||
|
|
||||||
filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC);
|
|
||||||
if (IS_ERR(filp)) {
|
|
||||||
ret = PTR_ERR(filp);
|
|
||||||
goto err_put_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
filp->private_data = req;
|
|
||||||
req->mdev = mdev;
|
req->mdev = mdev;
|
||||||
req->state = MEDIA_REQUEST_STATE_IDLE;
|
req->state = MEDIA_REQUEST_STATE_IDLE;
|
||||||
req->num_incomplete_objects = 0;
|
req->num_incomplete_objects = 0;
|
||||||
|
|
@ -320,19 +305,24 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd)
|
||||||
req->updating_count = 0;
|
req->updating_count = 0;
|
||||||
req->access_count = 0;
|
req->access_count = 0;
|
||||||
|
|
||||||
*alloc_fd = fd;
|
FD_PREPARE(fdf, O_CLOEXEC,
|
||||||
|
anon_inode_getfile("request", &request_fops, NULL,
|
||||||
|
O_CLOEXEC));
|
||||||
|
if (fdf.err) {
|
||||||
|
ret = fdf.err;
|
||||||
|
goto err_free_req;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_prepare_file(fdf)->private_data = req;
|
||||||
|
|
||||||
|
*alloc_fd = fd_publish(fdf);
|
||||||
|
|
||||||
snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d",
|
snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d",
|
||||||
atomic_inc_return(&mdev->request_id), fd);
|
atomic_inc_return(&mdev->request_id), *alloc_fd);
|
||||||
dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str);
|
dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str);
|
||||||
|
|
||||||
fd_install(fd, filp);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_put_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
|
|
||||||
err_free_req:
|
err_free_req:
|
||||||
if (mdev->ops->req_free)
|
if (mdev->ops->req_free)
|
||||||
mdev->ops->req_free(req);
|
mdev->ops->req_free(req);
|
||||||
|
|
|
||||||
|
|
@ -721,21 +721,12 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev,
|
||||||
|
|
||||||
static int ntsync_obj_get_fd(struct ntsync_obj *obj)
|
static int ntsync_obj_get_fd(struct ntsync_obj *obj)
|
||||||
{
|
{
|
||||||
struct file *file;
|
FD_PREPARE(fdf, O_CLOEXEC,
|
||||||
int fd;
|
anon_inode_getfile("ntsync", &ntsync_obj_fops, obj, O_RDWR));
|
||||||
|
if (fdf.err)
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
return fdf.err;
|
||||||
if (fd < 0)
|
obj->file = fd_prepare_file(fdf);
|
||||||
return fd;
|
return fd_publish(fdf);
|
||||||
file = anon_inode_getfile("ntsync", &ntsync_obj_fops, obj, O_RDWR);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return PTR_ERR(file);
|
|
||||||
}
|
|
||||||
obj->file = file;
|
|
||||||
fd_install(fd, file);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
||||||
|
|
|
||||||
|
|
@ -589,6 +589,23 @@ static inline void legacy_pty_init(void) { }
|
||||||
#ifdef CONFIG_UNIX98_PTYS
|
#ifdef CONFIG_UNIX98_PTYS
|
||||||
static struct cdev ptmx_cdev;
|
static struct cdev ptmx_cdev;
|
||||||
|
|
||||||
|
static struct file *ptm_open_peer_file(struct file *master,
|
||||||
|
struct tty_struct *tty, int flags)
|
||||||
|
{
|
||||||
|
struct path path;
|
||||||
|
struct file *file;
|
||||||
|
|
||||||
|
/* Compute the slave's path */
|
||||||
|
path.mnt = devpts_mntget(master, tty->driver_data);
|
||||||
|
if (IS_ERR(path.mnt))
|
||||||
|
return ERR_CAST(path.mnt);
|
||||||
|
path.dentry = tty->link->driver_data;
|
||||||
|
|
||||||
|
file = dentry_open(&path, flags, current_cred());
|
||||||
|
mntput(path.mnt);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ptm_open_peer - open the peer of a pty
|
* ptm_open_peer - open the peer of a pty
|
||||||
* @master: the open struct file of the ptmx device node
|
* @master: the open struct file of the ptmx device node
|
||||||
|
|
@ -601,42 +618,10 @@ static struct cdev ptmx_cdev;
|
||||||
*/
|
*/
|
||||||
int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
|
int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
struct file *filp;
|
|
||||||
int retval = -EINVAL;
|
|
||||||
struct path path;
|
|
||||||
|
|
||||||
if (tty->driver != ptm_driver)
|
if (tty->driver != ptm_driver)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(flags);
|
return FD_ADD(flags, ptm_open_peer_file(master, tty, flags));
|
||||||
if (fd < 0) {
|
|
||||||
retval = fd;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute the slave's path */
|
|
||||||
path.mnt = devpts_mntget(master, tty->driver_data);
|
|
||||||
if (IS_ERR(path.mnt)) {
|
|
||||||
retval = PTR_ERR(path.mnt);
|
|
||||||
goto err_put;
|
|
||||||
}
|
|
||||||
path.dentry = tty->link->driver_data;
|
|
||||||
|
|
||||||
filp = dentry_open(&path, flags, current_cred());
|
|
||||||
mntput(path.mnt);
|
|
||||||
if (IS_ERR(filp)) {
|
|
||||||
retval = PTR_ERR(filp);
|
|
||||||
goto err_put;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, filp);
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
err_put:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
err:
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pty_unix98_ioctl(struct tty_struct *tty,
|
static int pty_unix98_ioctl(struct tty_struct *tty,
|
||||||
|
|
|
||||||
|
|
@ -299,10 +299,8 @@ static int vfio_group_ioctl_get_device_fd(struct vfio_group *group,
|
||||||
char __user *arg)
|
char __user *arg)
|
||||||
{
|
{
|
||||||
struct vfio_device *device;
|
struct vfio_device *device;
|
||||||
struct file *filep;
|
|
||||||
char *buf;
|
char *buf;
|
||||||
int fdno;
|
int fd;
|
||||||
int ret;
|
|
||||||
|
|
||||||
buf = strndup_user(arg, PAGE_SIZE);
|
buf = strndup_user(arg, PAGE_SIZE);
|
||||||
if (IS_ERR(buf))
|
if (IS_ERR(buf))
|
||||||
|
|
@ -313,26 +311,10 @@ static int vfio_group_ioctl_get_device_fd(struct vfio_group *group,
|
||||||
if (IS_ERR(device))
|
if (IS_ERR(device))
|
||||||
return PTR_ERR(device);
|
return PTR_ERR(device);
|
||||||
|
|
||||||
fdno = get_unused_fd_flags(O_CLOEXEC);
|
fd = FD_ADD(O_CLOEXEC, vfio_device_open_file(device));
|
||||||
if (fdno < 0) {
|
if (fd < 0)
|
||||||
ret = fdno;
|
vfio_device_put_registration(device);
|
||||||
goto err_put_device;
|
return fd;
|
||||||
}
|
|
||||||
|
|
||||||
filep = vfio_device_open_file(device);
|
|
||||||
if (IS_ERR(filep)) {
|
|
||||||
ret = PTR_ERR(filep);
|
|
||||||
goto err_put_fdno;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fdno, filep);
|
|
||||||
return fdno;
|
|
||||||
|
|
||||||
err_put_fdno:
|
|
||||||
put_unused_fd(fdno);
|
|
||||||
err_put_device:
|
|
||||||
vfio_device_put_registration(device);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vfio_group_ioctl_get_status(struct vfio_group *group,
|
static int vfio_group_ioctl_get_status(struct vfio_group *group,
|
||||||
|
|
|
||||||
|
|
@ -280,27 +280,8 @@ static int __anon_inode_getfd(const char *name,
|
||||||
const struct inode *context_inode,
|
const struct inode *context_inode,
|
||||||
bool make_inode)
|
bool make_inode)
|
||||||
{
|
{
|
||||||
int error, fd;
|
return FD_ADD(flags, __anon_inode_getfile(name, fops, priv, flags,
|
||||||
struct file *file;
|
context_inode, make_inode));
|
||||||
|
|
||||||
error = get_unused_fd_flags(flags);
|
|
||||||
if (error < 0)
|
|
||||||
return error;
|
|
||||||
fd = error;
|
|
||||||
|
|
||||||
file = __anon_inode_getfile(name, fops, priv, flags, context_inode,
|
|
||||||
make_inode);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
error = PTR_ERR(file);
|
|
||||||
goto err_put_unused_fd;
|
|
||||||
}
|
|
||||||
fd_install(fd, file);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
err_put_unused_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -231,32 +231,14 @@ static int test_by_type(const struct path *path, void *p)
|
||||||
*/
|
*/
|
||||||
static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid)
|
static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid)
|
||||||
{
|
{
|
||||||
int err, fd;
|
struct path path __free(path_put) = {};
|
||||||
|
int err;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
err = find_autofs_mount(name, &path, test_by_dev, &devid);
|
||||||
if (likely(fd >= 0)) {
|
if (err)
|
||||||
struct file *filp;
|
return err;
|
||||||
struct path path;
|
|
||||||
|
|
||||||
err = find_autofs_mount(name, &path, test_by_dev, &devid);
|
return FD_ADD(O_CLOEXEC, dentry_open(&path, O_RDONLY, current_cred()));
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
filp = dentry_open(&path, O_RDONLY, current_cred());
|
|
||||||
path_put(&path);
|
|
||||||
if (IS_ERR(filp)) {
|
|
||||||
err = PTR_ERR(filp);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, filp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
out:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open a file descriptor on an autofs mount point */
|
/* Open a file descriptor on an autofs mount point */
|
||||||
|
|
|
||||||
29
fs/eventfd.c
29
fs/eventfd.c
|
|
@ -378,9 +378,7 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
|
||||||
|
|
||||||
static int do_eventfd(unsigned int count, int flags)
|
static int do_eventfd(unsigned int count, int flags)
|
||||||
{
|
{
|
||||||
struct eventfd_ctx *ctx;
|
struct eventfd_ctx *ctx __free(kfree) = NULL;
|
||||||
struct file *file;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
/* Check the EFD_* constants for consistency. */
|
/* Check the EFD_* constants for consistency. */
|
||||||
BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
|
BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
|
||||||
|
|
@ -398,26 +396,19 @@ static int do_eventfd(unsigned int count, int flags)
|
||||||
init_waitqueue_head(&ctx->wqh);
|
init_waitqueue_head(&ctx->wqh);
|
||||||
ctx->count = count;
|
ctx->count = count;
|
||||||
ctx->flags = flags;
|
ctx->flags = flags;
|
||||||
ctx->id = ida_alloc(&eventfd_ida, GFP_KERNEL);
|
|
||||||
|
|
||||||
flags &= EFD_SHARED_FCNTL_FLAGS;
|
flags &= EFD_SHARED_FCNTL_FLAGS;
|
||||||
flags |= O_RDWR;
|
flags |= O_RDWR;
|
||||||
fd = get_unused_fd_flags(flags);
|
|
||||||
if (fd < 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
file = anon_inode_getfile_fmode("[eventfd]", &eventfd_fops,
|
FD_PREPARE(fdf, flags,
|
||||||
ctx, flags, FMODE_NOWAIT);
|
anon_inode_getfile_fmode("[eventfd]", &eventfd_fops, ctx,
|
||||||
if (IS_ERR(file)) {
|
flags, FMODE_NOWAIT));
|
||||||
put_unused_fd(fd);
|
if (fdf.err)
|
||||||
fd = PTR_ERR(file);
|
return fdf.err;
|
||||||
goto err;
|
|
||||||
}
|
ctx->id = ida_alloc(&eventfd_ida, GFP_KERNEL);
|
||||||
fd_install(fd, file);
|
retain_and_null_ptr(ctx);
|
||||||
return fd;
|
return fd_publish(fdf);
|
||||||
err:
|
|
||||||
eventfd_free_ctx(ctx);
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
|
SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
|
||||||
|
|
|
||||||
|
|
@ -2165,9 +2165,8 @@ static void clear_tfile_check_list(void)
|
||||||
*/
|
*/
|
||||||
static int do_epoll_create(int flags)
|
static int do_epoll_create(int flags)
|
||||||
{
|
{
|
||||||
int error, fd;
|
int error;
|
||||||
struct eventpoll *ep = NULL;
|
struct eventpoll *ep;
|
||||||
struct file *file;
|
|
||||||
|
|
||||||
/* Check the EPOLL_* constant for consistency. */
|
/* Check the EPOLL_* constant for consistency. */
|
||||||
BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
|
BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
|
||||||
|
|
@ -2184,26 +2183,15 @@ static int do_epoll_create(int flags)
|
||||||
* Creates all the items needed to setup an eventpoll file. That is,
|
* Creates all the items needed to setup an eventpoll file. That is,
|
||||||
* a file structure and a free file descriptor.
|
* a file structure and a free file descriptor.
|
||||||
*/
|
*/
|
||||||
fd = get_unused_fd_flags(O_RDWR | (flags & O_CLOEXEC));
|
FD_PREPARE(fdf, O_RDWR | (flags & O_CLOEXEC),
|
||||||
if (fd < 0) {
|
anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep,
|
||||||
error = fd;
|
O_RDWR | (flags & O_CLOEXEC)));
|
||||||
goto out_free_ep;
|
if (fdf.err) {
|
||||||
|
ep_clear_and_put(ep);
|
||||||
|
return fdf.err;
|
||||||
}
|
}
|
||||||
file = anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep,
|
ep->file = fd_prepare_file(fdf);
|
||||||
O_RDWR | (flags & O_CLOEXEC));
|
return fd_publish(fdf);
|
||||||
if (IS_ERR(file)) {
|
|
||||||
error = PTR_ERR(file);
|
|
||||||
goto out_free_fd;
|
|
||||||
}
|
|
||||||
ep->file = file;
|
|
||||||
fd_install(fd, file);
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
out_free_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
out_free_ep:
|
|
||||||
ep_clear_and_put(ep);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE1(epoll_create1, int, flags)
|
SYSCALL_DEFINE1(epoll_create1, int, flags)
|
||||||
|
|
|
||||||
|
|
@ -1280,10 +1280,9 @@ int begin_new_exec(struct linux_binprm * bprm)
|
||||||
|
|
||||||
/* Pass the opened binary to the interpreter. */
|
/* Pass the opened binary to the interpreter. */
|
||||||
if (bprm->have_execfd) {
|
if (bprm->have_execfd) {
|
||||||
retval = get_unused_fd_flags(0);
|
retval = FD_ADD(0, bprm->executable);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
fd_install(retval, bprm->executable);
|
|
||||||
bprm->executable = NULL;
|
bprm->executable = NULL;
|
||||||
bprm->execfd = retval;
|
bprm->execfd = retval;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
fs/fhandle.c
30
fs/fhandle.c
|
|
@ -404,32 +404,28 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct file *file_open_handle(struct path *path, int open_flag)
|
||||||
|
{
|
||||||
|
const struct export_operations *eops;
|
||||||
|
|
||||||
|
eops = path->mnt->mnt_sb->s_export_op;
|
||||||
|
if (eops->open)
|
||||||
|
return eops->open(path, open_flag);
|
||||||
|
|
||||||
|
return file_open_root(path, "", open_flag, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
|
static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
|
||||||
int open_flag)
|
int open_flag)
|
||||||
{
|
{
|
||||||
long retval = 0;
|
long retval;
|
||||||
struct path path __free(path_put) = {};
|
struct path path __free(path_put) = {};
|
||||||
struct file *file;
|
|
||||||
const struct export_operations *eops;
|
|
||||||
|
|
||||||
retval = handle_to_path(mountdirfd, ufh, &path, open_flag);
|
retval = handle_to_path(mountdirfd, ufh, &path, open_flag);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
CLASS(get_unused_fd, fd)(open_flag);
|
return FD_ADD(open_flag, file_open_handle(&path, open_flag));
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
eops = path.mnt->mnt_sb->s_export_op;
|
|
||||||
if (eops->open)
|
|
||||||
file = eops->open(&path, open_flag);
|
|
||||||
else
|
|
||||||
file = file_open_root(&path, "", open_flag, 0);
|
|
||||||
if (IS_ERR(file))
|
|
||||||
return PTR_ERR(file);
|
|
||||||
|
|
||||||
fd_install(fd, file);
|
|
||||||
return take_fd(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
19
fs/file.c
19
fs/file.c
|
|
@ -1380,28 +1380,25 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
|
||||||
*/
|
*/
|
||||||
int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
|
int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
|
||||||
{
|
{
|
||||||
int new_fd;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = security_file_receive(file);
|
error = security_file_receive(file);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
new_fd = get_unused_fd_flags(o_flags);
|
FD_PREPARE(fdf, o_flags, file);
|
||||||
if (new_fd < 0)
|
if (fdf.err)
|
||||||
return new_fd;
|
return fdf.err;
|
||||||
|
get_file(file);
|
||||||
|
|
||||||
if (ufd) {
|
if (ufd) {
|
||||||
error = put_user(new_fd, ufd);
|
error = put_user(fd_prepare_fd(fdf), ufd);
|
||||||
if (error) {
|
if (error)
|
||||||
put_unused_fd(new_fd);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_install(new_fd, get_file(file));
|
__receive_sock(fd_prepare_file(fdf));
|
||||||
__receive_sock(file);
|
return fd_publish(fdf);
|
||||||
return new_fd;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(receive_fd);
|
EXPORT_SYMBOL_GPL(receive_fd);
|
||||||
|
|
||||||
|
|
|
||||||
103
fs/namespace.c
103
fs/namespace.c
|
|
@ -3100,19 +3100,7 @@ static struct file *vfs_open_tree(int dfd, const char __user *filename, unsigned
|
||||||
|
|
||||||
SYSCALL_DEFINE3(open_tree, int, dfd, const char __user *, filename, unsigned, flags)
|
SYSCALL_DEFINE3(open_tree, int, dfd, const char __user *, filename, unsigned, flags)
|
||||||
{
|
{
|
||||||
int fd;
|
return FD_ADD(flags, vfs_open_tree(dfd, filename, flags));
|
||||||
struct file *file __free(fput) = NULL;
|
|
||||||
|
|
||||||
file = vfs_open_tree(dfd, filename, flags);
|
|
||||||
if (IS_ERR(file))
|
|
||||||
return PTR_ERR(file);
|
|
||||||
|
|
||||||
fd = get_unused_fd_flags(flags & O_CLOEXEC);
|
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
fd_install(fd, no_free_ptr(file));
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -4281,10 +4269,10 @@ static unsigned int attr_flags_to_mnt_flags(u64 attr_flags)
|
||||||
SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
|
SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
|
||||||
unsigned int, attr_flags)
|
unsigned int, attr_flags)
|
||||||
{
|
{
|
||||||
|
struct path new_path __free(path_put) = {};
|
||||||
struct mnt_namespace *ns;
|
struct mnt_namespace *ns;
|
||||||
struct fs_context *fc;
|
struct fs_context *fc;
|
||||||
struct file *file;
|
struct vfsmount *new_mnt;
|
||||||
struct path newmount;
|
|
||||||
struct mount *mnt;
|
struct mount *mnt;
|
||||||
unsigned int mnt_flags = 0;
|
unsigned int mnt_flags = 0;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
@ -4322,35 +4310,36 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
|
||||||
|
|
||||||
fc = fd_file(f)->private_data;
|
fc = fd_file(f)->private_data;
|
||||||
|
|
||||||
ret = mutex_lock_interruptible(&fc->uapi_mutex);
|
ACQUIRE(mutex_intr, uapi_mutex)(&fc->uapi_mutex);
|
||||||
if (ret < 0)
|
ret = ACQUIRE_ERR(mutex_intr, &uapi_mutex);
|
||||||
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* There must be a valid superblock or we can't mount it */
|
/* There must be a valid superblock or we can't mount it */
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (!fc->root)
|
if (!fc->root)
|
||||||
goto err_unlock;
|
return ret;
|
||||||
|
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
if (mount_too_revealing(fc->root->d_sb, &mnt_flags)) {
|
if (mount_too_revealing(fc->root->d_sb, &mnt_flags)) {
|
||||||
errorfcp(fc, "VFS", "Mount too revealing");
|
errorfcp(fc, "VFS", "Mount too revealing");
|
||||||
goto err_unlock;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
if (fc->phase != FS_CONTEXT_AWAITING_MOUNT)
|
if (fc->phase != FS_CONTEXT_AWAITING_MOUNT)
|
||||||
goto err_unlock;
|
return ret;
|
||||||
|
|
||||||
if (fc->sb_flags & SB_MANDLOCK)
|
if (fc->sb_flags & SB_MANDLOCK)
|
||||||
warn_mandlock();
|
warn_mandlock();
|
||||||
|
|
||||||
newmount.mnt = vfs_create_mount(fc);
|
new_mnt = vfs_create_mount(fc);
|
||||||
if (IS_ERR(newmount.mnt)) {
|
if (IS_ERR(new_mnt))
|
||||||
ret = PTR_ERR(newmount.mnt);
|
return PTR_ERR(new_mnt);
|
||||||
goto err_unlock;
|
new_mnt->mnt_flags = mnt_flags;
|
||||||
}
|
|
||||||
newmount.dentry = dget(fc->root);
|
new_path.dentry = dget(fc->root);
|
||||||
newmount.mnt->mnt_flags = mnt_flags;
|
new_path.mnt = new_mnt;
|
||||||
|
|
||||||
/* We've done the mount bit - now move the file context into more or
|
/* We've done the mount bit - now move the file context into more or
|
||||||
* less the same state as if we'd done an fspick(). We don't want to
|
* less the same state as if we'd done an fspick(). We don't want to
|
||||||
|
|
@ -4360,38 +4349,27 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
|
||||||
vfs_clean_context(fc);
|
vfs_clean_context(fc);
|
||||||
|
|
||||||
ns = alloc_mnt_ns(current->nsproxy->mnt_ns->user_ns, true);
|
ns = alloc_mnt_ns(current->nsproxy->mnt_ns->user_ns, true);
|
||||||
if (IS_ERR(ns)) {
|
if (IS_ERR(ns))
|
||||||
ret = PTR_ERR(ns);
|
return PTR_ERR(ns);
|
||||||
goto err_path;
|
mnt = real_mount(new_path.mnt);
|
||||||
}
|
|
||||||
mnt = real_mount(newmount.mnt);
|
|
||||||
ns->root = mnt;
|
ns->root = mnt;
|
||||||
ns->nr_mounts = 1;
|
ns->nr_mounts = 1;
|
||||||
mnt_add_to_ns(ns, mnt);
|
mnt_add_to_ns(ns, mnt);
|
||||||
mntget(newmount.mnt);
|
mntget(new_path.mnt);
|
||||||
|
|
||||||
/* Attach to an apparent O_PATH fd with a note that we need to unmount
|
FD_PREPARE(fdf, (flags & FSMOUNT_CLOEXEC) ? O_CLOEXEC : 0,
|
||||||
* it, not just simply put it.
|
dentry_open(&new_path, O_PATH, fc->cred));
|
||||||
*/
|
if (fdf.err) {
|
||||||
file = dentry_open(&newmount, O_PATH, fc->cred);
|
dissolve_on_fput(new_path.mnt);
|
||||||
if (IS_ERR(file)) {
|
return fdf.err;
|
||||||
dissolve_on_fput(newmount.mnt);
|
|
||||||
ret = PTR_ERR(file);
|
|
||||||
goto err_path;
|
|
||||||
}
|
}
|
||||||
file->f_mode |= FMODE_NEED_UNMOUNT;
|
|
||||||
|
|
||||||
ret = get_unused_fd_flags((flags & FSMOUNT_CLOEXEC) ? O_CLOEXEC : 0);
|
/*
|
||||||
if (ret >= 0)
|
* Attach to an apparent O_PATH fd with a note that we
|
||||||
fd_install(ret, file);
|
* need to unmount it, not just simply put it.
|
||||||
else
|
*/
|
||||||
fput(file);
|
fd_prepare_file(fdf)->f_mode |= FMODE_NEED_UNMOUNT;
|
||||||
|
return fd_publish(fdf);
|
||||||
err_path:
|
|
||||||
path_put(&newmount);
|
|
||||||
err_unlock:
|
|
||||||
mutex_unlock(&fc->uapi_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int vfs_move_mount(const struct path *from_path,
|
static inline int vfs_move_mount(const struct path *from_path,
|
||||||
|
|
@ -5033,19 +5011,17 @@ SYSCALL_DEFINE5(open_tree_attr, int, dfd, const char __user *, filename,
|
||||||
unsigned, flags, struct mount_attr __user *, uattr,
|
unsigned, flags, struct mount_attr __user *, uattr,
|
||||||
size_t, usize)
|
size_t, usize)
|
||||||
{
|
{
|
||||||
struct file __free(fput) *file = NULL;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (!uattr && usize)
|
if (!uattr && usize)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
file = vfs_open_tree(dfd, filename, flags);
|
FD_PREPARE(fdf, flags, vfs_open_tree(dfd, filename, flags));
|
||||||
if (IS_ERR(file))
|
if (fdf.err)
|
||||||
return PTR_ERR(file);
|
return fdf.err;
|
||||||
|
|
||||||
if (uattr) {
|
if (uattr) {
|
||||||
int ret;
|
|
||||||
struct mount_kattr kattr = {};
|
struct mount_kattr kattr = {};
|
||||||
|
struct file *file = fd_prepare_file(fdf);
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (flags & OPEN_TREE_CLONE)
|
if (flags & OPEN_TREE_CLONE)
|
||||||
kattr.kflags = MOUNT_KATTR_IDMAP_REPLACE;
|
kattr.kflags = MOUNT_KATTR_IDMAP_REPLACE;
|
||||||
|
|
@ -5061,12 +5037,7 @@ SYSCALL_DEFINE5(open_tree_attr, int, dfd, const char __user *, filename,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = get_unused_fd_flags(flags & O_CLOEXEC);
|
return fd_publish(fdf);
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
fd_install(fd, no_free_ptr(file));
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int show_path(struct seq_file *m, struct dentry *root)
|
int show_path(struct seq_file *m, struct dentry *root)
|
||||||
|
|
|
||||||
|
|
@ -1597,16 +1597,20 @@ static struct hlist_head *fanotify_alloc_merge_hash(void)
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_CLASS(fsnotify_group,
|
||||||
|
struct fsnotify_group *,
|
||||||
|
if (!IS_ERR_OR_NULL(_T)) fsnotify_destroy_group(_T),
|
||||||
|
fsnotify_alloc_group(ops, flags),
|
||||||
|
const struct fsnotify_ops *ops, int flags)
|
||||||
|
|
||||||
/* fanotify syscalls */
|
/* fanotify syscalls */
|
||||||
SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
||||||
{
|
{
|
||||||
struct user_namespace *user_ns = current_user_ns();
|
struct user_namespace *user_ns = current_user_ns();
|
||||||
struct fsnotify_group *group;
|
|
||||||
int f_flags, fd;
|
int f_flags, fd;
|
||||||
unsigned int fid_mode = flags & FANOTIFY_FID_BITS;
|
unsigned int fid_mode = flags & FANOTIFY_FID_BITS;
|
||||||
unsigned int class = flags & FANOTIFY_CLASS_BITS;
|
unsigned int class = flags & FANOTIFY_CLASS_BITS;
|
||||||
unsigned int internal_flags = 0;
|
unsigned int internal_flags = 0;
|
||||||
struct file *file;
|
|
||||||
|
|
||||||
pr_debug("%s: flags=%x event_f_flags=%x\n",
|
pr_debug("%s: flags=%x event_f_flags=%x\n",
|
||||||
__func__, flags, event_f_flags);
|
__func__, flags, event_f_flags);
|
||||||
|
|
@ -1690,36 +1694,29 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
||||||
if (flags & FAN_NONBLOCK)
|
if (flags & FAN_NONBLOCK)
|
||||||
f_flags |= O_NONBLOCK;
|
f_flags |= O_NONBLOCK;
|
||||||
|
|
||||||
/* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */
|
CLASS(fsnotify_group, group)(&fanotify_fsnotify_ops,
|
||||||
group = fsnotify_alloc_group(&fanotify_fsnotify_ops,
|
|
||||||
FSNOTIFY_GROUP_USER);
|
FSNOTIFY_GROUP_USER);
|
||||||
if (IS_ERR(group)) {
|
/* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */
|
||||||
|
if (IS_ERR(group))
|
||||||
return PTR_ERR(group);
|
return PTR_ERR(group);
|
||||||
}
|
|
||||||
|
|
||||||
/* Enforce groups limits per user in all containing user ns */
|
/* Enforce groups limits per user in all containing user ns */
|
||||||
group->fanotify_data.ucounts = inc_ucount(user_ns, current_euid(),
|
group->fanotify_data.ucounts = inc_ucount(user_ns, current_euid(),
|
||||||
UCOUNT_FANOTIFY_GROUPS);
|
UCOUNT_FANOTIFY_GROUPS);
|
||||||
if (!group->fanotify_data.ucounts) {
|
if (!group->fanotify_data.ucounts)
|
||||||
fd = -EMFILE;
|
return -EMFILE;
|
||||||
goto out_destroy_group;
|
|
||||||
}
|
|
||||||
|
|
||||||
group->fanotify_data.flags = flags | internal_flags;
|
group->fanotify_data.flags = flags | internal_flags;
|
||||||
group->memcg = get_mem_cgroup_from_mm(current->mm);
|
group->memcg = get_mem_cgroup_from_mm(current->mm);
|
||||||
group->user_ns = get_user_ns(user_ns);
|
group->user_ns = get_user_ns(user_ns);
|
||||||
|
|
||||||
group->fanotify_data.merge_hash = fanotify_alloc_merge_hash();
|
group->fanotify_data.merge_hash = fanotify_alloc_merge_hash();
|
||||||
if (!group->fanotify_data.merge_hash) {
|
if (!group->fanotify_data.merge_hash)
|
||||||
fd = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out_destroy_group;
|
|
||||||
}
|
|
||||||
|
|
||||||
group->overflow_event = fanotify_alloc_overflow_event();
|
group->overflow_event = fanotify_alloc_overflow_event();
|
||||||
if (unlikely(!group->overflow_event)) {
|
if (unlikely(!group->overflow_event))
|
||||||
fd = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out_destroy_group;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (force_o_largefile())
|
if (force_o_largefile())
|
||||||
event_f_flags |= O_LARGEFILE;
|
event_f_flags |= O_LARGEFILE;
|
||||||
|
|
@ -1738,8 +1735,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
||||||
group->priority = FSNOTIFY_PRIO_PRE_CONTENT;
|
group->priority = FSNOTIFY_PRIO_PRE_CONTENT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fd = -EINVAL;
|
return -EINVAL;
|
||||||
goto out_destroy_group;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BUILD_BUG_ON(!(FANOTIFY_ADMIN_INIT_FLAGS & FAN_UNLIMITED_QUEUE));
|
BUILD_BUG_ON(!(FANOTIFY_ADMIN_INIT_FLAGS & FAN_UNLIMITED_QUEUE));
|
||||||
|
|
@ -1750,27 +1746,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & FAN_ENABLE_AUDIT) {
|
if (flags & FAN_ENABLE_AUDIT) {
|
||||||
fd = -EPERM;
|
|
||||||
if (!capable(CAP_AUDIT_WRITE))
|
if (!capable(CAP_AUDIT_WRITE))
|
||||||
goto out_destroy_group;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = get_unused_fd_flags(f_flags);
|
fd = FD_ADD(f_flags,
|
||||||
if (fd < 0)
|
anon_inode_getfile_fmode("[fanotify]", &fanotify_fops,
|
||||||
goto out_destroy_group;
|
group, f_flags, FMODE_NONOTIFY));
|
||||||
|
if (fd >= 0)
|
||||||
file = anon_inode_getfile_fmode("[fanotify]", &fanotify_fops, group,
|
retain_and_null_ptr(group);
|
||||||
f_flags, FMODE_NONOTIFY);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
put_unused_fd(fd);
|
|
||||||
fd = PTR_ERR(file);
|
|
||||||
goto out_destroy_group;
|
|
||||||
}
|
|
||||||
fd_install(fd, file);
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
out_destroy_group:
|
|
||||||
fsnotify_destroy_group(group);
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
47
fs/nsfs.c
47
fs/nsfs.c
|
|
@ -110,7 +110,6 @@ int ns_get_path(struct path *path, struct task_struct *task,
|
||||||
int open_namespace(struct ns_common *ns)
|
int open_namespace(struct ns_common *ns)
|
||||||
{
|
{
|
||||||
struct path path __free(path_put) = {};
|
struct path path __free(path_put) = {};
|
||||||
struct file *f;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* call first to consume reference */
|
/* call first to consume reference */
|
||||||
|
|
@ -118,16 +117,7 @@ int open_namespace(struct ns_common *ns)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
CLASS(get_unused_fd, fd)(O_CLOEXEC);
|
return FD_ADD(O_CLOEXEC, dentry_open(&path, O_RDONLY, current_cred()));
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
f = dentry_open(&path, O_RDONLY, current_cred());
|
|
||||||
if (IS_ERR(f))
|
|
||||||
return PTR_ERR(f);
|
|
||||||
|
|
||||||
fd_install(fd, f);
|
|
||||||
return take_fd(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int open_related_ns(struct ns_common *ns,
|
int open_related_ns(struct ns_common *ns,
|
||||||
|
|
@ -313,7 +303,6 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
|
||||||
struct mnt_ns_info kinfo = {};
|
struct mnt_ns_info kinfo = {};
|
||||||
struct mnt_ns_info __user *uinfo = (struct mnt_ns_info __user *)arg;
|
struct mnt_ns_info __user *uinfo = (struct mnt_ns_info __user *)arg;
|
||||||
struct path path __free(path_put) = {};
|
struct path path __free(path_put) = {};
|
||||||
struct file *f __free(fput) = NULL;
|
|
||||||
size_t usize = _IOC_SIZE(ioctl);
|
size_t usize = _IOC_SIZE(ioctl);
|
||||||
|
|
||||||
if (ns->ns_type != CLONE_NEWNS)
|
if (ns->ns_type != CLONE_NEWNS)
|
||||||
|
|
@ -332,28 +321,18 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
CLASS(get_unused_fd, fd)(O_CLOEXEC);
|
FD_PREPARE(fdf, O_CLOEXEC, dentry_open(&path, O_RDONLY, current_cred()));
|
||||||
if (fd < 0)
|
if (fdf.err)
|
||||||
return fd;
|
return fdf.err;
|
||||||
|
/*
|
||||||
f = dentry_open(&path, O_RDONLY, current_cred());
|
* If @uinfo is passed return all information about the
|
||||||
if (IS_ERR(f))
|
* mount namespace as well.
|
||||||
return PTR_ERR(f);
|
*/
|
||||||
|
ret = copy_ns_info_to_user(to_mnt_ns(ns), uinfo, usize, &kinfo);
|
||||||
if (uinfo) {
|
if (ret)
|
||||||
/*
|
return ret;
|
||||||
* If @uinfo is passed return all information about the
|
ret = fd_publish(fdf);
|
||||||
* mount namespace as well.
|
break;
|
||||||
*/
|
|
||||||
ret = copy_ns_info_to_user(to_mnt_ns(ns), uinfo, usize, &kinfo);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Transfer reference of @f to caller's fdtable. */
|
|
||||||
fd_install(fd, no_free_ptr(f));
|
|
||||||
/* File descriptor is live so hand it off to the caller. */
|
|
||||||
return take_fd(fd);
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
ret = -ENOTTY;
|
ret = -ENOTTY;
|
||||||
|
|
|
||||||
17
fs/open.c
17
fs/open.c
|
|
@ -1416,8 +1416,8 @@ static int do_sys_openat2(int dfd, const char __user *filename,
|
||||||
struct open_how *how)
|
struct open_how *how)
|
||||||
{
|
{
|
||||||
struct open_flags op;
|
struct open_flags op;
|
||||||
struct filename *tmp;
|
struct filename *tmp __free(putname) = NULL;
|
||||||
int err, fd;
|
int err;
|
||||||
|
|
||||||
err = build_open_flags(how, &op);
|
err = build_open_flags(how, &op);
|
||||||
if (unlikely(err))
|
if (unlikely(err))
|
||||||
|
|
@ -1427,18 +1427,7 @@ static int do_sys_openat2(int dfd, const char __user *filename,
|
||||||
if (IS_ERR(tmp))
|
if (IS_ERR(tmp))
|
||||||
return PTR_ERR(tmp);
|
return PTR_ERR(tmp);
|
||||||
|
|
||||||
fd = get_unused_fd_flags(how->flags);
|
return FD_ADD(how->flags, do_filp_open(dfd, tmp, &op));
|
||||||
if (likely(fd >= 0)) {
|
|
||||||
struct file *f = do_filp_open(dfd, tmp, &op);
|
|
||||||
if (IS_ERR(f)) {
|
|
||||||
put_unused_fd(fd);
|
|
||||||
fd = PTR_ERR(f);
|
|
||||||
} else {
|
|
||||||
fd_install(fd, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
putname(tmp);
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
|
int do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
|
||||||
|
|
|
||||||
|
|
@ -250,8 +250,6 @@ static const struct file_operations signalfd_fops = {
|
||||||
|
|
||||||
static int do_signalfd4(int ufd, sigset_t *mask, int flags)
|
static int do_signalfd4(int ufd, sigset_t *mask, int flags)
|
||||||
{
|
{
|
||||||
struct signalfd_ctx *ctx;
|
|
||||||
|
|
||||||
/* Check the SFD_* constants for consistency. */
|
/* Check the SFD_* constants for consistency. */
|
||||||
BUILD_BUG_ON(SFD_CLOEXEC != O_CLOEXEC);
|
BUILD_BUG_ON(SFD_CLOEXEC != O_CLOEXEC);
|
||||||
BUILD_BUG_ON(SFD_NONBLOCK != O_NONBLOCK);
|
BUILD_BUG_ON(SFD_NONBLOCK != O_NONBLOCK);
|
||||||
|
|
@ -263,7 +261,8 @@ static int do_signalfd4(int ufd, sigset_t *mask, int flags)
|
||||||
signotset(mask);
|
signotset(mask);
|
||||||
|
|
||||||
if (ufd == -1) {
|
if (ufd == -1) {
|
||||||
struct file *file;
|
int fd;
|
||||||
|
struct signalfd_ctx *ctx __free(kfree) = NULL;
|
||||||
|
|
||||||
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
|
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
|
|
@ -271,22 +270,16 @@ static int do_signalfd4(int ufd, sigset_t *mask, int flags)
|
||||||
|
|
||||||
ctx->sigmask = *mask;
|
ctx->sigmask = *mask;
|
||||||
|
|
||||||
ufd = get_unused_fd_flags(flags & O_CLOEXEC);
|
fd = FD_ADD(flags & O_CLOEXEC,
|
||||||
if (ufd < 0) {
|
anon_inode_getfile_fmode(
|
||||||
kfree(ctx);
|
"[signalfd]", &signalfd_fops, ctx,
|
||||||
return ufd;
|
O_RDWR | (flags & O_NONBLOCK), FMODE_NOWAIT));
|
||||||
}
|
if (fd >= 0)
|
||||||
|
retain_and_null_ptr(ctx);
|
||||||
file = anon_inode_getfile_fmode("[signalfd]", &signalfd_fops,
|
return fd;
|
||||||
ctx, O_RDWR | (flags & O_NONBLOCK),
|
|
||||||
FMODE_NOWAIT);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
put_unused_fd(ufd);
|
|
||||||
kfree(ctx);
|
|
||||||
return PTR_ERR(file);
|
|
||||||
}
|
|
||||||
fd_install(ufd, file);
|
|
||||||
} else {
|
} else {
|
||||||
|
struct signalfd_ctx *ctx;
|
||||||
|
|
||||||
CLASS(fd, f)(ufd);
|
CLASS(fd, f)(ufd);
|
||||||
if (fd_empty(f))
|
if (fd_empty(f))
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
|
||||||
29
fs/timerfd.c
29
fs/timerfd.c
|
|
@ -393,9 +393,8 @@ static const struct file_operations timerfd_fops = {
|
||||||
|
|
||||||
SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
|
SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
|
||||||
{
|
{
|
||||||
int ufd;
|
struct timerfd_ctx *ctx __free(kfree) = NULL;
|
||||||
struct timerfd_ctx *ctx;
|
int ret;
|
||||||
struct file *file;
|
|
||||||
|
|
||||||
/* Check the TFD_* constants for consistency. */
|
/* Check the TFD_* constants for consistency. */
|
||||||
BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
|
BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
|
||||||
|
|
@ -432,23 +431,13 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
|
||||||
|
|
||||||
ctx->moffs = ktime_mono_to_real(0);
|
ctx->moffs = ktime_mono_to_real(0);
|
||||||
|
|
||||||
ufd = get_unused_fd_flags(flags & TFD_SHARED_FCNTL_FLAGS);
|
ret = FD_ADD(flags & TFD_SHARED_FCNTL_FLAGS,
|
||||||
if (ufd < 0) {
|
anon_inode_getfile_fmode("[timerfd]", &timerfd_fops, ctx,
|
||||||
kfree(ctx);
|
O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS),
|
||||||
return ufd;
|
FMODE_NOWAIT));
|
||||||
}
|
if (ret >= 0)
|
||||||
|
retain_and_null_ptr(ctx);
|
||||||
file = anon_inode_getfile_fmode("[timerfd]", &timerfd_fops, ctx,
|
return ret;
|
||||||
O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS),
|
|
||||||
FMODE_NOWAIT);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
put_unused_fd(ufd);
|
|
||||||
kfree(ctx);
|
|
||||||
return PTR_ERR(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(ufd, file);
|
|
||||||
return ufd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_timerfd_settime(int ufd, int flags,
|
static int do_timerfd_settime(int ufd, int flags,
|
||||||
|
|
|
||||||
|
|
@ -2111,9 +2111,7 @@ static void init_once_userfaultfd_ctx(void *mem)
|
||||||
|
|
||||||
static int new_userfaultfd(int flags)
|
static int new_userfaultfd(int flags)
|
||||||
{
|
{
|
||||||
struct userfaultfd_ctx *ctx;
|
struct userfaultfd_ctx *ctx __free(kfree) = NULL;
|
||||||
struct file *file;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
VM_WARN_ON_ONCE(!current->mm);
|
VM_WARN_ON_ONCE(!current->mm);
|
||||||
|
|
||||||
|
|
@ -2135,26 +2133,18 @@ static int new_userfaultfd(int flags)
|
||||||
atomic_set(&ctx->mmap_changing, 0);
|
atomic_set(&ctx->mmap_changing, 0);
|
||||||
ctx->mm = current->mm;
|
ctx->mm = current->mm;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(flags & UFFD_SHARED_FCNTL_FLAGS);
|
FD_PREPARE(fdf, flags & UFFD_SHARED_FCNTL_FLAGS,
|
||||||
if (fd < 0)
|
anon_inode_create_getfile("[userfaultfd]", &userfaultfd_fops, ctx,
|
||||||
goto err_out;
|
O_RDONLY | (flags & UFFD_SHARED_FCNTL_FLAGS),
|
||||||
|
NULL));
|
||||||
|
if (fdf.err)
|
||||||
|
return fdf.err;
|
||||||
|
|
||||||
/* Create a new inode so that the LSM can block the creation. */
|
|
||||||
file = anon_inode_create_getfile("[userfaultfd]", &userfaultfd_fops, ctx,
|
|
||||||
O_RDONLY | (flags & UFFD_SHARED_FCNTL_FLAGS), NULL);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
put_unused_fd(fd);
|
|
||||||
fd = PTR_ERR(file);
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
/* prevent the mm struct to be freed */
|
/* prevent the mm struct to be freed */
|
||||||
mmgrab(ctx->mm);
|
mmgrab(ctx->mm);
|
||||||
file->f_mode |= FMODE_NOWAIT;
|
fd_prepare_file(fdf)->f_mode |= FMODE_NOWAIT;
|
||||||
fd_install(fd, file);
|
retain_and_null_ptr(ctx);
|
||||||
return fd;
|
return fd_publish(fdf);
|
||||||
err_out:
|
|
||||||
kmem_cache_free(userfaultfd_ctx_cachep, ctx);
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool userfaultfd_syscall_allowed(int flags)
|
static inline bool userfaultfd_syscall_allowed(int flags)
|
||||||
|
|
|
||||||
|
|
@ -233,14 +233,11 @@ xfs_open_by_handle(
|
||||||
xfs_fsop_handlereq_t *hreq)
|
xfs_fsop_handlereq_t *hreq)
|
||||||
{
|
{
|
||||||
const struct cred *cred = current_cred();
|
const struct cred *cred = current_cred();
|
||||||
int error;
|
|
||||||
int fd;
|
|
||||||
int permflag;
|
int permflag;
|
||||||
struct file *filp;
|
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
fmode_t fmode;
|
fmode_t fmode;
|
||||||
struct path path;
|
struct path path __free(path_put) = {};
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
@ -249,12 +246,11 @@ xfs_open_by_handle(
|
||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
return PTR_ERR(dentry);
|
return PTR_ERR(dentry);
|
||||||
inode = d_inode(dentry);
|
inode = d_inode(dentry);
|
||||||
|
path.dentry = dentry;
|
||||||
|
|
||||||
/* Restrict xfs_open_by_handle to directories & regular files. */
|
/* Restrict xfs_open_by_handle to directories & regular files. */
|
||||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
|
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
|
||||||
error = -EPERM;
|
return -EPERM;
|
||||||
goto out_dput;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if BITS_PER_LONG != 32
|
#if BITS_PER_LONG != 32
|
||||||
hreq->oflags |= O_LARGEFILE;
|
hreq->oflags |= O_LARGEFILE;
|
||||||
|
|
@ -263,48 +259,30 @@ xfs_open_by_handle(
|
||||||
permflag = hreq->oflags;
|
permflag = hreq->oflags;
|
||||||
fmode = OPEN_FMODE(permflag);
|
fmode = OPEN_FMODE(permflag);
|
||||||
if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
|
if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
|
||||||
(fmode & FMODE_WRITE) && IS_APPEND(inode)) {
|
(fmode & FMODE_WRITE) && IS_APPEND(inode))
|
||||||
error = -EPERM;
|
return -EPERM;
|
||||||
goto out_dput;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
|
if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode))
|
||||||
error = -EPERM;
|
return -EPERM;
|
||||||
goto out_dput;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Can't write directories. */
|
/* Can't write directories. */
|
||||||
if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) {
|
if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE))
|
||||||
error = -EISDIR;
|
return -EISDIR;
|
||||||
goto out_dput;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = get_unused_fd_flags(0);
|
path.mnt = mntget(parfilp->f_path.mnt);
|
||||||
if (fd < 0) {
|
|
||||||
error = fd;
|
|
||||||
goto out_dput;
|
|
||||||
}
|
|
||||||
|
|
||||||
path.mnt = parfilp->f_path.mnt;
|
FD_PREPARE(fdf, 0, dentry_open(&path, hreq->oflags, cred));
|
||||||
path.dentry = dentry;
|
if (fdf.err)
|
||||||
filp = dentry_open(&path, hreq->oflags, cred);
|
return fdf.err;
|
||||||
dput(dentry);
|
|
||||||
if (IS_ERR(filp)) {
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return PTR_ERR(filp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISREG(inode->i_mode)) {
|
if (S_ISREG(inode->i_mode)) {
|
||||||
|
struct file *filp = fd_prepare_file(fdf);
|
||||||
|
|
||||||
filp->f_flags |= O_NOATIME;
|
filp->f_flags |= O_NOATIME;
|
||||||
filp->f_mode |= FMODE_NOCMTIME;
|
filp->f_mode |= FMODE_NOCMTIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_install(fd, filp);
|
return fd_publish(fdf);
|
||||||
return fd;
|
|
||||||
|
|
||||||
out_dput:
|
|
||||||
dput(dentry);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,10 @@ const volatile void * __must_check_fn(const volatile void *val)
|
||||||
* CLASS(name, var)(args...):
|
* CLASS(name, var)(args...):
|
||||||
* declare the variable @var as an instance of the named class
|
* declare the variable @var as an instance of the named class
|
||||||
*
|
*
|
||||||
|
* CLASS_INIT(name, var, init_expr):
|
||||||
|
* declare the variable @var as an instance of the named class with
|
||||||
|
* custom initialization expression.
|
||||||
|
*
|
||||||
* Ex.
|
* Ex.
|
||||||
*
|
*
|
||||||
* DEFINE_CLASS(fdget, struct fd, fdput(_T), fdget(fd), int fd)
|
* DEFINE_CLASS(fdget, struct fd, fdput(_T), fdget(fd), int fd)
|
||||||
|
|
@ -290,6 +294,9 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
|
||||||
class_##_name##_t var __cleanup(class_##_name##_destructor) = \
|
class_##_name##_t var __cleanup(class_##_name##_destructor) = \
|
||||||
class_##_name##_constructor
|
class_##_name##_constructor
|
||||||
|
|
||||||
|
#define CLASS_INIT(_name, _var, _init_expr) \
|
||||||
|
class_##_name##_t _var __cleanup(class_##_name##_destructor) = (_init_expr)
|
||||||
|
|
||||||
#define __scoped_class(_name, var, _label, args...) \
|
#define __scoped_class(_name, var, _label, args...) \
|
||||||
for (CLASS(_name, var)(args); ; ({ goto _label; })) \
|
for (CLASS(_name, var)(args); ; ({ goto _label; })) \
|
||||||
if (0) { \
|
if (0) { \
|
||||||
|
|
|
||||||
|
|
@ -127,4 +127,130 @@ extern void __fput_sync(struct file *);
|
||||||
|
|
||||||
extern unsigned int sysctl_nr_open_min, sysctl_nr_open_max;
|
extern unsigned int sysctl_nr_open_min, sysctl_nr_open_max;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fd_prepare: Combined fd + file allocation cleanup class.
|
||||||
|
* @err: Error code to indicate if allocation succeeded.
|
||||||
|
* @__fd: Allocated fd (may not be accessed directly)
|
||||||
|
* @__file: Allocated struct file pointer (may not be accessed directly)
|
||||||
|
*
|
||||||
|
* Allocates an fd and a file together. On error paths, automatically cleans
|
||||||
|
* up whichever resource was successfully allocated. Allows flexible file
|
||||||
|
* allocation with different functions per usage.
|
||||||
|
*
|
||||||
|
* Do not use directly.
|
||||||
|
*/
|
||||||
|
struct fd_prepare {
|
||||||
|
s32 err;
|
||||||
|
s32 __fd; /* do not access directly */
|
||||||
|
struct file *__file; /* do not access directly */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Typedef for fd_prepare cleanup guards. */
|
||||||
|
typedef struct fd_prepare class_fd_prepare_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Accessors for fd_prepare class members.
|
||||||
|
* _Generic() is used for zero-cost type safety.
|
||||||
|
*/
|
||||||
|
#define fd_prepare_fd(_fdf) \
|
||||||
|
(_Generic((_fdf), struct fd_prepare: (_fdf).__fd))
|
||||||
|
|
||||||
|
#define fd_prepare_file(_fdf) \
|
||||||
|
(_Generic((_fdf), struct fd_prepare: (_fdf).__file))
|
||||||
|
|
||||||
|
/* Do not use directly. */
|
||||||
|
static inline void class_fd_prepare_destructor(const struct fd_prepare *fdf)
|
||||||
|
{
|
||||||
|
if (unlikely(fdf->err)) {
|
||||||
|
if (likely(fdf->__fd >= 0))
|
||||||
|
put_unused_fd(fdf->__fd);
|
||||||
|
if (unlikely(!IS_ERR_OR_NULL(fdf->__file)))
|
||||||
|
fput(fdf->__file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do not use directly. */
|
||||||
|
static inline int class_fd_prepare_lock_err(const struct fd_prepare *fdf)
|
||||||
|
{
|
||||||
|
if (unlikely(fdf->err))
|
||||||
|
return fdf->err;
|
||||||
|
if (unlikely(fdf->__fd < 0))
|
||||||
|
return fdf->__fd;
|
||||||
|
if (unlikely(IS_ERR(fdf->__file)))
|
||||||
|
return PTR_ERR(fdf->__file);
|
||||||
|
if (unlikely(!fdf->__file))
|
||||||
|
return -ENOMEM;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __FD_PREPARE_INIT - Helper to initialize fd_prepare class.
|
||||||
|
* @_fd_flags: flags for get_unused_fd_flags()
|
||||||
|
* @_file_owned: expression that returns struct file *
|
||||||
|
*
|
||||||
|
* Returns a struct fd_prepare with fd, file, and err set.
|
||||||
|
* If fd allocation fails, fd will be negative and err will be set. If
|
||||||
|
* fd succeeds but file_init_expr fails, file will be ERR_PTR and err
|
||||||
|
* will be set. The err field is the single source of truth for error
|
||||||
|
* checking.
|
||||||
|
*/
|
||||||
|
#define __FD_PREPARE_INIT(_fd_flags, _file_owned) \
|
||||||
|
({ \
|
||||||
|
struct fd_prepare fdf = { \
|
||||||
|
.__fd = get_unused_fd_flags((_fd_flags)), \
|
||||||
|
}; \
|
||||||
|
if (likely(fdf.__fd >= 0)) \
|
||||||
|
fdf.__file = (_file_owned); \
|
||||||
|
fdf.err = ACQUIRE_ERR(fd_prepare, &fdf); \
|
||||||
|
fdf; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FD_PREPARE - Macro to declare and initialize an fd_prepare variable.
|
||||||
|
*
|
||||||
|
* Declares and initializes an fd_prepare variable with automatic
|
||||||
|
* cleanup. No separate scope required - cleanup happens when variable
|
||||||
|
* goes out of scope.
|
||||||
|
*
|
||||||
|
* @_fdf: name of struct fd_prepare variable to define
|
||||||
|
* @_fd_flags: flags for get_unused_fd_flags()
|
||||||
|
* @_file_owned: struct file to take ownership of (can be expression)
|
||||||
|
*/
|
||||||
|
#define FD_PREPARE(_fdf, _fd_flags, _file_owned) \
|
||||||
|
CLASS_INIT(fd_prepare, _fdf, __FD_PREPARE_INIT(_fd_flags, _file_owned))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fd_publish - Publish prepared fd and file to the fd table.
|
||||||
|
* @_fdf: struct fd_prepare variable
|
||||||
|
*/
|
||||||
|
#define fd_publish(_fdf) \
|
||||||
|
({ \
|
||||||
|
struct fd_prepare *fdp = &(_fdf); \
|
||||||
|
VFS_WARN_ON_ONCE(fdp->err); \
|
||||||
|
VFS_WARN_ON_ONCE(fdp->__fd < 0); \
|
||||||
|
VFS_WARN_ON_ONCE(IS_ERR_OR_NULL(fdp->__file)); \
|
||||||
|
fd_install(fdp->__fd, fdp->__file); \
|
||||||
|
fdp->__fd; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/* Do not use directly. */
|
||||||
|
#define __FD_ADD(_fdf, _fd_flags, _file_owned) \
|
||||||
|
({ \
|
||||||
|
FD_PREPARE(_fdf, _fd_flags, _file_owned); \
|
||||||
|
s32 ret = _fdf.err; \
|
||||||
|
if (likely(!ret)) \
|
||||||
|
ret = fd_publish(_fdf); \
|
||||||
|
ret; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FD_ADD - Allocate and install an fd and file in one step.
|
||||||
|
* @_fd_flags: flags for get_unused_fd_flags()
|
||||||
|
* @_file_owned: struct file to take ownership of
|
||||||
|
*
|
||||||
|
* Returns the allocated fd number, or negative error code on failure.
|
||||||
|
*/
|
||||||
|
#define FD_ADD(_fd_flags, _file_owned) \
|
||||||
|
__FD_ADD(__UNIQUE_ID(fd_prepare), _fd_flags, _file_owned)
|
||||||
|
|
||||||
#endif /* __LINUX_FILE_H */
|
#endif /* __LINUX_FILE_H */
|
||||||
|
|
|
||||||
|
|
@ -211,10 +211,9 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
|
||||||
const struct file_operations *fops = &io_mock_fops;
|
const struct file_operations *fops = &io_mock_fops;
|
||||||
const struct io_uring_sqe *sqe = cmd->sqe;
|
const struct io_uring_sqe *sqe = cmd->sqe;
|
||||||
struct io_uring_mock_create mc, __user *uarg;
|
struct io_uring_mock_create mc, __user *uarg;
|
||||||
struct io_mock_file *mf = NULL;
|
struct file *file;
|
||||||
struct file *file = NULL;
|
struct io_mock_file *mf __free(kfree) = NULL;
|
||||||
size_t uarg_size;
|
size_t uarg_size;
|
||||||
int fd = -1, ret;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's a testing only driver that allows exercising edge cases
|
* It's a testing only driver that allows exercising edge cases
|
||||||
|
|
@ -246,10 +245,6 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
|
||||||
if (!mf)
|
if (!mf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
|
|
||||||
if (fd < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
init_waitqueue_head(&mf->poll_wq);
|
init_waitqueue_head(&mf->poll_wq);
|
||||||
mf->size = mc.file_size;
|
mf->size = mc.file_size;
|
||||||
mf->rw_delay_ns = mc.rw_delay_ns;
|
mf->rw_delay_ns = mc.rw_delay_ns;
|
||||||
|
|
@ -258,33 +253,25 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
|
||||||
mf->pollable = true;
|
mf->pollable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
file = anon_inode_create_getfile("[io_uring_mock]", fops,
|
FD_PREPARE(fdf, O_RDWR | O_CLOEXEC,
|
||||||
mf, O_RDWR | O_CLOEXEC, NULL);
|
anon_inode_create_getfile("[io_uring_mock]", fops, mf,
|
||||||
if (IS_ERR(file)) {
|
O_RDWR | O_CLOEXEC, NULL));
|
||||||
ret = PTR_ERR(file);
|
if (fdf.err)
|
||||||
goto fail;
|
return fdf.err;
|
||||||
}
|
|
||||||
|
|
||||||
file->f_mode |= FMODE_READ | FMODE_CAN_READ |
|
retain_and_null_ptr(mf);
|
||||||
FMODE_WRITE | FMODE_CAN_WRITE |
|
file = fd_prepare_file(fdf);
|
||||||
FMODE_LSEEK;
|
file->f_mode |= FMODE_READ | FMODE_CAN_READ | FMODE_WRITE |
|
||||||
|
FMODE_CAN_WRITE | FMODE_LSEEK;
|
||||||
if (mc.flags & IORING_MOCK_CREATE_F_SUPPORT_NOWAIT)
|
if (mc.flags & IORING_MOCK_CREATE_F_SUPPORT_NOWAIT)
|
||||||
file->f_mode |= FMODE_NOWAIT;
|
file->f_mode |= FMODE_NOWAIT;
|
||||||
|
|
||||||
mc.out_fd = fd;
|
mc.out_fd = fd_prepare_fd(fdf);
|
||||||
if (copy_to_user(uarg, &mc, uarg_size)) {
|
if (copy_to_user(uarg, &mc, uarg_size))
|
||||||
fput(file);
|
return -EFAULT;
|
||||||
ret = -EFAULT;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, file);
|
fd_publish(fdf);
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
|
||||||
if (fd >= 0)
|
|
||||||
put_unused_fd(fd);
|
|
||||||
kfree(mf);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int io_probe_mock(struct io_uring_cmd *cmd)
|
static int io_probe_mock(struct io_uring_cmd *cmd)
|
||||||
|
|
|
||||||
57
ipc/mqueue.c
57
ipc/mqueue.c
|
|
@ -892,15 +892,35 @@ static int prepare_open(struct dentry *dentry, int oflag, int ro,
|
||||||
return inode_permission(&nop_mnt_idmap, d_inode(dentry), acc);
|
return inode_permission(&nop_mnt_idmap, d_inode(dentry), acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct file *mqueue_file_open(struct filename *name,
|
||||||
|
struct vfsmount *mnt, int oflag, bool ro,
|
||||||
|
umode_t mode, struct mq_attr *attr)
|
||||||
|
{
|
||||||
|
struct dentry *dentry;
|
||||||
|
struct file *file;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dentry = start_creating_noperm(mnt->mnt_root, &QSTR(name->name));
|
||||||
|
if (IS_ERR(dentry))
|
||||||
|
return ERR_CAST(dentry);
|
||||||
|
|
||||||
|
ret = prepare_open(dentry, oflag, ro, mode, name, attr);
|
||||||
|
file = ERR_PTR(ret);
|
||||||
|
if (!ret) {
|
||||||
|
const struct path path = { .mnt = mnt, .dentry = dentry };
|
||||||
|
file = dentry_open(&path, oflag, current_cred());
|
||||||
|
}
|
||||||
|
|
||||||
|
end_creating(dentry);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
|
static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
|
||||||
struct mq_attr *attr)
|
struct mq_attr *attr)
|
||||||
{
|
{
|
||||||
|
struct filename *name __free(putname) = NULL;;
|
||||||
struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
|
struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
|
||||||
struct dentry *root = mnt->mnt_root;
|
int fd, ro;
|
||||||
struct filename *name;
|
|
||||||
struct path path;
|
|
||||||
int fd, error;
|
|
||||||
int ro;
|
|
||||||
|
|
||||||
audit_mq_open(oflag, mode, attr);
|
audit_mq_open(oflag, mode, attr);
|
||||||
|
|
||||||
|
|
@ -908,35 +928,10 @@ static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
|
||||||
if (IS_ERR(name))
|
if (IS_ERR(name))
|
||||||
return PTR_ERR(name);
|
return PTR_ERR(name);
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
|
||||||
if (fd < 0)
|
|
||||||
goto out_putname;
|
|
||||||
|
|
||||||
ro = mnt_want_write(mnt); /* we'll drop it in any case */
|
ro = mnt_want_write(mnt); /* we'll drop it in any case */
|
||||||
path.dentry = start_creating_noperm(root, &QSTR(name->name));
|
fd = FD_ADD(O_CLOEXEC, mqueue_file_open(name, mnt, oflag, ro, mode, attr));
|
||||||
if (IS_ERR(path.dentry)) {
|
|
||||||
error = PTR_ERR(path.dentry);
|
|
||||||
goto out_putfd;
|
|
||||||
}
|
|
||||||
path.mnt = mnt;
|
|
||||||
error = prepare_open(path.dentry, oflag, ro, mode, name, attr);
|
|
||||||
if (!error) {
|
|
||||||
struct file *file = dentry_open(&path, oflag, current_cred());
|
|
||||||
if (!IS_ERR(file))
|
|
||||||
fd_install(fd, file);
|
|
||||||
else
|
|
||||||
error = PTR_ERR(file);
|
|
||||||
}
|
|
||||||
out_putfd:
|
|
||||||
if (error) {
|
|
||||||
put_unused_fd(fd);
|
|
||||||
fd = error;
|
|
||||||
}
|
|
||||||
end_creating(path.dentry);
|
|
||||||
if (!ro)
|
if (!ro)
|
||||||
mnt_drop_write(mnt);
|
mnt_drop_write(mnt);
|
||||||
out_putname:
|
|
||||||
putname(name);
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -634,37 +634,24 @@ static int prepare_seq_file(struct file *file, struct bpf_iter_link *link)
|
||||||
int bpf_iter_new_fd(struct bpf_link *link)
|
int bpf_iter_new_fd(struct bpf_link *link)
|
||||||
{
|
{
|
||||||
struct bpf_iter_link *iter_link;
|
struct bpf_iter_link *iter_link;
|
||||||
struct file *file;
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
int err, fd;
|
int err;
|
||||||
|
|
||||||
if (link->ops != &bpf_iter_link_lops)
|
if (link->ops != &bpf_iter_link_lops)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
flags = O_RDONLY | O_CLOEXEC;
|
flags = O_RDONLY | O_CLOEXEC;
|
||||||
fd = get_unused_fd_flags(flags);
|
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
file = anon_inode_getfile("bpf_iter", &bpf_iter_fops, NULL, flags);
|
FD_PREPARE(fdf, flags, anon_inode_getfile("bpf_iter", &bpf_iter_fops, NULL, flags));
|
||||||
if (IS_ERR(file)) {
|
if (fdf.err)
|
||||||
err = PTR_ERR(file);
|
return fdf.err;
|
||||||
goto free_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter_link = container_of(link, struct bpf_iter_link, link);
|
iter_link = container_of(link, struct bpf_iter_link, link);
|
||||||
err = prepare_seq_file(file, iter_link);
|
err = prepare_seq_file(fd_prepare_file(fdf), iter_link);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_file;
|
return err; /* Automatic cleanup handles fput */
|
||||||
|
|
||||||
fd_install(fd, file);
|
return fd_publish(fdf);
|
||||||
return fd;
|
|
||||||
|
|
||||||
free_file:
|
|
||||||
fput(file);
|
|
||||||
free_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bpf_prog *bpf_iter_get_info(struct bpf_iter_meta *meta, bool in_stop)
|
struct bpf_prog *bpf_iter_get_info(struct bpf_iter_meta *meta, bool in_stop)
|
||||||
|
|
|
||||||
|
|
@ -110,16 +110,15 @@ const struct file_operations bpf_token_fops = {
|
||||||
|
|
||||||
int bpf_token_create(union bpf_attr *attr)
|
int bpf_token_create(union bpf_attr *attr)
|
||||||
{
|
{
|
||||||
|
struct bpf_token *token __free(kfree) = NULL;
|
||||||
struct bpf_mount_opts *mnt_opts;
|
struct bpf_mount_opts *mnt_opts;
|
||||||
struct bpf_token *token = NULL;
|
|
||||||
struct user_namespace *userns;
|
struct user_namespace *userns;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct file *file;
|
|
||||||
CLASS(fd, f)(attr->token_create.bpffs_fd);
|
CLASS(fd, f)(attr->token_create.bpffs_fd);
|
||||||
struct path path;
|
struct path path;
|
||||||
struct super_block *sb;
|
struct super_block *sb;
|
||||||
umode_t mode;
|
umode_t mode;
|
||||||
int err, fd;
|
int err;
|
||||||
|
|
||||||
if (fd_empty(f))
|
if (fd_empty(f))
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
@ -166,23 +165,20 @@ int bpf_token_create(union bpf_attr *attr)
|
||||||
inode->i_fop = &bpf_token_fops;
|
inode->i_fop = &bpf_token_fops;
|
||||||
clear_nlink(inode); /* make sure it is unlinked */
|
clear_nlink(inode); /* make sure it is unlinked */
|
||||||
|
|
||||||
file = alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME, O_RDWR, &bpf_token_fops);
|
FD_PREPARE(fdf, O_CLOEXEC,
|
||||||
if (IS_ERR(file)) {
|
alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME,
|
||||||
iput(inode);
|
O_RDWR, &bpf_token_fops));
|
||||||
return PTR_ERR(file);
|
if (fdf.err)
|
||||||
}
|
return fdf.err;
|
||||||
|
|
||||||
token = kzalloc(sizeof(*token), GFP_USER);
|
token = kzalloc(sizeof(*token), GFP_USER);
|
||||||
if (!token) {
|
if (!token)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic64_set(&token->refcnt, 1);
|
atomic64_set(&token->refcnt, 1);
|
||||||
|
|
||||||
/* remember bpffs owning userns for future ns_capable() checks */
|
/* remember bpffs owning userns for future ns_capable() checks. */
|
||||||
token->userns = get_user_ns(userns);
|
token->userns = userns;
|
||||||
|
|
||||||
token->allowed_cmds = mnt_opts->delegate_cmds;
|
token->allowed_cmds = mnt_opts->delegate_cmds;
|
||||||
token->allowed_maps = mnt_opts->delegate_maps;
|
token->allowed_maps = mnt_opts->delegate_maps;
|
||||||
token->allowed_progs = mnt_opts->delegate_progs;
|
token->allowed_progs = mnt_opts->delegate_progs;
|
||||||
|
|
@ -190,24 +186,11 @@ int bpf_token_create(union bpf_attr *attr)
|
||||||
|
|
||||||
err = security_bpf_token_create(token, attr, &path);
|
err = security_bpf_token_create(token, attr, &path);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_token;
|
return err;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
get_user_ns(token->userns);
|
||||||
if (fd < 0) {
|
fd_prepare_file(fdf)->private_data = no_free_ptr(token);
|
||||||
err = fd;
|
return fd_publish(fdf);
|
||||||
goto out_token;
|
|
||||||
}
|
|
||||||
|
|
||||||
file->private_data = token;
|
|
||||||
fd_install(fd, file);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
out_token:
|
|
||||||
bpf_token_free(token);
|
|
||||||
out_file:
|
|
||||||
fput(file);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_token_get_info_by_fd(struct bpf_token *token,
|
int bpf_token_get_info_by_fd(struct bpf_token *token,
|
||||||
|
|
|
||||||
29
mm/memfd.c
29
mm/memfd.c
|
|
@ -497,9 +497,9 @@ SYSCALL_DEFINE2(memfd_create,
|
||||||
const char __user *, uname,
|
const char __user *, uname,
|
||||||
unsigned int, flags)
|
unsigned int, flags)
|
||||||
{
|
{
|
||||||
struct file *file;
|
char *name __free(kfree) = NULL;
|
||||||
int fd, error;
|
unsigned int fd_flags;
|
||||||
char *name;
|
int error;
|
||||||
|
|
||||||
error = sanitize_flags(&flags);
|
error = sanitize_flags(&flags);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
|
|
@ -509,25 +509,6 @@ SYSCALL_DEFINE2(memfd_create,
|
||||||
if (IS_ERR(name))
|
if (IS_ERR(name))
|
||||||
return PTR_ERR(name);
|
return PTR_ERR(name);
|
||||||
|
|
||||||
fd = get_unused_fd_flags((flags & MFD_CLOEXEC) ? O_CLOEXEC : 0);
|
fd_flags = (flags & MFD_CLOEXEC) ? O_CLOEXEC : 0;
|
||||||
if (fd < 0) {
|
return FD_ADD(fd_flags, alloc_file(name, flags));
|
||||||
error = fd;
|
|
||||||
goto err_free_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
file = alloc_file(name, flags);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
error = PTR_ERR(file);
|
|
||||||
goto err_free_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, file);
|
|
||||||
kfree(name);
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
err_free_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
err_free_name:
|
|
||||||
kfree(name);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -224,9 +224,6 @@ static struct file *secretmem_file_create(unsigned long flags)
|
||||||
|
|
||||||
SYSCALL_DEFINE1(memfd_secret, unsigned int, flags)
|
SYSCALL_DEFINE1(memfd_secret, unsigned int, flags)
|
||||||
{
|
{
|
||||||
struct file *file;
|
|
||||||
int fd, err;
|
|
||||||
|
|
||||||
/* make sure local flags do not confict with global fcntl.h */
|
/* make sure local flags do not confict with global fcntl.h */
|
||||||
BUILD_BUG_ON(SECRETMEM_FLAGS_MASK & O_CLOEXEC);
|
BUILD_BUG_ON(SECRETMEM_FLAGS_MASK & O_CLOEXEC);
|
||||||
|
|
||||||
|
|
@ -238,22 +235,7 @@ SYSCALL_DEFINE1(memfd_secret, unsigned int, flags)
|
||||||
if (atomic_read(&secretmem_users) < 0)
|
if (atomic_read(&secretmem_users) < 0)
|
||||||
return -ENFILE;
|
return -ENFILE;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(flags & O_CLOEXEC);
|
return FD_ADD(flags & O_CLOEXEC, secretmem_file_create(flags));
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
file = secretmem_file_create(flags);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
err = PTR_ERR(file);
|
|
||||||
goto err_put_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, file);
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
err_put_fd:
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int secretmem_init_fs_context(struct fs_context *fc)
|
static int secretmem_init_fs_context(struct fs_context *fc)
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
struct handshake_net *hn = handshake_pernet(net);
|
struct handshake_net *hn = handshake_pernet(net);
|
||||||
struct handshake_req *req = NULL;
|
struct handshake_req *req = NULL;
|
||||||
struct socket *sock;
|
struct socket *sock;
|
||||||
int class, fd, err;
|
int class, err;
|
||||||
|
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
if (!hn)
|
if (!hn)
|
||||||
|
|
@ -106,27 +106,25 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
|
||||||
err = -EAGAIN;
|
err = -EAGAIN;
|
||||||
req = handshake_req_next(hn, class);
|
req = handshake_req_next(hn, class);
|
||||||
if (!req)
|
if (req) {
|
||||||
goto out_status;
|
sock = req->hr_sk->sk_socket;
|
||||||
|
|
||||||
sock = req->hr_sk->sk_socket;
|
FD_PREPARE(fdf, O_CLOEXEC, sock->file);
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
if (fdf.err) {
|
||||||
if (fd < 0) {
|
err = fdf.err;
|
||||||
err = fd;
|
goto out_complete;
|
||||||
goto out_complete;
|
}
|
||||||
|
|
||||||
|
get_file(sock->file); /* FD_PREPARE() consumes a reference. */
|
||||||
|
err = req->hr_proto->hp_accept(req, info, fd_prepare_fd(fdf));
|
||||||
|
if (err)
|
||||||
|
goto out_complete; /* Automatic cleanup handles fput */
|
||||||
|
|
||||||
|
trace_handshake_cmd_accept(net, req, req->hr_sk, fd_prepare_fd(fdf));
|
||||||
|
fd_publish(fdf);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = req->hr_proto->hp_accept(req, info, fd);
|
|
||||||
if (err) {
|
|
||||||
put_unused_fd(fd);
|
|
||||||
goto out_complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, get_file(sock->file));
|
|
||||||
|
|
||||||
trace_handshake_cmd_accept(net, req, req->hr_sk, fd);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_complete:
|
out_complete:
|
||||||
handshake_complete(req, -EIO, NULL);
|
handshake_complete(req, -EIO, NULL);
|
||||||
out_status:
|
out_status:
|
||||||
|
|
|
||||||
|
|
@ -1560,24 +1560,16 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||||
}
|
}
|
||||||
case SIOCKCMCLONE: {
|
case SIOCKCMCLONE: {
|
||||||
struct kcm_clone info;
|
struct kcm_clone info;
|
||||||
struct file *file;
|
|
||||||
|
|
||||||
info.fd = get_unused_fd_flags(0);
|
FD_PREPARE(fdf, 0, kcm_clone(sock));
|
||||||
if (unlikely(info.fd < 0))
|
if (fdf.err)
|
||||||
return info.fd;
|
return fdf.err;
|
||||||
|
|
||||||
file = kcm_clone(sock);
|
info.fd = fd_prepare_fd(fdf);
|
||||||
if (IS_ERR(file)) {
|
if (copy_to_user((void __user *)arg, &info, sizeof(info)))
|
||||||
put_unused_fd(info.fd);
|
|
||||||
return PTR_ERR(file);
|
|
||||||
}
|
|
||||||
if (copy_to_user((void __user *)arg, &info,
|
|
||||||
sizeof(info))) {
|
|
||||||
put_unused_fd(info.fd);
|
|
||||||
fput(file);
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
|
||||||
fd_install(info.fd, file);
|
fd_publish(fdf);
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
net/socket.c
34
net/socket.c
|
|
@ -503,21 +503,12 @@ EXPORT_SYMBOL(sock_alloc_file);
|
||||||
|
|
||||||
static int sock_map_fd(struct socket *sock, int flags)
|
static int sock_map_fd(struct socket *sock, int flags)
|
||||||
{
|
{
|
||||||
struct file *newfile;
|
int fd;
|
||||||
int fd = get_unused_fd_flags(flags);
|
|
||||||
if (unlikely(fd < 0)) {
|
fd = FD_ADD(flags, sock_alloc_file(sock, flags, NULL));
|
||||||
|
if (fd < 0)
|
||||||
sock_release(sock);
|
sock_release(sock);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
|
||||||
|
|
||||||
newfile = sock_alloc_file(sock, flags, NULL);
|
|
||||||
if (!IS_ERR(newfile)) {
|
|
||||||
fd_install(fd, newfile);
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return PTR_ERR(newfile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2012,8 +2003,6 @@ static int __sys_accept4_file(struct file *file, struct sockaddr __user *upeer_s
|
||||||
int __user *upeer_addrlen, int flags)
|
int __user *upeer_addrlen, int flags)
|
||||||
{
|
{
|
||||||
struct proto_accept_arg arg = { };
|
struct proto_accept_arg arg = { };
|
||||||
struct file *newfile;
|
|
||||||
int newfd;
|
|
||||||
|
|
||||||
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
|
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -2021,18 +2010,7 @@ static int __sys_accept4_file(struct file *file, struct sockaddr __user *upeer_s
|
||||||
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
|
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
|
||||||
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
|
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
|
||||||
|
|
||||||
newfd = get_unused_fd_flags(flags);
|
return FD_ADD(flags, do_accept(file, &arg, upeer_sockaddr, upeer_addrlen, flags));
|
||||||
if (unlikely(newfd < 0))
|
|
||||||
return newfd;
|
|
||||||
|
|
||||||
newfile = do_accept(file, &arg, upeer_sockaddr, upeer_addrlen,
|
|
||||||
flags);
|
|
||||||
if (IS_ERR(newfile)) {
|
|
||||||
put_unused_fd(newfd);
|
|
||||||
return PTR_ERR(newfile);
|
|
||||||
}
|
|
||||||
fd_install(newfd, newfile);
|
|
||||||
return newfd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -3276,9 +3276,6 @@ EXPORT_SYMBOL_GPL(unix_outq_len);
|
||||||
|
|
||||||
static int unix_open_file(struct sock *sk)
|
static int unix_open_file(struct sock *sk)
|
||||||
{
|
{
|
||||||
struct file *f;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
|
@ -3288,18 +3285,7 @@ static int unix_open_file(struct sock *sk)
|
||||||
if (!unix_sk(sk)->path.dentry)
|
if (!unix_sk(sk)->path.dentry)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
return FD_ADD(O_CLOEXEC, dentry_open(&unix_sk(sk)->path, O_PATH, current_cred()));
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
f = dentry_open(&unix_sk(sk)->path, O_PATH, current_cred());
|
|
||||||
if (IS_ERR(f)) {
|
|
||||||
put_unused_fd(fd);
|
|
||||||
return PTR_ERR(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_install(fd, f);
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue