Coverage Report

Created: 2023-09-25 07:09

/src/usbguard/src/Library/UEventParser.cpp
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright (C) 2016 Red Hat, Inc.
3
//
4
// This program is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 2 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17
// Authors: Daniel Kopecek <dkopecek@redhat.com>
18
//
19
#ifdef HAVE_BUILD_CONFIG_H
20
  #include <build-config.h>
21
#endif
22
23
#include "UEventParser.hpp"
24
#include "UEvent.hpp"
25
#include "Common/Utility.hpp"
26
27
#include "usbguard/Logger.hpp"
28
29
#include <fstream>
30
31
#if TAO_PEGTL_VERSION_MAJOR >= 3
32
  #include <tao/pegtl/contrib/trace.hpp>
33
#else
34
  #include <tao/pegtl/contrib/tracer.hpp>
35
#endif
36
using namespace tao;
37
38
namespace usbguard
39
{
40
  namespace UEventParser
41
  {
42
    template<typename Rule>
43
    struct actions
44
      : pegtl::nothing<Rule> {};
45
46
    template<>
47
    struct actions<attribute> {
48
      template<typename Input>
49
      static void apply(const Input& in, UEvent& uevent)
50
126k
      {
51
126k
        try {
52
126k
          const auto p = in.string().find_first_of('=');
53
54
126k
          if (p == std::string::npos || p == (in.string().size() - 1)) {
55
0
            throw pegtl::parse_error("invalid attribute format", in);
56
0
          }
57
58
126k
          const std::string key = in.string().substr(0, p);
59
126k
          const std::string value = trim(in.string().substr(p + 1, std::string::npos), std::string("\n\0", 2));
60
61
126k
          for (const std::string header_key : {
62
126k
              "ACTION", "DEVPATH"
63
253k
            }) {
64
253k
            if (key == header_key) {
65
              /*
66
               * Sanity check the value only if the value is already assigned,
67
               * because with umockdev device manager we need to parse ACTION
68
               * and DEVPATH from the uevent data and we don't know it before
69
               * that.
70
               */
71
1.28k
              if (!uevent.getAttribute(header_key).empty()) {
72
1.28k
                if (value != uevent.getAttribute(header_key)) {
73
239
                  throw pegtl::parse_error("header value mismatch", in);
74
239
                }
75
1.28k
              }
76
1.28k
            }
77
253k
          }
78
126k
          uevent.setAttribute(key, value);
79
126k
        }
80
126k
        catch (const pegtl::parse_error& ex) {
81
239
          throw;
82
239
        }
83
126k
        catch (const std::exception& ex) {
84
0
          throw pegtl::parse_error(ex.what(), in);
85
0
        }
86
126k
      }
87
    };
88
89
    template<>
90
    struct actions<action> {
91
      template<typename Input>
92
      static void apply(const Input& in, UEvent& uevent)
93
1.19k
      {
94
1.19k
        uevent.setAttribute("ACTION", in.string());
95
1.19k
      }
96
    };
97
98
    template<>
99
    struct actions<devpath> {
100
      template<typename Input>
101
      static void apply(const Input& in, UEvent& uevent)
102
1.08k
      {
103
1.08k
        uevent.setAttribute("DEVPATH", in.string());
104
1.08k
      }
105
    };
106
  } /* namespace UEventParser */
107
108
  void parseUEventFromFile(const std::string& uevent_path, UEvent& uevent, bool attributes_only, bool trace)
109
0
  {
110
0
    std::ifstream uevent_stream(uevent_path);
111
112
0
    if (uevent_stream.good()) {
113
0
      std::string uevent_string(4096, 0);
114
0
      uevent_stream.readsome(&uevent_string[0], uevent_string.capacity());
115
0
      const auto read_size = uevent_stream.gcount();
116
117
0
      if (read_size > 0) {
118
0
        uevent_string.resize(read_size);
119
0
        parseUEventFromString(uevent_string, uevent, attributes_only, trace);
120
0
      }
121
0
    }
122
0
    else {
123
0
      throw std::runtime_error("failed to open uevent source file");
124
0
    }
125
0
  }
126
127
  template<class G>
128
  void parseUEventFromString(const std::string& uevent_string, UEvent& uevent, bool trace)
129
1.21k
  {
130
1.21k
    try {
131
1.21k
      tao::pegtl::string_input<> in(uevent_string, std::string());
132
133
1.21k
      if (!trace) {
134
1.21k
        tao::pegtl::parse<G, UEventParser::actions>(in, uevent);
135
1.21k
      }
136
0
      else {
137
0
#if TAO_PEGTL_VERSION_MAJOR >= 3
138
0
        tao::pegtl::complete_trace<G, UEventParser::actions>(in, uevent);
139
#else
140
        tao::pegtl::parse<G, UEventParser::actions, tao::pegtl::tracer>(in, uevent);
141
#endif
142
0
      }
143
1.21k
    }
144
1.21k
    catch (...) {
145
239
      throw;
146
239
    }
147
1.21k
  }
Unexecuted instantiation: void usbguard::parseUEventFromString<usbguard::UEventParser::attributes>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, usbguard::UEvent&, bool)
void usbguard::parseUEventFromString<usbguard::UEventParser::grammar>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, usbguard::UEvent&, bool)
Line
Count
Source
129
1.21k
  {
130
1.21k
    try {
131
1.21k
      tao::pegtl::string_input<> in(uevent_string, std::string());
132
133
1.21k
      if (!trace) {
134
1.21k
        tao::pegtl::parse<G, UEventParser::actions>(in, uevent);
135
1.21k
      }
136
0
      else {
137
0
#if TAO_PEGTL_VERSION_MAJOR >= 3
138
0
        tao::pegtl::complete_trace<G, UEventParser::actions>(in, uevent);
139
#else
140
        tao::pegtl::parse<G, UEventParser::actions, tao::pegtl::tracer>(in, uevent);
141
#endif
142
0
      }
143
1.21k
    }
144
1.21k
    catch (...) {
145
239
      throw;
146
239
    }
147
1.21k
  }
148
149
  void parseUEventFromString(const std::string& uevent_string, UEvent& uevent, bool attributes_only, bool trace)
150
1.21k
  {
151
1.21k
    if (attributes_only) {
152
0
      parseUEventFromString<UEventParser::attributes>(uevent_string, uevent, trace);
153
0
    }
154
1.21k
    else {
155
1.21k
      parseUEventFromString<UEventParser::grammar>(uevent_string, uevent, trace);
156
1.21k
    }
157
1.21k
  }
158
} /* namespace usbguard */
159
160
/* vim: set ts=2 sw=2 et */