get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2218278/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2218278,
    "url": "http://patchwork.ozlabs.org/api/patches/2218278/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260331173656.35305-4-xukl2019@sjtu.edu.cn/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260331173656.35305-4-xukl2019@sjtu.edu.cn>",
    "list_archive_url": null,
    "date": "2026-03-31T17:36:26",
    "name": "[v1,3/3] contrib/plugins: handle more loader open syscalls in the syscall filter demos",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "4572e55716ed55ddc629f688299a0096e4662572",
    "submitter": {
        "id": 93022,
        "url": "http://patchwork.ozlabs.org/api/people/93022/?format=api",
        "name": "XU Kailiang",
        "email": "xukl2019@sjtu.edu.cn"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260331173656.35305-4-xukl2019@sjtu.edu.cn/mbox/",
    "series": [
        {
            "id": 498254,
            "url": "http://patchwork.ozlabs.org/api/series/498254/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=498254",
            "date": "2026-03-31T17:36:25",
            "name": "contrib/plugins: add syscall-filter local-library demos",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/498254/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2218278/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2218278/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)",
        "Received": [
            "from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4flgwF0rlfz1yGw\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 01 Apr 2026 08:18:51 +1100 (AEDT)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1w7gTL-0008Rl-0V; Tue, 31 Mar 2026 17:18:03 -0400",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <xukl2019@sjtu.edu.cn>)\n id 1w7dDn-0007Hl-Be\n for qemu-devel@nongnu.org; Tue, 31 Mar 2026 13:49:47 -0400",
            "from smtp232.sjtu.edu.cn ([202.120.2.232])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <xukl2019@sjtu.edu.cn>)\n id 1w7dDh-0000Ki-9D\n for qemu-devel@nongnu.org; Tue, 31 Mar 2026 13:49:45 -0400",
            "from proxy188.sjtu.edu.cn (smtp188.sjtu.edu.cn [202.120.2.188])\n by smtp232.sjtu.edu.cn (Postfix) with ESMTPS id 1ABD21009F96B;\n Wed,  1 Apr 2026 01:38:12 +0800 (CST)",
            "from xuklXiaoxin (unknown [202.120.32.222])\n by proxy188.sjtu.edu.cn (Postfix) with ESMTPSA id C9BE237C8CA;\n Wed,  1 Apr 2026 01:38:11 +0800 (CST)"
        ],
        "From": "XU Kailiang <xukl2019@sjtu.edu.cn>",
        "To": "qemu-devel <qemu-devel@nongnu.org>",
        "Cc": "=?utf-8?q?Alex_Benn=C3=A9e?= <alex.bennee@linaro.org>,\n Pierrick Bouvier <pierrick.bouvier@linaro.org>,\n Alexandre Iooss <erdnaxe@crans.org>, Mahmoud Mandour <ma.mandourr@gmail.com>,\n Ziyang Zhang <functioner@sjtu.edu.cn>, Yun Wang <yunwang94@sjtu.edu.cn>,\n Mingyuan Xia <xiamy@ultrarisc.com>, Zhengwei Qi <qizhwei@sjtu.edu.cn>,\n XU Kailiang <xukl2019@sjtu.edu.cn>",
        "Subject": "[PATCH v1 3/3] contrib/plugins: handle more loader open syscalls in\n the syscall filter demos",
        "Date": "Wed,  1 Apr 2026 01:36:26 +0800",
        "Message-ID": "<20260331173656.35305-4-xukl2019@sjtu.edu.cn>",
        "X-Mailer": "git-send-email 2.53.0",
        "In-Reply-To": "<20260331173656.35305-1-xukl2019@sjtu.edu.cn>",
        "References": "<20260331173656.35305-1-xukl2019@sjtu.edu.cn>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Received-SPF": "pass client-ip=202.120.2.232;\n envelope-from=xukl2019@sjtu.edu.cn;\n helo=smtp232.sjtu.edu.cn",
        "X-Spam_score_int": "1",
        "X-Spam_score": "0.1",
        "X-Spam_bar": "/",
        "X-Spam_report": "(0.1 / 5.0 requ) BAYES_00=-1.9,\n RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=1, RCVD_IN_VALIDITY_RPBL_BLOCKED=1,\n SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no",
        "X-Spam_action": "no action",
        "X-Mailman-Approved-At": "Tue, 31 Mar 2026 17:18:00 -0400",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "qemu development <qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"
    },
    "content": "Extend both syscall-filter demo plugins so the library redirection logic\nhandles open() and openat2() in addition to openat().\n\nFor openat2(), keep the fast path for unrelated library loads by reading\nthe guest pathname first and only decoding struct open_how after the\npathname matches the demo library name. Update the example README files\nand overview text so the reproduced commands and behavior describe all\nsupported loader entry points.\n\nSigned-off-by: XU Kailiang <xukl2019@sjtu.edu.cn>\nCo-authored-by: Ziyang Zhang <functioner@sjtu.edu.cn>\n---\n .../README.rst                                |  5 +-\n .../plugins/syscall_filter_callback_qsort.c   | 61 +++++++++++++++--\n .../syscall_filter_zlib-example/README.rst    |  5 +-\n contrib/plugins/syscall_filter_zlib.c         | 65 +++++++++++++++++--\n docs/about/emulation.rst                      |  6 +-\n 5 files changed, 124 insertions(+), 18 deletions(-)",
    "diff": "diff --git a/contrib/plugins/syscall_filter_callback_qsort-example/README.rst b/contrib/plugins/syscall_filter_callback_qsort-example/README.rst\nindex e2bba7e2b6..ab758e358b 100644\n--- a/contrib/plugins/syscall_filter_callback_qsort-example/README.rst\n+++ b/contrib/plugins/syscall_filter_callback_qsort-example/README.rst\n@@ -8,8 +8,9 @@ interception on ``qemu-x86_64``.\n \n * ``callback-demo.c`` is linked against ``libdemo-callback-qsort.so`` and calls\n   ``callback_qsort()`` directly.\n-* The plugin intercepts the loader's ``openat()`` and returns a file\n-  descriptor for ``./libdemo-callback-qsort-thunk.so`` instead.\n+* The plugin intercepts the loader's ``open()``, ``openat()``, or\n+  ``openat2()`` and returns a file descriptor for\n+  ``./libdemo-callback-qsort-thunk.so`` instead.\n * ``callback-thunk.S`` issues a ``START`` magic syscall for ``qsort()`` and a\n   ``RESUME`` magic syscall from a guest return trampoline.\n * ``contrib/plugins/syscall_filter_callback_qsort.c`` runs host ``qsort()``\ndiff --git a/contrib/plugins/syscall_filter_callback_qsort.c b/contrib/plugins/syscall_filter_callback_qsort.c\nindex 45a83cb5b1..8c6c0ddb91 100644\n--- a/contrib/plugins/syscall_filter_callback_qsort.c\n+++ b/contrib/plugins/syscall_filter_callback_qsort.c\n@@ -4,7 +4,7 @@\n  * x86_64-only prototype that demonstrates a callback-capable syscall filter\n  * plugin by redirecting a qsort() thunk library and bridging comparator calls\n  * back into guest translated code with ucontext. The loader redirection\n- * handles openat().\n+ * handles open(), openat(), and openat2().\n  *\n  * This demo intentionally assumes a linux-user run with guest_base == 0 on a\n  * little-endian 64-bit host, so guest virtual addresses are directly usable\n@@ -36,7 +36,14 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;\n #define GUEST_STRING_LIMIT (1 << 20)\n #define CALLBACK_QSORT_MAX_ELEMS (1 << 20)\n #define CALLBACK_QSORT_STACK_SIZE (1 << 20)\n+#define X86_64_OPEN_NR 2\n #define X86_64_OPENAT_NR 257\n+#define X86_64_OPENAT2_NR 437\n+\n+typedef struct GuestOpenHow {\n+    uint64_t flags;\n+    uint64_t mode;\n+} GuestOpenHow;\n \n typedef enum CallbackQsortPhase {\n     CALLBACK_QSORT_PHASE_IDLE,\n@@ -128,6 +135,19 @@ static void write_reg64(VcpuState *vcpu, struct qemu_plugin_register *reg,\n     g_assert(success);\n }\n \n+static void read_guest_buffer(uint64_t addr, void *dst, size_t len)\n+{\n+    g_autoptr(GByteArray) data = g_byte_array_sized_new(len);\n+\n+    if (len == 0) {\n+        return;\n+    }\n+\n+    g_byte_array_set_size(data, len);\n+    g_assert(qemu_plugin_read_memory_vaddr(addr, data, len));\n+    memcpy(dst, data->data, len);\n+}\n+\n static bool write_guest_u64(uint64_t addr, uint64_t value)\n {\n     GByteArray data = {\n@@ -138,6 +158,13 @@ static bool write_guest_u64(uint64_t addr, uint64_t value)\n     return qemu_plugin_write_memory_vaddr(addr, &data);\n }\n \n+static void read_guest_open_how(uint64_t addr, uint64_t guest_size,\n+                                GuestOpenHow *how)\n+{\n+    g_assert(guest_size >= sizeof(*how));\n+    read_guest_buffer(addr, how, sizeof(*how));\n+}\n+\n static char *read_guest_cstring(uint64_t addr)\n {\n     g_autoptr(GByteArray) data = g_byte_array_sized_new(GUEST_STRING_CHUNK);\n@@ -273,23 +300,49 @@ static bool handle_library_open(int64_t num, uint64_t a1, uint64_t a2,\n     g_autofree char *path = NULL;\n     g_autofree char *thunk_path = NULL;\n     g_autofree char *out = NULL;\n+    GuestOpenHow how = { 0 };\n+    uint64_t path_addr;\n+    int dirfd;\n+    int flags;\n+    mode_t mode;\n     int fd;\n \n-    if (num != X86_64_OPENAT_NR) {\n+    if (num == X86_64_OPEN_NR) {\n+        dirfd = AT_FDCWD;\n+        path_addr = a1;\n+        flags = (int)a2;\n+        mode = (mode_t)a3;\n+    } else if (num == X86_64_OPENAT_NR) {\n+        dirfd = (int)a1;\n+        path_addr = a2;\n+        flags = (int)a3;\n+        mode = (mode_t)a4;\n+    } else if (num == X86_64_OPENAT2_NR) {\n+        dirfd = (int)a1;\n+        path_addr = a2;\n+        flags = 0;\n+        mode = 0;\n+    } else {\n         return false;\n     }\n \n-    path = read_guest_cstring(a2);\n+    path = read_guest_cstring(path_addr);\n     if (path == NULL || !guest_path_matches_bridge(path)) {\n         return false;\n     }\n \n+    if (num == X86_64_OPENAT2_NR) {\n+        read_guest_open_how(a3, a4, &how);\n+        flags = (int)how.flags;\n+        mode = (mode_t)how.mode;\n+    }\n+\n     thunk_path = build_thunk_path(path);\n     if (access(thunk_path, F_OK) != 0) {\n         return false;\n     }\n \n-    fd = openat((int)a1, thunk_path, (int)a3, (mode_t)a4);\n+    fd = openat(dirfd, thunk_path, flags, mode);\n     g_assert(fd >= 0);\n \n     *sysret = fd;\ndiff --git a/contrib/plugins/syscall_filter_zlib-example/README.rst b/contrib/plugins/syscall_filter_zlib-example/README.rst\nindex 4920187a2b..0a1cd555ca 100644\n--- a/contrib/plugins/syscall_filter_zlib-example/README.rst\n+++ b/contrib/plugins/syscall_filter_zlib-example/README.rst\n@@ -8,8 +8,9 @@ This directory contains the guest-side pieces used by\n \n * ``zcompress-demo.c`` is linked against ``libdemo-zlib.so`` and calls the\n   compression helpers directly.\n-* The plugin intercepts the loader's ``openat()`` call and returns a file\n-  descriptor for ``./libdemo-zlib-thunk.so`` instead.\n+* The plugin intercepts the loader's ``open()``, ``openat()``, or\n+  ``openat2()`` call and returns a file descriptor for\n+  ``./libdemo-zlib-thunk.so`` instead.\n * ``zcompress-thunk.c`` exposes a tiny compression API as thin wrappers around\n   magic syscalls.\n * The plugin filters those magic syscalls and executes the host zlib\ndiff --git a/contrib/plugins/syscall_filter_zlib.c b/contrib/plugins/syscall_filter_zlib.c\nindex e8f430cbaf..59e3750c90 100644\n--- a/contrib/plugins/syscall_filter_zlib.c\n+++ b/contrib/plugins/syscall_filter_zlib.c\n@@ -5,10 +5,10 @@\n  * local library interception with a host zlib compression example.\n  *\n  * When the guest dynamic loader attempts to open \"./libdemo-zlib.so\", this\n- * plugin intercepts openat() and instead returns a file descriptor for\n- * \"libdemo-zlib-thunk.so\" in the same directory. The thunk library then\n- * forwards compression requests through magic syscalls, which are handled by\n- * this plugin and executed by the host's zlib implementation.\n+ * plugin intercepts open(), openat(), or openat2() and instead returns a file\n+ * descriptor for \"libdemo-zlib-thunk.so\" in the same directory. The thunk\n+ * library then forwards compression requests through magic syscalls, which are\n+ * handled by this plugin and executed by the host's zlib implementation.\n  *\n  * This demo intentionally assumes a linux-user run with guest_base == 0 on a\n  * little-endian 64-bit host, so guest virtual addresses are directly usable\n@@ -40,7 +40,14 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;\n #define ZLIB_COMPRESS_MAX_BUFFER (128 * 1024 * 1024)\n #define GUEST_STRING_CHUNK 64\n #define GUEST_STRING_LIMIT (1 << 20)\n+#define X86_64_OPEN_NR 2\n #define X86_64_OPENAT_NR 257\n+#define X86_64_OPENAT2_NR 437\n+\n+typedef struct GuestOpenHow {\n+    uint64_t flags;\n+    uint64_t mode;\n+} GuestOpenHow;\n \n static char *read_guest_cstring(uint64_t addr)\n {\n@@ -68,6 +75,25 @@ static char *read_guest_cstring(uint64_t addr)\n     return NULL;\n }\n \n+static void read_guest_buffer(uint64_t addr, void *dst, size_t len)\n+{\n+    g_autoptr(GByteArray) data = g_byte_array_sized_new(len);\n+\n+    if (len == 0) {\n+        return;\n+    }\n+\n+    g_byte_array_set_size(data, len);\n+    g_assert(qemu_plugin_read_memory_vaddr(addr, data, len));\n+    memcpy(dst, data->data, len);\n+}\n+\n+static void read_guest_open_how(uint64_t addr, uint64_t guest_size,\n+                                GuestOpenHow *how)\n+{\n+    g_assert(guest_size >= sizeof(*how));\n+    read_guest_buffer(addr, how, sizeof(*how));\n+}\n static bool guest_path_matches_zlib_compress(const char *path)\n {\n     g_autofree char *basename = g_path_get_basename(path);\n@@ -92,22 +118,47 @@ static bool handle_library_open(int64_t num, uint64_t a1, uint64_t a2,\n     g_autofree char *path = NULL;\n     g_autofree char *thunk_path = NULL;\n     g_autofree char *out = NULL;\n+    GuestOpenHow how = { 0 };\n+    uint64_t path_addr;\n+    int dirfd;\n+    int flags;\n+    mode_t mode;\n     int fd;\n \n-    if (num != X86_64_OPENAT_NR) {\n+    if (num == X86_64_OPEN_NR) {\n+        dirfd = AT_FDCWD;\n+        path_addr = a1;\n+        flags = (int)a2;\n+        mode = (mode_t)a3;\n+    } else if (num == X86_64_OPENAT_NR) {\n+        dirfd = (int)a1;\n+        path_addr = a2;\n+        flags = (int)a3;\n+        mode = (mode_t)a4;\n+    } else if (num == X86_64_OPENAT2_NR) {\n+        dirfd = (int)a1;\n+        path_addr = a2;\n+        flags = 0;\n+        mode = 0;\n+    } else {\n         return false;\n     }\n \n-    path = read_guest_cstring(a2);\n+    path = read_guest_cstring(path_addr);\n     if (path == NULL || !guest_path_matches_zlib_compress(path)) {\n         return false;\n     }\n+    if (num == X86_64_OPENAT2_NR) {\n+        read_guest_open_how(a3, a4, &how);\n+        flags = (int)how.flags;\n+        mode = (mode_t)how.mode;\n+    }\n     thunk_path = build_thunk_path(path);\n     if (access(thunk_path, F_OK) != 0) {\n         return false;\n     }\n \n-    fd = openat((int)a1, thunk_path, (int)a3, (mode_t)a4);\n+    fd = openat(dirfd, thunk_path, flags, mode);\n     g_assert(fd >= 0);\n \n     *sysret = fd;\ndiff --git a/docs/about/emulation.rst b/docs/about/emulation.rst\nindex 4afec85ff6..8630300b37 100644\n--- a/docs/about/emulation.rst\n+++ b/docs/about/emulation.rst\n@@ -246,9 +246,9 @@ side example lives in ``contrib/plugins/syscall_filter_zlib-example``.\n \n The plugin does two things:\n \n-* It filters the guest ``openat()`` that the dynamic loader issues for\n-  ``./libdemo-zlib.so`` and instead returns a file descriptor for\n-  ``libdemo-zlib-thunk.so``.\n+* It filters the guest ``open()``, ``openat()``, or ``openat2()`` that the\n+  dynamic loader issues for ``./libdemo-zlib.so`` and instead returns a file\n+  descriptor for ``libdemo-zlib-thunk.so``.\n * It filters magic syscalls from the thunk library and runs the host's zlib\n   ``compressBound()``, ``compress2()``, and ``uncompress()`` implementations\n   directly on guest buffers.\n",
    "prefixes": [
        "v1",
        "3/3"
    ]
}