#include <linux/proc_fs.h>
#include <linux/shmem_fs.h>
#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <linux/vs_context.h>
+#include <linux/vs_limit.h>
#include <asm/uaccess.h>
#include "util.h"
{
ipc_init_ids(&shm_ids, 1);
#ifdef CONFIG_PROC_FS
- create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL);
+ create_proc_read_entry("sysvipc/shm", 0, NULL, sysvipc_shm_read_proc, NULL);
#endif
}
static inline int shm_addid(struct shmid_kernel *shp)
{
- return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni+1);
+ return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
}
*/
static void shm_destroy (struct shmid_kernel *shp)
{
- shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ struct vx_info *vxi = locate_vx_info(shp->shm_perm.xid);
+ int numpages = (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ vx_ipcshm_sub(vxi, shp, numpages);
+ shm_tot -= numpages;
+
shm_rmid (shp->id);
shm_unlock(shp);
if (!is_file_hugepages(shp->shm_file))
- shmem_lock(shp->shm_file, 0);
+ shmem_lock(shp->shm_file, 0, shp->mlock_user);
+ else
+ user_shm_unlock(shp->shm_file->f_dentry->d_inode->i_size,
+ shp->mlock_user);
fput (shp->shm_file);
security_shm_free(shp);
- ipc_rcu_free(shp, sizeof(struct shmid_kernel));
+ put_vx_info(vxi);
+ ipc_rcu_putref(shp);
}
/*
.open = shm_open, /* callback for a new vm-area open */
.close = shm_close, /* callback for when the vm-area is released */
.nopage = shmem_nopage,
+#ifdef CONFIG_NUMA
+ .set_policy = shmem_set_policy,
+ .get_policy = shmem_get_policy,
+#endif
};
static int newseg (key_t key, int shmflg, size_t size)
if (shm_tot + numpages >= shm_ctlall)
return -ENOSPC;
+ if (!vx_ipcshm_avail(current->vx_info, numpages))
+ return -ENOSPC;
shp = ipc_rcu_alloc(sizeof(*shp));
if (!shp)
return -ENOMEM;
shp->shm_perm.key = key;
+ shp->shm_perm.xid = vx_current_xid();
shp->shm_flags = (shmflg & S_IRWXUGO);
+ shp->mlock_user = NULL;
shp->shm_perm.security = NULL;
error = security_shm_alloc(shp);
if (error) {
- ipc_rcu_free(shp, sizeof(*shp));
+ ipc_rcu_putref(shp);
return error;
}
- if (shmflg & SHM_HUGETLB)
+ if (shmflg & SHM_HUGETLB) {
+ /* hugetlb_zero_setup takes care of mlock user accounting */
file = hugetlb_zero_setup(size);
- else {
+ shp->mlock_user = current->user;
+ } else {
sprintf (name, "SYSV%08x", key);
file = shmem_file_setup(name, size, VM_ACCOUNT);
}
else
file->f_op = &shm_file_operations;
shm_tot += numpages;
+ vx_ipcshm_add(current->vx_info, key, numpages);
shm_unlock(shp);
return shp->id;
fput(file);
no_file:
security_shm_free(shp);
- ipc_rcu_free(shp, sizeof(*shp));
+ ipc_rcu_putref(shp);
return error;
}
case SHM_LOCK:
case SHM_UNLOCK:
{
-/* Allow superuser to lock segment in memory */
-/* Should the pages be faulted in here or leave it to user? */
-/* need to determine interaction with current->swappable */
- if (!capable(CAP_IPC_LOCK)) {
- err = -EPERM;
- goto out;
- }
-
shp = shm_lock(shmid);
if(shp==NULL) {
err = -EINVAL;
if(err)
goto out_unlock;
+ if (!capable(CAP_IPC_LOCK)) {
+ err = -EPERM;
+ if (current->euid != shp->shm_perm.uid &&
+ current->euid != shp->shm_perm.cuid)
+ goto out_unlock;
+ if (cmd == SHM_LOCK &&
+ !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
+ goto out_unlock;
+ }
+
err = security_shm_shmctl(shp, cmd);
if (err)
goto out_unlock;
if(cmd==SHM_LOCK) {
- if (!is_file_hugepages(shp->shm_file))
- shmem_lock(shp->shm_file, 1);
- shp->shm_flags |= SHM_LOCKED;
- } else {
- if (!is_file_hugepages(shp->shm_file))
- shmem_lock(shp->shm_file, 0);
+ 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_flags |= SHM_LOCKED;
+ shp->mlock_user = user;
+ }
+ }
+ } else if (!is_file_hugepages(shp->shm_file)) {
+ shmem_lock(shp->shm_file, 0, shp->mlock_user);
shp->shm_flags &= ~SHM_LOCKED;
+ shp->mlock_user = NULL;
}
shm_unlock(shp);
goto out;
o_flags = O_RDWR;
acc_mode = S_IRUGO | S_IWUGO;
}
+ if (shmflg & SHM_EXEC) {
+ prot |= PROT_EXEC;
+ acc_mode |= S_IXUGO;
+ }
/*
* We cannot rely on the fs check since SYSV IPC does have an
struct shmid_kernel* shp;
shp = shm_lock(i);
- if(shp!=NULL) {
+ if (shp) {
#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
char *format;
+ if (!vx_check(shp->shm_perm.xid, VX_IDENT)) {
+ shm_unlock(shp);
+ continue;
+ }
if (sizeof(size_t) <= sizeof(int))
format = SMALL_STRING;
else