Skip to content
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

ts: Make dostimestamp() fall back to epoch on parse failures #37

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

syzzer
Copy link

@syzzer syzzer commented Dec 13, 2023

If we detect corrupt timestamp data, fall back to the DOS epoch instead of passing on the ValueError raised by datetime(), which would stop the parsing run all together.

If we detect corrupt timestamp data, fall back to the DOS epoch instead
of passing on the ValueError from datetime(), which would stop parsing
all together.
@Schamper
Copy link
Member

There's a difference between a corrupt timestamp and an epoch timestamp though. Where does this currently break, perhaps that code should be more resilient? Or can you include a unit test for a corrupt timestamp?

@syzzer
Copy link
Author

syzzer commented Jan 29, 2024

There's a difference between a corrupt timestamp and an epoch timestamp though. Where does this currently break, perhaps that code should be more resilient? Or can you include a unit test for a corrupt timestamp?

That would involve every user of dostimestamp() wrapping the call in a try/except block. That might arguably be more correct from a layering perspective, but seems quite error-prone and tedious.

In my case, the exception was passed on by dissect.target's filesystems/exfat.py:

        ctime = dostimestamp(fe.create_time, fe.create_offset).replace(tzinfo=c_tz)
        mtime = dostimestamp(fe.modified_time, fe.modified_offset).replace(tzinfo=m_tz)
        atime = dostimestamp(fe.access_time).replace(tzinfo=a_tz)`

dissect.fat currently seems to use the DOS Epoch as a fallback, which is why I did the same here. See e.g. these accessors in class DirectoryEntry:

    @property
    def ctime(self):
        if self.dirent.DIR_CrtDate and self.dirent.DIR_CrtTime:
            return dostimestamp(
                (self.dirent.DIR_CrtDate << 16) | self.dirent.DIR_CrtTime,
                self.dirent.DIR_CrtTimeTenth,
            )
        return datetime.datetime(1980, 1, 1)

    @property
    def atime(self):
        if self.dirent.DIR_LstAccDate:
            return dostimestamp(self.dirent.DIR_LstAccDate << 16)
        return datetime.datetime(1980, 1, 1)

So I took that approach and applied it for corrupted data too. If it helps, I can of course document that "DOS Epoch" is the fallback for unavailable or corrupted timestamps.

@Schamper
Copy link
Member

Our ExFAT implementation hasn't been properly working for years and needs to be rewritten, so I wouldn't use that code as a reference for proper usage of this API. Perhaps the data it's trying to parse as a timestamp isn't even correct in the first place. As it currently stands I don't think this function should silently fallback to an epoch timestamp. In your current error case, I'd first start doubting the ExFAT code itself.

Doing this for this function also isn't in line with any of the other timestamp parsing functions. You'd want to at least log if an error occurred parsing a timestamp, but you don't have any useful context here on where or what timestamp actually failed to parse. That's information a consumer of this API has though, and could also decide on that the right course of action is (falling back on a default epoch, setting None, or breaking)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants