Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs: Fix the race condition in file_dup #2643

Merged
merged 2 commits into from Jan 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 22 additions & 24 deletions fs/inode/fs_files.c
Expand Up @@ -137,6 +137,7 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2)
{
FAR struct filelist *list;
FAR struct inode *inode;
struct file temp;
int ret;

if (filep1 == NULL || filep1->f_inode == NULL || filep2 == NULL)
Expand Down Expand Up @@ -169,18 +170,6 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2)
}
}

/* If there is already an inode contained in the new file structure,
* close the file and release the inode.
*/

ret = file_close(filep2);
if (ret < 0)
{
/* An error occurred while closing the driver */

goto errout_with_sem;
}

/* Increment the reference count on the contained inode */

inode = filep1->f_inode;
Expand All @@ -192,9 +181,10 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2)

/* Then clone the file structure */

filep2->f_oflags = filep1->f_oflags;
filep2->f_pos = filep1->f_pos;
filep2->f_inode = inode;
temp.f_oflags = filep1->f_oflags;
temp.f_pos = filep1->f_pos;
temp.f_inode = inode;
temp.f_priv = filep1->f_priv;

/* Call the open method on the file, driver, mountpoint so that it
* can maintain the correct open counts.
Expand All @@ -207,14 +197,14 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2)
{
/* Dup the open file on the in the new file structure */

ret = inode->u.i_mops->dup(filep1, filep2);
ret = inode->u.i_mops->dup(filep1, &temp);
}
else
#endif
{
/* (Re-)open the pseudo file or device driver */

ret = inode->u.i_ops->open(filep2);
ret = inode->u.i_ops->open(&temp);
}

/* Handle open failures */
Expand All @@ -225,6 +215,17 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2)
}
}

/* If there is already an inode contained in the new file structure,
* close the file and release the inode.
*/

ret = file_close(filep2);
DEBUGASSERT(ret == 0);

/* Return the file structure */

memcpy(filep2, &temp, sizeof(temp));

if (list != NULL)
{
_files_semgive(list);
Expand All @@ -235,11 +236,7 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2)
/* Handle various error conditions */

errout_with_inode:

inode_release(filep2->f_inode);
filep2->f_oflags = 0;
filep2->f_pos = 0;
filep2->f_inode = NULL;
inode_release(inode);

errout_with_sem:
if (list != NULL)
Expand All @@ -259,7 +256,8 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2)
*
****************************************************************************/

int files_allocate(FAR struct inode *inode, int oflags, off_t pos, int minfd)
int files_allocate(FAR struct inode *inode, int oflags, off_t pos,
FAR void *priv, int minfd)
{
FAR struct filelist *list;
int ret;
Expand All @@ -285,7 +283,7 @@ int files_allocate(FAR struct inode *inode, int oflags, off_t pos, int minfd)
list->fl_files[i].f_oflags = oflags;
list->fl_files[i].f_pos = pos;
list->fl_files[i].f_inode = inode;
list->fl_files[i].f_priv = NULL;
list->fl_files[i].f_priv = priv;
_files_semgive(list);
return i;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/inode/inode.h
Expand Up @@ -387,7 +387,7 @@ void weak_function files_initialize(void);
****************************************************************************/

int files_allocate(FAR struct inode *inode, int oflags, off_t pos,
int minfd);
FAR void *priv, int minfd);

/****************************************************************************
* Name: files_close
Expand Down
2 changes: 1 addition & 1 deletion fs/mqueue/mq_open.c
Expand Up @@ -269,7 +269,7 @@ static mqd_t nxmq_vopen(FAR const char *mq_name, int oflags, va_list ap)
return ret;
}

ret = files_allocate(mq.f_inode, mq.f_oflags, mq.f_pos, 0);
ret = files_allocate(mq.f_inode, mq.f_oflags, mq.f_pos, mq.f_priv, 0);
if (ret < 0)
{
file_mq_close(&mq);
Expand Down
25 changes: 11 additions & 14 deletions fs/vfs/fs_dupfd.c
Expand Up @@ -51,30 +51,27 @@

int file_dup(FAR struct file *filep, int minfd)
{
FAR struct file *filep2;
struct file filep2;
int fd2;
int ret;

/* Allocate a new file descriptor for the inode */
/* Let file_dup2() do the real work */

fd2 = files_allocate(NULL, 0, 0, minfd);
if (fd2 < 0)
{
return fd2;
}

ret = fs_getfilep(fd2, &filep2);
memset(&filep2, 0, sizeof(filep2));
ret = file_dup2(filep, &filep2);
if (ret < 0)
{
files_release(fd2);
return ret;
}

ret = file_dup2(filep, filep2);
if (ret < 0)
/* Then allocate a new file descriptor for the inode */

fd2 = files_allocate(filep2.f_inode, filep2.f_oflags,
filep2.f_pos, filep2.f_priv, minfd);
if (fd2 < 0)
{
files_release(fd2);
return ret;
file_close(&filep2);
return fd2;
}

return fd2;
Expand Down
2 changes: 1 addition & 1 deletion fs/vfs/fs_open.c
Expand Up @@ -204,7 +204,7 @@ int nx_vopen(FAR const char *path, int oflags, va_list ap)

/* Associate the inode with a file structure */

fd = files_allocate(inode, oflags, 0, 0);
fd = files_allocate(inode, oflags, 0, NULL, 0);
if (fd < 0)
{
ret = fd;
Expand Down
2 changes: 1 addition & 1 deletion include/nuttx/fs/fs.h
Expand Up @@ -401,7 +401,7 @@ struct file
int f_oflags; /* Open mode flags */
off_t f_pos; /* File position */
FAR struct inode *f_inode; /* Driver or file system interface */
void *f_priv; /* Per file driver private data */
FAR void *f_priv; /* Per file driver private data */
};

/* This defines a list of files indexed by the file descriptor */
Expand Down