diff -Nru syslog-ng-3.2.4.orig/lib/gprocess.c syslog-ng-3.2.4/lib/gprocess.c --- syslog-ng-3.2.4.orig/lib/gprocess.c 2011-05-04 13:57:48.000000000 +0200 +++ syslog-ng-3.2.4/lib/gprocess.c 2011-08-23 17:47:48.378752176 +0200 @@ -98,6 +98,7 @@ static gint init_result_pipe[2] = { -1, -1 }; static GProcessKind process_kind = G_PK_STARTUP; static gboolean stderr_present = TRUE; +static int have_capsyslog = FALSE; /* global variables */ static struct @@ -216,6 +217,14 @@ if (!process_opts.caps) return TRUE; +#ifdef CAP_SYSLOG + /* + * if libcap or kernel doesn't support cap_syslog, then resort to + * cap_sys_admin + */ + if (capability == CAP_SYSLOG && !have_capsyslog) + capability = CAP_SYS_ADMIN; +#endif caps = cap_get_proc(); if (!caps) return FALSE; @@ -422,7 +431,7 @@ * capability set. The process will change its capabilities to this value * during startup, provided it has enough permissions to do so. **/ -void +static void g_process_set_caps(const gchar *caps) { if (!process_opts.caps) @@ -430,6 +439,43 @@ } /** + * g_process_setup_caps(void) + * + * NOTE: polling /proc/kmsg requires cap_sys_admin, otherwise it'll always + * indicate readability. Enabling/disabling cap_sys_admin on every poll + * invocation seems to be too expensive. So I enable it for now. + */ +void +g_process_setup_caps(void) +{ + int ret; + gchar * capsstr = "cap_net_bind_service,cap_net_broadcast,cap_net_raw," + "cap_dac_read_search,cap_dac_override,cap_chown,cap_fowner=p " + "cap_sys_admin=ep"; +#ifdef CAP_SYSLOG + cap_t caps; + + /* Check whether cap_syslog exists. If not, get cap_sys_admin, else get + * cap_syslog */ + caps = cap_from_text("cap_syslog=p"); + if (caps) { + cap_free(caps); + /* libcap knows it, does the kernel? */ + ret = prctl(PR_CAPBSET_READ, CAP_SYSLOG); + if (ret != -1) { + /* kernel knows cap_syslog! Use it */ + capsstr = "cap_net_bind_service,cap_net_broadcast,cap_net_raw," + "cap_dac_read_search,cap_dac_override,cap_chown,cap_fowner=p " + "cap_syslog=ep"; + have_capsyslog = TRUE; + } + } +#endif + + g_process_set_caps(capsstr); +} + +/** * g_process_set_argv_space: * @argc: Original argc, as received by the main function in it's first parameter * @argv: Original argv, as received by the main function in it's second parameter diff -Nru syslog-ng-3.2.4.orig/lib/gprocess.h syslog-ng-3.2.4/lib/gprocess.h --- syslog-ng-3.2.4.orig/lib/gprocess.h 2011-05-04 13:57:48.000000000 +0200 +++ syslog-ng-3.2.4/lib/gprocess.h 2011-08-23 17:48:47.057167382 +0200 @@ -66,7 +66,7 @@ void g_process_set_pidfile(const gchar *pidfile); void g_process_set_pidfile_dir(const gchar *pidfile_dir); void g_process_set_working_dir(const gchar *cwd); -void g_process_set_caps(const gchar *caps); +void g_process_setup_caps(void); void g_process_set_argv_space(gint argc, gchar **argv); void g_process_set_use_fdlimit(gboolean use); void g_process_set_check(gint check_period, gboolean (*check_fn)(void)); diff -Nru syslog-ng-3.2.4.orig/modules/affile/affile.c syslog-ng-3.2.4/modules/affile/affile.c --- syslog-ng-3.2.4.orig/modules/affile/affile.c 2011-05-01 18:59:14.000000000 +0200 +++ syslog-ng-3.2.4/modules/affile/affile.c 2011-08-23 17:49:24.880790428 +0200 @@ -59,7 +59,11 @@ if (privileged) { g_process_cap_modify(CAP_DAC_READ_SEARCH, TRUE); +#ifdef CAP_SYSLOG + g_process_cap_modify(CAP_SYSLOG, TRUE); +#else g_process_cap_modify(CAP_SYS_ADMIN, TRUE); +#endif } else { diff -Nru syslog-ng-3.2.4.orig/syslog-ng/main.c syslog-ng-3.2.4/syslog-ng/main.c --- syslog-ng-3.2.4.orig/syslog-ng/main.c 2010-11-20 09:47:33.000000000 +0100 +++ syslog-ng-3.2.4/syslog-ng/main.c 2011-08-23 17:50:19.263248447 +0200 @@ -374,14 +374,10 @@ z_mem_trace_init("syslog-ng.trace"); g_process_set_argv_space(argc, (gchar **) argv); - - /* NOTE: polling /proc/kmsg requires cap_sys_admin, otherwise it'll always - * indicate readability. Enabling/disabling cap_sys_admin on every poll - * invocation seems to be too expensive. So I enable it for now. */ - - g_process_set_caps("cap_net_bind_service,cap_net_broadcast,cap_net_raw," - "cap_dac_read_search,cap_dac_override,cap_chown,cap_fowner=p " - "cap_sys_admin=ep"); + + /* Set up the minimal privilege we'll need */ + g_process_setup_caps(); + ctx = g_option_context_new("syslog-ng"); g_process_add_option_group(ctx); msg_add_option_group(ctx);