Libseccomp: RFE: nilai pengembalian kesalahan yang lebih tepat didefinisikan

Dibuat pada 7 Okt 2017  ·  24Komentar  ·  Sumber: seccomp/libseccomp

Melihat nilai pengembalian kesalahan libseccomp tentang panggilan sistem, tidak mungkin menentukan alasan berikut yang menyebabkan kesalahan:

  1. syscall tidak ada di beberapa lengkungan
  2. syscall tidak dapat dicocokkan pada beberapa lengkungan (karena multipleks, pikirkan socket/socketcall)
  3. kasus kesalahan lainnya

Saat membuat filter seccomp, pemanggil mungkin menganggap beberapa alasan ini fatal tetapi tidak yang lain, jadi informasi kesalahan yang lebih detail (kumpulan nilai kesalahan yang lebih luas daripada hanya -EINVAL ) akan diperlukan.

Lihat juga systemd PR 6952 .

enhancement prioritmedium

Komentar yang paling membantu

Terima kasih banyak. Saya memiliki tambalan setengah matang yang akan saya selesaikan dan kirimkan sebagai PR untuk ditinjau.

Semua 24 komentar

Hai @topimiettinen , maaf butuh waktu lama untuk sampai ke ini, tapi saya pikir sudah waktunya kita memperbaikinya.

@drakenclimber yang ini akan menjadi doozy. Semua libseccomp API harus memiliki halaman manual pada saat ini (jika tidak, kita perlu membuat masalah untuk itu), dengan semua halaman manual memiliki beberapa komentar "nilai negatif pada kesalahan" bergelombang di bagian RETURN VALUE. Saya pikir kita perlu melakukan hal berikut:

  • audit secara manual setiap panggilan API untuk menghasilkan daftar kemungkinan nilai yang dikembalikan
  • putuskan apakah nilai pengembalian ini masuk akal, ubah kode jika tidak
  • mendokumentasikan setiap kemungkinan nilai pengembalian di halaman manual terkait dengan penjelasan singkat tentang apa yang ditunjukkan oleh kode kesalahan

Pikiran?

Hai @topimiettinen , maaf butuh waktu lama untuk sampai ke ini, tapi saya pikir sudah waktunya kita memperbaikinya.

@drakenclimber yang ini akan menjadi doozy. Semua libseccomp API harus memiliki halaman manual pada saat ini (jika tidak, kita perlu membuat masalah untuk itu), dengan semua halaman manual memiliki beberapa komentar "nilai negatif pada kesalahan" bergelombang di bagian RETURN VALUE. Saya pikir kita perlu melakukan hal berikut:

* manually audit each API call to generate a list of possible return values

* decide if these return values make sense, modify the code if they don't

* document each possible return value in the associated manpage with a brief explanation of what the error code indicates

Pikiran?

Dang.... Dengan enggan saya setuju dengan semua yang Anda tulis di atas, terutama upaya yang diperlukan :). Mendapatkan kode pengembalian dengan benar, dan kemudian mendokumentasikannya akan menjadi upaya yang sangat besar.

Dan ya, meski bukan pekerjaan yang glamor, saya pikir ini penting. Saya telah mengerjakan beberapa hal cgroup dan kami baru-baru ini menemukan implementasi wadah yang sepenuhnya salah memahami fitur cgroup ... mereka bisa.

Sangat menyenangkan melihat aktivitas tentang masalah ini! Saya tidak menentang tinjauan menyeluruh, tetapi permintaan asli terbatas hanya untuk dapat membedakan mode kegagalan yang berbeda, yang agak ortogonal. Tinjauan itu pasti akan membantu, bahkan prasyarat untuk gelar yang saya pikir.

Sangat menyenangkan melihat aktivitas tentang masalah ini! Saya tidak menentang tinjauan menyeluruh, tetapi permintaan asli terbatas hanya untuk dapat membedakan mode kegagalan yang berbeda, yang agak ortogonal. Tinjauan itu pasti akan membantu, bahkan prasyarat untuk gelar yang saya pikir.

Kami perlu melakukan peninjauan di beberapa titik, dan mungkin juga sekarang. Semakin lama kita menunda, semakin tidak berguna kode kesalahan bagi penelepon dan inti dari libseccomp adalah membuat hal ini lebih mudah digunakan :)

Dang.... Dengan enggan saya setuju dengan semua yang Anda tulis di atas, terutama upaya yang diperlukan :). Mendapatkan kode pengembalian dengan benar, dan kemudian mendokumentasikannya akan menjadi upaya yang sangat besar.

