-
Notifications
You must be signed in to change notification settings - Fork 347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PSIP table parsing should be more robust #623
Comments
Better validation is always a good plan. As I recall, at least some of the code may have originated from libdvbv5. Looking at that upstream repo I see a number of commits about improving robustness over the years. Does it make any sense to either resync with, or perhaps just depend on, the upstream library (yes, some refactor may be needed)? |
By and large I do agree with doing more checks and especially I like optimizing performance by improving buffer allocations.
Line 626 in mpegtables.cpp, commit fe6d17e, the additional check on DescriptorID, is a functional change. Is this really checked against the relevant standards? Is the IsVideo() check that preceeds it really not good enough to check that this is a video stream? If the IsVideo() not good enough is that not something that also should be fixed? Which stream created the problem for which this change is a fix? Really sure that this does not break anything? For a functional change I would appreciate a separate commit, with a clear description of what problem is fixed by this commit, possible a stream that shows the problem so that it can be reproduced. |
Klaas, Yes, my motivation is to eliminate bugs in MythTV to make it a better program. We run three well know static analysis tools (clang-tidy, Coverity, and cppcheck) and one lesser known static analysis tool (clazy) in order to point out problems in the code or point out places where the code could be improved. I have taken on the task of trying to fix these warnings (or at least analyze and notate why they shouldn't be fixed) because no-one else seems to have the time. As you pointed out I occasionally make mistakes, but my track record over the last five years is pretty damn good. When I started working on MythTV even a simple "clean" compilation threw several hundred warning messages. That was long before I started looking at the output from the static analysis tools. My original comment should have referenced issue #589 (not 596), which was due to I had already created a separate commit for the functional change in I specifically wanted you to look at these proposed changes because you spend far more time in this part of the code than I do, and probably understand it better than I ever will. I see you're in basic agreement that checking is good, as is optimizing buffer allocations. What about the idea of discarding a malformed table vs processing only the parts of the table that fit within the packet? I think that if any part of a table is determined as corrupt, we shouldn't process any part of that table. I've come to believe that the constructor throwing an error is the correct response to an invalid packet, but there is not a lot of error processing in MythTV that is designed using throw/catch (although there is more than I expected to find when I checked). The other approach would be to set a flag that says this newly allocated data structure is corrupt, shouldn't be used, and should be immediately deleted. There's no memory management when throwing an error because the object is never created. I don't think adding a throw to the code causes any extra processing to the non-throwing case. If the throw is executed you're already into error handling code, and a few extra cycles to find the landing spot for the throw (which should always be the first landing spot) shouldn't cause too much slowdown. Its been a long time since I looked at compiler internals though. What about the idea of splitting out the ATSC/SCTE/DVB tests into their own separate test files, as there are going to be significantly more test cases than before? Or should they all remain in a single file? These are the sorts of questions I was hoping to address by filing this issue. |
Gary, thanks for the pointer to libdvbv5. I looked at it and and it doesn't seem to bear that much resemblance to our code. |
Given the recent issue with noisy recordings (#596) and the ~40 Coverity errors related to blindly trusting data received from the network, I thought I'd take a look at trying to fix some of these errors.
As it stands today, the only validity checking that the PSIP table parsers perform is to validate the CRC (if present). Once processing of a table begins, there are no checks to ensure that the table is consistent or to ensure that processing doesn't read past the end of the received data. If any errors have crept into the tables before the application of the CRC (most tables require a CRC, but not all) then it is entirely possible for the parser to access memory past the end of the received data. This could cause unexpected behavior, anything from a glitch in AV processing to a crash of the system. MythTV should be able to recognize malformed tables, drop the portions that run out of bounds or drop them entirely, and then continue running.
I have a tree where I've enhanced the ATSC table parsers to perform bounds checking at each step, and to protect the system by dropping any field in a table that exceeds those bounds (and drop all subsequent fields). This should prevent MythTV from processing any data that could potentially crash the system. These parsers currently perform better than the existing parsers, in large part because they calculate the maximum table size up front and perform a single memory allocation, making those parts of the functions O(1) instead of the current O(log2 n). There's also no data copying each time the table is resized. The remainder of the functions are still O(n) processing the tables.
Example timing without optimization:
and with optimization
I don't believe that these changes go far enough. I think MythTV should completely drop any PSIP table when it detects that any of the fields exceeds the bounds of the received data. It should just throw an error from the constructor and let the caller handle it.
If there's agreement that this level of checking is worthwhile, then all the other *tables.cpp files should have similar changes.
The text was updated successfully, but these errors were encountered: