This is one (untested until tomorrow) way of solving the major problems
It
1. Makes shmat/shmctl and friends work in a chrooted environment
but not the shmfs.
2. Fixes the emulation bug in IPC_RMID which does not remove the ID
but marks it to be removed when nattch hits zero (as per SYS5.3/4
and *BSD systems)
It doesnt solve the rest of the chroot issue. In an ideal world the
shmfs would have one namespace per shmfs and a single one of them would
be mounted as the sys5 space. That would give controlled private shared
memory spaces to chrooted environments. That one however is a lot harder
--- ../linux.vanilla/ipc/shm.c Sat Mar 11 13:59:17 2000
+++ ipc/shm.c Mon Mar 13 01:42:07 2000
@@ -22,6 +22,8 @@
* environment
* 4) Read and write are not implemented (should they?)
* 5) No special nodes are supported
+ * 6) It fails to follow the SYS5.4, BSD and older Linux API correctly
+ * and breaks many applications right now (netscape, doom, gimp, ..)
*/
#include <linux/config.h>
@@ -71,6 +73,7 @@
unsigned long shm_npages; /* size of segment (pages) */
pte_t **shm_dir; /* ptr to arr of ptrs to frames */
int id;
+ int destroyed; /* set if the final detach kills */
union permap {
struct shmem {
time_t atime;
@@ -115,6 +118,7 @@
static void killseg_core(struct shmid_kernel *shp, int doacc);
static void shm_open (struct vm_area_struct *shmd);
static void shm_close (struct vm_area_struct *shmd);
+static void shm_remove_name(int id);
static struct page * shm_nopage(struct vm_area_struct *, unsigned long, int);
static int shm_swapout(struct page *, struct file *);
#ifdef CONFIG_PROC_FS
@@ -310,6 +314,25 @@
return 0;
}
+static struct dentry *shm_push_root(void)
+{
+ struct dentry *old,*new;
+ lock_kernel();
+ new=init_task_union.task->fs->root;
+ old=current->fs->root;
+ current->fs->root=dget(new);
+ unlock_kernel();
+ return old;
+}
+
+static void shm_pop_root(struct dentry *root)
+{
+ lock_kernel();
+ dput(current->fs->root);
+ current->fs->root=root;
+ unlock_kernel();
+}
+
static void shm_put_super(struct super_block *sb)
{
struct super_block **p = &shm_sb;
@@ -696,9 +719,11 @@
{
struct shmid_kernel *shp;
int err, id = 0;
+ static int count=0;
if (!shm_sb) {
- printk ("shmget: shm filesystem not mounted\n");
+ if(count++<5)
+ printk(KERN_WARNING "shmget: shm filesystem not mounted\n");
return -EINVAL;
}
@@ -886,9 +911,11 @@
struct shm_setbuf setbuf;
struct shmid_kernel *shp;
int err, version;
+ static int count;
if (!shm_sb) {
- printk ("shmctl: shm filesystem not mounted\n");
+ if(count++<5)
+ printk (KERN_WARNING "shmctl: shm filesystem not mounted\n");
return -EINVAL;
}
@@ -1008,18 +1035,29 @@
}
case IPC_RMID:
{
- char *name;
+ /*
+ * We cannot simply remove the file. The SVID states
+ * that the block remains until the last person
+ * detaches from it, then is deleted. A shmat() on
+ * an RMID segment is legal in SYS5.3-4, and *BSD,
+ * (ie everywhere).
+ *
+ * Instead we set a destroyed flag, and then blow
+ * the name away when the usage hits zero.
+ */
if ((shmid % SEQ_MULTIPLIER)== zero_id)
return -EINVAL;
- name = shm_getname(shmid);
- if (IS_ERR(name))
- return PTR_ERR(name);
- lock_kernel();
- err = do_unlink (name);
- unlock_kernel();
- putname (name);
- if (err == -ENOENT)
- err = -EINVAL;
+ shp = shm_lock(shmid);
+ if(shp==NULL)
+ return -EINVAL;
+ err=-EIDRM;
+ if(shm_checkid(shp,shmid))
+ goto out_unlock;
+ if(shp->nattch==0)
+ shm_remove_name(shmid);
+ else
+ shp->destroyed=1;
+ shm_unlock(shmid);
return err;
}
@@ -1099,6 +1137,7 @@
int err;
int flags;
char *name;
+ struct dentry *saved;
if (!shm_sb || (shmid % SEQ_MULTIPLIER) == zero_id)
return -EINVAL;
@@ -1119,7 +1158,10 @@
if (IS_ERR (name))
return PTR_ERR (name);
+ saved=shm_push_root();
file = filp_open (name, O_RDWR, 0);
+ shm_pop_root(saved);
+
putname (name);
if (IS_ERR (file))
goto bad_file;
@@ -1147,6 +1189,21 @@
shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino);
}
+static void shm_remove_name(int id)
+{
+ char *name = shm_getname(id);
+ if (!IS_ERR(name))
+ {
+ struct dentry *saved;
+ lock_kernel();
+ saved=shm_push_chroot();
+ do_unlink (name);
+ shm_pop_chroot(saved);
+ unlock_kernel();
+ putname (name);
+ }
+}
+
/*
* remove the attach descriptor shmd.
* free memory for segment if it is marked destroyed.
@@ -1164,7 +1221,14 @@
shp->shm_lprid = current->pid;
shp->shm_dtim = CURRENT_TIME;
shp->shm_nattch--;
- shm_unlock(id);
+ if(shp->shm_nattch==0 && shp->destroyed)
+ {
+ shp->destroyed=0;
+ shm_remove_name(id);
+ shm_unlock(id);
+ }
+ else
+ shm_unlock(id);
}
/*
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Wed Mar 15 2000 - 21:00:23 EST