Name: Linux kernel proc restriction patch Purpose: Restrict users from viewing all processes + additional /proc restrictions Author: Robert Annessi Date: 24.07.2007 License: GPLv2 Credits: Brad Spengler (based on grsecurity-2.1.10-2.6.19.2-200701222307.patch) diff -urN linux-2.6.18.orig/drivers/char/keyboard.c linux-2.6.18/drivers/char/keyboard.c --- linux-2.6.18.orig/drivers/char/keyboard.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/drivers/char/keyboard.c 2007-07-08 11:37:08.000000000 +0200 @@ -618,6 +618,16 @@ kbd->kbdmode == VC_MEDIUMRAW) && value != KVAL(K_SAK)) return; /* SAK is allowed even in raw mode */ + +#if defined(CONFIG_PROC_RESTRICT_USER) || defined(CONFIG_PROC_RESTRICT_GROUP) + { + void *func = fn_handler[value]; + if (func == fn_show_state || func == fn_show_ptregs || + func == fn_show_mem) + return; + } +#endif + fn_handler[value](vc, regs); } diff -urN linux-2.6.18.orig/fs/Kconfig linux-2.6.18/fs/Kconfig --- linux-2.6.18.orig/fs/Kconfig 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/fs/Kconfig 2007-07-08 14:45:56.000000000 +0200 @@ -817,7 +817,44 @@ config PROC_KCORE bool "/proc/kcore support" if !ARM - depends on PROC_FS && MMU + depends on PROC_FS && MMU && !PROC_RESTRICT_ADD + +choice + prompt "/proc restrictions" + depends on PROC_FS + default PROC_RESTRICT_NONE + +config PROC_RESTRICT_NONE + bool "None" + help + No restrictions will apply to /proc. + +config PROC_RESTRICT_USER + bool "User" + help + Non-root users will only be able to view their own processes. + +config PROC_RESTRICT_GROUP + bool "Group" + help + Non-root users not belonging to a special group will only be able to + view their own processes. + +endchoice + +config PROC_RESTRICT_GID + int "GID for special group" + depends on PROC_RESTRICT_GROUP + default 0 + +config PROC_RESTRICT_ADD + bool "Additional /proc restrictions" + depends on PROC_RESTRICT_USER || PROC_RESTRICT_GROUP + help + If you say Y here, additional restrictions will be placed on /proc + that keep normal users from viewing information that could be useful + for exploits (cmdline, devices, net, bus, config.gz, kallsyms, + ioports, iomem, slabinfo, kcore). config PROC_VMCORE bool "/proc/vmcore support (EXPERIMENTAL)" diff -urN linux-2.6.18.orig/fs/proc/base.c linux-2.6.18/fs/proc/base.c --- linux-2.6.18.orig/fs/proc/base.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/fs/proc/base.c 2007-07-08 12:00:12.000000000 +0200 @@ -1320,7 +1320,11 @@ inode->i_gid = 0; if (task_dumpable(task)) { inode->i_uid = task->euid; +#ifdef CONFIG_PROC_RESTRICT_GROUP + inode->i_gid = CONFIG_PROC_RESTRICT_GID; +#else inode->i_gid = task->egid; +#endif } security_task_to_inode(task, inode); @@ -1355,9 +1359,18 @@ struct task_struct *task = get_proc_task(inode); if (task) { if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || +#ifdef CONFIG_PROC_RESTRICT_USER + (inode->i_mode == (S_IFDIR|S_IRUSR|S_IXUSR)) || +#elif defined(CONFIG_PROC_RESTRICT_GROUP) + (inode->i_mode == (S_IFDIR|S_IRUSR|S_IRGRP|S_IXUSR|S_IXGRP)) || +#endif task_dumpable(task)) { inode->i_uid = task->euid; +#ifdef CONFIG_PROC_RESTRICT_GROUP + inode->i_gid = CONFIG_PROC_RESTRICT_GID; +#else inode->i_gid = task->egid; +#endif } else { inode->i_uid = 0; inode->i_gid = 0; @@ -1375,17 +1388,38 @@ { struct inode *inode = dentry->d_inode; struct task_struct *task; +#if defined(CONFIG_PROC_RESTRICT_USER) || defined(CONFIG_PROC_RESTRICT_GROUP) + struct task_struct *tmp = current; +#endif + generic_fillattr(inode, stat); rcu_read_lock(); stat->uid = 0; stat->gid = 0; task = pid_task(proc_pid(inode), PIDTYPE_PID); - if (task) { + if (task +#if defined(CONFIG_PROC_RESTRICT_USER) || defined(CONFIG_PROC_RESTRICT_GROUP) + && (!tmp->uid || (tmp->uid == task->uid) +#ifdef CONFIG_PROC_RESTRICT_GROUP + || in_group_p(CONFIG_PROC_RESTRICT_GID) +#endif + ) +#endif + ) { if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || +#ifdef CONFIG_PROC_RESTRICT_USER + (inode->i_mode == (S_IFDIR|S_IRUSR|S_IXUSR)) || +#elif defined(CONFIG_PROC_RESTRICT_GROUP) + (inode->i_mode == (S_IFDIR|S_IRUSR|S_IRGRP|S_IXUSR|S_IXGRP)) || +#endif task_dumpable(task)) { stat->uid = task->euid; +#ifdef CONFIG_PROC_RESTRICT_GROUP + stat->gid = CONFIG_PROC_RESTRICT_GID; +#else stat->gid = task->egid; +#endif } } rcu_read_unlock(); @@ -2061,7 +2095,14 @@ if (!inode) goto out_put_task; +#ifdef CONFIG_PROC_RESTRICT_USER + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR; +#elif defined(CONFIG_PROC_RESTRICT_GROUP) + inode->i_gid = CONFIG_PROC_RESTRICT_GID; + inode->i_mode = S_IFDIR|S_IRUSR|S_IRGRP|S_IXUSR|S_IXGRP; +#else inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; +#endif inode->i_op = &proc_tgid_base_inode_operations; inode->i_fop = &proc_tgid_base_operations; inode->i_flags|=S_IMMUTABLE; @@ -2212,6 +2253,9 @@ { char buf[PROC_NUMBUF]; unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; +#if defined(CONFIG_PROC_RESTRICT_USER) || defined(CONFIG_PROC_RESTRICT_GROUP) + struct task_struct *tmp = current; +#endif struct task_struct *task; int tgid; @@ -2235,6 +2279,16 @@ int len; ino_t ino; tgid = task->pid; + +#if defined(CONFIG_PROC_RESTRICT_USER) || defined(CONFIG_PROC_RESTRICT_GROUP) + if (tmp->uid && (task->uid != tmp->uid) +#ifdef CONFIG_PROC_RESTRICT_GROUP + && !in_group_p(CONFIG_PROC_RESTRICT_GID) +#endif + ) + continue; +#endif + len = snprintf(buf, sizeof(buf), "%d", tgid); ino = fake_ino(tgid, PROC_TGID_INO); if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) { diff -urN linux-2.6.18.orig/fs/proc/inode.c linux-2.6.18/fs/proc/inode.c --- linux-2.6.18.orig/fs/proc/inode.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/fs/proc/inode.c 2007-07-08 11:31:47.000000000 +0200 @@ -166,7 +166,11 @@ if (de->mode) { inode->i_mode = de->mode; inode->i_uid = de->uid; +#ifdef CONFIG_PROC_RESTRICT_GROUP + inode->i_gid = CONFIG_PROC_RESTRICT_GID; +#else inode->i_gid = de->gid; +#endif } if (de->size) inode->i_size = de->size; diff -urN linux-2.6.18.orig/fs/proc/proc_misc.c linux-2.6.18/fs/proc/proc_misc.c --- linux-2.6.18.orig/fs/proc/proc_misc.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/fs/proc/proc_misc.c 2007-07-08 14:38:01.000000000 +0200 @@ -655,6 +655,10 @@ void __init proc_misc_init(void) { struct proc_dir_entry *entry; +#if defined(CONFIG_PROC_RESTRICT_USER) || defined(CONFIG_PROC_RESTRICT_GROUP) + int gr_mode = 0; +#endif + static struct { char *name; int (*read_proc)(char*,char**,off_t,int,int*,void*); @@ -670,7 +674,9 @@ {"stram", stram_read_proc}, #endif {"filesystems", filesystems_read_proc}, +#ifndef CONFIG_PROC_RESTRICT_ADD {"cmdline", cmdline_read_proc}, +#endif {"locks", locks_read_proc}, {"execdomains", execdomains_read_proc}, {NULL,} @@ -678,19 +684,38 @@ for (p = simple_ones; p->name; p++) create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL); +#ifdef CONFIG_PROC_RESTRICT_USER + gr_mode = S_IRUSR; +#elif defined(CONFIG_PROC_RESTRICT_GROUP) + gr_mode = S_IRUSR | S_IRGRP; +#endif +#ifdef CONFIG_PROC_RESTRICT_ADD + create_proc_read_entry("cmdline", gr_mode, NULL, &cmdline_read_proc, + NULL); +#endif + proc_symlink("mounts", NULL, "self/mounts"); /* And now for trickier ones */ entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); if (entry) entry->proc_fops = &proc_kmsg_operations; +#ifdef CONFIG_PROC_RESTRICT_ADD + create_seq_entry("devices", gr_mode, &proc_devinfo_operations); +#else create_seq_entry("devices", 0, &proc_devinfo_operations); +#endif create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); create_seq_entry("partitions", 0, &proc_partitions_operations); create_seq_entry("stat", 0, &proc_stat_operations); create_seq_entry("interrupts", 0, &proc_interrupts_operations); #ifdef CONFIG_SLAB +#ifdef CONFIG_PROC_RESTRICT_ADD + create_seq_entry("slabinfo", S_IWUSR|gr_mode, + &proc_slabinfo_operations); +#else create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); +#endif #ifdef CONFIG_DEBUG_SLAB_LEAK create_seq_entry("slab_allocators", 0 ,&proc_slabstats_operations); #endif @@ -705,7 +728,7 @@ #ifdef CONFIG_SCHEDSTATS create_seq_entry("schedstat", 0, &proc_schedstat_operations); #endif -#ifdef CONFIG_PROC_KCORE +#if defined(CONFIG_PROC_KCORE) && !defined(CONFIG_PROC_RESTRICT_ADD) proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL); if (proc_root_kcore) { proc_root_kcore->proc_fops = &proc_kcore_operations; diff -urN linux-2.6.18.orig/fs/proc/root.c linux-2.6.18/fs/proc/root.c --- linux-2.6.18.orig/fs/proc/root.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/fs/proc/root.c 2007-07-08 14:50:01.000000000 +0200 @@ -52,7 +52,16 @@ return; } proc_misc_init(); +#ifdef CONFIG_PROC_RESTRICT_ADD +#ifdef CONFIG_PROC_RESTRICT_USER + proc_net = proc_mkdir_mode("net", S_IRUSR | S_IXUSR, NULL); +#elif defined(CONFIG_PROC_RESTRICT_GROUP) + proc_net = proc_mkdir_mode("net", S_IRUSR | S_IXUSR | S_IRGRP | + S_IXGRP, NULL); +#endif +#else proc_net = proc_mkdir("net", NULL); +#endif proc_net_stat = proc_mkdir("net/stat", NULL); #ifdef CONFIG_SYSVIPC @@ -76,7 +84,16 @@ #ifdef CONFIG_PROC_DEVICETREE proc_device_tree_init(); #endif +#ifdef CONFIG_PROC_RESTRICT_ADD +#ifdef CONFIG_PROC_RESTRICT_USER + proc_bus = proc_mkdir_mode("bus", S_IRUSR | S_IXUSR, NULL); +#elif defined(CONFIG_PROC_RESTRICT_GROUP) + proc_bus = proc_mkdir_mode("bus", S_IRUSR | S_IXUSR | S_IRGRP | + S_IXGRP, NULL); +#endif +#else proc_bus = proc_mkdir("bus", NULL); +#endif } static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat diff -urN linux-2.6.18.orig/kernel/configs.c linux-2.6.18/kernel/configs.c --- linux-2.6.18.orig/kernel/configs.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/kernel/configs.c 2007-07-08 11:31:47.000000000 +0200 @@ -88,8 +88,17 @@ struct proc_dir_entry *entry; /* create the current config file */ +#ifdef CONFIG_PROC_RESTRICT_ADD +#ifdef CONFIG_PROC_RESTRICT_USER + entry = create_proc_entry("config.gz", S_IFREG | S_IRUSR, &proc_root); +#elif CONFIG_PROC_RESTRICT_GROUP + entry = create_proc_entry("config.gz", S_IFREG | S_IRUSR | S_IRGRP, + &proc_root); +#endif +#else entry = create_proc_entry("config.gz", S_IFREG | S_IRUGO, &proc_root); +#endif if (!entry) return -ENOMEM; diff -urN linux-2.6.18.orig/kernel/kallsyms.c linux-2.6.18/kernel/kallsyms.c --- linux-2.6.18.orig/kernel/kallsyms.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/kernel/kallsyms.c 2007-07-08 11:31:47.000000000 +0200 @@ -411,7 +411,16 @@ { struct proc_dir_entry *entry; +#ifdef CONFIG_PROC_RESTRICT_ADD +#ifdef CONFIG_PROC_RESTRICT_USER + entry = create_proc_entry("kallsyms", S_IFREG | S_IRUSR, NULL); +#elif CONFIG_PROC_RESTRICT_GROUP + entry = create_proc_entry("kallsyms", S_IFREG | S_IRUSR | S_IRGRP, + NULL); +#endif +#else entry = create_proc_entry("kallsyms", 0444, NULL); +#endif if (entry) entry->proc_fops = &kallsyms_operations; return 0; diff -urN linux-2.6.18.orig/kernel/resource.c linux-2.6.18/kernel/resource.c --- linux-2.6.18.orig/kernel/resource.c 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.18/kernel/resource.c 2007-07-08 11:31:47.000000000 +0200 @@ -133,10 +133,27 @@ { struct proc_dir_entry *entry; +#ifdef CONFIG_PROC_RESTRICT_ADD +#ifdef CONFIG_PROC_RESTRICT_USER + entry = create_proc_entry("ioports", S_IRUSR, NULL); +#elif CONFIG_PROC_RESTRICT_GROUP + entry = create_proc_entry("ioports", S_IRUSR | S_IRGRP, NULL); +#endif +#else entry = create_proc_entry("ioports", 0, NULL); +#endif if (entry) entry->proc_fops = &proc_ioports_operations; + +#ifdef CONFIG_PROC_RESTRICT_ADD +#ifdef CONFIG_PROC_RESTRICT_USER + entry = create_proc_entry("iomem", S_IRUSR, NULL); +#elif CONFIG_PROC_RESTRICT_GROUP + entry = create_proc_entry("iomem", S_IRUSR | S_IRGRP, NULL); +#endif +#else entry = create_proc_entry("iomem", 0, NULL); +#endif if (entry) entry->proc_fops = &proc_iomem_operations; return 0;