Python 嵌入权限

Python 脚本的访问控制和安全限制 #

将 GraalPy 嵌入 Java 使用 GraalVM 多语言沙箱

Python 的 POSIX 接口 #

操作系统接口向 Python 脚本公开的方式是 GraalPy 特定的。默认情况下,所有访问都通过 Java 接口进行路由,但一些软件包依赖于 POSIX API 的详细信息,需要直接访问原生系统。

Graal 语言(在 Truffle 框架 上实现的语言)通常使用 Truffle 抽象层 来实现与系统相关的函数,该层与操作系统无关,并为用户提供扩展点,以便将 GraalPy 或其他 Graal 语言嵌入 Java 应用程序中。例如,请参见 Truffle 文件系统服务提供者

标准 Python 库也提供了 OS 抽象,但公开了更低级的接口。例如,os 模块直接公开了某些 POSIX 函数。在非 POSIX 平台上,此接口在一定程度上被模拟。

GraalPy 提供了两种替代实现(分别称为“后端”)来实现内置 Python 模块(如 os)提供的与系统相关的功能。PosixModuleBackend 选项决定使用哪个后端:有效值为 nativejava

原生后端 #

此后端直接调用 POSIX API,方式与 CPython(参考 Python 实现)基本相同。

这种方法与 CPython 最兼容,并提供对底层 OS 接口的直接访问,而无需中间模拟层。

默认情况下,此实现绕过 Truffle 抽象层,因此它不受沙箱限制,不支持 Truffle 文件系统服务提供者 的自定义实现,以及与系统接口相关的其他多语言 API 提供者。

当 GraalPy 通过 graalpy 或任何其他 Python 相关启动器启动时,默认情况下会选择原生后端。例外情况是带有 -managed 后缀的 Python 相关启动器(仅在 Oracle GraalVM 中可用,例如 graalpy-managed),它们默认情况下使用 java POSIX 后端。

原生后端的限制

已知的限制是

  • os.fork 不受支持
  • _posixsubprocess.fork_exec 不支持 preexec_fn 参数

Java 后端 #

此后端使用 Truffle 抽象层,因此支持与系统接口和沙箱相关的自定义多语言 API 提供者。由于这种抽象是 POSIX 独立的,因此它不会公开所有必要的功能。某些功能被模拟,而某些功能不受支持。

当 GraalPy 通过 Context API 运行时,即 嵌入 Java 应用程序,或者使用带有 -managed 后缀的 Python 相关启动器(仅在 Oracle GraalVM 中可用)启动时,Java 后端是默认后端。

Java 后端的限制

GraalPy 可以记录有关在运行时执行的函数的已知不兼容性的信息,其中包括与 OS 接口相关的函数。要打开此日志记录,请使用命令行选项 --log.python.compatibility.level=FINE(或其他所需的日志记录级别)。

Java 后端的已知限制是

  • 其状态与实际的 OS 状态断开连接,这特别适用于
    • 文件描述符:Python 级别的文件描述符不能在原生代码中使用。
    • 当前工作目录:在启动时初始化为当前工作目录,但随后单独维护。因此,例如,Python 中的 chdir 不会更改进程的实际当前工作目录。
    • umask:与当前工作目录具有相同的限制,但它始终初始化为 0022,而不管启动时的实际系统值如何。
  • 文件访问/修改时间的解析取决于 JDK。Java 后端能保证的最佳分辨率是秒级。
  • os.access 和任何其他基于 faccessat POSIX 函数的功能不支持
    • 有效 ID。
    • follow_symlinks=False,除非模式仅为 F_OK

Python 原生扩展 #

Python 原生扩展默认情况下作为原生二进制文件运行,可以完全访问底层系统。请参见 嵌入限制

运行原生扩展所需的上下文权限是

.allowIO(IOAccess.ALL)
.allowCreateThread(true)
.allowNativeAccess(true)

联系我们