Commit 34f5a398 authored by Theodore Ts'o's avatar Theodore Ts'o Committed by Linus Torvalds

[PATCH] Add TAINT_USER and ability to set taint flags from userspace

Allow taint flags to be set from userspace by writing to
/proc/sys/kernel/tainted, and add a new taint flag, TAINT_USER, to be used
when userspace has potentially done something dangerous that might
compromise the kernel.  This will allow support personnel to ask further
questions about what may have caused the user taint flag to have been set.

For example, they might examine the logs of the realtime JVM to see if the
Java program has used the really silly, stupid, dangerous, and
completely-non-portable direct access to physical memory feature which MUST
be implemented according to the Real-Time Specification for Java (RTSJ).
Sigh.  What were those silly people at Sun thinking?

[akpm@osdl.org: build fix]
[bunk@stusta.de: cleanup]
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: default avatarAdrian Bunk <bunk@stusta.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a136e99f
...@@ -200,6 +200,7 @@ extern enum system_states { ...@@ -200,6 +200,7 @@ extern enum system_states {
#define TAINT_FORCED_RMMOD (1<<3) #define TAINT_FORCED_RMMOD (1<<3)
#define TAINT_MACHINE_CHECK (1<<4) #define TAINT_MACHINE_CHECK (1<<4)
#define TAINT_BAD_PAGE (1<<5) #define TAINT_BAD_PAGE (1<<5)
#define TAINT_USER (1<<6)
extern void dump_stack(void); extern void dump_stack(void);
......
...@@ -150,6 +150,7 @@ EXPORT_SYMBOL(panic); ...@@ -150,6 +150,7 @@ EXPORT_SYMBOL(panic);
* 'R' - User forced a module unload. * 'R' - User forced a module unload.
* 'M' - Machine had a machine check experience. * 'M' - Machine had a machine check experience.
* 'B' - System has hit bad_page. * 'B' - System has hit bad_page.
* 'U' - Userspace-defined naughtiness.
* *
* The string is overwritten by the next call to print_taint(). * The string is overwritten by the next call to print_taint().
*/ */
...@@ -158,13 +159,14 @@ const char *print_tainted(void) ...@@ -158,13 +159,14 @@ const char *print_tainted(void)
{ {
static char buf[20]; static char buf[20];
if (tainted) { if (tainted) {
snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c", snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c",
tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
tainted & TAINT_FORCED_MODULE ? 'F' : ' ', tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
tainted & TAINT_FORCED_RMMOD ? 'R' : ' ', tainted & TAINT_FORCED_RMMOD ? 'R' : ' ',
tainted & TAINT_MACHINE_CHECK ? 'M' : ' ', tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
tainted & TAINT_BAD_PAGE ? 'B' : ' '); tainted & TAINT_BAD_PAGE ? 'B' : ' ',
tainted & TAINT_USER ? 'U' : ' ');
} }
else else
snprintf(buf, sizeof(buf), "Not tainted"); snprintf(buf, sizeof(buf), "Not tainted");
......
...@@ -151,6 +151,8 @@ static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, ...@@ -151,6 +151,8 @@ static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
#ifdef CONFIG_PROC_SYSCTL #ifdef CONFIG_PROC_SYSCTL
static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos); void __user *buffer, size_t *lenp, loff_t *ppos);
static int proc_dointvec_taint(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
#endif #endif
static ctl_table root_table[]; static ctl_table root_table[];
...@@ -174,6 +176,7 @@ extern ctl_table inotify_table[]; ...@@ -174,6 +176,7 @@ extern ctl_table inotify_table[];
int sysctl_legacy_va_layout; int sysctl_legacy_va_layout;
#endif #endif
static void *get_uts(ctl_table *table, int write) static void *get_uts(ctl_table *table, int write)
{ {
char *which = table->data; char *which = table->data;
...@@ -344,14 +347,16 @@ static ctl_table kern_table[] = { ...@@ -344,14 +347,16 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_dostring, .proc_handler = &proc_dostring,
.strategy = &sysctl_string, .strategy = &sysctl_string,
}, },
#ifdef CONFIG_PROC_SYSCTL
{ {
.ctl_name = KERN_TAINTED, .ctl_name = KERN_TAINTED,
.procname = "tainted", .procname = "tainted",
.data = &tainted, .data = &tainted,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0444, .mode = 0644,
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec_taint,
}, },
#endif
{ {
.ctl_name = KERN_CAP_BSET, .ctl_name = KERN_CAP_BSET,
.procname = "cap-bound", .procname = "cap-bound",
...@@ -1927,6 +1932,7 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp, ...@@ -1927,6 +1932,7 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
#define OP_SET 0 #define OP_SET 0
#define OP_AND 1 #define OP_AND 1
#define OP_OR 2
static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp, static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
int *valp, int *valp,
...@@ -1938,6 +1944,7 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp, ...@@ -1938,6 +1944,7 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
switch(op) { switch(op) {
case OP_SET: *valp = val; break; case OP_SET: *valp = val; break;
case OP_AND: *valp &= val; break; case OP_AND: *valp &= val; break;
case OP_OR: *valp |= val; break;
} }
} else { } else {
int val = *valp; int val = *valp;
...@@ -1970,6 +1977,22 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, ...@@ -1970,6 +1977,22 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
do_proc_dointvec_bset_conv,&op); do_proc_dointvec_bset_conv,&op);
} }
/*
* Taint values can only be increased
*/
static int proc_dointvec_taint(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int op;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
op = OP_OR;
return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
do_proc_dointvec_bset_conv,&op);
}
struct do_proc_dointvec_minmax_conv_param { struct do_proc_dointvec_minmax_conv_param {
int *min; int *min;
int *max; int *max;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment