- shmmni
 - stop-a                      [ SPARC only ]
 - sysrq                       ==> Documentation/sysrq.txt
+- sysctl_writes_strict
 - tainted
 - threads-max
 - unknown_nmi_panic
 
 ==============================================================
 
+sysctl_writes_strict:
+
+Control how file position affects the behavior of updating sysctl values
+via the /proc/sys interface:
+
+  -1 - Legacy per-write sysctl value handling, with no printk warnings.
+       Each write syscall must fully contain the sysctl value to be
+       written, and multiple writes on the same sysctl file descriptor
+       will rewrite the sysctl value, regardless of file position.
+   0 - (default) Same behavior as above, but warn about processes that
+       perform writes to a sysctl file descriptor when the file position
+       is not 0.
+   1 - Respect file position when writing sysctl strings. Multiple writes
+       will append to the sysctl value buffer. Anything past the max length
+       of the sysctl value buffer will be ignored. Writes to numeric sysctl
+       entries must always be at file position 0 and the value must be
+       fully contained in the buffer sent in the write syscall.
+
+==============================================================
+
 tainted:
 
 Non-zero if the kernel has been tainted.  Numeric values, which
 
 #endif
 
 #ifdef CONFIG_PROC_SYSCTL
+
+#define SYSCTL_WRITES_LEGACY   -1
+#define SYSCTL_WRITES_WARN      0
+#define SYSCTL_WRITES_STRICT    1
+
+static int sysctl_writes_strict = SYSCTL_WRITES_WARN;
+
 static int proc_do_cad_pid(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
 static int proc_taint(struct ctl_table *table, int write,
                .mode           = 0644,
                .proc_handler   = proc_taint,
        },
+       {
+               .procname       = "sysctl_writes_strict",
+               .data           = &sysctl_writes_strict,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &neg_one,
+               .extra2         = &one,
+       },
 #endif
 #ifdef CONFIG_LATENCYTOP
        {
        }
 
        if (write) {
-               /* Start writing from beginning of buffer. */
-               len = 0;
+               if (sysctl_writes_strict == SYSCTL_WRITES_STRICT) {
+                       /* Only continue writes not past the end of buffer. */
+                       len = strlen(data);
+                       if (len > maxlen - 1)
+                               len = maxlen - 1;
+
+                       if (*ppos > len)
+                               return 0;
+                       len = *ppos;
+               } else {
+                       /* Start writing from beginning of buffer. */
+                       len = 0;
+               }
+
                *ppos += *lenp;
                p = buffer;
                while ((p - buffer) < *lenp && len < maxlen - 1) {
        return 0;
 }
 
+static void warn_sysctl_write(struct ctl_table *table)
+{
+       pr_warn_once("%s wrote to %s when file position was not 0!\n"
+               "This will not be supported in the future. To silence this\n"
+               "warning, set kernel.sysctl_writes_strict = -1\n",
+               current->comm, table->procname);
+}
+
 /**
  * proc_dostring - read a string sysctl
  * @table: the sysctl table
 int proc_dostring(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos)
 {
+       if (write && *ppos && sysctl_writes_strict == SYSCTL_WRITES_WARN)
+               warn_sysctl_write(table);
+
        return _proc_do_string((char *)(table->data), table->maxlen, write,
                               (char __user *)buffer, lenp, ppos);
 }
                conv = do_proc_dointvec_conv;
 
        if (write) {
+               if (*ppos) {
+                       switch (sysctl_writes_strict) {
+                       case SYSCTL_WRITES_STRICT:
+                               goto out;
+                       case SYSCTL_WRITES_WARN:
+                               warn_sysctl_write(table);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
                page = __get_free_page(GFP_TEMPORARY);
                        return err ? : -EINVAL;
        }
        *lenp -= left;
+out:
        *ppos += *lenp;
        return err;
 }
        left = *lenp;
 
        if (write) {
+               if (*ppos) {
+                       switch (sysctl_writes_strict) {
+                       case SYSCTL_WRITES_STRICT:
+                               goto out;
+                       case SYSCTL_WRITES_WARN:
+                               warn_sysctl_write(table);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
                page = __get_free_page(GFP_TEMPORARY);
                        return err ? : -EINVAL;
        }
        *lenp -= left;
+out:
        *ppos += *lenp;
        return err;
 }