Libseccomp: BUG: SCMP_CMP_GT / GE / LT / LE لا يعمل كما هو متوقع لوسائط syscall السلبية

تم إنشاؤها على ١٨ يناير ٢٠١٧  ·  20تعليقات  ·  مصدر: seccomp/libseccomp

أهلا!

لست متأكدًا مما إذا كان السلوك الحالي لـ SCMP_CMP_GT / GE / LT / LE يعمل على النحو المنشود أو إذا كان هناك خطأ في تنفيذه. صفحة الرجل seccomp_rule_add لديها هذا فقط لتقوله عن SCMP_CMP_GT:

SCMP_CMP_GT:
        Matches when the argument value is greater than the datum value,
        example:

        SCMP_CMP( arg , SCMP_CMP_GT , datum )

لا تحدد صفحة الدليل نوع المرجع ولديها أمثلة لأنواع مختلفة (ضمنية) (ومجموعة واحدة إلى scmp_datum_t).

بناءً على صفحة الدليل ، توقعت أن يعمل شيء كهذا لأي قيمة مُعطاة للوسيطة الثالثة لـ setpriority (افترض السياسة الافتراضية لـ SCMP_ACT_ALLOW لهذا):

rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM),
        SCMP_SYS(setpriority),
        3,
        SCMP_A0(SCMP_CMP_EQ, PRIO_PROCESS),
        SCMP_A1(SCMP_CMP_EQ, 0),
        SCMP_A2(SCMP_CMP_GT, 0));

بدلاً من ذلك ، ينتج عن setpriority(PRIO_PROCESS, 0, -1) حظر مكالمة النظام عندما يكون الرقم "-1" أقل من "0" بشكل واضح. setpriority(PRIO_PROCESS, 0, 0) و setpriority(PRIO_PROCESS, 0, 1) كما هو متوقع. ما يحدث هو أنه يتم تحويل "-1" إلى scmp_datum_t (uint64_t من secomp.h.in) مما يجعلها بالطبع إيجابية ، لكن SCMP_CMP_GT والأصدقاء لا يتعاملون مع هذا التحويل. يعمل SCMP_CMP_EQ بشكل جيد مع المسند السلبي (مسند التخمين لا يزال موجبًا (لم أتحقق منه) ، لكن المقارنة بين scmp_datum_t المحولة).

تم تأكيد هذا السلوك مع 2.1.0 + dfsg-1 (Ubuntu 14.04 LTS ، 3.13 kernel) ، 2.2.3-3ubuntu3 (Ubuntu 16.04 LTS ، 4.9 kernel) ، 2.3.1-2ubuntu2 (إصدار Ubuntu 17.04 dev ، 4.9 kernel) و سيد منذ لحظات قليلة (على إصدار مطور Ubuntu 17.04 ، 4.9 kernel) ، كل ذلك على amd64.

AFAICT ، لا توجد اختبارات لـ SCMP_CMP_GT و SCMP_CMP_LE. لا يبدو أن الاختبارات القليلة لـ SCMP_CMP_LT تأخذ في الاعتبار القيم السالبة ولا الاختبار الخاص بـ SCMP_CMP_GE (يرجى تصحيح لي إذا كنت مخطئًا).

والسؤال إذن: هل هذا السلوك مقصود؟ إذا كان الأمر كذلك ، فبينما أعترف بأنه يمكن القول بأن صفحة الدليل دقيقة لأن هذه تعمل بشكل صحيح عند فهم أن scmp_datum_t هو نوع البيانات ، فإن هذا الموقف ليس واضحًا على الفور وربما يجب أن تذكر صفحة الدليل أن التطبيقات تحتاج إلى حساب هذه. بخلاف ذلك ، يبدو أن هذا خطأ في تنفيذ SCMP_CMP_GT / GE / LT / LE.

إليك برنامج صغير يوضح هذه المشكلة مع SCMP_CMP_GT ، على الرغم من أنه يمكن ملاحظة أن لدى GE و LT ​​و LE نفس السلوك:

/*
 * gcc -o test-nice test-nice.c -lseccomp
 * sudo ./test-nice 0 1  # should be denied
 * sudo ./test-nice 0 0  # should be allowed
 * sudo ./test-nice 0 -1 # should be allowed?
 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <stdarg.h>
#include <seccomp.h>
#include <sys/resource.h>

int main(int argc, char **argv)
{
    if (argc < 3) {
        fprintf(stderr, "test-nice N N\n");
        return 1;
    }

    int rc = 0;
    scmp_filter_ctx ctx = NULL;
    int filter_n = atoi(argv[1]);
    int n = atoi(argv[2]);

    // Allow everything by default for this test
    ctx = seccomp_init(SCMP_ACT_ALLOW);
    if (ctx == NULL)
        return ENOMEM;

    printf("set EPERM for nice(>%d)\n", filter_n);
    rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM),
            SCMP_SYS(setpriority),
            3,
            SCMP_A0(SCMP_CMP_EQ, PRIO_PROCESS),
            SCMP_A1(SCMP_CMP_EQ, 0),
            SCMP_A2(SCMP_CMP_GT, filter_n));

    if (rc != 0) {
        perror("seccomp_rule_add failed");
        goto out;
    }

    rc = seccomp_load(ctx);
    if (rc != 0) {
        perror("seccomp_load failed");
        goto out;
    }

    // try to use the filtered syscall
    errno = 0;
    printf("Attempting nice(%d)\n", n);
    nice(n);
    if (errno != 0) {
        perror("could not nice");
        if (filter_n > n)
            fprintf(stderr, "nice(%d) unsuccessful. bug?\n", n);
        rc = 1;
        goto out;
    } else
        printf("nice(%d) successful\n", n);

out:
    seccomp_release(ctx);

    return rc;
}
bug prioritmedium

ال 20 كومينتر

شكرا لتقرير المشكلة. هذا جيد.

بأي فرصة ، هل حاولت كتابة الناسخ باستخدام الرؤوس / وحدات الماكرو في دليل / seccomp ؟

كان لدي انطباع بأن رمز BPF في النواة تعامل مع القيم الفورية على أنها موقعة ؛ قد لا يكون هذا هو الحال ، أو ربما أكون قد أفسدت شيئًا ما في كود libseccomp.

FWIW، BPF نفسها تستخدم u32 لوسائلها. هل libseccomp لا تمديد التوقيع على الحجج المتوافقة؟ (ربما لا ينبغي ذلك ، ولكن بعد ذلك يجب أن تكون القواعد المطابقة "-1" مختلفة بين 32 بت و 64 بت ...)

المشكلة التي تقلقني الآن هي مقارنات BPF GT / GE في مشغل القفز ، خاصة وأنني أشك في أن معظم الجميع يتعامل مع BPF على الفور كقيمة موقعة لهذه المقارنات.

kees ما هي الطريقة الموصى بها لإجراء مقارنات موقعة بين وسيطات syscall مع آلة seccomp-bpf الخاصة بالنواة؟ آمل ألا يكون هذا شيئًا على غرار "تحقق من البت المرتفع أولاً ثم قم بإجراء تحويل المجاملة الضروري للاثنين قبل مقارنة الأرقام السالبة". في حين أنه مزعج ، يمكننا دائمًا تغيير libseccomp لإنشاء BPF الضروري (على الرغم من أن المرشحات التي تم إنشاؤها ستكون الآن أكبر بكثير في بعض الحالات) ، لكنني قلق بشأن التطبيقات التي تنشئ مرشحات BPF الخاصة بها ؛ من المحتمل ألا تكون احتمالات تعاملهم مع هذا الأمر بشكل صحيح جيدة جدًا.

لسوء الحظ ، نظرًا لأن وسيطات syscall "غير موقعة طويلة" (راجع syscall_get_arguments () و architecture seccomp_data) ، فلا توجد أي حالة شائعة لكيفية معالجة syscall للتحويلات. ستؤدي بعض عمليات syscalls عند عبور حاجز المواطن إلى تمديد التوقيع ، والبعض الآخر (prctl) لا يفعل ذلك. هل هناك الكثير من حجج النظام السلبي ولكن ليس ناقصًا واحدًا؟

بالعودة إلى هذا اليوم ، وبعد أن لعبت بالأشياء أكثر قليلاً هذا الصباح ، أعتقد أن هذا سينتهي به الأمر إلى توثيق / "كن حذرًا!" مشكلة لأنه لا يوجد حل جيد ، خاصة عندما نتحدث عن المستخدمين الحاليين. اسمحوا لي أن أحاول تقديم بعض خلفية / شرح libseccomp للتوافق مع تعليقات

FWIW، BPF نفسها تستخدم u32 لوسائلها. هل libseccomp لا تمديد التوقيع على الحجج المتوافقة؟ (ربما لا ينبغي ذلك ، ولكن بعد ذلك يجب أن تكون القواعد المطابقة "-1" مختلفة بين 32 [بت و 64 بت ...)

تفسر وظائف قاعدة libseccomp API جميع القيم الفورية على أنها _uint64_t_ لذا إذا كنت مهملًا في أنواعك / إرسالك ، فقد تواجه مشكلات. مثال:

$ cat 00-test.c
    /* ... */
    seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, 1000, 1,
                           SCMP_A0(SCMP_CMP_GT, -1));
    seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, 1001, 1,
                           SCMP_A0(SCMP_CMP_GT, (uint32_t)-1));
    seccomp_rule_add_exact(ctx, SCMP_ACT_KILL, 1002, 1,
                           SCMP_A0(SCMP_CMP_GT, 0xffffffff));
    /* ... */
$ make 00-test
  CC       00-test.o
  CCLD     00-test
$ ./00-test -p
  #
  # pseudo filter code start
  #
  # filter for arch x86_64 (3221225534)
  if ($arch == 3221225534)
    # filter for syscall "UNKNOWN" (1002) [priority: 65533]
    if ($syscall == 1002)
      if ($a0.hi32 >= 0)
        if ($a0.lo32 > 4294967295)
          action KILL;
    # filter for syscall "UNKNOWN" (1001) [priority: 65533]
    if ($syscall == 1001)
      if ($a0.hi32 >= 0)
        if ($a0.lo32 > 4294967295)
          action KILL;
    # filter for syscall "UNKNOWN" (1000) [priority: 65533]
    if ($syscall == 1000)
      if ($a0.hi32 >= 4294967295)
        if ($a0.lo32 > 4294967295)
          action KILL;
    # default action
    action ALLOW;
  # invalid architecture action
  action KILL;
  #
  # pseudo filter code end
  # 
$ ./00-test -b | ../tools/scmp_bpf_disasm 
   line  OP   JT   JF   K
  =================================
   0000: 0x20 0x00 0x00 0x00000004   ld  $data[4]
   0001: 0x15 0x00 0x0c 0xc000003e   jeq 3221225534 true:0002 false:0014
   0002: 0x20 0x00 0x00 0x00000000   ld  $data[0]
   0003: 0x35 0x0a 0x00 0x40000000   jge 1073741824 true:0014 false:0004
   0004: 0x15 0x00 0x02 0x000003e8   jeq 1000 true:0005 false:0007
   0005: 0x20 0x00 0x00 0x00000014   ld  $data[20]
   0006: 0x35 0x04 0x06 0xffffffff   jge 4294967295 true:0011 false:0013
   0007: 0x15 0x01 0x00 0x000003e9   jeq 1001 true:0009 false:0008
   0008: 0x15 0x00 0x04 0x000003ea   jeq 1002 true:0009 false:0013
   0009: 0x20 0x00 0x00 0x00000014   ld  $data[20]
   0010: 0x35 0x00 0x02 0x00000000   jge 0    true:0011 false:0013
   0011: 0x20 0x00 0x00 0x00000010   ld  $data[16]
   0012: 0x25 0x01 0x00 0xffffffff   jgt 4294967295 true:0014 false:0013
   0013: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
   0014: 0x06 0x00 0x00 0x00000000   ret KILL

... كما نرى ، إذا كنت تستخدم الصب المناسب ، فلن يتم تمديد القيمة. ومع ذلك ، أتوقع أن هذا ليس ما يفعله معظم الناس. الخبر السار هو أنني أتخيل عدد مرات syscalls التي تأخذ الحجج السلبية لتكون صغيرة نسبيًا ، لذلك يجب أن يكون التأثير محدودًا إلى حد ما.

للمضي قدمًا ، نحتاج بالتأكيد إلى وضع شيء ما في المستندات حول هذا الأمر ومعرفة ما إذا كان بإمكاننا القيام بشيء ما لتسهيل الحياة على المطورين ، وربما تنفيذ متغيرات 32 بت لوحدات الماكرو _SCMP_A * _.

pcmoore - شكرًا على الرد التفصيلي https://github.com/torvalds/linux/tree/master/samples/seccomp حتى الآن ، ولكن بناءً على ملاحظاتك يبدو أنني لست بحاجة إلى ذلك. اسمحوا لي أن أعرف إذا كنت بحاجة إلى أي شيء آخر. في الوقت الحالي ، سأتخذ نهج "كن حذرًا" وأرسل تقريرًا إذا كان لدي أي مشاكل ، وأتطلع إلى كيفية تسهيل ذلك في المستقبل.

jdstrand أعتقد أننا جميعًا مستعدون للوقت الحالي. شكرًا مرة أخرى على التقرير ، يؤسفني أنه لم يكن لدي إجابة أفضل لك ، ولكن آمل أن يكون لدينا شيء في المستقبل.

في غضون ذلك ، إذا واجهت أي مشاكل مرة واحدة مع كتابة قيمة المصبوب بشكل صحيح ، فلا تتردد في تحديث هذه المشكلة.

الخبر السار هو أنني أتخيل عدد مرات syscalls التي تأخذ الحجج السلبية لتكون صغيرة نسبيًا ، لذلك يجب أن يكون التأثير محدودًا إلى حد ما.

لقد واجهت هذه المشكلة للتو عند التحقق (من بين أشياء أخرى) ما إذا كانت معلمة fd لـ openat () تساوي القيمة الخاصة AT_FDCWD وهي -100. هذا يؤدي إلى:

  # filter for syscall "openat" (257) [priority: 131067]
  if ($syscall == 257)
    if ($a0.hi32 == 4294967295)
      if ($a0.lo32 == 4294967196)
        if ($a2.hi32 & 0x00000000 == 0)
          if ($a2.lo32 & 0x00000003 == 0)
            action ERRNO(2);

أين يجب أن يكون:

  # filter for syscall "openat" (257) [priority: 131067]
  if ($syscall == 257)
    if ($a0.hi32 == 0)
      if ($a0.lo32 == 4294967196)
        if ($a2.hi32 & 0x00000000 == 0)
          if ($a2.lo32 & 0x00000003 == 0)
            action ERRNO(2);

نظرًا لأن glibc 2.26+ يبدو أنه يستخدم نظام openat syscall حصريًا مع AT_FDCWD لتنفيذ open () ، فقد يتسبب ذلك في إزعاج الكثير من الأشخاص. أدى تطبيق فريق عمل على uint32_t كما هو مقترح أعلاه إلى إصلاح المشكلة بالنسبة لي:

        // selector, action, syscall, no of args, args
        { SEL, SCMP_ACT_ERRNO(ENOENT), "openat", 2,
-               { SCMP_A0(SCMP_CMP_EQ, AT_FDCWD), /* glibc 2.26+ */
+               { SCMP_A0(SCMP_CMP_EQ, (uint32_t)AT_FDCWD), /* glibc 2.26+ */
                  SCMP_A2(SCMP_CMP_MASKED_EQ, O_ACCMODE, O_RDONLY) }},

من المؤكد أنه سيكون من الجيد وجود SCMP_A0_U32 صريح.

drakenclimberjdstrandmichaelweiser ماذا يا رفاق التفكير في https://github.com/pcmoore/misc-libseccomp/commit/b9ce39d776ed5a984c7e9e6db3b87463edce82a7 كحل لهذا؟

pcmoore : شكرًا لك على مواصلة النظر في هذا الأمر! لقد أعطيته دوامة ويبدو أنه رائع حقًا في الكود:

static struct {
        const uint64_t promises;
        const uint32_t action;
        const char *syscall;
        const int arg_cnt;
        const struct scmp_arg_cmp args[3];
} scsb_calls[] = {
[...]
        { PLEDGE_WPATH, SCMP_ACT_ALLOW, "openat", 2, /* glibc 2.26+ */
                { SCMP_A0_32(SCMP_CMP_EQ, AT_FDCWD),
                  SCMP_A2_64(SCMP_CMP_MASKED_EQ, O_ACCMODE, O_WRONLY) }},

لسوء الحظ ، يبدو أن الوظيفة المساعدة ليست مناسبة لمهيئ البنية:

In file included from pledge.c:42:
/include/seccomp.h:230:26: error: initializer element is not constant
 #define SCMP_CMP32(...)  (__scmp_arg_32(SCMP_CMP64(__VA_ARGS__)))
                          ^
/include/seccomp.h:241:26: note: in expansion of macro ‘SCMP_CMP32’
 #define SCMP_A0_32(...)  SCMP_CMP32(0, __VA_ARGS__)
                          ^~~~~~~~~~
pledge.c:188:5: note: in expansion of macro ‘SCMP_A0_32’
   { SCMP_A0_32(SCMP_CMP_EQ, AT_FDCWD),
     ^~~~~~~~~~
/include/seccomp.h:230:26: note: (near initialization for ‘scsb_calls[21].args[0]’)
 #define SCMP_CMP32(...)  (__scmp_arg_32(SCMP_CMP64(__VA_ARGS__)))
                          ^
/include/seccomp.h:241:26: note: in expansion of macro ‘SCMP_CMP32’
 #define SCMP_A0_32(...)  SCMP_CMP32(0, __VA_ARGS__)
                          ^~~~~~~~~~
pledge.c:188:5: note: in expansion of macro ‘SCMP_A0_32’
   { SCMP_A0_32(SCMP_CMP_EQ, AT_FDCWD),
     ^~~~~~~~~~

شكرًا للمراجعة michaelweiser ، لسوء الحظ لم أعتقد أن الناس كانوا يستخدمون وحدات الماكرو هذه كمبدعين ، لكن هذا استخدام صالح وبالتأكيد هناك عدد قليل من الأشخاص يستخدمونه بهذه الطريقة.

سأحتاج إلى التفكير في هذا قليلاً ... هل لديك أي أفكار حول كيفية حل هذا بطريقة أنيقة؟

لا توجد فكرة ، آسف ، لقد فتحت عيني بالفعل بالمباريات. :)

بالنظر إليها الآن أعتقد أنني أرى المشكلة: نظرًا لقوائم الوسيطات المتغيرة ، لا يمكنك حقن القوالب الضرورية ، أليس كذلك؟

هل يمكن أن يحتوي scmp_arg_cmp على اتحاد يعطي وجهات نظر مختلفة حول البيانات بالعرض الصحيح والمحاذاة (وربما حتى ترتيب البايت) (والتي تتعارض IMO مع كلمة "Elegant") :؟ إذا كان الأمر داخليًا تمامًا لـ libseccomp ولا يحتاج إلى أن يكون متوافقًا مع واجهة kernel ، فهل يمكن أن يحمل مؤشر نوع البيانات كحقل منفصل وأن تقوم وظائف المستخدم بفرزها؟ وهل يمكن حتى تهيئة ذلك باستخدام varargs؟

بخلاف ذلك ، بدلاً من وضع علامة على العملية ككل 32/64 بت ، هل يمكن وضع تعليقات توضيحية على المعاملات ، وتغليف طاقم العمل وتقديم توصية صارمة للمستخدم (كما تفعل) لاستخدام هذه التعليقات التوضيحية دائمًا على عقوبة الوقوع في مشاكل يصعب تصحيحها ؟

{ SCMP_A0(SCMP_CMP_EQ, SCMP_OP_32(AT_FDCWD)),
  SCMP_A2(SCMP_CMP_MASKED_EQ, SCMP_OP_64(O_ACCMODE), SCMP_OP_64(O_WRONLY)) }},

أو

{ SCMP_A0(SCMP_CMP_EQ, SCMP_OP1_32(AT_FDCWD)),
  SCMP_A2(SCMP_CMP_MASKED_EQ, SCMP_OP2_64(O_ACCMODE, O_WRONLY)) }},

أنا لست كافيًا لكسر المعالج المسبق للتوصل إلى المزيد ، آسف.

pcmoore ، تبدو التغييرات جيدة بالنسبة لي. لست خبيرًا في المعالجة المسبقة ، لكنني سألقي نظرة على المشكلة التي ذكرها michaelweiser أعلاه

بالنظر إليها الآن أعتقد أنني أرى المشكلة: نظرًا لقوائم الوسيطات المتغيرة ، لا يمكنك حقن القوالب الضرورية ، أليس كذلك؟

نعم ، هذا كل شيء إلى حد كبير. ربما هناك طريقة غير رهيبة للتغلب على ذلك ، لكنني لم أجد واحدة بعد.

هل يمكن أن يحتوي scmp_arg_cmp على اتحاد يعطي وجهات نظر مختلفة حول البيانات بالعرض الصحيح والمحاذاة (وربما حتى ترتيب البايت) (والتي تتعارض IMO مع كلمة "Elegant") :؟ إذا كان الأمر داخليًا تمامًا لـ libseccomp ولا يحتاج إلى أن يكون متوافقًا مع واجهة kernel ، فهل يمكن أن يحمل مؤشر نوع البيانات كحقل منفصل وأن تقوم وظائف المستخدم بفرزها؟ وهل يمكن حتى تهيئة ذلك باستخدام varargs؟

لدينا مشكلة في أن بنية scmp_arg_cmp هي جزء من واجهة برمجة تطبيقات libseccomp ، لذلك ما لم نرغب في رفع الإصدار الرئيسي من libseccomp ، فلا يمكننا تغيير حجم البنية أو إزاحة أي من حقول الأعضاء ؛ سيؤدي القيام بذلك إلى كسر الواجهة الثنائية الحالية مع التطبيقات الحالية. يجب أن يكون تحويل حقول البيانات ذات 64 بت إلى اتحاد يحتوي إما على قيمة 64 بت أو 32 بت أمرًا مقبولاً في حد ذاته ، ولكنك ستحتاج أيضًا إلى إضافة بعض المعلومات الإضافية إلى بنية scmp_arg_cmp للإشارة إلى عضو الاتحاد الذي يجب استخدامه ؛ هذا هو العلم الإضافي الذي يمكن أن يكون مشكلة.

قد يكون من الممكن سرقة بعض البتات من حقلي "arg" أو "op" ، وكلاهما قيم 32 بت ويستخدمان جزءًا صغيرًا فقط من تلك المساحة. ومع ذلك ، أنا أعتبر هذا خيارًا متطرفًا إلى حد ما وأود تجنب ذلك إن أمكن.

بخلاف ذلك ، بدلاً من وضع علامة على العملية ككل 32/64 بت ، هل يمكن وضع تعليقات توضيحية على المعاملات ، وتغليف طاقم العمل وتقديم توصية صارمة للمستخدم (كما تفعل) لاستخدام هذه التعليقات التوضيحية دائمًا على عقوبة الوقوع في مشاكل يصعب تصحيحها ؟

لا أفهم تمامًا ما الذي سنكسبه من خلال تغليف المعاملات بوحدة ماكرو ، هل يمكنك توضيح المزيد؟ يمكننا توفير ماكرو لالتفاف قيم الإسناد ، لكن هذا لا يختلف حقًا عن مجرد مطالبة المتصلين بتوفير الصب المناسب.

pcmoore ، تبدو التغييرات جيدة بالنسبة لي. لست خبيرًا في المعالجة المسبقة ، لكنني سألقي نظرة على المشكلة التي ذكرها michaelweiser أعلاه

عظيم شكرا. نأمل بيننا نحن الثلاثة أن نأتي بشيء مفيد هنا.

pcmoore : النظر في http://efesx.com/2010/07/17/variadic-macro-to-count-number-of-arguments/ و http://efesx.com/2010/08/31/overloading- وحدات الماكرو / ابتكرت ما يلي:

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
#define macro_dispatcher(func, ...) \
            macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__))
#define macro_dispatcher_(func, nargs) \
            macro_dispatcher__(func, nargs)
#define macro_dispatcher__(func, nargs) \
            func ## nargs

#define SCMP_CMP64(...)         ((struct scmp_arg_cmp){__VA_ARGS__})

#define SCMP_CMP32_1(x)                 SCMP_CMP64(x)
#define SCMP_CMP32_2(x, y)              SCMP_CMP64(x, y)
#define SCMP_CMP32_3(x, y, z)           SCMP_CMP64(x, y, (uint32_t)(z))
#define SCMP_CMP32_4(x, y, z, q)        SCMP_CMP64(x, y, (uint32_t)(z), (uint32_t)(q))
#define SCMP_CMP32(...) macro_dispatcher(SCMP_CMP32_, __VA_ARGS__)(__VA_ARGS__)

#define SCMP_A0_64(...)         SCMP_CMP64(0, __VA_ARGS__)
#define SCMP_A0_32(...)         SCMP_CMP32(0, __VA_ARGS__)

لحالة الاختبار هذه:

        struct scmp_arg_cmp f[] = {
                SCMP_A0_64(SCMP_CMP_EQ, 1, 20),
                SCMP_A0_32(SCMP_CMP_EQ, 2, 3),
                SCMP_A0_32(SCMP_CMP_LT, 2),
        };

يأتي من gcc-7.4.0 -E و clang-7 -E النحو التالي:

 struct scmp_arg_cmp f[] = {
  ((struct scmp_arg_cmp){0, SCMP_CMP_EQ, 1, 20}),
  ((struct scmp_arg_cmp){0, SCMP_CMP_EQ, (uint32_t)(2), (uint32_t)(3)}),
  ((struct scmp_arg_cmp){0, SCMP_CMP_LT, (uint32_t)(2)}),
 };

على افتراض أن SCMP_A[0-5]_43 يحتاج على الأقل op للعمل و SCMP_CMP32 يتطلب arg ، يمكن حفظ سطرين بجعل هذه المعلمات موضعية:

#define SCMP_CMP32_1(x, y, z)           SCMP_CMP64(x, y, (uint32_t)(z))
#define SCMP_CMP32_2(x, y, z, q)        SCMP_CMP64(x, y, (uint32_t)(z), (uint32_t)(q))
#define SCMP_CMP32(x, y,...)            macro_dispatcher(SCMP_CMP32_, __VA_ARGS__)(x, y, __VA_ARGS__)

#define SCMP_A0_32(x,...)       SCMP_CMP32(0, x, __VA_ARGS__)

أحسنت صنع @ michaelweiser! هل كنت ترغب في تجميع العلاقات العامة حتى نتمكن من مراجعة التغييرات والتعليق عليها بشكل أسهل قليلاً؟ إذا لم يكن الأمر كذلك ، فهذا جيد تمامًا ، سأجمع واحدة معًا وأحرص على حصولك على الكثير من الائتمان :)

سأقوم بعمل مشروع العلاقات العامة الليلة. فوق https://github.com/pcmoore/misc-libseccomp/commit/b9ce39d776ed5a984c7e9e6db3b87463edce82a7 أم من الصفر؟
كيف ننسب الفضل إلى Blogger Roman في حل التحميل الزائد؟ تم العثور على ما يبدو أنه المنزل الحالي لمدونته على https://kecher.net/overloading-macros/. منشوره يبدو تماما مثل المصدر الأصلي. تعليق مع رابط إلى المنشور فوق المنطق macro_dispatcher ؟

سأقوم بعمل مشروع العلاقات العامة الليلة. على رأس pcmoore @ b9ce39d أم من الصفر؟

رائع شكرا لك! المضي قدمًا وإسنادها من الفرع الرئيسي ، لم أقم أبدًا بدمج الأشياء في شجرة متفرقات libseccomp الخاصة بي ، ولا أخطط لذلك في هذه المرحلة لأن أسلوبك أفضل بكثير.

كيف ننسب الفضل إلى Blogger Roman في حل التحميل الزائد؟ تم العثور على ما يبدو أنه المنزل الحالي لمدونته على https://kecher.net/overloading-macros/. منشوره يبدو تماما مثل المصدر الأصلي. تعليق مع رابط إلى المنشور فوق المنطق macro_dispatcher ؟

بشكل عام لا نعتمد الأشخاص مباشرة في المصدر ، ما لم يكن هناك بعض متطلبات الترخيص ؛ أود أن أوصي بإضافة تعليق في وصف التصحيح يعزو إلى رومان الفكرة الأساسية ويوفر رابطًا إلى منشور مدونته. لا أرى أي ترخيص أو قيود موضوعة على أمثلةه ، لذلك لا أعتقد أن هناك أي مشاكل في هذا الصدد ، وبناءً على عينة من مدونته ، أعتقد أن نيته هي مشاركة هذه الأفكار مع الآخرين (مثلنا ) لمساعدتهم على حل مشاكلهم. إذا كان لديك عنوان بريد إلكتروني لرومان ، فيمكنك دائمًا محاولة إرسال بعض البريد الإلكتروني إليه ؛ إذا لم نتمكن من الوصول إليه لأي سبب من الأسباب ، أعتقد أنه من المقبول المضي قدمًا.

تم الحل عبر 80a987d6f8d0152def07fa90ace6417d56eea741.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات