#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/file.h>
+#include <linux/capability.h>
#include <linux/dnotify.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/security.h>
#include <linux/ptrace.h>
#include <linux/signal.h>
+#include <linux/rcupdate.h>
#include <asm/poll.h>
#include <asm/siginfo.h>
spin_unlock(&files->file_lock);
}
-static inline int get_close_on_exec(unsigned int fd)
+static int get_close_on_exec(unsigned int fd)
{
struct files_struct *files = current->files;
struct fdtable *fdt;
int res;
- spin_lock(&files->file_lock);
+ rcu_read_lock();
fdt = files_fdtable(files);
res = FD_ISSET(fd, fdt->close_on_exec);
- spin_unlock(&files->file_lock);
+ rcu_read_unlock();
return res;
}
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
goto out;
- fdt = files_fdtable(files);
repeat:
+ fdt = files_fdtable(files);
/*
* Someone might have closed fd's in the range
* orig_start..fdt->next_fd
*/
start = orig_start;
- if (start < fdt->next_fd)
- start = fdt->next_fd;
+ if (start < files->next_fd)
+ start = files->next_fd;
newfd = start;
if (start < fdt->max_fdset) {
if (error)
goto repeat;
- if (start <= fdt->next_fd)
- fdt->next_fd = newfd + 1;
-
+ /*
+ * We reacquired files_lock, so we are safe as long as
+ * we reacquire the fdtable pointer and use it while holding
+ * the lock, no one can free it during that time.
+ */
+ if (start <= files->next_fd)
+ files->next_fd = newfd + 1;
+
error = newfd;
out:
if (!tofree && FD_ISSET(newfd, fdt->open_fds))
goto out_fput;
- fdt->fd[newfd] = file;
+ rcu_assign_pointer(fdt->fd[newfd], file);
FD_SET(newfd, fdt->open_fds);
FD_CLR(newfd, fdt->close_on_exec);
spin_unlock(&files->file_lock);
struct inode * inode = filp->f_dentry->d_inode;
int error = 0;
- /* O_APPEND cannot be cleared if the file is marked as append-only */
- if (!(arg & O_APPEND) && IS_APPEND(inode))
+ /*
+ * O_APPEND cannot be cleared if the file is marked as append-only
+ * and the file is open for write.
+ */
+ if (((arg ^ filp->f_flags) & O_APPEND) && IS_APPEND(inode))
return -EPERM;
/* O_NOATIME can only be set by the owner or superuser */
/* Table to convert sigio signal codes into poll band bitmaps */
-static long band_table[NSIGPOLL] = {
+static const long band_table[NSIGPOLL] = {
POLLIN | POLLRDNORM, /* POLL_IN */
POLLOUT | POLLWRNORM | POLLWRBAND, /* POLL_OUT */
POLLIN | POLLRDNORM | POLLMSG, /* POLL_MSG */
/* Make sure we are called with one of the POLL_*
reasons, otherwise we could leak kernel stack into
userspace. */
- if ((reason & __SI_MASK) != __SI_POLL)
- BUG();
+ BUG_ON((reason & __SI_MASK) != __SI_POLL);
if (reason - POLL_IN >= NSIGPOLL)
si.si_band = ~0L;
else
si.si_band = band_table[reason - POLL_IN];
si.si_fd = fd;
- if (!send_group_sig_info(fown->signum, &si, p))
+ if (!group_send_sig_info(fown->signum, &si, p))
break;
/* fall-through: fall back on the old plain SIGIO signal */
case 0:
- send_group_sig_info(SIGIO, SEND_SIG_PRIV, p);
+ group_send_sig_info(SIGIO, SEND_SIG_PRIV, p);
}
}
struct fown_struct *fown)
{
if (sigio_perm(p, fown, SIGURG))
- send_group_sig_info(SIGURG, SEND_SIG_PRIV, p);
+ group_send_sig_info(SIGURG, SEND_SIG_PRIV, p);
}
int send_sigurg(struct fown_struct *fown)
}
static DEFINE_RWLOCK(fasync_lock);
-static kmem_cache_t *fasync_cache;
+static kmem_cache_t *fasync_cache __read_mostly;
/*
* fasync_helper() is used by some character device drivers (mainly mice)