AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 491823
Accepted
Reinstate Monica
Reinstate Monica
Asked: 2019-01-01 13:13:22 +0800 CST2019-01-01 13:13:22 +0800 CST 2019-01-01 13:13:22 +0800 CST

强制关闭文件描述符的最安全方法

  • 772

有时您需要卸载文件系统或分离循环设备,但这是busy因为打开的文件描述符,可能是因为smb服务器进程。

要强制卸载,您可以终止有问题的进程(或 try kill -SIGTERM),但这会关闭smb连接(即使它打开的某些文件不需要关闭)。

这里使用gdbto call描述了一种强制进程关闭给定文件描述符的 hacky 方法close(fd)。然而,这似乎很危险。如果关闭的描述符被回收了怎么办?该进程可能使用旧的存储描述符,但没有意识到它现在指的是完全不同的文件。

我有一个想法,但不知道它有什么样的缺陷:使用gdb,打开/dev/null方式O_WRONLY(编辑:建议O_PATH作为更好的选择的评论),然后dup2关闭有问题的文件描述符并将其描述符重用于/dev/null. 这样,对文件描述符的任何读取或写入都将失败。

像这样:

sudo gdb -p 234532
(gdb) set $dummy_fd = open("/dev/null", 0x200000) // O_PATH
(gdb) p dup2($dummy_fd, offending_fd)
(gdb) p close($dummy_fd)
(gdb) detach
(gdb) quit

会出什么问题?

linux file-descriptors
  • 2 2 个回答
  • 7901 Views

2 个回答

  • Voted
  1. Best Answer
    thrig
    2019-01-03T11:12:03+08:002019-01-03T11:12:03+08:00

    摆弄一个流程gdb几乎从来都不是安全的,但如果有一些紧急情况并且流程需要保持开放并且所涉及的所有风险和代码都被理解,则可能是必要的。

    大多数情况下,我会简单地终止该进程,尽管某些情况可能会有所不同,并且可能取决于环境、谁拥有相关系统和所涉及的进程、该进程正在做什么、是否有关于“可以杀死它”或“不,先联系某某”等。这些细节可能需要在尘埃落定后的事后会议上制定。如果有计划的迁移,最好提前检查是否有任何进程打开了有问题的文件描述符,以便可以在非紧急设置中处理这些问题(cron 作业或仅在迁移时的凌晨运行的其他计划任务如果您只在白天检查,可能很容易错过)。

    只写与读取与读写

    您重新打开文件描述符的想法O_WRONLY是有问题的,因为并非所有文件描述符都是只写的。John Viega 和 Matt Messier 在“Secure Programming Cookbook for C and C++”一书中采用了更细致入微的方法,并以不同于标准输出和标准错误的方式处理标准输入(第 25 页,“安全管理文件描述符”):

    static int open_devnull(int fd) {
      FILE *f = 0;
    
      if (!fd) f = freopen(_PATH_DEVNULL, "rb", stdin);
      else if (fd == 1) f = freopen(_PATH_DEVNULL, "wb", stdout);
      else if (fd == 2) f = freopen(_PATH_DEVNULL, "wb", stderr);
      return (f && fileno(f) == fd);
    }
    

    在这种gdb情况下,需要检查描述符(或FILE *句柄)是只读的、读写的还是只写的,并在/dev/null. 如果不是这样,如果进程试图从中读取,现在只写的曾经只读句柄将导致不必要的错误。

    会出什么问题?

    当它的文件描述符(可能还有 FILE *句柄)在幕后被摆弄时,进程的行为究竟如何取决于进程,并且如果该描述符永远不会被使用,则从“没什么大不了”到现在有一​​个“噩梦模式”由于未刷新的数据、没有正确关闭文件的指示器或其他一些未预料到的问题,导致文件损坏。

    对于FILE *句柄,fflush(3)在关闭句柄之前添加调用可能会有所帮助,或者可能导致双缓冲或其他一些问题;这是在gdb 不确切知道源代码的作用和期望的情况下进行随机调用的几个危险之一。fd 软件还可能在描述符或句柄之上构建额外的复杂层,FILE *这些也可能需要处理。猴子修补代码很容易变成猴子扳手。

    概括

    向进程发送标准终止信号应该给它一个正确关闭资源的机会,就像系统正常关闭时一样。摆弄一个过程gdb可能不会正确地结束事情,并且可能会使情况变得更糟。

    • 2
  2. pizdelect
    2019-01-03T15:12:00+08:002019-01-03T15:12:00+08:00

    使用 O_WRONLY 打开 /dev/null,然后使用 dup2 关闭有问题的文件描述符并将其描述符重新用于 /dev/null。这样,对文件描述符的任何读取或写入都将失败。

    如果将描述符复制到/dev/null,则任何写入都不会失败,而是成功,并且读取将成功并返回 0 (eof)。

    这可能是也可能不是您想要的。

    在 linux 上,您还可以打开一个带有 flags = 3 ( O_WRONLY|O_RDWRaka O_NOACCESS) 的文件,这将导致任何读取或写入失败EBADF。

    该文件仅可用于 ioctls - 这带来了其他答案和评论中未提及的危险:读取和写入并不是对文件描述符进行的唯一操作。(关于lseek或ftruncate?)。

    更新:

    我发现了比无证更好的东西O_WRONLY|O_RDWR:O_PATH = 010000000 / 0x200000。根据 open(2) 联机帮助页:

    O_PATH (since Linux 2.6.39)
         Obtain a file descriptor that can be used for two  purposes:  to
         indicate a location in the filesystem tree and to perform opera-
         tions that act purely at the file descriptor  level.   The  file
         itself  is not opened, and other file operations (e.g., read(2),
         write(2), fchmod(2), fchown(2), fgetxattr(2), mmap(2)) fail with
         the error EBADF.
    
        The  following operations can be performed on the resulting file
         descriptor:
    
        *  close(2); fchdir(2) (since Linux 3.5); fstat(2) (since  Linux
            3.6).
    
        *  Duplicating  the  file  descriptor (dup(2), fcntl(2) F_DUPFD,
            etc.).
    
    • 2

相关问题

  • 有没有办法让 ls 只显示某些目录的隐藏文件?

  • 使用键盘快捷键启动/停止 systemd 服务 [关闭]

  • 需要一些系统调用

  • astyle 不会更改源文件格式

  • 通过标签将根文件系统传递给linux内核

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve