varlinks! (and 2.1.98 works for me)

Rogier Wolff (R.E.Wolff@BitWizard.nl)
Sun, 26 Apr 1998 16:26:38 +0200 (MET DST)


Hi,

Something went wrong the first time.... Sorry.

Two things: first a 2.1.98 works for me story, and then the "varlink"
stuff.

----------------------------------------------------------------------

It seems that 2.1.98 works for me....

Even with concurrent heavy IDE and SCSI activity.

3:42pm up 1:02, 19 users, load average: 5.05, 5.13, 4.94
151 processes: 147 sleeping, 4 running, 0 zombie, 0 stopped
CPU states: 74.0% user, 25.8% system, 89.5% nice, 1.1% idle
Mem: 95320K av, 92020K used, 3300K free, 14896K shrd, 4484K buff
Swap: 130748K av, 36024K used, 94724K free 9988K cached

PID USER PRI NI SIZE RSS SHARE STAT LIB %CPU %MEM TIME COMMAND
885 wolff 8 0 284 256 144 R 0 39.0 0.2 2:10 l3dec
312 wolff 20 19 136 108 88 R N 0 33.9 0.1 14:21 rc5des
919 wolff 2 0 240 224 136 D 0 7.0 0.2 0:15 find
947 wolff 1 0 452 452 284 D 0 5.9 0.4 0:03 diff
903 wolff 0 0 70076 59M 24 D 0 1.1 63.3 0:14 hogmem

The l3dec is streaming audio to my audio card, Almost uninterruptedly.
The rc5des just eats all the remaining CPU time.
The "find" is looking through 140000 files on my md-striped disk on
my two scsi disks.
The diff was generating the "varlink" diff, attached below.
The hogmem is causing the machine to swap all the time on my IDE disk.

So far it's been stable. Occasionally a little slow, but that's to be
expected. I'm pestering it pretty much.

Oh. And it turns out I forgot to turn off SMP in the Makefile again.
So, this is an SMP kernel running on a single processor.

-----------------------------------------------------------------------

Varlinks.

What are varlinks?

varlinks are symlinks that have a variable part in them. An example
will make things clear:

id[wolff@cave ~] id
uid=500(wolff) gid=500(wolff) groups=100(users),500(wolff)
[wolff@cave ~] ls -lF link
lrwxrwxrwx 1 wolff wolff 22 Mar 10 14:12 link -> /home/wolff/tmp/${uid}/
[wolff@cave ~] cd link
[wolff@cave ~/link] pwd
/home/wolff/tmp/500
[wolff@cave ~/link]

As you see, the "${uid}" part of the link isn't taken litterally. It
puts in my numeric uid.

You can set variables by doing

echo "HOME=/home/wolff" > /proc/$$/varlinks

This sets the "HOME" variable, allowing ${HOME} function in a varlink.
If the variable isn't found, the string is left untouched. This allows
you to create a default. Just put it under the litteral name
'${HOME}'.

This all started when a flurry of /tmp-exploits kept popping up. My
suggestion is to use a symlink "/tmp -> /.tmp/${uid}". The system
operator is responsible for populating the /.tmp directory.

Someone asked last thursday for a varlink for /home . That's exactly
what this does. (You can make "/home" be YOUR homedir. Don't put
/home on everybodies passwd line, because it won't work for deamons
that are looking a file in your homedir. Ehm. Actually, it would
filter out those deamons that don't use YOUR uid to check your
.forward or your .plan, but most importantly, your fellow users
would end up in their own homedir if they would "cd ~someuser")

Oh,... As of now, this only works for ext2fs. It shouldn't be
too hard to apply the same oneliner to different filesystems....
(I just tried it for NFS, and it doesn't work yet.).

Talking about NFS, this is a client-side thing. This allows this to
work with say a "sun" server, and Linux clients.

The patch is of a "proof-of-concept" quality. If there is interest
I'll polish it up such that it could go into the standard kernel.

Todo:
-- Check for memory leaks.
-- Allow overwriting of variables using the /proc interface.
-- Adapt to Linus' indentation style.
-- Improve efficientcy here and there....
-- Do the oneliner for the other filesystems.
-- Remove the debugging output.
-- Move the "vars" from the "task" to the "fs" structure.
-- split "uid" to "ruid", "euid" and "fsuid".

Linus: If you disregard the coding style, some inefficiencies, and
possible races for now, would it be possible to include this in the
running-kernel-series? Or "wait for 2.3" or "not over my dead body"?

everybody: I'd appreciate feedback "it works", "I'd like this feature,
but I didn't have time to try it", "It doesn't work".

Regards,

Roger Wolff.

--------------
diff -ur linux-2.1.98.clean/fs/Config.in linux/fs/Config.in
--- linux-2.1.98.clean/fs/Config.in Sun Apr 26 12:51:24 1998
+++ linux/fs/Config.in Sun Apr 26 13:59:16 1998
@@ -5,6 +5,7 @@
comment 'Filesystems'

bool 'Quota support' CONFIG_QUOTA
+bool 'varlink support' CONFIG_VARLINKS

tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
diff -ur linux-2.1.98.clean/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- linux-2.1.98.clean/fs/ext2/symlink.c Sun Jan 4 09:53:41 1998
+++ linux/fs/ext2/symlink.c Sun Apr 26 14:38:35 1998
@@ -68,7 +68,7 @@
link = bh->b_data;
}
UPDATE_ATIME(inode);
- base = lookup_dentry(link, base, 1);
+ base = lookup_varlink_dentry(link, base, 1);
if (bh)
brelse(bh);
return base;
diff -ur linux-2.1.98.clean/fs/namei.c linux/fs/namei.c
--- linux-2.1.98.clean/fs/namei.c Tue Jan 13 00:03:28 1998
+++ linux/fs/namei.c Sun Apr 26 14:42:43 1998
@@ -12,6 +12,7 @@
* lookup logic.
*/

+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -22,6 +23,7 @@
#include <linux/proc_fs.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/varlink.h>

#include <asm/uaccess.h>
#include <asm/unaligned.h>
@@ -331,6 +333,89 @@
}
return dentry;
}
+
+
+#ifdef CONFIG_VARLINKS
+
+static char *find_variable (char *varname)
+{
+ static char buf[20];
+ struct cvar_s *t;
+
+ printk (KERN_INFO "find: %s\n", varname);
+ if (strcmp (varname, "uid") == 0) {
+ sprintf (buf, "%d", current->fsuid);
+ printk (KERN_INFO "got: %s\n", buf);
+ return buf;
+ }
+
+ for (t= current->vars;t != NULL;t=t->next) {
+ if (strcmp (varname, t->var) == 0) {
+ return t->val;
+ }
+ }
+
+ return NULL;
+}
+
+
+static char *expand_name (const char *oldname)
+{
+ char *to, *p2;
+ const char *from, *p1;
+ char *newname = kmalloc (1000, GFP_KERNEL);
+ char varname[32];
+
+ printk (KERN_INFO "expand: %s\n", oldname);
+ /* if (base->sb->flags & OPTION_ENABLE_VARLINKS) */
+ for (from=oldname, to=newname; *from;) {
+ if ((*from == '$') && (*(from+1) == '{')) {
+ for (from=from+2, p2 = varname;*from && (*from != '}');) {
+ *p2++ = *from++;
+ }
+ if (*from) from++;
+ *p2++ = '\0';
+ p1 = find_variable (varname);
+ if (p1) {
+ while (*p1)
+ *to++ = *p1++;
+ *to = '\0';
+ printk (KERN_INFO "newname is now: %s\n", newname);
+ continue;
+ }
+ /* If variable not found, take the symlink literally. */
+ }
+ *to++ = *from++;
+ }
+ *to++ = '\0';
+ printk (KERN_INFO "returning: %s\n", newname);
+ return newname;
+}
+#endif
+
+
+struct dentry *lookup_varlink_dentry (const char * name, struct dentry * base, int follow_link)
+{
+#ifdef CONFIG_VARLINKS
+ const char *ch;
+ char *newname;
+ struct dentry *dentry;
+
+ /* printk (KERN_INFO "symlink: '%s'\n", name); */
+ /* if (base->sb->flags & OPTION_ENABLE_VARLINKS) */
+ for (ch=name; *ch;ch++) {
+ if ((*ch == '$') && (*(ch+1) == '{')) {
+ newname = expand_name (name);
+ dentry = lookup_dentry (newname, base, follow_link);
+ kfree (newname);
+ return (dentry);
+ }
+ }
+#endif
+ return lookup_dentry (name, base, follow_link);
+}
+
+

/*
* Name resolution.
diff -ur linux-2.1.98.clean/fs/proc/Makefile linux/fs/proc/Makefile
--- linux-2.1.98.clean/fs/proc/Makefile Sat Aug 16 18:53:08 1997
+++ linux/fs/proc/Makefile Sun Apr 26 13:59:16 1998
@@ -9,7 +9,7 @@

O_TARGET := proc.o
O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
- kmsg.o scsi.o proc_tty.o
+ kmsg.o scsi.o proc_tty.o varlink.o
ifdef CONFIG_OMIRR
O_OBJS := $(O_OBJS) omirr.o
endif
diff -ur linux-2.1.98.clean/fs/proc/base.c linux/fs/proc/base.c
--- linux-2.1.98.clean/fs/proc/base.c Sun Apr 26 12:50:24 1998
+++ linux/fs/proc/base.c Sun Apr 26 14:38:35 1998
@@ -151,6 +151,17 @@
NULL, proc_pid_fill_inode,
};

+#ifdef CONFIG_VARLINKS
+extern struct inode_operations proc_varlink_inode_operations;
+
+static struct proc_dir_entry proc_pid_varlinks = {
+ PROC_PID_VARLINKS, 8, "varlinks",
+ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+ 0, &proc_varlink_inode_operations,
+ NULL, proc_pid_fill_inode,
+};
+#endif
+
#if CONFIG_AP1000
static struct proc_dir_entry proc_pid_ringbuf = {
PROC_PID_RINGBUF, 7, "ringbuf",
@@ -185,6 +196,9 @@
proc_register(&proc_pid, &proc_pid_stat);
proc_register(&proc_pid, &proc_pid_statm);
proc_register(&proc_pid, &proc_pid_maps);
+#ifdef CONFIG_VARLINKS
+ proc_register(&proc_pid, &proc_pid_varlinks);
+#endif
#ifdef __SMP__
proc_register(&proc_pid, &proc_pid_cpu);
#endif
diff -ur linux-2.1.98.clean/fs/proc/varlink.c linux/fs/proc/varlink.c
--- linux-2.1.98.clean/fs/proc/varlink.c Sun Apr 26 14:02:23 1998
+++ linux/fs/proc/varlink.c Sun Apr 26 14:38:35 1998
@@ -0,0 +1,148 @@
+/*
+ * linux/fs/proc/varlink.c
+ *
+ * Copyright (C) 1998 R.E.Wolff@BitWizard.nl
+ *
+ * proc varlink handling functions
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/varlink.h>
+
+
+#ifdef CONFIG_VARLINKS
+
+#define PROC_BLOCK_SIZE (3*1024)
+
+
+static ssize_t varlink_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+ char *page;
+ unsigned int pid;
+ struct task_struct *tsk;
+ char *p;
+ struct cvar_s *cvar;
+ int t;
+
+ if (count > PROC_BLOCK_SIZE)
+ count = PROC_BLOCK_SIZE;
+ if (!(page = (char *) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ pid = inode->i_ino >> 16;
+
+ printk (KERN_INFO "varlink: reading %d bytes for pid %d at %lld.\n",
+ count, pid, *ppos);
+
+ tsk = find_task_by_pid (pid);
+
+ cvar = tsk->vars;
+
+ /* printk ("Got tsk= %p, cvar=%p.\n", tsk, cvar);*/
+
+ t=0;
+ while (cvar && (t < *ppos)) {
+ cvar = cvar->next;
+ t += 1024;
+ }
+
+ p = page;
+ while ((p < (page + PROC_BLOCK_SIZE)) &&
+ (cvar)) {
+ printk ("reporting %s = %s.\n", cvar->var, cvar->val);
+ p += sprintf (p, "%s=%s\n", cvar->var, cvar->val);
+ cvar = cvar->next;
+ *ppos += 1024;
+ }
+ printk ("Returing %d bytes.\n", p-page);
+ copy_to_user(buf, page, p-page);
+ return (p-page);
+}
+
+#if 0
+/* For now, debugging */
+#define varlink_write NULL
+
+#else
+
+static ssize_t varlink_write(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+ char mybuf[1024];
+ char *p;
+ struct cvar_s *t;
+ struct task_struct *tsk;
+ int pid;
+
+ if (count > 1000) count = 1000;
+ copy_from_user (mybuf, buf, count);
+ if (mybuf[count-1] == '\n')
+ mybuf[count-1] = '\0';
+ else
+ mybuf[count] = '\0';
+
+ printk ("Got a varlink write: '%s'\n", mybuf);
+
+ pid = inode->i_ino >> 16;
+ tsk = find_task_by_pid (pid);
+
+ if ((p=strchr (mybuf, '='))) {
+ *p++ = '\0';
+ printk ("setting var '%s' to '%s' for task %d.\n", mybuf, p, pid);
+ t = kmalloc (sizeof (struct cvar_s), GFP_KERNEL);
+ t->var = kmalloc (p-mybuf + 1, GFP_KERNEL);
+ t->val = kmalloc (strlen (p)+ 1, GFP_KERNEL);
+ strcpy (t->var, mybuf);
+ strcpy (t->val, p);
+ t->next = tsk->vars;
+ tsk->vars = t;
+ return count;
+ }
+ return -EIO;
+}
+
+#endif
+
+static struct file_operations proc_varlink_operations = {
+ NULL, /* varlink_lseek */
+ varlink_read, /* varlink_read */
+ varlink_write, /* varlink_write */
+ NULL, /* varlink_readdir */
+ NULL, /* varlink_poll */
+ NULL, /* varlink_ioctl */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+struct inode_operations proc_varlink_inode_operations = {
+ &proc_varlink_operations, /* varlink-file file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+
+#endif
diff -ur linux-2.1.98.clean/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux-2.1.98.clean/include/linux/proc_fs.h Sun Apr 26 13:01:08 1998
+++ linux/include/linux/proc_fs.h Sun Apr 26 14:00:05 1998
@@ -65,6 +65,7 @@
PROC_PID_STAT,
PROC_PID_STATM,
PROC_PID_MAPS,
+ PROC_PID_VARLINKS, /* whether enabled or not */
#if CONFIG_AP1000
PROC_PID_RINGBUF,
#endif
diff -ur linux-2.1.98.clean/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.1.98.clean/include/linux/sched.h Sun Apr 26 13:01:05 1998
+++ linux/include/linux/sched.h Sun Apr 26 13:59:17 1998
@@ -291,6 +291,7 @@
int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */
/* Spinlocks for various pieces or per-task state. */
spinlock_t sigmask_lock; /* Protects signal and blocked */
+ struct cvar_s *vars;
};

/*
@@ -366,7 +367,8 @@
/* mm */ &init_mm, \
/* signals */ &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, \
/* SMP */ 0,0,0,0, \
-/* locks */ INIT_LOCKS \
+/* locks */ INIT_LOCKS, \
+/* varlink */ NULL \
}

union task_union {
diff -ur linux-2.1.98.clean/include/linux/varlink.h linux/include/linux/varlink.h
--- linux-2.1.98.clean/include/linux/varlink.h Sun Apr 26 14:02:23 1998
+++ linux/include/linux/varlink.h Sun Apr 26 14:00:57 1998
@@ -0,0 +1,15 @@
+/*
+ * linux/fs/proc/fd.c
+ *
+ * Copyright (C) 1998 R.E.Wolff@BitWizard.nl
+ *
+ * varlink defines.
+ */
+
+
+struct cvar_s {
+ struct cvar_s *next;
+ char *var;
+ char *val;
+};
+
diff -ur linux-2.1.98.clean/kernel/exit.c linux/kernel/exit.c
--- linux-2.1.98.clean/kernel/exit.c Sun Apr 26 12:51:13 1998
+++ linux/kernel/exit.c Sun Apr 26 14:38:35 1998
@@ -21,6 +21,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/acct.h>
+#include <linux/varlink.h>
+

#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -205,6 +207,23 @@
__exit_files(tsk);
}

+
+#ifdef CONFIG_VARLINKS
+void exit_vars (struct task_struct *tsk)
+{
+ struct cvar_s *cv, *t;
+
+ for (cv = tsk->vars;cv;) {
+ t = cv;
+ cv = cv->next;
+ kfree (t->var);
+ kfree (t->val);
+ kfree (t);
+ }
+}
+#endif
+
+
static inline void __exit_fs(struct task_struct *tsk)
{
struct fs_struct * fs = tsk->fs;
@@ -352,6 +371,9 @@
__exit_mm(current);
#if CONFIG_AP1000
exit_msc(current);
+#endif
+#ifdef CONFIG_VARLINKS
+ exit_vars (current);
#endif
__exit_files(current);
__exit_fs(current);
diff -ur linux-2.1.98.clean/kernel/fork.c linux/kernel/fork.c
--- linux-2.1.98.clean/kernel/fork.c Sun Apr 26 12:52:03 1998
+++ linux/kernel/fork.c Sun Apr 26 14:38:35 1998
@@ -11,6 +11,7 @@
* management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
*/

+#include <linux/config.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -23,6 +24,8 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/module.h>
+#include <linux/varlink.h>
+

#include <asm/system.h>
#include <asm/pgtable.h>
@@ -459,6 +462,25 @@
return 0;
}

+#ifdef CONFIG_VARLINKS
+static inline int copy_vars (struct task_struct *tsk)
+{
+ struct cvar_s *cv, *t;
+
+ tsk->vars = NULL;
+ for (cv=current->vars;cv != NULL; cv=cv->next) {
+ t = kmalloc (sizeof (struct cvar_s), GFP_KERNEL);
+ t->var = kmalloc (1+strlen (cv->var), GFP_KERNEL);
+ strcpy (t->var, cv->var);
+ t->val = kmalloc (1+strlen (cv->val), GFP_KERNEL);
+ strcpy (t->val, cv->val);
+ t->next = tsk->vars;
+ tsk->vars = t;
+ }
+ return 0;
+}
+#endif
+
/*
* Ok, this is the main fork-routine. It copies the system process
* information (task[nr]) and sets up the necessary registers. It
@@ -538,6 +560,10 @@

error = -ENOMEM;
/* copy all the process information */
+#ifdef CONFIG_VARLINKS
+ if (copy_vars(p))
+ goto bad_fork_cleanup;
+#endif
if (copy_files(clone_flags, p))
goto bad_fork_cleanup;
if (copy_fs(clone_flags, p))

-- 
If it's there and you can see it, it's REAL      |___R.E.Wolff@BitWizard.nl  |
If it's there and you can't see it, it's TRANSPARENT |  Tel: +31-15-2137555  |
If it's not there and you can see it, it's VIRTUAL   |__FAX:_+31-15-2138217  |
If it's not there and you can't see it, it's GONE! -- Roy Wilks, 1983  |_____|

-- 
If it's there and you can see it, it's REAL      |___R.E.Wolff@BitWizard.nl  |
If it's there and you can't see it, it's TRANSPARENT |  Tel: +31-15-2137555  |
If it's not there and you can see it, it's VIRTUAL   |__FAX:_+31-15-2138217  |
If it's not there and you can't see it, it's GONE! -- Roy Wilks, 1983  |_____|

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu