[PATCH] changing process privileges via procfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux