From 591484116054b8a3b114518b0ee113c634d2ee7d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 14 Oct 2021 20:08:51 -0400 Subject: [PATCH] [Osquery] Fix sql query parser logic (#114932) (#115110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patryk KopyciƄski --- .../queries/ecs_mapping_editor_field.tsx | 215 +++++++++++------- 1 file changed, 132 insertions(+), 83 deletions(-) diff --git a/x-pack/plugins/osquery/public/scheduled_query_groups/queries/ecs_mapping_editor_field.tsx b/x-pack/plugins/osquery/public/scheduled_query_groups/queries/ecs_mapping_editor_field.tsx index d653cc7ecc54..cfd2712bafbf 100644 --- a/x-pack/plugins/osquery/public/scheduled_query_groups/queries/ecs_mapping_editor_field.tsx +++ b/x-pack/plugins/osquery/public/scheduled_query_groups/queries/ecs_mapping_editor_field.tsx @@ -6,7 +6,7 @@ */ import { produce } from 'immer'; -import { isEmpty, find, orderBy, sortedUniqBy, isArray, map } from 'lodash'; +import { each, isEmpty, find, orderBy, sortedUniqBy, isArray, map, reduce, get } from 'lodash'; import React, { forwardRef, useCallback, @@ -625,30 +625,47 @@ export const ECSMappingEditorField = ({ field, query, fieldRef }: ECSMappingEdit return currentValue; } - const tablesOrderMap = + const astOsqueryTables: Record< + string, + { + columns: OsqueryColumn[]; + order: number; + } + > = ast?.from?.value?.reduce( ( - acc: { [x: string]: number }, - table: { value: { alias?: { value: string }; value: { value: string } } }, - index: number - ) => { - acc[table.value.alias?.value ?? table.value.value.value] = index; - return acc; - }, - {} - ) ?? {}; - - const astOsqueryTables: Record = - ast?.from?.value?.reduce( - ( - acc: { [x: string]: OsqueryColumn[] }, - table: { value: { alias?: { value: string }; value: { value: string } } } - ) => { - const osqueryTable = find(osquerySchema, ['name', table.value.value.value]); - - if (osqueryTable) { - acc[table.value.alias?.value ?? table.value.value.value] = osqueryTable.columns; + acc: { + [x: string]: { + columns: OsqueryColumn[]; + order: number; + }; + }, + table: { + value: { + left?: { value: { value: string }; alias?: { value: string } }; + right?: { value: { value: string }; alias?: { value: string } }; + value?: { value: string }; + alias?: { value: string }; + }; } + ) => { + each(['value.left', 'value.right', 'value'], (valueKey) => { + if (valueKey) { + const osqueryTable = find(osquerySchema, [ + 'name', + get(table, `${valueKey}.value.value`), + ]); + + if (osqueryTable) { + acc[ + get(table, `${valueKey}.alias.value`) ?? get(table, `${valueKey}.value.value`) + ] = { + columns: osqueryTable.columns, + order: Object.keys(acc).length, + }; + } + } + }); return acc; }, @@ -660,75 +677,107 @@ export const ECSMappingEditorField = ({ field, query, fieldRef }: ECSMappingEdit return currentValue; } - /* - Simple query - select * from users; - */ - if ( - ast?.selectItems?.value?.length && - ast?.selectItems?.value[0].value === '*' && - ast.from?.value?.length && - ast?.from.value[0].value?.value?.value && - astOsqueryTables[ast.from.value[0].value.value.value] - ) { - const tableName = - ast.from.value[0].value.alias?.value ?? ast.from.value[0].value.value.value; - - return astOsqueryTables[ast.from.value[0].value.value.value].map((osqueryColumn) => ({ - label: osqueryColumn.name, - value: { - name: osqueryColumn.name, - description: osqueryColumn.description, - table: tableName, - tableOrder: tablesOrderMap[tableName], - suggestion_label: osqueryColumn.name, - }, - })); - } - - /* - Advanced query - select i.*, p.resident_size, p.user_time, p.system_time, time.minutes as counter from osquery_info i, processes p, time where p.pid = i.pid; - */ const suggestions = isArray(ast?.selectItems?.value) && ast?.selectItems?.value - // @ts-expect-error update types - ?.map((selectItem) => { - const [table, column] = selectItem.value?.split('.'); + ?.map((selectItem: { type: string; value: string; hasAs: boolean; alias?: string }) => { + if (selectItem.type === 'Identifier') { + /* + select * from routes, uptime; + */ + if (ast?.selectItems?.value.length === 1 && selectItem.value === '*') { + return reduce( + astOsqueryTables, + (acc, { columns: osqueryColumns, order: tableOrder }, table) => { + acc.push( + ...osqueryColumns.map((osqueryColumn) => ({ + label: osqueryColumn.name, + value: { + name: osqueryColumn.name, + description: osqueryColumn.description, + table, + tableOrder, + suggestion_label: osqueryColumn.name, + }, + })) + ); + return acc; + }, + [] as OsquerySchemaOption[] + ); + } - if (column === '*' && astOsqueryTables[table]) { - return astOsqueryTables[table].map((osqueryColumn) => ({ - label: osqueryColumn.name, - value: { - name: osqueryColumn.name, - description: osqueryColumn.description, - table, - tableOrder: tablesOrderMap[table], - suggestion_label: `${osqueryColumn.name}`, - }, - })); + /* + select i.*, p.resident_size, p.user_time, p.system_time, time.minutes as counter from osquery_info i, processes p, time where p.pid = i.pid; + */ + + const [table, column] = selectItem.value.includes('.') + ? selectItem.value?.split('.') + : [Object.keys(astOsqueryTables)[0], selectItem.value]; + + if (column === '*' && astOsqueryTables[table]) { + const { columns: osqueryColumns, order: tableOrder } = astOsqueryTables[table]; + return osqueryColumns.map((osqueryColumn) => ({ + label: osqueryColumn.name, + value: { + name: osqueryColumn.name, + description: osqueryColumn.description, + table, + tableOrder, + suggestion_label: `${osqueryColumn.name}`, + }, + })); + } + + if (astOsqueryTables[table]) { + const osqueryColumn = find(astOsqueryTables[table].columns, ['name', column]); + + if (osqueryColumn) { + const label = selectItem.hasAs ? selectItem.alias : column; + + return [ + { + label, + value: { + name: osqueryColumn.name, + description: osqueryColumn.description, + table, + tableOrder: astOsqueryTables[table].order, + suggestion_label: `${label}`, + }, + }, + ]; + } + } } - if (astOsqueryTables && astOsqueryTables[table]) { - const osqueryColumn = find(astOsqueryTables[table], ['name', column]); + /* + SELECT pid, uid, name, ROUND(( + (user_time + system_time) / (cpu_time.tsb - cpu_time.itsb) + ) * 100, 2) AS percentage + FROM processes, ( + SELECT ( + SUM(user) + SUM(nice) + SUM(system) + SUM(idle) * 1.0) AS tsb, + SUM(COALESCE(idle, 0)) + SUM(COALESCE(iowait, 0)) AS itsb + FROM cpu_time + ) AS cpu_time + ORDER BY user_time+system_time DESC + LIMIT 5; + */ - if (osqueryColumn) { - const label = selectItem.hasAs ? selectItem.alias : column; - - return [ - { - label, - value: { - name: osqueryColumn.name, - description: osqueryColumn.description, - table, - tableOrder: tablesOrderMap[table], - suggestion_label: `${label}`, - }, + if (selectItem.type === 'FunctionCall' && selectItem.hasAs) { + return [ + { + label: selectItem.alias, + value: { + name: selectItem.alias, + description: '', + table: '', + tableOrder: -1, + suggestion_label: selectItem.alias, }, - ]; - } + }, + ]; } return [];