From 687ec7152134648666267317fe32f2bf71efda5d Mon Sep 17 00:00:00 2001 From: Taylor Beebe Date: Sat, 7 Oct 2023 20:36:30 -0700 Subject: [PATCH] Paging Audit: Refactor Filter Logic and add Logical OR Filtering Description 1. Refactor the filtering logic to be more general instead of requiring an update function for each filterable column. 2. Add a toggle to the filter logic to switch between logical AND and logical OR filtering when comparing column values in each row. This is a nice to have feature when parsing the data. - [x] Impacts functionality? - **Functionality** - Does the change ultimately impact how firmware functions? - Examples: Add a new library, publish a new PPI, update an algorithm, ... - [ ] Impacts security? - **Security** - Does the change have a direct security impact on an application, flow, or firmware? - Examples: Crypto algorithm change, buffer overflow fix, parameter validation improvement, ... - [ ] Breaking change? - **Breaking change** - Will anyone consuming this change experience a break in build or boot behavior? - Examples: Add a new library class, move a module to a different repo, call a function in a new library class in a pre-existing module, ... - [ ] Includes tests? - **Tests** - Does the change include any explicit test code? - Examples: Unit tests, integration tests, robot tests, ... - [ ] Includes documentation? - **Documentation** - Does the change contain explicit documentation additions outside direct code modifications (and comments)? - Examples: Update readme file, add feature readme file, link to documentation on an a separate Web page, ... How This Was Tested Tested on Q35 and SBSA Integration Instructions N/A --- .../Windows/DxePaging_template_AArch64.html | 309 +++++++++--------- .../Windows/DxePaging_template_X64.html | 300 ++++++++--------- 2 files changed, 286 insertions(+), 323 deletions(-) diff --git a/UefiTestingPkg/AuditTests/PagingAudit/Windows/DxePaging_template_AArch64.html b/UefiTestingPkg/AuditTests/PagingAudit/Windows/DxePaging_template_AArch64.html index a4d875462b..03762dd8d6 100644 --- a/UefiTestingPkg/AuditTests/PagingAudit/Windows/DxePaging_template_AArch64.html +++ b/UefiTestingPkg/AuditTests/PagingAudit/Windows/DxePaging_template_AArch64.html @@ -127,8 +127,8 @@

Test Results

Actions
- Filters: - + +

@@ -303,6 +303,18 @@

External Licenses

$('button#ClearPageFilter').click(); }); + var currentLogic = "AND"; + + $(document).on("click", "#toggleLogic", function () { + if (currentLogic === "AND") { + currentLogic = "OR"; + $(this).text("Filter Logic: OR"); + } else { + currentLogic = "AND"; + $(this).text("Filter Logic: AND"); + } + applyFilter(currentLogic); + }); //table for modules var mTable = $('table#MemoryRanges').dataTable({ @@ -367,171 +379,149 @@

External Licenses

} ], //end of column def initComplete: function () { - //Setup the filters - this.api().column(2).every(function () { - var column = this; - var select = $("#PageSizeFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 2 - Page Size + var tableApi = this.api(); - this.api().column(6).every(function () { + tableApi.columns().every(function () { var column = this; - var select = $("#ExecuteFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 6 - execute Attribute - - this.api().column(4).every(function () { - var column = this; - var select = $("#AccessFlagFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 4 - Present Attribute - - this.api().column(5).every(function () { - var column = this; - var select = $("#RWFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 5 - RW attribute - - this.api().column(9).every(function () { - var column = this; - var select = $("#SectionFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column.search(SearchRegex, true, false).draw(); - }); // on change + var select; + + switch (column.index()) { + case 2: + select = $("#PageSizeFilter"); + break; + case 4: + select = $("#AccessFlagFilter"); + break; + case 5: + select = $("#RWFilter"); + break; + case 6: + select = $("#ExecuteFilter"); + break; + case 7: + select = $("#MemoryTypeFilter"); + break; + case 8: + select = $("#MemorySpaceTypeFilter"); + break; + case 9: + select = $("#SectionFilter"); + break; + case 10: + select = $("#SpecialMemoryRegionsFilter"); + break; + case 11: + select = $("#MemoryContentsFilter"); + break; + default: + console.log("Unhandled column index in init:", column.index()); + return; + } column.data().unique().sort().each(function (d, j) { - select.append('') + if (d !== null) { + select.append(''); + } }); - }); //column 10 - Section Type for code/data sections + }); - this.api().column(7).every(function () { - var column = this; - var select = $("#MemoryTypeFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 8 - Memory Type + $(".selectpicker").on("change", function () { + applyFilter(currentLogic); + }); + } + }) + + var columnKeyMapping = { + "Page Size": "PageSize", + "Execute": "Execute", + "Access Flag": "AccessFlag", + "Read/Write": "RW", + "UEFI Memory Type": "MemoryType", + "GCD Memory Type": "MemorySpaceType", + "Special Memory Usage": "SpecialMemoryRegions", + "UEFI Memory Contents": "MemoryContents", + "Section Type": "SectionType" + }; + + function applyFilter(logic) { + $.fn.dataTable.ext.search = []; + + var selectedValues = { + PageSize: $("#PageSizeFilter").val(), + Execute: $("#ExecuteFilter").val(), + AccessFlag: $("#AccessFlagFilter").val(), + RW: $("#RWFilter").val(), + MemoryType: $("#MemoryTypeFilter").val(), + MemorySpaceType: $("#MemorySpaceTypeFilter").val(), + SpecialMemoryRegions: $("#SpecialMemoryRegionsFilter").val(), + MemoryContents: $("#MemoryContentsFilter").val(), + SectionType: $("#SectionFilter").val() + } - this.api().column(8).every(function () { - var column = this; - var select = $("#MemorySpaceTypeFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 9 - GCD Memory Type + // Bail if no filters are selected + var noFiltersSelected = Object.values(selectedValues).every(arr => arr.length === 0); + if (noFiltersSelected) { + mTable.api().search('').columns().search('').draw(); + return; + } - this.api().column(10).every(function () { - var column = this; - var select = $("#SpecialMemoryRegionsFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 11 - special Memory Type + var searchRegexes = { + PageSize: CreateRegexForSearchMultiselect(selectedValues.PageSize), + Execute: CreateRegexForSearchMultiselect(selectedValues.Execute), + AccessFlag: CreateRegexForSearchMultiselect(selectedValues.AccessFlag), + RW: CreateRegexForSearchMultiselect(selectedValues.RW), + MemoryType: CreateRegexForSearchMultiselect(selectedValues.MemoryType), + MemorySpaceType: CreateRegexForSearchMultiselect(selectedValues.MemorySpaceType), + SpecialMemoryRegions: CreateRegexForSearchMultiselect(selectedValues.SpecialMemoryRegions), + MemoryContents: CreateRegexForSearchMultiselect(selectedValues.MemoryContents), + SectionType: CreateRegexForSearchMultiselect(selectedValues.SectionType) + }; + + if (logic === "AND") { + mTable.api().columns().every(function () { + var columnTitle = this.header().textContent.trim(); + var searchKey = columnKeyMapping[columnTitle]; + if (searchRegexes[searchKey]) { + this.search(searchRegexes[searchKey], true, false); + } else { + this.search(''); + } + }); + } else if (logic === "OR") { + mTable.api().columns().search(''); + $.fn.dataTable.ext.search.push(function (settings, searchData, index, rowData, counter) { + for (var key in columnKeyMapping) { + var columnTitle = key; + var searchKey = columnKeyMapping[columnTitle]; + var regexStr = searchRegexes[searchKey]; + var regex = new RegExp(regexStr); + if (regexStr && regex.test(searchData[settings.aoColumns.findIndex(col => col.sTitle === columnTitle)])) { + return true; + } + } + return false; + }); + } + mTable.api().draw(); + } - this.api().column(11).every(function () { - var column = this; - var select = $("#MemoryContentsFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - if (d === null) { - d = "Nothing Found"; //this must align with the default content - } - select.append('') - }); - }); //column 12 - Memory Contents - } //end init complete func - }) //end of modules table - - /** Memory Range JSON looks like: - {"Page Size": "4k", - "Present": "Yes", - "Read/Write": "Enabled", - "Execute": "UX/PX", - "Start": "0x0000058000", - "End": "0x0000058FFF", - "Number of Entries": 1, - "Memory Type": "EfiReservedMemoryType", - "GCD Memory Type": "EfiGcdMemoryTypeReserved" - "Attributes": "EFI_MEMORY_RO, EFI_MEMORY_RUNTIME" - "System Memory": "None" + /** Memory Range JSON looks like: + {"Page Size": "4k", + "Access Flag": "No", + "Read/Write": "Enabled", + "Execute": "Enabled", + "Start": "0x0000000000", + "End": "0x0000000FFF", + "Number of Entries": 1, + "Memory Type": "None", + "GCD Memory Type": "EfiGcdMemoryTypeNonExistent", + "Section Type": "Not Tracked", + "System Memory": "NULL Page", "Memory Contents": null, - "Partial Page": False + "Partial Page": false } - **/ + **/ var SavedFilters = []; SavedFilters.push({ "Name": "RW+X", @@ -647,19 +637,12 @@

External Licenses

function CreateRegexForSearchMultiselect(mylist) { var re = ''; - // console.log(mylist); mylist.forEach(function (v, i, a) { if (i > 0) { re += "|"; - } else { - re += "(" } - re += '^' + $.fn.dataTable.util.escapeRegex(v) + '?'; + re += '^' + $.fn.dataTable.util.escapeRegex(v) + '$'; }); - if (re !== '') { - re += ")" - } - // console.log(re); return re; } diff --git a/UefiTestingPkg/AuditTests/PagingAudit/Windows/DxePaging_template_X64.html b/UefiTestingPkg/AuditTests/PagingAudit/Windows/DxePaging_template_X64.html index 2c258216e0..e51764f51b 100644 --- a/UefiTestingPkg/AuditTests/PagingAudit/Windows/DxePaging_template_X64.html +++ b/UefiTestingPkg/AuditTests/PagingAudit/Windows/DxePaging_template_X64.html @@ -134,7 +134,8 @@

Test Results

Actions
- Filters: + +

@@ -310,6 +311,18 @@

External Licenses

$('button#ClearPageFilter').click(); }); + var currentLogic = "AND"; + + $(document).on("click", "#toggleLogic", function () { + if (currentLogic === "AND") { + currentLogic = "OR"; + $(this).text("Filter Logic: OR"); + } else { + currentLogic = "AND"; + $(this).text("Filter Logic: AND"); + } + applyFilter(currentLogic); + }); //table for modules var mTable = $('table#MemoryRanges').dataTable({ @@ -378,166 +391,140 @@