Ya, ini adalah salah satu alasan mengapa masalah ini berlangsung begitu lama, tetapi saya telah menundanya cukup lama (setidaknya @drakenclimber dapat mengatakan bahwa dia telah menundanya selama kurang dari setahun!). Nanti hari ini (besok?) Saya akan memecah ini menjadi beberapa bagian/beberapa masalah (dengan beberapa saran) untuk membuatnya lebih mudah untuk ditangani berkeping-keping.

Sebagai sedikit positif, sepertinya libseccomp benar-benar hanya menggunakan sembilan nilai errno unik (menurut pemeriksaan yang sangat kasar):

# grep -e "-E[A-Z0-9]\+" src/*.{h,c} | sed 's/.*-\(E[A-Z0-9]\+\).*/\1/' | sort -u
EACCES
EDOM
EEXIST
EFAULT
EINVAL
ENOMEM
EOPNOTSUPP
EPERM
ESRCH

... ini akan membantu mengecilkan ruang masalah sedikit, terutama jika kita dapat menyetujui nilai semantik umum untuk setiap kode kesalahan di seluruh perpustakaan (yang pasti harus kita lakukan).

Ini sedikit lebih lambat dari yang dimaksudkan, tetapi berikut adalah daftar lengkap fungsi yang membentuk libseccomp API:

const struct scmp_version *seccomp_version(void)
unsigned int seccomp_api_get(void)
int seccomp_api_set(unsigned int level)
scmp_filter_ctx seccomp_init(uint32_t def_action)
int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action)
void seccomp_release(scmp_filter_ctx ctx)
int seccomp_merge(scmp_filter_ctx ctx_dst, scmp_filter_ctx ctx_src)
uint32_t seccomp_arch_resolve_name(const char *arch_name)
uint32_t seccomp_arch_native(void)
int seccomp_arch_exist(const scmp_filter_ctx ctx, uint32_t arch_token)
int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token)
int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token)
int seccomp_load(const scmp_filter_ctx ctx)
int seccomp_attr_get(const scmp_filter_ctx ctx, enum scmp_filter_attr attr, uint32_t *value)
int seccomp_attr_set(scmp_filter_ctx ctx, enum scmp_filter_attr attr, uint32_t value)
char *seccomp_syscall_resolve_num_arch(uint32_t arch_token, int num)
int seccomp_syscall_resolve_name_arch(uint32_t arch_token, const char *name)
int seccomp_syscall_resolve_name_rewrite(uint32_t arch_token, const char *name)
int seccomp_syscall_resolve_name(const char *name)
int seccomp_syscall_priority(scmp_filter_ctx ctx, int syscall, uint8_t priority)
int seccomp_rule_add_array(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array)
int seccomp_rule_add(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, ...)
int seccomp_rule_add_exact_array(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array)
int seccomp_rule_add_exact(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, ...)
int seccomp_notify_alloc(struct seccomp_notif **req, struct seccomp_notif_resp **resp)
void seccomp_notify_free(struct seccomp_notif *req, struct seccomp_notif_resp *resp)
int seccomp_notify_receive(int fd, struct seccomp_notif *req)
int seccomp_notify_respond(int fd, struct seccomp_notif_resp *resp)
int seccomp_notify_id_valid(int fd, uint64_t id)
int seccomp_notify_fd(const scmp_filter_ctx ctx)
int seccomp_export_pfc(const scmp_filter_ctx ctx, int fd)
int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd)

... dari fungsi-fungsi ini, kita hanya perlu khawatir tentang fungsi yang mengembalikan "int".

Kemungkinan pengelompokan fungsi yang seharusnya memiliki jalur kode yang sama dan mengembalikan nilai.

  • grup A
int seccomp_arch_exist(const scmp_filter_ctx ctx, uint32_t arch_token)
int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token)
int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token)
  • Grup B
int seccomp_attr_get(const scmp_filter_ctx ctx, enum scmp_filter_attr attr, uint32_t *value)
int seccomp_attr_set(scmp_filter_ctx ctx, enum scmp_filter_attr attr, uint32_t value)
  • Grup C
int seccomp_syscall_resolve_name_arch(uint32_t arch_token, const char *name)
int seccomp_syscall_resolve_name_rewrite(uint32_t arch_token, const char *name)
int seccomp_syscall_resolve_name(const char *name)
  • Grup D
int seccomp_rule_add_array(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array)
int seccomp_rule_add(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, ...)
int seccomp_rule_add_exact_array(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array)
int seccomp_rule_add_exact(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, ...)
  • Grup E
int seccomp_notify_receive(int fd, struct seccomp_notif *req)
int seccomp_notify_respond(int fd, struct seccomp_notif_resp *resp)
int seccomp_notify_id_valid(int fd, uint64_t id)
int seccomp_notify_fd(const scmp_filter_ctx ctx)
  • Grup F
int seccomp_load(const scmp_filter_ctx ctx)
int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd)

... jika fungsi tersebut tidak termasuk dalam salah satu grup di atas, kemungkinan fungsi tersebut unik dalam jalur kodenya dan/atau nilai kembaliannya.

Grup C hanya mengembalikan __NR_SCMP_ERROR.

Grup D dapat mengembalikan salah satu dari EINVAL, EPERM, EOPNOTSUPP, ENOMEM, EDOM, EFAULT, EEXIST.

seccomp_load() dapat mengembalikan EINVAL, ENOMEM, ESRCH dan juga nilai errno dari prctl() (hanya EACCES, EFAULT, EINVAL untuk PR_SET_NO_NEW_PRIVS dan PR_SET_SECCOMP) dan seccomp() (EACCES, EFAULT, EINVAL, CHENOMEM) ke panggilan manualnya halaman.

Ketika datang ke libseccomp meneruskan kesalahan syscall kembali ke pemanggil, misalnya prctl() dan seccomp(), saya pikir kita hanya perlu menyembunyikannya di balik nilai errno tunggal (mungkin ENOSYS?) sehingga libseccomp tidak terpengaruh oleh setiap perubahan dalam kernel (atau perbedaan ABI).

Jika ini menjadi masalah untuk debugging, mungkin kita bisa memperkenalkan attr baru yang akan meneruskan nilai errno langsung kembali ke pemanggil.

Mungkin, tetapi akan lebih baik untuk memastikan tidak ada kerusakan ABI/API jika pengguna libseccomp sudah mengharapkan nilai errno tertentu. Masalah aslinya adalah bahwa beberapa panggilan sistem hanya ada pada beberapa arsitektur (seperti ugetrlimit hanya pada x86_32) tetapi ini tidak dapat dibedakan dari nama panggilan sistem yang salah ketik, sehingga kode kesalahan yang berbeda (mungkin sintetis) akan diperlukan .

Yah, seperti yang telah kami katakan sebelumnya, saat ini kami tidak benar-benar menjamin nilai errno tertentu, hanya "nilai negatif pada kegagalan" jadi meskipun akan disayangkan untuk mematahkan pengguna yang saat ini membuat asumsi tentang nilai errno tertentu, saya pikir mengubah banyak hal untuk memberikan jaminan errno yang kuat di seluruh versi kernel dan ABI di masa depan adalah tradeoff yang berharga.

Yah, seperti yang telah kami katakan sebelumnya, saat ini kami tidak benar-benar menjamin nilai errno tertentu, hanya "nilai negatif pada kegagalan" jadi meskipun akan disayangkan untuk mematahkan pengguna yang saat ini membuat asumsi tentang nilai errno tertentu, saya pikir mengubah banyak hal untuk memberikan jaminan errno yang kuat di seluruh versi kernel dan ABI di masa depan adalah tradeoff yang berharga.

Saya setuju.

Setelah evaluasi ini selesai dan kami memperbarui nilai errno pada kegagalan, saya akan merasa lebih nyaman membuat semacam jaminan nilai errno dikembalikan.

Ide pengelompokan mungkin bukan yang terbaik, jadi mari kita mulai daftar untuk melacak semua ini _(Saya akan terus memperbarui ini seiring kemajuan kita)_:

  • [x] seccomp_reset
    Saat ini kembali: EINVAL, ENOMEM.

  • [x] seccomp_merge
    Saat ini kembali: EINVAL, EDOM, EEXIST, ENOMEM.

  • [x] seccomp_arch_exist
    Saat ini kembali: EINVAL, EEXIST.

  • [x] seccomp_arch_add
    Saat ini kembali: EINVAL, EEXIST, ENOMEM, EDOM.

  • [x] seccomp_arch_remove
    Saat ini kembali: EINVAL, EEXIST.

  • [x] seccomp_load
    Saat ini kembali: EINVAL, ENOMEM, ESRCH, ECANCELED.

  • [x] seccomp_attr_get
    Saat ini kembali: EINVAL, EEXIST.

  • [x] seccomp_attr_set
    Saat ini kembali: EINVAL, EACCES, EOPNOTSUPP, EEXIST.

  • [x] seccomp_syscall_resolve_name_arch
    Sudah didefinisikan dengan baik, mengembalikan nilai syscall atau __NR_SCMP_ERROR saat gagal.

  • [x] seccomp_syscall_resolve_name_rewrite
    Sudah didefinisikan dengan baik, mengembalikan nilai syscall atau __NR_SCMP_ERROR saat gagal.

  • [x] seccomp_syscall_resolve_name
    Sudah didefinisikan dengan baik, mengembalikan nilai syscall atau __NR_SCMP_ERROR saat gagal.

  • [x] seccomp_syscall_priority
    Saat ini kembali: EINVAL, EDOM, EFAULT, ENOMEM.

  • [x] seccomp_rule_add_array
    Saat ini kembali: EINVAL, EOPNOTSUPP, ENOMEM, EDOM, EFAULT, EEXIST.

  • [x] seccomp_rule_add
    Saat ini kembali: EINVAL, EOPNOTSUPP, ENOMEM, EDOM, EFAULT, EEXIST.

  • [x] seccomp_rule_add_exact_array
    Saat ini kembali: EINVAL, EOPNOTSUPP, ENOMEM, EDOM, EFAULT, EEXIST.

  • [x] seccomp_rule_add_exact
    Saat ini kembali: EINVAL, EOPNOTSUPP, ENOMEM, EDOM, EFAULT, EEXIST.

  • [x] seccomp_notify_alloc
    Saat ini kembali: EOPNOTSUPP, ENOMEM, EFAULT, ECANCELED. Halaman manual sudah menentukan -1 pada kesalahan, yang kemungkinan merujuk hanya pada seccomp() errno.

  • [x] seccomp_notify_receive
    Saat ini kembali: EOPNOTSUPP dan ECANCELED. Halaman manual sudah menentukan -1 pada kesalahan, yang kemungkinan merujuk hanya pada seccomp() errno.

  • [x] seccomp_notify_respond
    Saat ini kembali: EOPNOTSUPP dan ECANCELED. Halaman manual sudah menentukan -1 pada kesalahan, yang kemungkinan merujuk hanya pada seccomp() errno.

  • [x] seccomp_notify_id_valid
    Saat ini kembali: EOPNOTSUPP dan ECANCELED. Halaman manual sudah menentukan -ENOENT pada kesalahan (ID tidak valid), yang kemungkinan merujuk hanya pada seccomp() errno.

  • [x] seccomp_notify_fd
    Sudah didefinisikan dengan baik, mengembalikan notifikasi fd.

  • [x] seccomp_export_pfc
    Saat ini kembali: EINVAL dan ECANCELED.

  • [x] seccomp_export_bpf
    Saat ini kembali: EINVAL, ENOMEM, dan ECANCELED.

Sekarang kita memiliki daftar fungsi apa yang mengembalikan kode kesalahan apa, saya merasa sedikit lebih baik tentang ini, terutama karena kami sudah cukup konsisten dengan cara kami menggunakan kode kesalahan kami. Bagian terakhir itu akan sangat membantu.

Saya akan memulai PR sehingga kami dapat mulai mengumpulkan perbaikan dan umpan balik tentang perubahan, saya akan segera mempostingnya di sini.

Mengingat sifat ENOSYS yang agak "khusus", saya ragu untuk menggunakan errno sebagai kernel/libc catch-all kami. Saya harus melihat nilai-nilai lain, apakah ada yang punya perasaan/pikiran yang kuat tentang ini?

Masih banyak yang hilang, sebagian besar pengeditan halaman manual dan komentar kode (belum lagi pengujian), tetapi Anda dapat melihat cabang berikut untuk mendapatkan gambaran tentang apa yang saya pikirkan:

Mengingat sifat ENOSYS yang agak "khusus", saya ragu untuk menggunakan errno sebagai kernel/libc catch-all kami. Saya harus melihat nilai-nilai lain, apakah ada yang punya perasaan/pikiran yang kuat tentang ini?

Bagaimana dengan EIO?

Bagaimana dengan EIO?

Saya tidak tahu apakah itu akan membuat kesalahan lebih bisa ditindaklanjuti. Bagaimana kalau memperluas API dengan fungsi yang tidak menggunakan nilai errno, tetapi misalnya:

  • SCMP_ERROR_UNKNOWN_SYSCALL: syscall tidak diketahui oleh libseccomp: pemanggil dapat menggunakan ini untuk menolak input pengguna (misalnya salah ketik dalam nama syscall)
  • SCMP_ERROR_SYSCALL_NOT_FOR_THIS_ARCH: syscall dikenal oleh libseccomp tetapi tidak tersedia di sini: pemanggil dapat mengabaikan kesalahan ini hanya untuk arsitektur ini
  • SCMP_ERROR_API_USAGE: libseccomp mendeteksi masalah dengan logika panggilan yang seharusnya tidak terjadi dalam kode yang ditulis dengan benar: pemanggil dapat memicu assert()
  • SCMP_ERROR_KERNEL_OTHER: libseccomp OK dengan input dan urutan panggilan, tetapi kernel mengembalikan kesalahan tertentu yang didefinisikan dengan baik misalnya ENOMEM, EPERM, ENOSYS: pemanggil harus memeriksa errno untuk tindakan. Jika alasan kesalahan diketahui oleh libseccomp terjadi karena kesalahan yang dibuat oleh pemanggil (misalnya EFAULT), mungkin SCMP_ERROR_API_USAGE dapat digunakan sebagai gantinya.
  • SCMP_ERROR_KERNEL_API_USAGE: libseccomp baik-baik saja dengan input dll, tetapi kernel tidak menyukainya karena alasan yang tidak begitu jelas dan jelas. Ini dapat menunjukkan perubahan kernel, konfigurasi yang dinonaktifkan, bug di libseccomp atau pemanggil, input pengguna yang sangat aneh, dll. Tindakan untuk pemanggil dapat berupa mencatat acara dan errno dengan permintaan untuk meneruskan info ke pengembang (pemanggil dan/atau libseccomp) untuk analisis lebih lanjut, tidak dapat ditegaskan ().

Atau, API dengan errnos dapat tetap apa adanya, tetapi fungsi baru dapat digunakan untuk meminta kode kesalahan di atas.

Mungkin @poettering atau @keszybz bisa berkomentar juga.

Saya tidak tahu apakah itu akan membuat kesalahan lebih bisa ditindaklanjuti. Bagaimana kalau memperluas API dengan fungsi yang tidak menggunakan nilai errno ...

Nah, sebelum kita bahkan dapat mempertimbangkan untuk melakukan sesuatu seperti itu (dan saya tidak yakin kita ingin melakukannya), kita perlu menetapkan kode pengembalian yang stabil dan didukung. Itulah yang sedang kami kerjakan di sini dan apa yang kami targetkan untuk v2.5.

Mari dapatkan kode pengembalian yang stabil/didukung di v2.5 dan kita dapat melihat bagaimana hasilnya, jika kita perlu melakukan sesuatu tambahan, kita dapat mempertimbangkannya untuk v2.6.

Bagaimana dengan EIO?

Saya melakukan ini untuk sementara waktu karena prioritas pekerjaan lain dan beberapa hal kernel, tetapi sekarang setelah saya kembali ke libseccomp, saya menyadari bahwa menggunakan EIO di sini tampaknya salah. Biarkan saya berpikir lebih banyak tentang ini.

Bagaimana dengan ECANCELED sebagai kode kesalahan kernel catch-all?

Saya ingin tahu apa yang Anda pikirkan @drakenclimber , Anda sudah lama diam tentang ini.

Saya melakukan ini untuk sementara waktu karena prioritas pekerjaan lain dan beberapa hal kernel, tetapi sekarang setelah saya kembali ke libseccomp, saya menyadari bahwa menggunakan EIO di sini tampaknya salah. Biarkan saya berpikir lebih banyak tentang ini.

Sama disini. Hal-hal telah sedikit sibuk akhir-akhir ini :/.

Saya ingin tahu apa yang Anda pikirkan @drakenclimber , Anda sudah lama diam tentang ini.

Tentu. Saya ingin membaca seluruh utas lagi, dan kemudian saya akan bergabung.

Bagaimana dengan ECANCELED sebagai kode kesalahan kernel catch-all?

Saya akui saya tidak terlalu akrab dengan ECANCELED. Saya secara singkat melihat melalui sumber kernel untuk penggunaannya dan melakukan pencarian google juga. ECANCELED tidak memiliki bentrokan dengan libseccomp, prctl(), atau API lain yang telah kami gunakan sebelumnya, dan saya pikir itu dapat merangkum kesalahan apa pun yang dilemparkan kernel kepada kami.

tl;dr - Saya baik-baik saja dengan ECANCELED sebagai solusi kami untuk semua kesalahan kernel.

Terima kasih banyak. Saya memiliki tambalan setengah matang yang akan saya selesaikan dan kirimkan sebagai PR untuk ditinjau.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat