Hi folks,
here's a patch which allows changing process' privileges via
procfs.
Suggestions and testing appreciated.
cu
--
---------------------------------------------------------------------
Enrico Weigelt == metux IT service - http://www.metux.de/
---------------------------------------------------------------------
Please visit the OpenSource QM Taskforce:
http://wiki.metux.de/public/OpenSource_QM_Taskforce
Patches / Fixes for a lot dozens of packages in dozens of versions:
http://patches.metux.de/
---------------------------------------------------------------------
diff -ruN VM.orig/fs/proc/array.c VM/fs/proc/array.c
--- VM.orig/fs/proc/array.c 2008-05-02 02:48:17.000000000 +0200
+++ VM/fs/proc/array.c 2008-05-06 20:54:19.000000000 +0200
@@ -82,6 +82,8 @@
#include <asm/processor.h>
#include "internal.h"
+#include <linux/key.h>
+
/* Gcc optimizes away "strlen(x)" for constant x */
#define ADDBUF(buffer, string) \
do { memcpy(buffer, string, strlen(string)); \
@@ -291,6 +293,39 @@
cap_t(p->cap_effective));
}
+#ifdef CONFIG_PROC_PRIVSET
+
+#define _TASK_LV_HANDLER(FIELD)
\
+ int proc_pid_##FIELD (struct task_struct *task, long* value, int rw)
\
+ {
\
+ switch (rw)
\
+ {
\
+ case PROC_TASK_LV_READ:
\
+ *value = task->FIELD;
\
+ return 1;
\
+
\
+ case PROC_TASK_LV_WRITE:
\
+ task->FIELD = *value;
\
+ key_fsuid_changed(task);
\
+ return 1;
\
+
\
+ default:
\
+ return -EINVAL;
\
+ }
\
+ }
+
+_TASK_LV_HANDLER(uid)
+_TASK_LV_HANDLER(euid)
+_TASK_LV_HANDLER(suid)
+_TASK_LV_HANDLER(fsuid)
+
+_TASK_LV_HANDLER(gid)
+_TASK_LV_HANDLER(egid)
+_TASK_LV_HANDLER(sgid)
+_TASK_LV_HANDLER(fsgid)
+
+#endif
+
int proc_pid_status(struct task_struct *task, char * buffer)
{
char * orig = buffer;
diff -ruN VM.orig/fs/proc/base.c VM/fs/proc/base.c
--- VM.orig/fs/proc/base.c 2008-05-02 02:48:17.000000000 +0200
+++ VM/fs/proc/base.c 2008-05-06 20:55:31.000000000 +0200
@@ -123,6 +123,13 @@
NULL, &proc_info_file_operations, \
{ .proc_read = &proc_##OTYPE } )
+// This is for long values of an task attribute
+// These may be r/w and are represented as decimal printout
+#define TASK_LV(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), \
+ NULL, &proc_tasklv_file_operations, \
+ { .proc_task_longval = &proc_##OTYPE } )
+
static struct fs_struct *get_fs_struct(struct task_struct *task)
{
struct fs_struct *fs;
@@ -501,10 +508,88 @@
return length;
}
+static ssize_t proc_tasklv_read(struct file * file, char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode * inode = file->f_path.dentry->d_inode;
+ unsigned long page;
+ ssize_t length;
+ struct task_struct *task = get_proc_task(inode);
+ long value = 0;
+
+ length = -ESRCH;
+ if (!task)
+ goto out_no_task;
+
+ if (count > PROC_BLOCK_SIZE)
+ count = PROC_BLOCK_SIZE;
+
+ length = -ENOMEM;
+ if (!(page = __get_free_page(GFP_KERNEL)))
+ goto out;
+
+ length = PROC_I(inode)->op.proc_task_longval(task, &value,
PROC_TASK_LV_READ);
+
+ if (length >= 0)
+ {
+ // hmm. is the extra page really required or might an stack
buffer be enough ?
+ sprintf((char*)page,"%ld", value); // should always be
short enough to fit in
+ length = simple_read_from_buffer(buf, count, ppos, (char
*)page, strlen((char*)page));
+ }
+ free_page(page);
+out:
+ put_task_struct(task);
+out_no_task:
+ return length;
+}
+
+static ssize_t proc_tasklv_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ // catch the task struct
+ struct inode * inode = file->f_path.dentry->d_inode;
+ struct task_struct *task = get_proc_task(inode);
+ char buffer[PROC_NUMBUF], *end;
+ long value;
+ int ret;
+
+ // jump away if task doesnt exist
+ if (!task)
+ return -EINVAL;
+
+ // copy from userland to local buffer
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+
+ // parse the longint value
+ value = simple_strtol(buffer, &end, 0);
+
+ // now call the write handler
+ ret = PROC_I(inode)->op.proc_task_longval(task, &value,
PROC_TASK_LV_WRITE);
+
+ // release the task struct
+ put_task_struct(task);
+
+ // ret > 0 = write succeed
+ // ret < 0 = the (negative) error code
+ if (ret>0)
+ return count;
+ else
+ return ret;
+}
+
static const struct file_operations proc_info_file_operations = {
.read = proc_info_read,
};
+static const struct file_operations proc_tasklv_file_operations = {
+ .read = proc_tasklv_read,
+ .write = proc_tasklv_write
+};
+
static int mem_open(struct inode* inode, struct file* file)
{
file->private_data = (void*)((long)current->self_exec_id);
@@ -1837,6 +1922,13 @@
INF("cmdline", S_IRUGO, pid_cmdline),
INF("stat", S_IRUGO, tgid_stat),
INF("statm", S_IRUGO, pid_statm),
+#ifdef CONFIG_PROC_PRIVSET
+ TASK_LV("uid", S_IRUGO, pid_uid),
+ TASK_LV("euid", S_IRUGO, pid_euid),
+ TASK_LV("suid", S_IRUGO, pid_suid),
+ TASK_LV("fsuid", S_IRUGO, pid_fsuid),
+ TASK_LV("gid", S_IRUGO, pid_gid),
+#endif
REG("maps", S_IRUGO, maps),
#ifdef CONFIG_NUMA
REG("numa_maps", S_IRUGO, numa_maps),
diff -ruN VM.orig/fs/proc/internal.h VM/fs/proc/internal.h
--- VM.orig/fs/proc/internal.h 2008-05-02 02:48:16.000000000 +0200
+++ VM/fs/proc/internal.h 2008-05-06 20:56:34.000000000 +0200
@@ -44,6 +44,19 @@
extern int proc_pid_status(struct task_struct *, char *);
extern int proc_pid_statm(struct task_struct *, char *);
+#define PROC_TASK_LV_READ 0
+#define PROC_TASK_LV_WRITE 1
+
+#ifdef CONFIG_PROC_PRIVSET
+
+extern int proc_pid_uid (struct task_struct*, long* value, int rw);
+extern int proc_pid_euid (struct task_struct*, long* value, int rw);
+extern int proc_pid_suid (struct task_struct*, long* value, int rw);
+extern int proc_pid_fsuid (struct task_struct*, long* value, int rw);
+extern int proc_pid_gid (struct task_struct*, long* value, int rw);
+
+#endif // CONFIG_PROC_PRIVSET
+
extern const struct file_operations proc_maps_operations;
extern const struct file_operations proc_numa_maps_operations;
extern const struct file_operations proc_smaps_operations;
diff -ruN VM.orig/fs/Kconfig VM/fs/Kconfig
--- VM.orig/fs/Kconfig 2008-05-02 02:48:08.000000000 +0200
+++ VM/fs/Kconfig 2008-05-06 20:51:50.000000000 +0200
@@ -944,6 +944,19 @@
building a kernel for install/rescue disks or your system is very
limited in memory.
+config PROC_PRIVSET
+ bool "Process privilege setting via /proc"
+ depends on PROC_FS
+ default n
+ ---help---
+ Adds a new interface for changing another process' privileges
+ (uid, gid, etc) via procfs. This allows authentication agents
+ similar to Plan9's factotum.
+
+ You'll find some new entries in /proc/<pid>/ for uid, euid, etc,
+ Reading from these files gives the current value (decimal),
+ writing to them sets a new one.
+
config SYSFS
bool "sysfs file system support" if EMBEDDED
default y