Commit 9ba720c1 authored by Al Viro's avatar Al Viro

shmctl: split the work from copyin/copyout

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 5771a8c0
...@@ -813,23 +813,17 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, ...@@ -813,23 +813,17 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
* NOTE: no locks must be held, the rwsem is taken inside this function. * NOTE: no locks must be held, the rwsem is taken inside this function.
*/ */
static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd, static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
struct shmid_ds __user *buf, int version) struct shmid64_ds *shmid64)
{ {
struct kern_ipc_perm *ipcp; struct kern_ipc_perm *ipcp;
struct shmid64_ds shmid64;
struct shmid_kernel *shp; struct shmid_kernel *shp;
int err; int err;
if (cmd == IPC_SET) {
if (copy_shmid_from_user(&shmid64, buf, version))
return -EFAULT;
}
down_write(&shm_ids(ns).rwsem); down_write(&shm_ids(ns).rwsem);
rcu_read_lock(); rcu_read_lock();
ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd, ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd,
&shmid64.shm_perm, 0); &shmid64->shm_perm, 0);
if (IS_ERR(ipcp)) { if (IS_ERR(ipcp)) {
err = PTR_ERR(ipcp); err = PTR_ERR(ipcp);
goto out_unlock1; goto out_unlock1;
...@@ -849,7 +843,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd, ...@@ -849,7 +843,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
goto out_up; goto out_up;
case IPC_SET: case IPC_SET:
ipc_lock_object(&shp->shm_perm); ipc_lock_object(&shp->shm_perm);
err = ipc_update_perm(&shmid64.shm_perm, ipcp); err = ipc_update_perm(&shmid64->shm_perm, ipcp);
if (err) if (err)
goto out_unlock0; goto out_unlock0;
shp->shm_ctim = get_seconds(); shp->shm_ctim = get_seconds();
...@@ -868,67 +862,51 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd, ...@@ -868,67 +862,51 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
return err; return err;
} }
static int shmctl_nolock(struct ipc_namespace *ns, int shmid, static int shmctl_ipc_info(struct ipc_namespace *ns,
int cmd, int version, void __user *buf) struct shminfo64 *shminfo)
{ {
int err; int err = security_shm_shmctl(NULL, IPC_INFO);
struct shmid_kernel *shp; if (!err) {
memset(shminfo, 0, sizeof(*shminfo));
/* preliminary security checks for *_INFO */ shminfo->shmmni = shminfo->shmseg = ns->shm_ctlmni;
if (cmd == IPC_INFO || cmd == SHM_INFO) { shminfo->shmmax = ns->shm_ctlmax;
err = security_shm_shmctl(NULL, cmd); shminfo->shmall = ns->shm_ctlall;
if (err) shminfo->shmmin = SHMMIN;
return err;
}
switch (cmd) {
case IPC_INFO:
{
struct shminfo64 shminfo;
memset(&shminfo, 0, sizeof(shminfo));
shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
shminfo.shmmax = ns->shm_ctlmax;
shminfo.shmall = ns->shm_ctlall;
shminfo.shmmin = SHMMIN;
if (copy_shminfo_to_user(buf, &shminfo, version))
return -EFAULT;
down_read(&shm_ids(ns).rwsem); down_read(&shm_ids(ns).rwsem);
err = ipc_get_maxid(&shm_ids(ns)); err = ipc_get_maxid(&shm_ids(ns));
up_read(&shm_ids(ns).rwsem); up_read(&shm_ids(ns).rwsem);
if (err < 0) if (err < 0)
err = 0; err = 0;
goto out;
} }
case SHM_INFO: return err;
{ }
struct shm_info shm_info;
memset(&shm_info, 0, sizeof(shm_info)); static int shmctl_shm_info(struct ipc_namespace *ns,
struct shm_info *shm_info)
{
int err = security_shm_shmctl(NULL, SHM_INFO);
if (!err) {
memset(shm_info, 0, sizeof(*shm_info));
down_read(&shm_ids(ns).rwsem); down_read(&shm_ids(ns).rwsem);
shm_info.used_ids = shm_ids(ns).in_use; shm_info->used_ids = shm_ids(ns).in_use;
shm_get_stat(ns, &shm_info.shm_rss, &shm_info.shm_swp); shm_get_stat(ns, &shm_info->shm_rss, &shm_info->shm_swp);
shm_info.shm_tot = ns->shm_tot; shm_info->shm_tot = ns->shm_tot;
shm_info.swap_attempts = 0; shm_info->swap_attempts = 0;
shm_info.swap_successes = 0; shm_info->swap_successes = 0;
err = ipc_get_maxid(&shm_ids(ns)); err = ipc_get_maxid(&shm_ids(ns));
up_read(&shm_ids(ns).rwsem); up_read(&shm_ids(ns).rwsem);
if (copy_to_user(buf, &shm_info, sizeof(shm_info))) { if (err < 0)
err = -EFAULT; err = 0;
goto out;
} }
return err;
}
err = err < 0 ? 0 : err; static int shmctl_stat(struct ipc_namespace *ns, int shmid,
goto out; int cmd, struct shmid64_ds *tbuf)
} {
case SHM_STAT: struct shmid_kernel *shp;
case IPC_STAT:
{
struct shmid64_ds tbuf;
int result; int result;
int err;
rcu_read_lock(); rcu_read_lock();
if (cmd == SHM_STAT) { if (cmd == SHM_STAT) {
...@@ -955,58 +933,28 @@ static int shmctl_nolock(struct ipc_namespace *ns, int shmid, ...@@ -955,58 +933,28 @@ static int shmctl_nolock(struct ipc_namespace *ns, int shmid,
if (err) if (err)
goto out_unlock; goto out_unlock;
memset(&tbuf, 0, sizeof(tbuf)); memset(tbuf, 0, sizeof(*tbuf));
kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm); kernel_to_ipc64_perm(&shp->shm_perm, &tbuf->shm_perm);
tbuf.shm_segsz = shp->shm_segsz; tbuf->shm_segsz = shp->shm_segsz;
tbuf.shm_atime = shp->shm_atim; tbuf->shm_atime = shp->shm_atim;
tbuf.shm_dtime = shp->shm_dtim; tbuf->shm_dtime = shp->shm_dtim;
tbuf.shm_ctime = shp->shm_ctim; tbuf->shm_ctime = shp->shm_ctim;
tbuf.shm_cpid = shp->shm_cprid; tbuf->shm_cpid = shp->shm_cprid;
tbuf.shm_lpid = shp->shm_lprid; tbuf->shm_lpid = shp->shm_lprid;
tbuf.shm_nattch = shp->shm_nattch; tbuf->shm_nattch = shp->shm_nattch;
rcu_read_unlock(); rcu_read_unlock();
return result;
if (copy_shmid_to_user(buf, &tbuf, version))
err = -EFAULT;
else
err = result;
goto out;
}
default:
return -EINVAL;
}
out_unlock: out_unlock:
rcu_read_unlock(); rcu_read_unlock();
out:
return err; return err;
} }
SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd)
{ {
struct shmid_kernel *shp; struct shmid_kernel *shp;
int err, version;
struct ipc_namespace *ns;
if (cmd < 0 || shmid < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
switch (cmd) {
case IPC_INFO:
case SHM_INFO:
case SHM_STAT:
case IPC_STAT:
return shmctl_nolock(ns, shmid, cmd, version, buf);
case IPC_RMID:
case IPC_SET:
return shmctl_down(ns, shmid, cmd, buf, version);
case SHM_LOCK:
case SHM_UNLOCK:
{
struct file *shm_file; struct file *shm_file;
int err;
rcu_read_lock(); rcu_read_lock();
shp = shm_obtain_object_check(ns, shmid); shp = shm_obtain_object_check(ns, shmid);
...@@ -1070,10 +1018,6 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) ...@@ -1070,10 +1018,6 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
fput(shm_file); fput(shm_file);
return err; return err;
}
default:
return -EINVAL;
}
out_unlock0: out_unlock0:
ipc_unlock_object(&shp->shm_perm); ipc_unlock_object(&shp->shm_perm);
...@@ -1082,6 +1026,59 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) ...@@ -1082,6 +1026,59 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
return err; return err;
} }
SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
{
int err, version;
struct ipc_namespace *ns;
struct shmid64_ds tbuf;
if (cmd < 0 || shmid < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
switch (cmd) {
case IPC_INFO: {
struct shminfo64 shminfo;
err = shmctl_ipc_info(ns, &shminfo);
if (err < 0)
return err;
if (copy_shminfo_to_user(buf, &shminfo, version))
err = -EFAULT;
return err;
}
case SHM_INFO: {
struct shm_info shm_info;
err = shmctl_shm_info(ns, &shm_info);
if (err < 0)
return err;
if (copy_to_user(buf, &shm_info, sizeof(shm_info)))
err = -EFAULT;
return err;
}
case SHM_STAT:
case IPC_STAT: {
err = shmctl_stat(ns, shmid, cmd, &tbuf);
if (err < 0)
return err;
if (copy_shmid_to_user(buf, &tbuf, version))
err = -EFAULT;
return err;
}
case IPC_SET:
if (copy_shmid_from_user(&tbuf, buf, version))
return -EFAULT;
case IPC_RMID:
return shmctl_down(ns, shmid, cmd, &tbuf);
case SHM_LOCK:
case SHM_UNLOCK:
return shmctl_do_lock(ns, shmid, cmd);
default:
return -EINVAL;
}
}
/* /*
* Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment