summaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/mqueue.c94
-rw-r--r--ipc/msg.c14
-rw-r--r--ipc/sem.c13
-rw-r--r--ipc/shm.c19
-rw-r--r--ipc/util.c35
-rw-r--r--ipc/util.h2
6 files changed, 96 insertions, 81 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 9a08acc..71a3ca1 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -142,7 +142,6 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
leaf = kmalloc(sizeof(*leaf), GFP_ATOMIC);
if (!leaf)
return -ENOMEM;
- rb_init_node(&leaf->rb_node);
INIT_LIST_HEAD(&leaf->msg_list);
info->qsize += sizeof(*leaf);
}
@@ -773,7 +772,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
{
struct path path;
struct file *filp;
- char *name;
+ struct filename *name;
struct mq_attr attr;
int fd, error;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
@@ -796,7 +795,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
ro = mnt_want_write(mnt); /* we'll drop it in any case */
error = 0;
mutex_lock(&root->d_inode->i_mutex);
- path.dentry = lookup_one_len(name, root, strlen(name));
+ path.dentry = lookup_one_len(name->name, root, strlen(name->name));
if (IS_ERR(path.dentry)) {
error = PTR_ERR(path.dentry);
goto out_putfd;
@@ -805,7 +804,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
if (oflag & O_CREAT) {
if (path.dentry->d_inode) { /* entry already exists */
- audit_inode(name, path.dentry);
+ audit_inode(name, path.dentry, 0);
if (oflag & O_EXCL) {
error = -EEXIST;
goto out;
@@ -825,7 +824,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
error = -ENOENT;
goto out;
}
- audit_inode(name, path.dentry);
+ audit_inode(name, path.dentry, 0);
filp = do_open(&path, oflag);
}
@@ -850,7 +849,7 @@ out_putname:
SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
{
int err;
- char *name;
+ struct filename *name;
struct dentry *dentry;
struct inode *inode = NULL;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
@@ -864,7 +863,8 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
if (err)
goto out_name;
mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT);
- dentry = lookup_one_len(name, mnt->mnt_root, strlen(name));
+ dentry = lookup_one_len(name->name, mnt->mnt_root,
+ strlen(name->name));
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
goto out_unlock;
@@ -944,7 +944,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
size_t, msg_len, unsigned int, msg_prio,
const struct timespec __user *, u_abs_timeout)
{
- struct file *filp;
+ struct fd f;
struct inode *inode;
struct ext_wait_queue wait;
struct ext_wait_queue *receiver;
@@ -967,21 +967,21 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
audit_mq_sendrecv(mqdes, msg_len, msg_prio, timeout ? &ts : NULL);
- filp = fget(mqdes);
- if (unlikely(!filp)) {
+ f = fdget(mqdes);
+ if (unlikely(!f.file)) {
ret = -EBADF;
goto out;
}
- inode = filp->f_path.dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations)) {
+ inode = f.file->f_path.dentry->d_inode;
+ if (unlikely(f.file->f_op != &mqueue_file_operations)) {
ret = -EBADF;
goto out_fput;
}
info = MQUEUE_I(inode);
- audit_inode(NULL, filp->f_path.dentry);
+ audit_inode(NULL, f.file->f_path.dentry, 0);
- if (unlikely(!(filp->f_mode & FMODE_WRITE))) {
+ if (unlikely(!(f.file->f_mode & FMODE_WRITE))) {
ret = -EBADF;
goto out_fput;
}
@@ -1013,7 +1013,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
if (!info->node_cache && new_leaf) {
/* Save our speculative allocation into the cache */
- rb_init_node(&new_leaf->rb_node);
INIT_LIST_HEAD(&new_leaf->msg_list);
info->node_cache = new_leaf;
info->qsize += sizeof(*new_leaf);
@@ -1023,7 +1022,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
}
if (info->attr.mq_curmsgs == info->attr.mq_maxmsg) {
- if (filp->f_flags & O_NONBLOCK) {
+ if (f.file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
} else {
wait.task = current;
@@ -1056,7 +1055,7 @@ out_free:
if (ret)
free_msg(msg_ptr);
out_fput:
- fput(filp);
+ fdput(f);
out:
return ret;
}
@@ -1067,7 +1066,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
{
ssize_t ret;
struct msg_msg *msg_ptr;
- struct file *filp;
+ struct fd f;
struct inode *inode;
struct mqueue_inode_info *info;
struct ext_wait_queue wait;
@@ -1084,21 +1083,21 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL);
- filp = fget(mqdes);
- if (unlikely(!filp)) {
+ f = fdget(mqdes);
+ if (unlikely(!f.file)) {
ret = -EBADF;
goto out;
}
- inode = filp->f_path.dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations)) {
+ inode = f.file->f_path.dentry->d_inode;
+ if (unlikely(f.file->f_op != &mqueue_file_operations)) {
ret = -EBADF;
goto out_fput;
}
info = MQUEUE_I(inode);
- audit_inode(NULL, filp->f_path.dentry);
+ audit_inode(NULL, f.file->f_path.dentry, 0);
- if (unlikely(!(filp->f_mode & FMODE_READ))) {
+ if (unlikely(!(f.file->f_mode & FMODE_READ))) {
ret = -EBADF;
goto out_fput;
}
@@ -1121,7 +1120,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
if (!info->node_cache && new_leaf) {
/* Save our speculative allocation into the cache */
- rb_init_node(&new_leaf->rb_node);
INIT_LIST_HEAD(&new_leaf->msg_list);
info->node_cache = new_leaf;
info->qsize += sizeof(*new_leaf);
@@ -1130,7 +1128,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
}
if (info->attr.mq_curmsgs == 0) {
- if (filp->f_flags & O_NONBLOCK) {
+ if (f.file->f_flags & O_NONBLOCK) {
spin_unlock(&info->lock);
ret = -EAGAIN;
} else {
@@ -1160,7 +1158,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
free_msg(msg_ptr);
}
out_fput:
- fput(filp);
+ fdput(f);
out:
return ret;
}
@@ -1174,7 +1172,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
const struct sigevent __user *, u_notification)
{
int ret;
- struct file *filp;
+ struct fd f;
struct sock *sock;
struct inode *inode;
struct sigevent notification;
@@ -1220,13 +1218,13 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
skb_put(nc, NOTIFY_COOKIE_LEN);
/* and attach it to the socket */
retry:
- filp = fget(notification.sigev_signo);
- if (!filp) {
+ f = fdget(notification.sigev_signo);
+ if (!f.file) {
ret = -EBADF;
goto out;
}
- sock = netlink_getsockbyfilp(filp);
- fput(filp);
+ sock = netlink_getsockbyfilp(f.file);
+ fdput(f);
if (IS_ERR(sock)) {
ret = PTR_ERR(sock);
sock = NULL;
@@ -1245,14 +1243,14 @@ retry:
}
}
- filp = fget(mqdes);
- if (!filp) {
+ f = fdget(mqdes);
+ if (!f.file) {
ret = -EBADF;
goto out;
}
- inode = filp->f_path.dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations)) {
+ inode = f.file->f_path.dentry->d_inode;
+ if (unlikely(f.file->f_op != &mqueue_file_operations)) {
ret = -EBADF;
goto out_fput;
}
@@ -1292,7 +1290,7 @@ retry:
}
spin_unlock(&info->lock);
out_fput:
- fput(filp);
+ fdput(f);
out:
if (sock) {
netlink_detachskb(sock, nc);
@@ -1308,7 +1306,7 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
{
int ret;
struct mq_attr mqstat, omqstat;
- struct file *filp;
+ struct fd f;
struct inode *inode;
struct mqueue_inode_info *info;
@@ -1319,14 +1317,14 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
return -EINVAL;
}
- filp = fget(mqdes);
- if (!filp) {
+ f = fdget(mqdes);
+ if (!f.file) {
ret = -EBADF;
goto out;
}
- inode = filp->f_path.dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations)) {
+ inode = f.file->f_path.dentry->d_inode;
+ if (unlikely(f.file->f_op != &mqueue_file_operations)) {
ret = -EBADF;
goto out_fput;
}
@@ -1335,15 +1333,15 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
spin_lock(&info->lock);
omqstat = info->attr;
- omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
+ omqstat.mq_flags = f.file->f_flags & O_NONBLOCK;
if (u_mqstat) {
audit_mq_getsetattr(mqdes, &mqstat);
- spin_lock(&filp->f_lock);
+ spin_lock(&f.file->f_lock);
if (mqstat.mq_flags & O_NONBLOCK)
- filp->f_flags |= O_NONBLOCK;
+ f.file->f_flags |= O_NONBLOCK;
else
- filp->f_flags &= ~O_NONBLOCK;
- spin_unlock(&filp->f_lock);
+ f.file->f_flags &= ~O_NONBLOCK;
+ spin_unlock(&f.file->f_lock);
inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
@@ -1356,7 +1354,7 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
ret = -EFAULT;
out_fput:
- fput(filp);
+ fdput(f);
out:
return ret;
}
diff --git a/ipc/msg.c b/ipc/msg.c
index 7385de2..a71af5a 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -443,9 +443,12 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
goto out_unlock;
}
+ err = ipc_update_perm(&msqid64.msg_perm, ipcp);
+ if (err)
+ goto out_unlock;
+
msq->q_qbytes = msqid64.msg_qbytes;
- ipc_update_perm(&msqid64.msg_perm, ipcp);
msq->q_ctime = get_seconds();
/* sleeping receivers might be excluded by
* stricter permissions.
@@ -922,6 +925,7 @@ out:
#ifdef CONFIG_PROC_FS
static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
{
+ struct user_namespace *user_ns = seq_user_ns(s);
struct msg_queue *msq = it;
return seq_printf(s,
@@ -933,10 +937,10 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
msq->q_qnum,
msq->q_lspid,
msq->q_lrpid,
- msq->q_perm.uid,
- msq->q_perm.gid,
- msq->q_perm.cuid,
- msq->q_perm.cgid,
+ from_kuid_munged(user_ns, msq->q_perm.uid),
+ from_kgid_munged(user_ns, msq->q_perm.gid),
+ from_kuid_munged(user_ns, msq->q_perm.cuid),
+ from_kgid_munged(user_ns, msq->q_perm.cgid),
msq->q_stime,
msq->q_rtime,
msq->q_ctime);
diff --git a/ipc/sem.c b/ipc/sem.c
index 5215a81..58d31f1 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1104,7 +1104,9 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
freeary(ns, ipcp);
goto out_up;
case IPC_SET:
- ipc_update_perm(&semid64.sem_perm, ipcp);
+ err = ipc_update_perm(&semid64.sem_perm, ipcp);
+ if (err)
+ goto out_unlock;
sma->sem_ctime = get_seconds();
break;
default:
@@ -1677,6 +1679,7 @@ void exit_sem(struct task_struct *tsk)
#ifdef CONFIG_PROC_FS
static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
{
+ struct user_namespace *user_ns = seq_user_ns(s);
struct sem_array *sma = it;
return seq_printf(s,
@@ -1685,10 +1688,10 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
sma->sem_perm.id,
sma->sem_perm.mode,
sma->sem_nsems,
- sma->sem_perm.uid,
- sma->sem_perm.gid,
- sma->sem_perm.cuid,
- sma->sem_perm.cgid,
+ from_kuid_munged(user_ns, sma->sem_perm.uid),
+ from_kgid_munged(user_ns, sma->sem_perm.gid),
+ from_kuid_munged(user_ns, sma->sem_perm.cuid),
+ from_kgid_munged(user_ns, sma->sem_perm.cgid),
sma->sem_otime,
sma->sem_ctime);
}
diff --git a/ipc/shm.c b/ipc/shm.c
index 00faa05..dff40c9 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -758,7 +758,9 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
do_shm_rmid(ns, ipcp);
goto out_up;
case IPC_SET:
- ipc_update_perm(&shmid64.shm_perm, ipcp);
+ err = ipc_update_perm(&shmid64.shm_perm, ipcp);
+ if (err)
+ goto out_unlock;
shp->shm_ctim = get_seconds();
break;
default:
@@ -893,10 +895,10 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
audit_ipc_obj(&(shp->shm_perm));
if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
- uid_t euid = current_euid();
+ kuid_t euid = current_euid();
err = -EPERM;
- if (euid != shp->shm_perm.uid &&
- euid != shp->shm_perm.cuid)
+ if (!uid_eq(euid, shp->shm_perm.uid) &&
+ !uid_eq(euid, shp->shm_perm.cuid))
goto out_unlock;
if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
goto out_unlock;
@@ -1220,6 +1222,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
#ifdef CONFIG_PROC_FS
static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
{
+ struct user_namespace *user_ns = seq_user_ns(s);
struct shmid_kernel *shp = it;
unsigned long rss = 0, swp = 0;
@@ -1242,10 +1245,10 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
shp->shm_cprid,
shp->shm_lprid,
shp->shm_nattch,
- shp->shm_perm.uid,
- shp->shm_perm.gid,
- shp->shm_perm.cuid,
- shp->shm_perm.cgid,
+ from_kuid_munged(user_ns, shp->shm_perm.uid),
+ from_kgid_munged(user_ns, shp->shm_perm.gid),
+ from_kuid_munged(user_ns, shp->shm_perm.cuid),
+ from_kgid_munged(user_ns, shp->shm_perm.cgid),
shp->shm_atim,
shp->shm_dtim,
shp->shm_ctim,
diff --git a/ipc/util.c b/ipc/util.c
index eb07fd3..72fd078 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -249,8 +249,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;
+ kuid_t euid;
+ kgid_t egid;
int id, err;
if (size > IPCMNI)
@@ -606,14 +606,14 @@ void ipc_rcu_putref(void *ptr)
int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
{
- uid_t euid = current_euid();
+ kuid_t euid = current_euid();
int requested_mode, granted_mode;
audit_ipc_obj(ipcp);
requested_mode = (flag >> 6) | (flag >> 3) | flag;
granted_mode = ipcp->mode;
- if (euid == ipcp->cuid ||
- euid == ipcp->uid)
+ if (uid_eq(euid, ipcp->cuid) ||
+ uid_eq(euid, ipcp->uid))
granted_mode >>= 6;
else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
granted_mode >>= 3;
@@ -643,10 +643,10 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
{
out->key = in->key;
- out->uid = in->uid;
- out->gid = in->gid;
- out->cuid = in->cuid;
- out->cgid = in->cgid;
+ out->uid = from_kuid_munged(current_user_ns(), in->uid);
+ out->gid = from_kgid_munged(current_user_ns(), in->gid);
+ out->cuid = from_kuid_munged(current_user_ns(), in->cuid);
+ out->cgid = from_kgid_munged(current_user_ns(), in->cgid);
out->mode = in->mode;
out->seq = in->seq;
}
@@ -747,12 +747,19 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
* @in: the permission given as input.
* @out: the permission of the ipc to set.
*/
-void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
+int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
{
- out->uid = in->uid;
- out->gid = in->gid;
+ kuid_t uid = make_kuid(current_user_ns(), in->uid);
+ kgid_t gid = make_kgid(current_user_ns(), in->gid);
+ if (!uid_valid(uid) || !gid_valid(gid))
+ return -EINVAL;
+
+ out->uid = uid;
+ out->gid = gid;
out->mode = (out->mode & ~S_IRWXUGO)
| (in->mode & S_IRWXUGO);
+
+ return 0;
}
/**
@@ -777,7 +784,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
struct ipc64_perm *perm, int extra_perm)
{
struct kern_ipc_perm *ipcp;
- uid_t euid;
+ kuid_t euid;
int err;
down_write(&ids->rw_mutex);
@@ -793,7 +800,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
perm->gid, perm->mode);
euid = current_euid();
- if (euid == ipcp->cuid || euid == ipcp->uid ||
+ if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) ||
ns_capable(ns->user_ns, CAP_SYS_ADMIN))
return ipcp;
diff --git a/ipc/util.h b/ipc/util.h
index 850ef3e..c8fe2f7 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -125,7 +125,7 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
-void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
+int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
struct ipc_ids *ids, int id, int cmd,
struct ipc64_perm *perm, int extra_perm);
OpenPOWER on IntegriCloud