External Licenses

} ], //end of column def initComplete: function () { - //Setup the filters - this.api().column(2).every(function () { - var column = this; - var select = $("#PageSizeFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 2 - Page Size - - this.api().column(6).every(function () { - var column = this; - var select = $("#ExecuteFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 6 - execute Attribute - - this.api().column(4).every(function () { - var column = this; - var select = $("#PresentFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 4 - Present Attribute - - this.api().column(5).every(function () { - var column = this; - var select = $("#RWFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 5 - RW attribute - - this.api().column(7).every(function () { - var column = this; - var select = $("#PrivilegeFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column.search(SearchRegex, true, false).draw(); - }); // on change + var tableApi = this.api(); - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 7 - Privilege (User / Supervisor) - - this.api().column(10).every(function () { + tableApi.columns().every(function () { var column = this; - var select = $("#SectionFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column.search(SearchRegex, true, false).draw(); - }); // on change - - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 10 - Section Type for code/data sections - - this.api().column(8).every(function () { - var column = this; - var select = $("#MemoryTypeFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 8 - Memory Type + var select; + + switch (column.index()) { + case 2: + select = $("#PageSizeFilter"); + break; + case 4: + select = $("#PresentFilter"); + break; + case 6: + select = $("#ExecuteFilter"); + break; + case 5: + select = $("#RWFilter"); + break; + case 7: + select = $("#PrivilegeFilter"); + break; + case 8: + select = $("#MemoryTypeFilter"); + break; + case 9: + select = $("#MemorySpaceTypeFilter"); + break; + case 10: + select = $("#SectionFilter"); + break; + case 11: + select = $("#SpecialMemoryRegionsFilter"); + break; + case 12: + select = $("#MemoryContentsFilter"); + break; + default: + console.log("Unhandled column index in init:", column.index()); + return; + } - this.api().column(9).every(function () { - var column = this; - var select = $("#MemorySpaceTypeFilter").on('change', function () { - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options column.data().unique().sort().each(function (d, j) { - select.append('') + if (d !== null) { + select.append(''); + } }); - }); //column 9 - GCD Memory Type + }); - this.api().column(11).every(function () { - var column = this; - var select = $("#SpecialMemoryRegionsFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - select.append('') - }); - }); //column 11 - special Memory Type + $(".selectpicker").on("change", function () { + applyFilter(currentLogic); + }); + } + }) + + var columnKeyMapping = { + "Page Size": "PageSize", + "Present": "Present", + "Read/Write": "RW", + "Execute": "Execute", + "Privilege": "Privilege", + "UEFI Memory Type": "MemoryType", + "GCD Memory Type": "MemorySpaceType", + "Section Type": "SectionType", + "Special Memory Usage": "SpecialMemoryRegions", + "UEFI Memory Contents": "MemoryContents" + }; + + function applyFilter(logic) { + $.fn.dataTable.ext.search = []; + + var selectedValues = { + PageSize: $("#PageSizeFilter").val(), + Execute: $("#ExecuteFilter").val(), + Present: $("#PresentFilter").val(), + RW: $("#RWFilter").val(), + Privilege: $("#PrivilegeFilter").val(), + MemoryType: $("#MemoryTypeFilter").val(), + MemorySpaceType: $("#MemorySpaceTypeFilter").val(), + SpecialMemoryRegions: $("#SpecialMemoryRegionsFilter").val(), + MemoryContents: $("#MemoryContentsFilter").val(), + SectionType: $("#SectionFilter").val() + } + // Check if filters are selected + var noFiltersSelected = Object.values(selectedValues).every(arr => arr.length === 0); + if (noFiltersSelected) { + mTable.api().search('').columns().search('').draw(); + return; + } - this.api().column(12).every(function () { - var column = this; - var select = $("#MemoryContentsFilter").on('change', function () { - //var SelectedValues = $(this).val() || []; - var SearchRegex = CreateRegexForSearchMultiselect($(this).val()); - column - //.search( val ? '^'+val+'$' : '', true, false ) - .search(SearchRegex, true, false) - .draw(); - }); // on change - - //populate with options - column.data().unique().sort().each(function (d, j) { - if (d === null) { - d = "Nothing Found"; //this must align with the default content + var searchRegexes = { + PageSize: CreateRegexForSearchMultiselect(selectedValues.PageSize), + Execute: CreateRegexForSearchMultiselect(selectedValues.Execute), + Present: CreateRegexForSearchMultiselect(selectedValues.Present), + RW: CreateRegexForSearchMultiselect(selectedValues.RW), + Privilege: CreateRegexForSearchMultiselect(selectedValues.Privilege), + MemoryType: CreateRegexForSearchMultiselect(selectedValues.MemoryType), + MemorySpaceType: CreateRegexForSearchMultiselect(selectedValues.MemorySpaceType), + SpecialMemoryRegions: CreateRegexForSearchMultiselect(selectedValues.SpecialMemoryRegions), + MemoryContents: CreateRegexForSearchMultiselect(selectedValues.MemoryContents), + SectionType: CreateRegexForSearchMultiselect(selectedValues.SectionType) + }; + + if (logic === "AND") { + mTable.api().columns().every(function () { + var columnTitle = this.header().textContent.trim(); + var searchKey = columnKeyMapping[columnTitle]; + if (searchRegexes[searchKey]) { + this.search(searchRegexes[searchKey], true, false); + } else { + this.search(''); + } + }); + } else if (logic === "OR") { + mTable.api().columns().search(''); + + // Push our custom search function + $.fn.dataTable.ext.search.push(function (settings, searchData, index, rowData, counter) { + for (var key in columnKeyMapping) { + var columnTitle = key; + var searchKey = columnKeyMapping[columnTitle]; + var regexStr = searchRegexes[searchKey]; + var regex = new RegExp(regexStr); + if (regexStr && regex.test(searchData[settings.aoColumns.findIndex(col => col.sTitle === columnTitle)])) { + return true; } - select.append('') - }); - }); //column 12 - Memory Contents - } //end init complete func - }) //end of modules table + } + return false; + }); + + } + mTable.api().draw(); + } /** Memory Range JSON looks like: {"Page Size": "4k", @@ -666,19 +653,12 @@

External Licenses

function CreateRegexForSearchMultiselect(mylist) { var re = ''; - // console.log(mylist); mylist.forEach(function (v, i, a) { if (i > 0) { re += "|"; - } else { - re += "(" } - re += '^' + $.fn.dataTable.util.escapeRegex(v) + '?'; + re += '^' + $.fn.dataTable.util.escapeRegex(v) + '$'; }); - if (re !== '') { - re += ")" - } - // console.log(re); return re; }