debian-security-advisory.pl 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. #!/usr/bin/perl
  2. ###############################################################################
  3. ##
  4. ## Functions for downloading and parsing Debian Security Advisories (DSAs)
  5. ## Currently also includes some FreeBSD Advisory parsing (which sucks)
  6. ##
  7. ###############################################################################
  8. use strict;
  9. use warnings;
  10. #use Storable; # persistant storage
  11. use LWP::UserAgent;
  12. #use Config::Auto; # libconfig-auto-perl
  13. use Time::ParseDate; # libtime-modules-perl
  14. #use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error);
  15. #use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
  16. #use Digest::MD5 qw(md5_hex);
  17. use POSIX qw(mktime);
  18. #use File::Path qw(make_path);
  19. use HTML::Parser;
  20. use feature "switch";
  21. # Track renamed packages here, easy but manual. We tried to automate it
  22. # using package metadata for distribution upgrades but that really sucked.
  23. sub unifySrcName {
  24. my $name = shift;
  25. given ($name) {
  26. ## TODO: it should map to the most recent version, not unversioned
  27. ## TODO: we can partially automate this..
  28. ## -> make all lower-case
  29. ## -> replace -X.Y version numbers by highest encounter(?)
  30. ## -> handle special cases like xfree86
  31. when ("proftp-dfsg") { $name = "proftp" };
  32. when ("mozilla-firefox") { $name = "iceweasel" };
  33. when ("mozilla-thunderbird") { $name = "icedove" };
  34. when ("squid3") { $name = "squid" };
  35. when ("squid/squid3") { $name = "squid" };
  36. when ("tk8.3") { $name = "tk8.4" };
  37. when ("tk8.4") { $name = "tk8.4" };
  38. when ("xpdf-i") { $name = "xpdf" };
  39. when ("zope2.10/zope2.9") { $name = "zope2.7" };
  40. when ("zope-cmfplone") { $name = "zope2.7" };
  41. when ("zope-ldapuserfolder") { $name = "zope2.7" };
  42. when ("librmagick-ruby") { $name = "ruby-rmagick" };
  43. when ("libcompass-ruby") { $name = "ruby-compass" };
  44. when ("bio-ruby") { $name = "ruby-bio" };
  45. when ("request-tracker3.4") { $name = "request-tracker3.8" };
  46. when ("request-tracker3.6") { $name = "request-tracker3.8" };
  47. when ("perl-5.005") { $name = "perl" };
  48. when ("otrs2") { $name = "otrs" };
  49. when ("openldap2.3") { $name = "openldap" };
  50. when ("openldap2") { $name = "openldap" };
  51. when ("libreoffice") { $name = "openoffice.org" };
  52. when ("nsd3") { $name = "nsd" };
  53. when ("network-manager/network-manager-applet") { $name = "network-manager" };
  54. when ("nagios3") { $name = "nagios" };
  55. when ("nagios2") { $name = "nagios" };
  56. when ("mysql-dfsg-4.1") { $name = "mysql" };
  57. when ("mysql-dfsg-5.0") { $name = "mysql" };
  58. when ("mysql-dfsg") { $name = "mysql" };
  59. when ("linux-2.6.24") { $name = "linux-2.6" };
  60. when ("linux-kernel-alpha") { $name = "linux-2.4" };
  61. when ("linux-kernel-i386") { $name = "linux-2.4" };
  62. when ("libmusicbrainz-2.0") { $name = "libmusicbrainz3" };
  63. when ("libmusicbrainz-2.1") { $name = "libmusicbrainz3" };
  64. when ("libgtop1") { $name = "libgtop2" };
  65. when ("libgd1") { $name = "libgd2" };
  66. when ("libast1") { $name = "libast" };
  67. when ("libmozjs0d") { $name = "libast" };
  68. when (/^kernel-source-2.2.*/) { $name = "linux-2.2" };
  69. when (/^kernel-patch-2.2.*/) { $name = "linux-2.2" };
  70. when ("kernel") { $name = "linux-2.4" };
  71. when (/^kernel-source-2.4.*/) { $name = "linux-2.4" };
  72. when (/^kernel-image-2.2.*/) { $name = "linux-2.2" };
  73. when (/^kernel-image-2.4.*/) { $name = "linux-2.4" };
  74. when (/^kernel-patch-2.4.*/) { $name = "linux-2.4" };
  75. when ("kernel-patch-benh") { $name = "linux-2.4" };
  76. when ("kernel-patch-vserver") { $name = "linux-2.4" };
  77. when (/^kernel-source-2.6.*/) { $name = "linux-2.6" };
  78. when ("gnutls11") { $name = "gnutls26" };
  79. when ("gnutls13") { $name = "gnutls26" };
  80. when ("gallery2") { $name = "gallery" };
  81. when ("firebird2") { $name = "firebird2.5" };
  82. when ("firebird2.0") { $name = "firebird2.5" };
  83. when ("firebird2.1") { $name = "firebird2.5" };
  84. when ("fltk1.1") { $name = "fltk1.3" };
  85. when ("fox1.4") { $name = "fox1.6" };
  86. when ("exim-tls") { $name = "exim" };
  87. when ("exim4") { $name = "exim" };
  88. when ("epic4") { $name = "epic" };
  89. when ("drupal6") { $name = "drupal" };
  90. when ("dhcp") { $name = "dhcp3" };
  91. when ("cyrus-sasl") { $name = "cyrus-sasl2" };
  92. when (/^cyrus-imapd.*/) { $name = "cyrus-imapd" };
  93. when (/^kolab-cyrus-imapd.*/) { $name = "cyrus-imapd" };
  94. when ("cfengine") { $name = "cfengine2" };
  95. when ("bind") { $name = "bind9" };
  96. when ("apache") { $name = "apache2" };
  97. when ("horde2") { $name = "horde3" };
  98. when ("mediawiki1.7") { $name = "mediawiki" };
  99. when ("ffmpeg-debian") { $name = "ffmpeg" };
  100. when ("xserver-xorg") { $name = "xorg-server" };
  101. when ("xfree86-1") { $name = "xorg-server" };
  102. when ("xfree86v3") { $name = "xorg-server" };
  103. when ("xfree86") { $name = "xorg-server" };
  104. when ("xfree86") { $name = "xorg-server" };
  105. when ("xorg") { $name = "xorg-server" };
  106. when ("typo3") { $name = "typo3-src" };
  107. when ("lvm10") { $name = "lvm2" };
  108. when ("cupsys") { $name = "cups" };
  109. when ("ethereal") { $name = "wireshark" };
  110. when ("libboost1.42") { $name = "libboost1.46" };
  111. when ("cinelerra-cv") { $name = "cinelerra" };
  112. when ("mplayer-dmo") { $name = "mplayer" };
  113. when ("libcap") { $name = "libgda2" };
  114. when ("xkb-data-legacy") { $name = "xkeyboard-config" };
  115. when ("boost-defaults") { $name = "boost" };
  116. when ("xen-3") { $name = "xen" };
  117. when ("kde-icons-gorilla") { $name = "kde-icons-korilla" };
  118. when ("kde4libs") { $name = "kdelibs" };
  119. when ("libcgi-application-extra-plugin-bundle-perl") { $name = "libcgi-application-plugins-perl"};
  120. when (/^openssl\d$/) { $name = "openssl" };
  121. when (/^tomcat\d/) { $name = "tomcat7" };
  122. when (/^tomcat\d.\d$/) { $name = "tomcat7" };
  123. when (/^libgda\d/) { $name = "libgda4" };
  124. when (/^readline\d/) { $name = "readline6" };
  125. when (/^libwnck\d/) { $name = "libwnck" };
  126. when (/^xerces-c\d/) { $name = "xerces-c" };
  127. when (/^libticalcs\d/) { $name = "libticals" };
  128. when (/^libtifiles\d/) { $name = "libtifiles" };
  129. when (/^db\d.\d$/) { $name = "db4.8" };
  130. when (/^gcc-.*/) { $name = "gcc" };
  131. when (/^automake\d+.*/) { $name = "automake" };
  132. when (/^sun-java\d/) { $name = "sun-java6" };
  133. when (/^open-jdk\d/) { $name = "open-jdk7" };
  134. when (/^mbrola-es\d/) { $name = "mbrola-es" };
  135. when (/^mgltools-.*/) { $name = "mgltools" };
  136. when (/^coin\d$/) { $name = "coin" };
  137. when (/^adobereader-\.*/) { $name = "adobereader" };
  138. when (/^picon-\.*/) { $name = "picon" };
  139. when (/^nvidia-graphics-drivers\.*/) { $name = "nvidia-graphics-drivers" };
  140. when (/^boost\d\.\d\d/) { $name = "boost" };
  141. when (/^llvm-\d.\d/) { $name = "llvm" };
  142. when (/^octave\d.\d/) { $name = "octave" };
  143. when (/^libjibx\d.\d-java/) { $name = "libjibx-java" };
  144. when (/^emacs2\d/) { $name = "emacs23" };
  145. when (/^emacs2\d-non-dfsg/) { $name = "emacs23" };
  146. when (/^libupnp\d/) { $name = "libupnp" };
  147. when (/^python\d.\d/) { $name = "python3.2" };
  148. when (/^postgresql-\d.\d/) { $name = "postgresql-9.0" };
  149. when (/^ruby\d.\d/) { $name = "ruby1.9" };
  150. when (/^php\d/) { $name = "php5" };
  151. when (/^PHP\d/) { $name = "php5" };
  152. };
  153. return $name;
  154. }
  155. ## Should this advisory be skipped?
  156. sub blacklistedDSA {
  157. my $dsa_id = shift or die "Advisory blacklist: no id given..";
  158. ## check if DSA is blacklisted..
  159. my @id_blacklist = ("DSA-1975", "DSA-2360");
  160. grep ($_ eq $dsa_id, @id_blacklist) and return "true";
  161. return; # FALSE
  162. }
  163. ## Static map to correct errors in DSAs
  164. ## Return fixed list of CVE IDs or 0 to skip DSA
  165. sub fixDSAquirks {
  166. my $dsa_id = shift;
  167. my $dsa_state = shift;
  168. my @new_names = @{@$dsa_state[0]};
  169. my $new_date = @$dsa_state[1];
  170. my @new_cves = @{@$dsa_state[2]};
  171. ## most of these have dupe/wrong CVE referenced
  172. given ($dsa_id) {
  173. when ($_ eq "085") {
  174. @new_cves = ("CVE-2001-1562", "LOCAL-03/04/05", "LOCAL-08/24/08");
  175. }
  176. when ($_ eq "745") {
  177. @new_cves = ("CVE-2005-1921", "CVE-2005-2106", "CVE-2005-1921");
  178. }
  179. when ($_ eq "1095") {
  180. @new_cves = ("CVE-2006-0747", "CVE-2006-1861", "CVE-2006-2661");
  181. }
  182. when ($_ eq "1284") {
  183. @new_cves = ("CVE-2007-1320", "CVE-2007-1321", "CVE-2007-1322",
  184. "CVE-2007-2893", "CVE-2007-1366");
  185. }
  186. when ($_ eq "1502") {
  187. @new_cves = ("CVE-2007-2821", "CVE-2007-3238", "CVE-2008-0193", "CVE-2008-0194");
  188. }
  189. when ($_ eq "1706") {
  190. @new_cves = ("CVE-2009-0135", "CVE-2009-0136");
  191. }
  192. when ($_ eq "1757") {
  193. @new_cves = ("CVE-2007-2383", "CVE-2008-7220", "CVE-2009-1208");
  194. }
  195. when ($_ eq "1896") {
  196. @new_cves = ("CVE-2009-3474", "CVE-2009-3475", "CVE-2009-3476");
  197. }
  198. when ($_ eq "1896") {
  199. @new_cves = ("CVE-2009-3474", "CVE-2009-3475", "CVE-2009-3476");
  200. }
  201. when ($_ eq "1931") {
  202. @new_cves = ("CVE-2009-0689", "CVE-2009-2463");
  203. }
  204. when ($_ eq "1989") {
  205. @new_cves = ("CVE-2010-0789");
  206. }
  207. when ($_ eq "1941") {
  208. @new_cves = ("CVE-2009-0755", "CVE-2009-3903", "CVE-2009-3904",
  209. "CVE-2009-3905", "CVE-2009-3606", "CVE-2009-3607", "CVE-2009-3608",
  210. "CVE-2009-3909", "CVE-2009-3938");
  211. }
  212. when ($_ eq "2004") {
  213. @new_cves = ("CVE-2010-0787", "CVE-2010-0547");
  214. }
  215. when ($_ eq "2008") {
  216. @new_cves = ("LOCAL-02/23/10", "LOCAL-02/23/10", "LOCAL-02/23/10",
  217. "LOCAL-02/23/10");
  218. }
  219. when ($_ eq "2043") {
  220. @new_cves = ("CVE-2010-2062");
  221. }
  222. when ($_ eq "2044") {
  223. @new_cves = ("CVE-2010-2062");
  224. }
  225. when ($_ eq "2056") {
  226. @new_cves = ("CVE-2010-2155", "CVE-2009-4882");
  227. }
  228. when ($_ eq "2092") {
  229. @new_cves = ("CVE-2010-1625", "CVE-2010-1448", "CVE-2009-4497");
  230. }
  231. when ($_ eq "2098") {
  232. @new_cves = ("CVE-2010-3659", "CVE-2010-3660", "CVE-2010-3661",
  233. "CVE-2010-3662", "CVE-2010-3663", "CVE-2010-3664", "CVE-2010-3665",
  234. "CVE-2010-3666", "CVE-2010-3667", "CVE-2010-3668", "CVE-2010-3669",
  235. "CVE-2010-3670", "CVE-2010-3671", "CVE-2010-3672", "CVE-2010-3673",
  236. "CVE-2010-3674");
  237. }
  238. when ($_ eq "2103") {
  239. @new_cves = ("CVE-2010-3076");
  240. }
  241. when ($_ eq "2218") {
  242. @new_cves = ("CVE-2011-1684");
  243. }
  244. when ($_ eq "2229") {
  245. @new_cves = ("CVE-2005-4494", "CVE-2006-0517", "CVE-2006-0518",
  246. "CVE-2006-0519", "CVE-2006-0625", "CVE-2006-0626", "CVE-2006-1295",
  247. "CVE-2006-1702", "CVE-2007-4525", "CVE-2008-5812", "CVE-2008-5813",
  248. "CVE-2009-3041");
  249. }
  250. when ($_ eq "2261") {
  251. @new_cves = ("CVE-2009-4078", "CVE-2009-4079", "CVE-2009-4059",
  252. "LOCAL-12/30/10", "LOCAL-12/30/10");
  253. }
  254. when ($_ eq "2262") {
  255. @new_cves = ("LOCAL-03/01/11", "LOCAL-03/01/11", "LOCAL-03/01/11",
  256. "LOCAL-03/01/11", "LOCAL-05/18/11", "LOCAL-05/18/11");
  257. }
  258. when ($_ eq "2286") {
  259. @new_names = ("phpmyadmin");
  260. }
  261. when ($_ eq "2289") {
  262. @new_cves = ( "LOCAL-07/27/11", "LOCAL-07/27/11", "LOCAL-07/27/11",
  263. "LOCAL-07/27/11", "LOCAL-07/27/11", "LOCAL-07/27/11", "LOCAL-07/27/11",
  264. "LOCAL-07/27/11", "LOCAL-07/27/11", "LOCAL-07/27/11", "LOCAL-07/27/11",
  265. "LOCAL-07/27/11");
  266. }
  267. };
  268. return (\@new_names, $new_date, \@new_cves);
  269. }
  270. ## Fetch DSA from debian archive. Can't use tracker since dates are missing.
  271. ## DSA started counting in November 2000. We'll simply bruteforce which DSA
  272. ## was in which year and start in 2000 til current.
  273. sub fetchDSA {
  274. my $dsa_id = shift;
  275. my $base_url = shift;
  276. my $year= 2000;
  277. my $current_year = (gmtime())[5] + 1900;
  278. my $dsa;
  279. trace " Fetching DSA-$dsa_id\n";
  280. given ($dsa_id) {
  281. when ($_ >= 2140) { $year=2011; }
  282. when ($_ >= 1965) { $year=2010; }
  283. when ($_ >= 1694) { $year=2009; }
  284. when ($_ >= 1443) { $year=2008; }
  285. when ($_ >= 1245) { $year=2007; }
  286. when ($_ >= 929) { $year=2006; }
  287. when ($_ >= 622) { $year=2005; }
  288. when ($_ >= 406) { $year=2004; }
  289. when ($_ >= 220) { $year=2003; }
  290. when ($_ >= 96) { $year=2002; }
  291. when ($_ >= 11) { $year=2001; }
  292. };
  293. until (defined $dsa) {
  294. #my $url= $config->{"dsa_base_url"} . $year . "/dsa-" . sprintf("%03d",$dsa_id);
  295. my $url= $base_url . $year . "/dsa-" . sprintf("%03d",$dsa_id);
  296. $dsa = get $url;
  297. return $dsa if (defined $dsa);
  298. if ($year >= $current_year) {
  299. note " Could not fetch DSA $dsa_id\n";
  300. return "";
  301. }
  302. $year++;
  303. }
  304. }
  305. # fetch FSAs from freeside. returns 3-tuple (("kfreebsd-8"), $date, @CVE) if
  306. # kernel-fsa and () if not
  307. our @__FSAINDEX;
  308. our $__FSAIDXTIMESTAMP = 0;
  309. sub fetchFSA($$) {
  310. my $id = shift;
  311. our $fsa_base_url = shift;
  312. sub getFSAurls() {
  313. $\ = "\n";
  314. #print $__FSAIDXTIMESTAMP;
  315. #print time;
  316. return @__FSAINDEX if $__FSAIDXTIMESTAMP + 60 >= time;
  317. #print "not caching";
  318. $__FSAIDXTIMESTAMP = time();
  319. our @fsaurls;
  320. sub start {
  321. my ($self, $tagname, $attr, $attrseq, $origtext) = @_;
  322. if ($tagname eq 'a') {
  323. if ($attr->{"href"} =~ /^FreeBSD-SA-/ && $attr->{"href"} ne "FreeBSD-SA-06%3a14-amd.txt") {
  324. # wtf? what douchbag added this as a FreeBSD-SA?
  325. push @fsaurls, $fsa_base_url . "/" . $attr->{href};
  326. }
  327. }
  328. }
  329. sub getIDfromFSA ($) {
  330. $_ = shift;
  331. /FreeBSD-SA-(\d\d)%3a(\d\d)/;
  332. my $year = $1;
  333. my $num = $2;
  334. $year += 2000 if $year < 90;
  335. $year *= 1000;
  336. return $year + $num;
  337. }
  338. my $p = HTML::Parser->new;
  339. $p->handler(start => \&start);
  340. #$p->parse(get ($fsabase));
  341. $p->parse(get ($_)) foreach @fsaurls;
  342. $p->eof;
  343. @__FSAINDEX = sort { getIDfromFSA $a > getIDfromFSA $b } @fsaurls;
  344. return @__FSAINDEX;
  345. }
  346. my @fsas = getFSAurls();
  347. # die "unexisting FSA" if $id > $#fsas;
  348. return "" if ($id > $#fsas);
  349. return get $fsas[$id];
  350. }
  351. ## Try to find new DSAs by iteration, return table of DSAs to process
  352. sub checkDSAs {
  353. my $state = shift;
  354. my $config = shift;
  355. my %dsatable;
  356. my $next_dsa = $state->{"next_adv"};
  357. trace "Checking for new DSAs..\n";
  358. if ($next_dsa < $config->{"first_dsa"}) {
  359. note "Cache was deleted, starting at DSA $next_dsa\n";
  360. $next_dsa = $config->{"first_dsa"};
  361. }
  362. $next_dsa++ if (blacklistedDSA("DSA-".$next_dsa));
  363. my $dsa = fetchDSA($next_dsa, $config->{"dsa_base_url"});
  364. until ($dsa eq "") {
  365. debug " Got DSA-$next_dsa\n";
  366. $dsa =~ s/.*<div\ id="inner">//si;
  367. $dsa =~ s/<div\ id="footer">.*//si;
  368. $dsatable{$next_dsa} = $dsa;
  369. $next_dsa++;
  370. $next_dsa++ if (blacklistedDSA("DSA-".$next_dsa));
  371. $dsa = fetchDSA($next_dsa, $config->{"dsa_base_url"});
  372. }
  373. my $next_fsa = $state->{"next_fsa"};
  374. if ($next_fsa < $config->{"first_fsa"}) {
  375. note "Cache was deleted, starting at FSA $next_fsa\n";
  376. $next_fsa = $config->{"first_fsa"};
  377. }
  378. my $fsa = fetchFSA($next_fsa, $config->{"fsa_base_url"});
  379. until ($fsa eq "") {
  380. debug " Got FSA-$next_fsa\n";
  381. $dsatable{"FSA-$next_fsa"} = $fsa;
  382. $next_fsa++;
  383. $fsa = fetchFSA($next_fsa, $config->{"fsa_base_url"});
  384. }
  385. $state->{"next_adv"} = $next_dsa;
  386. $state->{"next_fsa"} = $next_fsa;
  387. return \%dsatable;
  388. }
  389. ## Parse DSA html data and return array
  390. ## (src-pkg-name date (CVE-id)*)
  391. sub parseDSAhtml {
  392. my $dsa = shift;
  393. my @dsa_names;
  394. my @dsa_CVEs;
  395. my @tmp;
  396. my %tmp;
  397. # Date Reported -> $dsa_date
  398. $dsa =~ /<dt>Date\ Reported:<\/dt>\s+<dd>(\d+)\s+(\w+)\s+(\d+)<\/dd>/s;
  399. my $dsa_date = parsedate("$1-$2-$3");
  400. die " Unable to extract date from DSA" unless (defined $dsa_date);
  401. # Affected Packages -> @dsa_names
  402. $dsa =~ /<dt>Affected\ Packages:<\/dt>(.*)<\/dd>\s+<dt>Vulnerable:/s;
  403. die "Unable to find src package in DSA" unless defined $1;
  404. @tmp = split(/, /, $1);
  405. foreach my $tmpstr (@tmp) {
  406. if ($tmpstr =~ /<a href=.*>(.*)<\/a>/s) {
  407. #push(@dsa_names, $1);
  408. #push(@dsa_names, unifySrcName($1));
  409. $tmp{unifySrcName($1)} = 1;
  410. }
  411. }
  412. @dsa_names = keys %tmp;
  413. # Security database references (CVEs) -> @dsa_CVEs
  414. $dsa =~ /<dt>Security\ database\ references:<\/dt>\s+<dd>(.*)<\/dd>\s+<dt>More\ information:/s;
  415. die " Unable to find CVEs in DSA" unless defined $1;
  416. @tmp = split(/(,|<br>)/, $1);
  417. foreach my $tmpstr (@tmp) {
  418. if ($tmpstr =~ /<a href=.*mitre.org.*>(.*)<\/a>/s) {
  419. push(@dsa_CVEs, $1);
  420. }
  421. }
  422. return (\@dsa_names, $dsa_date, \@dsa_CVEs);
  423. }
  424. # parse freebsd security announcements
  425. sub parseFSA ($) {
  426. my $str = shift;
  427. my %FSA;
  428. my %details;
  429. ($_, %FSA) = split /\n[IVX]+\.\s+(.*)\n/, $str;
  430. $FSA{"Preamble"} = $_;
  431. my @src = ("kfreebsd");
  432. # get cve and reldate
  433. /\nCVE Name:\s*(.*)\n/;
  434. my @CVE = split /, /, $1 if defined $1;
  435. /\nAnnounced:\**(.*)\n/;
  436. my $reldate = 0;
  437. $reldate = parsedate $1 if defined $1;
  438. return (\@src, $reldate, \@CVE) if /\nModule:\s*kernel\n/;
  439. # make sure this is a kernel package
  440. return () if !defined $FSA{"Correction details"};
  441. foreach (split /\n/, $FSA{"Correction details"}) {
  442. return (\@src, $reldate, \@CVE) if /^ src\/sys\/(?!conf\/newvers\.sh)/;
  443. }
  444. return ();
  445. }
  446. 1;