Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
[linux-drm-fsl-dcu.git] / kernel / sysctl.c
index 600b33358ded97ea54e90b6cc39dafef8e03fa40..e0ac6cd79fcf6955c6105815b4c8ab4d9d53e97f 100644 (file)
@@ -151,6 +151,8 @@ static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
 #ifdef CONFIG_PROC_SYSCTL
 static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
                  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
 
 static ctl_table root_table[];
@@ -174,6 +176,7 @@ extern ctl_table inotify_table[];
 int sysctl_legacy_va_layout;
 #endif
 
+
 static void *get_uts(ctl_table *table, int write)
 {
        char *which = table->data;
@@ -344,14 +347,16 @@ static ctl_table kern_table[] = {
                .proc_handler   = &proc_dostring,
                .strategy       = &sysctl_string,
        },
+#ifdef CONFIG_PROC_SYSCTL
        {
                .ctl_name       = KERN_TAINTED,
                .procname       = "tainted",
                .data           = &tainted,
                .maxlen         = sizeof(int),
-               .mode           = 0444,
-               .proc_handler   = &proc_dointvec,
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_taint,
        },
+#endif
        {
                .ctl_name       = KERN_CAP_BSET,
                .procname       = "cap-bound",
@@ -1681,13 +1686,12 @@ static int _proc_do_string(void* data, int maxlen, int write,
        size_t len;
        char __user *p;
        char c;
-       
-       if (!data || !maxlen || !*lenp ||
-           (*ppos && !write)) {
+
+       if (!data || !maxlen || !*lenp) {
                *lenp = 0;
                return 0;
        }
-       
+
        if (write) {
                len = 0;
                p = buffer;
@@ -1708,6 +1712,15 @@ static int _proc_do_string(void* data, int maxlen, int write,
                len = strlen(data);
                if (len > maxlen)
                        len = maxlen;
+
+               if (*ppos > len) {
+                       *lenp = 0;
+                       return 0;
+               }
+
+               data += *ppos;
+               len  -= *ppos;
+
                if (len > *lenp)
                        len = *lenp;
                if (len)
@@ -1927,6 +1940,7 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
 
 #define OP_SET 0
 #define OP_AND 1
+#define OP_OR  2
 
 static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
                                      int *valp,
@@ -1938,6 +1952,7 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
                switch(op) {
                case OP_SET:    *valp = val; break;
                case OP_AND:    *valp &= val; break;
+               case OP_OR:     *valp |= val; break;
                }
        } else {
                int val = *valp;
@@ -1961,7 +1976,7 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
 {
        int op;
 
-       if (!capable(CAP_SYS_MODULE)) {
+       if (write && !capable(CAP_SYS_MODULE)) {
                return -EPERM;
        }
 
@@ -1970,6 +1985,22 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
                                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 {
        int *min;
        int *max;
@@ -2553,17 +2584,23 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
-       if (oldval) {
+       if (oldval && oldlenp) {
                size_t olen;
-               if (oldlenp) { 
-                       if (get_user(olen, oldlenp))
+
+               if (get_user(olen, oldlenp))
+                       return -EFAULT;
+               if (olen) {
+                       int val;
+
+                       if (olen < sizeof(int))
+                               return -EINVAL;
+
+                       val = *(int *)(table->data) / HZ;
+                       if (put_user(val, (int __user *)oldval))
+                               return -EFAULT;
+                       if (put_user(sizeof(int), oldlenp))
                                return -EFAULT;
-                       if (olen!=sizeof(int))
-                               return -EINVAL; 
                }
-               if (put_user(*(int *)(table->data)/HZ, (int __user *)oldval) ||
-                   (oldlenp && put_user(sizeof(int),oldlenp)))
-                       return -EFAULT;
        }
        if (newval && newlen) { 
                int new;
@@ -2581,17 +2618,23 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
-       if (oldval) {
+       if (oldval && oldlenp) {
                size_t olen;
-               if (oldlenp) { 
-                       if (get_user(olen, oldlenp))
+
+               if (get_user(olen, oldlenp))
+                       return -EFAULT;
+               if (olen) {
+                       int val;
+
+                       if (olen < sizeof(int))
+                               return -EINVAL;
+
+                       val = jiffies_to_msecs(*(int *)(table->data));
+                       if (put_user(val, (int __user *)oldval))
+                               return -EFAULT;
+                       if (put_user(sizeof(int), oldlenp))
                                return -EFAULT;
-                       if (olen!=sizeof(int))
-                               return -EINVAL; 
                }
-               if (put_user(jiffies_to_msecs(*(int *)(table->data)), (int __user *)oldval) ||
-                   (oldlenp && put_user(sizeof(int),oldlenp)))
-                       return -EFAULT;
        }
        if (newval && newlen) { 
                int new;
@@ -2732,12 +2775,14 @@ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
 {
        return -ENOSYS;
 }
+#ifdef CONFIG_SYSVIPC
 static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
                void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
+#endif
 #endif /* CONFIG_SYSCTL_SYSCALL */
 
 /*