与OS X钥匙串相关的不可见文件

14

看起来一个keychain文件(扩展名为.keychain)通常会有一个与之关联的不可见文件,位于同一目录下。

这个不可见文件始终具有以下属性:

  • It is empty (zero bytes).
  • Its permissions are 0444 (read-only for all users).
  • Its name consists of .fl followed by 8 hex characters. For example:

    .fl043D1EDD
    .fl947E1BDB
    .fl9FAF0136
    .fl12663120
    .fl8E6EFC6C
    .flCF600F4B
    .fl1D8ECE61
    .fl0D1D1BA9
    .fl79E88CD1
    .fl62323D2F
    .fl75262C83
    .fl652F188E
    

这个不可见的文件可以被删除,但是当钥匙串内容下次被修改时,这个不可见的文件将会以同样的名称重新创建。

以下是一些步骤,使用Keychain Access实用程序进行演示:

  1. 通过选择文件 > 新建钥匙串并选择要创建它的目录来创建一个新的钥匙串。在与新钥匙串相同的目录中会创建一个不可见的文件。
  2. 删除不可见的文件(使用Finder或终端)。
  3. 修改钥匙串的内容。例如,通过选择文件 > 新建安全笔记项向钥匙串添加一个安全笔记。不可见的文件将以相同的名称重新创建。
  4. 通过选择文件 > 删除钥匙串 > 删除参考和文件来删除钥匙串。不可见的文件也将被删除。

我已确认这个问题发生在OS X 10.810.9上。


更新

使用苹果终端中的security工具操作钥匙串时,同样会创建相同的不可见文件:

  1. Create a new keychain. An invisible file is also created.

    $ cd ~/Desktop/
    $ ls -1a
    .
    ..
    $ /usr/bin/security create-keychain ~/Desktop/Test.keychain
    $ ls -1a
    .
    ..
    .fl1BCE4B9A
    Test.keychain
    
  2. Delete the invisible file.

    $ rm .fl1BCE4B9A
    $ ls -1a
    .
    ..
    Test.keychain
    
  3. Modify the keychain's contents (eg: by adding an internet password). The invisible file is recreated with the same name.

    $ /usr/bin/security add-internet-password -a account -s google.com -w password ~/Desktop/Test.keychain
    $ ls -1a
    .
    ..
    .fl1BCE4B9A
    Test.keychain
    
  4. Delete the keychain. The invisible file is deleted too.

    $ /usr/bin/security delete-keychain ~/Desktop/Test.keychain
    $ ls -1a
    .
    ..
    

问题

  1. 为什么会创建这些不可见文件?它们的目的是什么?
  2. 文件名中的fl是什么意思?
  3. 文件名中的8个十六进制字符是什么?是一种唯一标识符或哈希值来识别钥匙串吗?
  4. 是否有办法防止在创建或修改钥匙串时创建这些文件?

同样也会在OS X 10.7下发生。 - JWWalker
1个回答

13

经过大量的调查研究,我已经回答了大部分问题:

  1. 隐形文件为钥匙串数据库实现了写锁
  2. .fl是安全框架中AtomicFile类创建的锁文件的文件名前缀。
  3. 文件名中8个十六进制字符是钥匙串文件名SHA-1哈希的开头。例如,如果钥匙串文件名为Test.keychain,则其文件名的SHA-1哈希以1BCE4B9A...开头,因此锁文件将被命名为.fl1BCE4B9A
  4. 我还没有发现防止在创建或修改钥匙串时创建锁文件的方法。我认为这可能是不可能的,但如果有人能找到一种方法,我会非常感兴趣

以下是我的调查细节:

钥匙串的锁定/解锁状态

我注意到隐形文件不受钥匙串locked/unlocked状态的影响。如果隐形文件已被删除,则锁定/解锁钥匙串不会重新创建隐形文件。

系统调用

我使用苹果公司的Instruments工具中的文件活动模板进行了一些调查。

这些系统调用负责操作隐形文件:

  • 当创建新的钥匙串时,创建不可见文件:
    • Security::AtomicFile::create(unsigned short)
    • Security::RefPointer<Security::AtomicLockedFile>::release_internal()
    • 相关调用树部分
  • 当修改钥匙串内容时,重新创建不可见文件:
    • Security::AtomicFile::write()
    • Security::RefPointer<Security::AtomicLockedFile>::release_internal()
    • 相关调用树部分
  • 当删除钥匙串时,删除不可见文件:

C++ 文件

这些是相关的文件和类(源代码可从Apple Open Source获取,适用于OS X 10.9.2):
  • AtomicFile.cpp
    • Security::AtomicFile
    • Security::AtomicLockedFile
    • Security::AtomicTempFile
    • Security::LocalFileLocker
  • AppleDatabase.cpp
    • Security::AppleDatabase
    • Security::DbModifier

源代码中的注释

那些文件中的注释提供了一些线索:

  • AtomicFile::AtomicFile()
    • "计算此文件的锁定文件的名称"
  • AtomicFile::create()
    • "锁定文件以进行写入并返回新创建的AtomicTempFile。"
    • "现在我们已经创建了锁定和新的db文件,创建一个临时文件对象。"
  • LocalFileLocker::lock()
    • "如果锁定文件不存在,则创建它"
    • "尝试获取对该文件的独占访问权"
    • "检查并查看我们访问的文件是否仍然存在。 如果不存在,则另一个文件由于哈希冲突共享了我们的文件锁,并且已将我们的锁丢弃 - 或者用户自己删除了锁定文件。"
  • DbModifier::modifyDatabase()
    • "现在我们持有写锁"
  • AtomicFile::write()
    • "锁定数据库文件以进行写入并返回新创建的AtomicTempFile。"
  • AtomicFile::performDelete()
    • "获取写锁并删除文件。"
    • "取消链接我们的锁定文件"

生成锁文件名

我在AtomicFile构造函数中发现了这段代码:

char buffer[256];
sprintf(buffer, "%08X", hash);
mLockFilePath = mDir + ".fl" + buffer;

其中hash是钥匙串文件名的SHA-1哈希的前4个字节。

注意:仅使用哈希的4个字节(32位),存在合理的哈希冲突机会,这在LocalFileLocker::lock()的注释中提到。

锁的操作

使用flock()系统调用来操作锁定文件上的锁。

以下是当钥匙串数据库被锁定以进行写入时的调用树:

DbModifier::createDatabase() or ::modifyDatabase() or ::deleteDatabase()
  AtomicFile::create() or ::write() or ::performDelete()
    AtomicLockedFile::lock()
      LocalFileLocker::lock()
        flock(mLockFile, LOCK_EX)  // exclusive lock

在写入后解锁时:

DbModifier::commit()
  AtomicTempFile::commit()
    RefPointer<AtomicLockedFile>::setPointer(AtomicLockedFile*)
      RefPointer<AtomicLockedFile>::release_internal()
        AtomicLockedFile::~AtomicLockedFile()  // destructor
          AtomicLockedFile::unlock()
            LocalFileLocker::unlock()
              flock(mLockFile, LOCK_UN)  // unlock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接