summaryrefslogtreecommitdiff
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/ipc_sysctl.c46
-rw-r--r--ipc/mqueue.c120
-rw-r--r--ipc/sem.c3
-rw-r--r--ipc/shm.c28
-rw-r--r--ipc/util.c36
5 files changed, 115 insertions, 118 deletions
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index 0dfebc50942..4a7a12c95ab 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -26,29 +26,6 @@ static void *get_ipc(ctl_table *table)
return which;
}
-/*
- * Routine that is called when the file "auto_msgmni" has successfully been
- * written.
- * Two values are allowed:
- * 0: unregister msgmni's callback routine from the ipc namespace notifier
- * chain. This means that msgmni won't be recomputed anymore upon memory
- * add/remove or ipc namespace creation/removal.
- * 1: register back the callback routine.
- */
-static void ipc_auto_callback(int val)
-{
- if (!val)
- unregister_ipcns_notifier(current->nsproxy->ipc_ns);
- else {
- /*
- * Re-enable automatic recomputing only if not already
- * enabled.
- */
- recompute_msgmni(current->nsproxy->ipc_ns);
- cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
- }
-}
-
#ifdef CONFIG_PROC_FS
static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
@@ -94,6 +71,29 @@ static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
lenp, ppos);
}
+/*
+ * Routine that is called when the file "auto_msgmni" has successfully been
+ * written.
+ * Two values are allowed:
+ * 0: unregister msgmni's callback routine from the ipc namespace notifier
+ * chain. This means that msgmni won't be recomputed anymore upon memory
+ * add/remove or ipc namespace creation/removal.
+ * 1: register back the callback routine.
+ */
+static void ipc_auto_callback(int val)
+{
+ if (!val)
+ unregister_ipcns_notifier(current->nsproxy->ipc_ns);
+ else {
+ /*
+ * Re-enable automatic recomputing only if not already
+ * enabled.
+ */
+ recompute_msgmni(current->nsproxy->ipc_ns);
+ cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
+ }
+}
+
static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
{
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 68eb857cfde..23fdb8492b8 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -112,21 +112,20 @@ static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode)
static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
struct mq_attr *attr)
{
+ struct user_struct *u = current_user();
struct inode *inode;
inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
- inode->i_blocks = 0;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_mtime = inode->i_ctime = inode->i_atime =
CURRENT_TIME;
if (S_ISREG(mode)) {
struct mqueue_inode_info *info;
struct task_struct *p = current;
- struct user_struct *u = p->user;
unsigned long mq_bytes, mq_msg_tblsz;
inode->i_fop = &mqueue_file_operations;
@@ -506,8 +505,9 @@ static void __do_notify(struct mqueue_inode_info *info)
sig_i.si_errno = 0;
sig_i.si_code = SI_MESGQ;
sig_i.si_value = info->notify.sigev_value;
- sig_i.si_pid = task_tgid_vnr(current);
- sig_i.si_uid = current->uid;
+ sig_i.si_pid = task_tgid_nr_ns(current,
+ ns_of_pid(info->notify_owner));
+ sig_i.si_uid = current_uid();
kill_pid_info(info->notify.sigev_signo,
&sig_i, info->notify_owner);
@@ -524,31 +524,27 @@ static void __do_notify(struct mqueue_inode_info *info)
wake_up(&info->wait_q);
}
-static long prepare_timeout(const struct timespec __user *u_arg)
+static long prepare_timeout(struct timespec *p)
{
- struct timespec ts, nowts;
+ struct timespec nowts;
long timeout;
- if (u_arg) {
- if (unlikely(copy_from_user(&ts, u_arg,
- sizeof(struct timespec))))
- return -EFAULT;
-
- if (unlikely(ts.tv_nsec < 0 || ts.tv_sec < 0
- || ts.tv_nsec >= NSEC_PER_SEC))
+ if (p) {
+ if (unlikely(p->tv_nsec < 0 || p->tv_sec < 0
+ || p->tv_nsec >= NSEC_PER_SEC))
return -EINVAL;
nowts = CURRENT_TIME;
/* first subtract as jiffies can't be too big */
- ts.tv_sec -= nowts.tv_sec;
- if (ts.tv_nsec < nowts.tv_nsec) {
- ts.tv_nsec += NSEC_PER_SEC;
- ts.tv_sec--;
+ p->tv_sec -= nowts.tv_sec;
+ if (p->tv_nsec < nowts.tv_nsec) {
+ p->tv_nsec += NSEC_PER_SEC;
+ p->tv_sec--;
}
- ts.tv_nsec -= nowts.tv_nsec;
- if (ts.tv_sec < 0)
+ p->tv_nsec -= nowts.tv_nsec;
+ if (p->tv_sec < 0)
return 0;
- timeout = timespec_to_jiffies(&ts) + 1;
+ timeout = timespec_to_jiffies(p) + 1;
} else
return MAX_SCHEDULE_TIMEOUT;
@@ -592,21 +588,18 @@ static int mq_attr_ok(struct mq_attr *attr)
* Invoked when creating a new queue via sys_mq_open
*/
static struct file *do_create(struct dentry *dir, struct dentry *dentry,
- int oflag, mode_t mode, struct mq_attr __user *u_attr)
+ int oflag, mode_t mode, struct mq_attr *attr)
{
- struct mq_attr attr;
+ const struct cred *cred = current_cred();
struct file *result;
int ret;
- if (u_attr) {
- ret = -EFAULT;
- if (copy_from_user(&attr, u_attr, sizeof(attr)))
- goto out;
+ if (attr) {
ret = -EINVAL;
- if (!mq_attr_ok(&attr))
+ if (!mq_attr_ok(attr))
goto out;
/* store for use during create */
- dentry->d_fsdata = &attr;
+ dentry->d_fsdata = attr;
}
mode &= ~current->fs->umask;
@@ -618,7 +611,7 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry,
if (ret)
goto out_drop_write;
- result = dentry_open(dentry, mqueue_mnt, oflag);
+ result = dentry_open(dentry, mqueue_mnt, oflag, cred);
/*
* dentry_open() took a persistent mnt_want_write(),
* so we can now drop this one.
@@ -637,8 +630,10 @@ out:
/* Opens existing queue */
static struct file *do_open(struct dentry *dentry, int oflag)
{
-static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
- MAY_READ | MAY_WRITE };
+ const struct cred *cred = current_cred();
+
+ static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
+ MAY_READ | MAY_WRITE };
if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
dput(dentry);
@@ -652,7 +647,7 @@ static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
return ERR_PTR(-EACCES);
}
- return dentry_open(dentry, mqueue_mnt, oflag);
+ return dentry_open(dentry, mqueue_mnt, oflag, cred);
}
asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
@@ -661,11 +656,13 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
struct dentry *dentry;
struct file *filp;
char *name;
+ struct mq_attr attr;
int fd, error;
- error = audit_mq_open(oflag, mode, u_attr);
- if (error != 0)
- return error;
+ if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
+ return -EFAULT;
+
+ audit_mq_open(oflag, mode, u_attr ? &attr : NULL);
if (IS_ERR(name = getname(u_name)))
return PTR_ERR(name);
@@ -691,7 +688,8 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
filp = do_open(dentry, oflag);
} else {
filp = do_create(mqueue_mnt->mnt_root, dentry,
- oflag, mode, u_attr);
+ oflag, mode,
+ u_attr ? &attr : NULL);
}
} else {
error = -ENOENT;
@@ -826,17 +824,22 @@ asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
struct ext_wait_queue *receiver;
struct msg_msg *msg_ptr;
struct mqueue_inode_info *info;
+ struct timespec ts, *p = NULL;
long timeout;
int ret;
- ret = audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout);
- if (ret != 0)
- return ret;
+ if (u_abs_timeout) {
+ if (copy_from_user(&ts, u_abs_timeout,
+ sizeof(struct timespec)))
+ return -EFAULT;
+ p = &ts;
+ }
if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
return -EINVAL;
- timeout = prepare_timeout(u_abs_timeout);
+ audit_mq_sendrecv(mqdes, msg_len, msg_prio, p);
+ timeout = prepare_timeout(p);
ret = -EBADF;
filp = fget(mqdes);
@@ -915,12 +918,17 @@ asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
struct inode *inode;
struct mqueue_inode_info *info;
struct ext_wait_queue wait;
+ struct timespec ts, *p = NULL;
- ret = audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout);
- if (ret != 0)
- return ret;
+ if (u_abs_timeout) {
+ if (copy_from_user(&ts, u_abs_timeout,
+ sizeof(struct timespec)))
+ return -EFAULT;
+ p = &ts;
+ }
- timeout = prepare_timeout(u_abs_timeout);
+ audit_mq_sendrecv(mqdes, msg_len, 0, p);
+ timeout = prepare_timeout(p);
ret = -EBADF;
filp = fget(mqdes);
@@ -1000,17 +1008,17 @@ asmlinkage long sys_mq_notify(mqd_t mqdes,
struct mqueue_inode_info *info;
struct sk_buff *nc;
- ret = audit_mq_notify(mqdes, u_notification);
- if (ret != 0)
- return ret;
-
- nc = NULL;
- sock = NULL;
- if (u_notification != NULL) {
+ if (u_notification) {
if (copy_from_user(&notification, u_notification,
sizeof(struct sigevent)))
return -EFAULT;
+ }
+ audit_mq_notify(mqdes, u_notification ? &notification : NULL);
+
+ nc = NULL;
+ sock = NULL;
+ if (u_notification != NULL) {
if (unlikely(notification.sigev_notify != SIGEV_NONE &&
notification.sigev_notify != SIGEV_SIGNAL &&
notification.sigev_notify != SIGEV_THREAD))
@@ -1147,11 +1155,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t mqdes,
omqstat = info->attr;
omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
if (u_mqstat) {
- ret = audit_mq_getsetattr(mqdes, &mqstat);
- if (ret != 0) {
- spin_unlock(&info->lock);
- goto out_fput;
- }
+ audit_mq_getsetattr(mqdes, &mqstat);
if (mqstat.mq_flags & O_NONBLOCK)
filp->f_flags |= O_NONBLOCK;
else
diff --git a/ipc/sem.c b/ipc/sem.c
index 082122469b1..c68cd3f8f0c 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -58,7 +58,7 @@
* SMP-threaded, sysctl's added
* (c) 1999 Manfred Spraul <manfred@colorfullife.com>
* Enforced range limit on SEM_UNDO
- * (c) 2001 Red Hat Inc <alan@redhat.com>
+ * (c) 2001 Red Hat Inc
* Lockless wakeup
* (c) 2003 Manfred Spraul <manfred@colorfullife.com>
*
@@ -1216,7 +1216,6 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
if (timeout && jiffies_left == 0)
error = -EAGAIN;
list_del(&queue.list);
- goto out_unlock_free;
out_unlock_free:
sem_unlock(sma);
diff --git a/ipc/shm.c b/ipc/shm.c
index 867e5d6a55c..b125b560240 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -75,7 +75,7 @@ void shm_init_ns(struct ipc_namespace *ns)
ns->shm_ctlall = SHMALL;
ns->shm_ctlmni = SHMMNI;
ns->shm_tot = 0;
- ipc_init_ids(&ns->ids[IPC_SHM_IDS]);
+ ipc_init_ids(&shm_ids(ns));
}
/*
@@ -366,7 +366,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
if (shmflg & SHM_HUGETLB) {
/* hugetlb_file_setup takes care of mlock user accounting */
file = hugetlb_file_setup(name, size);
- shp->mlock_user = current->user;
+ shp->mlock_user = current_user();
} else {
int acctflag = VM_ACCOUNT;
/*
@@ -644,7 +644,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
if (err)
return err;
- memset(&shminfo,0,sizeof(shminfo));
+ memset(&shminfo, 0, sizeof(shminfo));
shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
shminfo.shmmax = ns->shm_ctlmax;
shminfo.shmall = ns->shm_ctlall;
@@ -669,7 +669,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
if (err)
return err;
- memset(&shm_info,0,sizeof(shm_info));
+ memset(&shm_info, 0, sizeof(shm_info));
down_read(&shm_ids(ns).rw_mutex);
shm_info.used_ids = shm_ids(ns).in_use;
shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
@@ -678,7 +678,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
shm_info.swap_successes = 0;
err = ipc_get_maxid(&shm_ids(ns));
up_read(&shm_ids(ns).rw_mutex);
- if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
+ if (copy_to_user(buf, &shm_info, sizeof(shm_info))) {
err = -EFAULT;
goto out;
}
@@ -692,11 +692,6 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
struct shmid64_ds tbuf;
int result;
- if (!buf) {
- err = -EFAULT;
- goto out;
- }
-
if (cmd == SHM_STAT) {
shp = shm_lock(ns, shmid);
if (IS_ERR(shp)) {
@@ -712,7 +707,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
}
result = 0;
}
- err=-EACCES;
+ err = -EACCES;
if (ipcperms (&shp->shm_perm, S_IRUGO))
goto out_unlock;
err = security_shm_shmctl(shp, cmd);
@@ -747,14 +742,13 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
goto out;
}
- err = audit_ipc_obj(&(shp->shm_perm));
- if (err)
- goto out_unlock;
+ audit_ipc_obj(&(shp->shm_perm));
if (!capable(CAP_IPC_LOCK)) {
+ uid_t euid = current_euid();
err = -EPERM;
- if (current->euid != shp->shm_perm.uid &&
- current->euid != shp->shm_perm.cuid)
+ if (euid != shp->shm_perm.uid &&
+ euid != shp->shm_perm.cuid)
goto out_unlock;
if (cmd == SHM_LOCK &&
!current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
@@ -766,7 +760,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
goto out_unlock;
if(cmd==SHM_LOCK) {
- struct user_struct * user = current->user;
+ struct user_struct *user = current_user();
if (!is_file_hugepages(shp->shm_file)) {
err = shmem_lock(shp->shm_file, 1, user);
if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
diff --git a/ipc/util.c b/ipc/util.c
index 361fd1c96fc..7585a72e259 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -258,6 +258,8 @@ int ipc_get_maxid(struct ipc_ids *ids)
int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
{
+ uid_t euid;
+ gid_t egid;
int id, err;
if (size > IPCMNI)
@@ -280,8 +282,9 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
ids->in_use++;
- new->cuid = new->uid = current->euid;
- new->gid = new->cgid = current->egid;
+ current_euid_egid(&euid, &egid);
+ new->cuid = new->uid = euid;
+ new->gid = new->cgid = egid;
new->seq = ids->seq++;
if(ids->seq > ids->seq_max)
@@ -620,13 +623,14 @@ void ipc_rcu_putref(void *ptr)
int ipcperms (struct kern_ipc_perm *ipcp, short flag)
{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
- int requested_mode, granted_mode, err;
+ uid_t euid = current_euid();
+ int requested_mode, granted_mode;
- if (unlikely((err = audit_ipc_obj(ipcp))))
- return err;
+ audit_ipc_obj(ipcp);
requested_mode = (flag >> 6) | (flag >> 3) | flag;
granted_mode = ipcp->mode;
- if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
+ if (euid == ipcp->cuid ||
+ euid == ipcp->uid)
granted_mode >>= 6;
else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
granted_mode >>= 3;
@@ -788,6 +792,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
struct ipc64_perm *perm, int extra_perm)
{
struct kern_ipc_perm *ipcp;
+ uid_t euid;
int err;
down_write(&ids->rw_mutex);
@@ -797,22 +802,17 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
goto out_up;
}
- err = audit_ipc_obj(ipcp);
- if (err)
- goto out_unlock;
-
- if (cmd == IPC_SET) {
- err = audit_ipc_set_perm(extra_perm, perm->uid,
+ audit_ipc_obj(ipcp);
+ if (cmd == IPC_SET)
+ audit_ipc_set_perm(extra_perm, perm->uid,
perm->gid, perm->mode);
- if (err)
- goto out_unlock;
- }
- if (current->euid == ipcp->cuid ||
- current->euid == ipcp->uid || capable(CAP_SYS_ADMIN))
+
+ euid = current_euid();
+ if (euid == ipcp->cuid ||
+ euid == ipcp->uid || capable(CAP_SYS_ADMIN))
return ipcp;
err = -EPERM;
-out_unlock:
ipc_unlock(ipcp);
out_up:
up_write(&ids->rw_mutex);