tick/broadcast: Prevent NULL pointer dereference
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / printk.c
index fa36e149442092f28dd339b03345f2a07fe91b31..ee8f6be7d8a976c88f5bcbd45fd2f78b03bb4ecb 100644 (file)
@@ -107,7 +107,7 @@ static struct console *exclusive_console;
  */
 struct console_cmdline
 {
-       char    name[8];                        /* Name of the driver       */
+       char    name[16];                       /* Name of the driver       */
        int     index;                          /* Minor dev. to use        */
        char    *options;                       /* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
@@ -363,6 +363,53 @@ static void log_store(int facility, int level,
        log_next_seq++;
 }
 
+#ifdef CONFIG_SECURITY_DMESG_RESTRICT
+int dmesg_restrict = 1;
+#else
+int dmesg_restrict;
+#endif
+
+static int syslog_action_restricted(int type)
+{
+       if (dmesg_restrict)
+               return 1;
+       /*
+        * Unless restricted, we allow "read all" and "get buffer size"
+        * for everybody.
+        */
+       return type != SYSLOG_ACTION_READ_ALL &&
+              type != SYSLOG_ACTION_SIZE_BUFFER;
+}
+
+static int check_syslog_permissions(int type, bool from_file)
+{
+       /*
+        * If this is from /proc/kmsg and we've already opened it, then we've
+        * already done the capabilities checks at open time.
+        */
+       if (from_file && type != SYSLOG_ACTION_OPEN)
+               return 0;
+
+       if (syslog_action_restricted(type)) {
+               if (capable(CAP_SYSLOG))
+                       return 0;
+               /*
+                * For historical reasons, accept CAP_SYS_ADMIN too, with
+                * a warning.
+                */
+               if (capable(CAP_SYS_ADMIN)) {
+                       pr_warn_once("%s (%d): Attempt to access syslog with "
+                                    "CAP_SYS_ADMIN but no CAP_SYSLOG "
+                                    "(deprecated).\n",
+                                current->comm, task_pid_nr(current));
+                       return 0;
+               }
+               return -EPERM;
+       }
+       return security_syslog(type);
+}
+
+
 /* /dev/kmsg - userspace message inject/listen interface */
 struct devkmsg_user {
        u64 seq;
@@ -620,7 +667,8 @@ static int devkmsg_open(struct inode *inode, struct file *file)
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                return 0;
 
-       err = security_syslog(SYSLOG_ACTION_READ_ALL);
+       err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
+                                      SYSLOG_FROM_READER);
        if (err)
                return err;
 
@@ -813,45 +861,6 @@ static inline void boot_delay_msec(int level)
 }
 #endif
 
-#ifdef CONFIG_SECURITY_DMESG_RESTRICT
-int dmesg_restrict = 1;
-#else
-int dmesg_restrict;
-#endif
-
-static int syslog_action_restricted(int type)
-{
-       if (dmesg_restrict)
-               return 1;
-       /* Unless restricted, we allow "read all" and "get buffer size" for everybody */
-       return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
-}
-
-static int check_syslog_permissions(int type, bool from_file)
-{
-       /*
-        * If this is from /proc/kmsg and we've already opened it, then we've
-        * already done the capabilities checks at open time.
-        */
-       if (from_file && type != SYSLOG_ACTION_OPEN)
-               return 0;
-
-       if (syslog_action_restricted(type)) {
-               if (capable(CAP_SYSLOG))
-                       return 0;
-               /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
-               if (capable(CAP_SYS_ADMIN)) {
-                       printk_once(KERN_WARNING "%s (%d): "
-                                "Attempt to access syslog with CAP_SYS_ADMIN "
-                                "but no CAP_SYSLOG (deprecated).\n",
-                                current->comm, task_pid_nr(current));
-                       return 0;
-               }
-               return -EPERM;
-       }
-       return 0;
-}
-
 #if defined(CONFIG_PRINTK_TIME)
 static bool printk_time = 1;
 #else
@@ -1249,7 +1258,7 @@ out:
 
 SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
 {
-       return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
+       return do_syslog(type, buf, len, SYSLOG_FROM_READER);
 }
 
 /*
@@ -1360,9 +1369,9 @@ static int console_trylock_for_printk(unsigned int cpu)
                }
        }
        logbuf_cpu = UINT_MAX;
+       raw_spin_unlock(&logbuf_lock);
        if (wake)
                up(&console_sem);
-       raw_spin_unlock(&logbuf_lock);
        return retval;
 }
 
@@ -2024,13 +2033,24 @@ void console_unlock(void)
        static u64 seen_seq;
        unsigned long flags;
        bool wake_klogd = false;
-       bool retry;
+       bool do_cond_resched, retry;
 
        if (console_suspended) {
                up(&console_sem);
                return;
        }
 
+       /*
+        * Console drivers are called under logbuf_lock, so
+        * @console_may_schedule should be cleared before; however, we may
+        * end up dumping a lot of lines, for example, if called from
+        * console registration path, and should invoke cond_resched()
+        * between lines if allowable.  Not doing so can cause a very long
+        * scheduling stall on a slow console leading to RCU stall and
+        * softlockup warnings which exacerbate the issue with more
+        * messages practically incapacitating the system.
+        */
+       do_cond_resched = console_may_schedule;
        console_may_schedule = 0;
 
        /* flush buffered message fragment immediately to console */
@@ -2087,6 +2107,9 @@ skip:
                call_console_drivers(level, text, len);
                start_critical_timings();
                local_irq_restore(flags);
+
+               if (do_cond_resched)
+                       cond_resched();
        }
        console_locked = 0;
        mutex_release(&console_lock_dep_map, 1, _RET_IP_);
@@ -2155,6 +2178,25 @@ void console_unblank(void)
        console_unlock();
 }
 
+/**
+ * console_flush_on_panic - flush console content on panic
+ *
+ * Immediately output all pending messages no matter what.
+ */
+void console_flush_on_panic(void)
+{
+       /*
+        * If someone else is holding the console lock, trylock will fail
+        * and may_schedule may be set.  Ignore and proceed to unlock so
+        * that messages are flushed out.  As this can be called from any
+        * context and we don't want to get preempted while flushing,
+        * ensure may_schedule is cleared.
+        */
+       console_trylock();
+       console_may_schedule = 0;
+       console_unlock();
+}
+
 /*
  * Return the console tty driver structure and its associated index
  */
@@ -2281,6 +2323,8 @@ void register_console(struct console *newcon)
         */
        for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
                        i++) {
+               BUILD_BUG_ON(sizeof(console_cmdline[i].name) !=
+                            sizeof(newcon->name));
                if (strcmp(console_cmdline[i].name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
@@ -2476,7 +2520,7 @@ void wake_up_klogd(void)
        preempt_enable();
 }
 
-int printk_sched(const char *fmt, ...)
+int printk_deferred(const char *fmt, ...)
 {
        unsigned long flags;
        va_list args;