From adb5eabda368cdd05e9ed02cf91ce5e02bc26e0b Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Wed, 25 May 2016 13:35:28 +0200
Subject: [PATCH] koops: do not assume version has 3 levels

Correct commit 9023d77ad5539433146b59e5ac80e3cefcb20cf7

Some ancient kernel versions have 4 levels. This commit allows version
string to have any level equal or greater than 3. The first 3 levels
must be numbers and the rest can be almost anything - it just must
follow the logical structure of levels (i.e. dot something dot
something) - this should allow a git hash in the version string.

In order to eliminate possible false positives introduced by the
flexibility of version levels the commit adds checks for
the prefixes ' ', '(' or 'kernel-' and the suffix ' #' or ') #'.

Resolves #1378469

Signed-off-by: Jakub Filak <jfilak@redhat.com>
---
 src/lib/kernel.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/src/lib/kernel.c b/src/lib/kernel.c
index 4e27d05..1a9d327 100644
--- a/src/lib/kernel.c
+++ b/src/lib/kernel.c
@@ -534,7 +534,10 @@ char *koops_extract_version(const char *linepointer)
      || strstr(linepointer, "REGS")
      || strstr(linepointer, "EFLAGS")
     ) {
-        const char *regexp = "([0-9]+\\.[0-9]+\\.[0-9]+-[^ \\)]+)[ \\)]";
+        /* "(4.7.0-2.x86_64.fc25) #"    */
+        /* " 4.7.0-2.x86_64.fc25 #"     */
+        /* " 2.6.3.4.5-2.x86_64.fc22 #" */
+        const char *regexp = "([ \\(]|kernel-)([0-9]+\\.[0-9]+\\.[0-9]+(\\.[^.-]+)*-[^ \\)]+)\\)? #";
         regex_t re;
         int r = regcomp(&re, regexp, REG_EXTENDED);
         if (r != 0)
@@ -545,8 +548,8 @@ char *koops_extract_version(const char *linepointer)
             return NULL;
         }
 
-        regmatch_t matchptr[2];
-        r = regexec(&re, linepointer, 2, matchptr, 0);
+        regmatch_t matchptr[3];
+        r = regexec(&re, linepointer, sizeof(matchptr)/sizeof(matchptr[0]), matchptr, 0);
         if (r != 0)
         {
             if (r != REG_NOMATCH)
@@ -565,7 +568,11 @@ char *koops_extract_version(const char *linepointer)
             return NULL;
         }
 
-        char *ret = xstrndup(linepointer + matchptr[1].rm_so, matchptr[1].rm_eo - matchptr[1].rm_so);
+        /* 0: entire string */
+        /* 1: version prefix */
+        /* 2: version string */
+        const regmatch_t *const ver = matchptr + 2;
+        char *ret = xstrndup(linepointer + ver->rm_so, ver->rm_eo - ver->rm_so);
 
         regfree(&re);
         return ret;
-- 
1.8.3.1

