Message ID | 1495138038-32212-2-git-send-email-siddhesh@sourceware.org |
---|---|
State | New |
Headers | show |
On 18/05/2017 17:07, Siddhesh Poyarekar wrote: > This change adds two new tunable macros to get and update tunables > respectively called TUNABLE_GET and TUNABLE_UPDATE_VAL. > > TUNABLE_GET accepts the top namespace, tunable namespace and tunable > id along with the target type as arguments and returns a value of the > target type. For example: > > TUNABLE_GET (glibc, malloc, check, int32_t) > > will return the tunable value for glibc.malloc.check in an int32_t. > > TUNABLE_UPDATE_VAL accepts the top namespace, tunable namespace and > tunable id along with the value to be stored into the tunable > structure followed by the type of the value. For example: > > TUNABLE_UPDATE_VAL (glibc, malloc, check, 1, int32_t); > > will update the glibc.malloc.check tunable. > > Given that the tunable structure is now relro, this is only really > possible from within the dynamic linker before it is relocated. In > future the tunable list may get split into mutable and immutable > tunables where mutable tunables can be modified by the library and > userspace after relocation as well. However whenever we actually do > that, we will have to ensure that the mutable tunables are protected > with locks. > > * elf/dl-tunables.h (strval): Replace with a bool initialized. > (TUNABLE_ENUM_NAME, TUNABLE_ENUM_NAME1): Adjust names to > prevent collision. > (__tunable_update_val): New function. > (TUNABLE_GET): New macro. > (TUNABLE_SET_VAL_FULL_WITH_CALLBACK): New macro. > (TUNABLE_SET_VAL): Use it. > (TUNABLE_SET_VAL_WITH_CALLBACK): Likewise. > (TUNABLE_UPDATE_VAL): New macro. > (tunables_strtoul): Replace strval with initialized. > (__tunables_init): Likewise. > (__tunable_set_val): Likewise. > (do_tunable_update_val): New function. > (tunables_initialize): Use it. > (__tunable_update_val): New function. > * README.tunables: Document the new macros. LGTM (I added just some document extension points and it is not a patch blocker). > --- > README.tunables | 27 +++++++++++++++++++++++++++ > elf/dl-tunables.c | 43 +++++++++++++++++++++++++++++++++++-------- > elf/dl-tunables.h | 40 ++++++++++++++++++++++++++++------------ > 3 files changed, 90 insertions(+), 20 deletions(-) > > diff --git a/README.tunables b/README.tunables > index 0e9b0d7..0bea2ca 100644 > --- a/README.tunables > +++ b/README.tunables > @@ -75,6 +75,33 @@ The list of allowed attributes are: > TUNABLE_SET_VALUE_WITH_CALLBACK instead and additionally pass a pointer to > the function that should be called if the tunable value has been set. > > +GETTING A TUNABLE VALUE > +----------------------- > + > +One may get the value of a tunable anywhere in glibc code using the TUNABLE_GET > +macro as follows: > + > + TUNABLE_GET (glibc, malloc, check, int32_t) > + > +The first three arguments of the macro are the top namespace, tunable namespace > +and the tunable name respectively. The last argument is the type of the > +tunable and must match the type of the tunable. > + > +UPDATING A TUNABLE VALUE > +------------------------ > + > +The tunable list is currently stored in a relro section, i.e. it cannot be > +modified after relocation. As a result, one may update the value of a tunable > +only in the dynamic linker. The TUNABLE_UPDATE_VALUE macro can be used to do > +this: > + > + TUNABLE_UPDATE_VAL (glibc, malloc, check, val, int32_t); > + > +where the first thre arguments of the macro are the top namespace, tunable > +namespace and the tunable name respectively. The fourth argument is the value > +to assign to the tunable and the last argument is the type of the tunable. The > +type in the fifth argument must match the type of the tunable. > + Wouldn't be worth do point where in code it updates now? The idea would just to add some reference point for possible future work. > FUTURE WORK > ----------- > > diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c > index 8d72e26..abf10e5 100644 > --- a/elf/dl-tunables.c > +++ b/elf/dl-tunables.c > @@ -184,19 +184,17 @@ tunables_strtoul (const char *nptr) > if ((__type) (__val) >= min && (__type) (val) <= max) \ > { \ > (__cur)->val.numval = val; \ > - (__cur)->strval = strval; \ > + (__cur)->initialized = true; \ > } \ > }) > > -/* Validate range of the input value and initialize the tunable CUR if it looks > - good. */ > static void > -tunable_initialize (tunable_t *cur, const char *strval) > +do_tunable_update_val (tunable_t *cur, const void *valp) > { > uint64_t val; > > if (cur->type.type_code != TUNABLE_TYPE_STRING) > - val = tunables_strtoul (strval); > + val = *((int64_t *) valp); > > switch (cur->type.type_code) > { > @@ -217,7 +215,7 @@ tunable_initialize (tunable_t *cur, const char *strval) > } > case TUNABLE_TYPE_STRING: > { > - cur->val.strval = cur->strval = strval; > + cur->val.strval = valp; > break; > } > default: > @@ -225,6 +223,35 @@ tunable_initialize (tunable_t *cur, const char *strval) > } > } > > +/* Validate range of the input value and initialize the tunable CUR if it looks > + good. */ > +static void > +tunable_initialize (tunable_t *cur, const char *strval) > +{ > + uint64_t val; > + const void *valp; > + > + if (cur->type.type_code != TUNABLE_TYPE_STRING) > + { > + val = tunables_strtoul (strval); > + valp = &val; > + } > + else > + { > + cur->initialized = true; > + valp = strval; > + } > + do_tunable_update_val (cur, valp); > +} > + > +void > +__tunable_update_val (tunable_id_t id, void *valp) > +{ > + tunable_t *cur = &tunable_list[id]; > + > + do_tunable_update_val (cur, valp); > +} > + > #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring > /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may > be unsafe for AT_SECURE processes so that it can be used as the new > @@ -375,7 +402,7 @@ __tunables_init (char **envp) > > /* Skip over tunables that have either been set already or should be > skipped. */ > - if (cur->strval != NULL || cur->env_alias == NULL) > + if (cur->initialized || cur->env_alias == NULL) > continue; > > const char *name = cur->env_alias; > @@ -432,7 +459,7 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback) > > /* Don't do anything if our tunable was not set during initialization or if > it failed validation. */ > - if (cur->strval == NULL) > + if (!cur->initialized) > return; > > /* Caller does not need the value, just call the callback with our tunable > diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h > index f33adfb..f465370 100644 > --- a/elf/dl-tunables.h > +++ b/elf/dl-tunables.h > @@ -39,8 +39,8 @@ struct _tunable > const char *name; /* Internal name of the tunable. */ > tunable_type_t type; /* Data type of the tunable. */ > tunable_val_t val; /* The value. */ > - const char *strval; /* The string containing the value, > - points into envp. */ > + bool initialized; /* Flag to indicate that the tunable is > + initialized. */ > tunable_seclevel_t security_level; /* Specify the security level for the > tunable with respect to AT_SECURE > programs. See description of > @@ -61,29 +61,45 @@ typedef struct _tunable tunable_t; > /* Full name for a tunable is top_ns.tunable_ns.id. */ > # define TUNABLE_NAME_S(top,ns,id) #top "." #ns "." #id > > -# define TUNABLE_ENUM_NAME(top,ns,id) TUNABLE_ENUM_NAME1 (top,ns,id) > -# define TUNABLE_ENUM_NAME1(top,ns,id) top ## _ ## ns ## _ ## id > +# define TUNABLE_ENUM_NAME(__top,__ns,__id) TUNABLE_ENUM_NAME1 (__top,__ns,__id) > +# define TUNABLE_ENUM_NAME1(__top,__ns,__id) __top ## _ ## __ns ## _ ## __id > > # include "dl-tunable-list.h" > > extern void __tunables_init (char **); > extern void __tunable_set_val (tunable_id_t, void *, tunable_callback_t); > +extern void __tunable_update_val (tunable_id_t, void *); > + > +/* Get and return a tunable value. */ > +# define TUNABLE_GET(__top, __ns, __id, __type) \ > +({ \ > + tunable_id_t id = TUNABLE_ENUM_NAME (__top, __ns, __id); \ > + __type ret; \ > + TUNABLE_SET_VAL_FULL_WITH_CALLBACK (id, &ret, NULL); \ > + ret; \ > +}) > > /* Check if the tunable has been set to a non-default value and if it is, copy > it over into __VAL. */ > # define TUNABLE_SET_VAL(__id,__val) \ > -({ \ > - __tunable_set_val \ > - (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \ > - NULL); \ > -}) > + TUNABLE_SET_VAL_FULL_WITH_CALLBACK (TUNABLE_ENUM_NAME (TOP_NAMESPACE, \ > + TUNABLE_NAMESPACE, \ > + __id), (__val), NULL) > > /* Same as TUNABLE_SET_VAL, but also call the callback function __CB. */ > # define TUNABLE_SET_VAL_WITH_CALLBACK(__id,__val,__cb) \ > + TUNABLE_SET_VAL_FULL_WITH_CALLBACK (TUNABLE_ENUM_NAME (TOP_NAMESPACE, \ > + TUNABLE_NAMESPACE, \ > + __id), \ > + (__val), DL_TUNABLE_CALLBACK (__cb)) > + > +# define TUNABLE_SET_VAL_FULL_WITH_CALLBACK(__id,__val,__cb)\ > + __tunable_set_val (__id, (__val), (__cb)) > + > +# define TUNABLE_UPDATE_VAL(__top, __ns, __id, __val, __type) \ > ({ \ > - __tunable_set_val \ > - (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \ > - DL_TUNABLE_CALLBACK (__cb)); \ > + __tunable_update_val (TUNABLE_ENUM_NAME (__top, __ns, __id), \ > + & (__type) {__val}); \ > }) > > /* Namespace sanity for callback functions. Use this macro to keep the >
diff --git a/README.tunables b/README.tunables index 0e9b0d7..0bea2ca 100644 --- a/README.tunables +++ b/README.tunables @@ -75,6 +75,33 @@ The list of allowed attributes are: TUNABLE_SET_VALUE_WITH_CALLBACK instead and additionally pass a pointer to the function that should be called if the tunable value has been set. +GETTING A TUNABLE VALUE +----------------------- + +One may get the value of a tunable anywhere in glibc code using the TUNABLE_GET +macro as follows: + + TUNABLE_GET (glibc, malloc, check, int32_t) + +The first three arguments of the macro are the top namespace, tunable namespace +and the tunable name respectively. The last argument is the type of the +tunable and must match the type of the tunable. + +UPDATING A TUNABLE VALUE +------------------------ + +The tunable list is currently stored in a relro section, i.e. it cannot be +modified after relocation. As a result, one may update the value of a tunable +only in the dynamic linker. The TUNABLE_UPDATE_VALUE macro can be used to do +this: + + TUNABLE_UPDATE_VAL (glibc, malloc, check, val, int32_t); + +where the first thre arguments of the macro are the top namespace, tunable +namespace and the tunable name respectively. The fourth argument is the value +to assign to the tunable and the last argument is the type of the tunable. The +type in the fifth argument must match the type of the tunable. + FUTURE WORK ----------- diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c index 8d72e26..abf10e5 100644 --- a/elf/dl-tunables.c +++ b/elf/dl-tunables.c @@ -184,19 +184,17 @@ tunables_strtoul (const char *nptr) if ((__type) (__val) >= min && (__type) (val) <= max) \ { \ (__cur)->val.numval = val; \ - (__cur)->strval = strval; \ + (__cur)->initialized = true; \ } \ }) -/* Validate range of the input value and initialize the tunable CUR if it looks - good. */ static void -tunable_initialize (tunable_t *cur, const char *strval) +do_tunable_update_val (tunable_t *cur, const void *valp) { uint64_t val; if (cur->type.type_code != TUNABLE_TYPE_STRING) - val = tunables_strtoul (strval); + val = *((int64_t *) valp); switch (cur->type.type_code) { @@ -217,7 +215,7 @@ tunable_initialize (tunable_t *cur, const char *strval) } case TUNABLE_TYPE_STRING: { - cur->val.strval = cur->strval = strval; + cur->val.strval = valp; break; } default: @@ -225,6 +223,35 @@ tunable_initialize (tunable_t *cur, const char *strval) } } +/* Validate range of the input value and initialize the tunable CUR if it looks + good. */ +static void +tunable_initialize (tunable_t *cur, const char *strval) +{ + uint64_t val; + const void *valp; + + if (cur->type.type_code != TUNABLE_TYPE_STRING) + { + val = tunables_strtoul (strval); + valp = &val; + } + else + { + cur->initialized = true; + valp = strval; + } + do_tunable_update_val (cur, valp); +} + +void +__tunable_update_val (tunable_id_t id, void *valp) +{ + tunable_t *cur = &tunable_list[id]; + + do_tunable_update_val (cur, valp); +} + #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may be unsafe for AT_SECURE processes so that it can be used as the new @@ -375,7 +402,7 @@ __tunables_init (char **envp) /* Skip over tunables that have either been set already or should be skipped. */ - if (cur->strval != NULL || cur->env_alias == NULL) + if (cur->initialized || cur->env_alias == NULL) continue; const char *name = cur->env_alias; @@ -432,7 +459,7 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback) /* Don't do anything if our tunable was not set during initialization or if it failed validation. */ - if (cur->strval == NULL) + if (!cur->initialized) return; /* Caller does not need the value, just call the callback with our tunable diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h index f33adfb..f465370 100644 --- a/elf/dl-tunables.h +++ b/elf/dl-tunables.h @@ -39,8 +39,8 @@ struct _tunable const char *name; /* Internal name of the tunable. */ tunable_type_t type; /* Data type of the tunable. */ tunable_val_t val; /* The value. */ - const char *strval; /* The string containing the value, - points into envp. */ + bool initialized; /* Flag to indicate that the tunable is + initialized. */ tunable_seclevel_t security_level; /* Specify the security level for the tunable with respect to AT_SECURE programs. See description of @@ -61,29 +61,45 @@ typedef struct _tunable tunable_t; /* Full name for a tunable is top_ns.tunable_ns.id. */ # define TUNABLE_NAME_S(top,ns,id) #top "." #ns "." #id -# define TUNABLE_ENUM_NAME(top,ns,id) TUNABLE_ENUM_NAME1 (top,ns,id) -# define TUNABLE_ENUM_NAME1(top,ns,id) top ## _ ## ns ## _ ## id +# define TUNABLE_ENUM_NAME(__top,__ns,__id) TUNABLE_ENUM_NAME1 (__top,__ns,__id) +# define TUNABLE_ENUM_NAME1(__top,__ns,__id) __top ## _ ## __ns ## _ ## __id # include "dl-tunable-list.h" extern void __tunables_init (char **); extern void __tunable_set_val (tunable_id_t, void *, tunable_callback_t); +extern void __tunable_update_val (tunable_id_t, void *); + +/* Get and return a tunable value. */ +# define TUNABLE_GET(__top, __ns, __id, __type) \ +({ \ + tunable_id_t id = TUNABLE_ENUM_NAME (__top, __ns, __id); \ + __type ret; \ + TUNABLE_SET_VAL_FULL_WITH_CALLBACK (id, &ret, NULL); \ + ret; \ +}) /* Check if the tunable has been set to a non-default value and if it is, copy it over into __VAL. */ # define TUNABLE_SET_VAL(__id,__val) \ -({ \ - __tunable_set_val \ - (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \ - NULL); \ -}) + TUNABLE_SET_VAL_FULL_WITH_CALLBACK (TUNABLE_ENUM_NAME (TOP_NAMESPACE, \ + TUNABLE_NAMESPACE, \ + __id), (__val), NULL) /* Same as TUNABLE_SET_VAL, but also call the callback function __CB. */ # define TUNABLE_SET_VAL_WITH_CALLBACK(__id,__val,__cb) \ + TUNABLE_SET_VAL_FULL_WITH_CALLBACK (TUNABLE_ENUM_NAME (TOP_NAMESPACE, \ + TUNABLE_NAMESPACE, \ + __id), \ + (__val), DL_TUNABLE_CALLBACK (__cb)) + +# define TUNABLE_SET_VAL_FULL_WITH_CALLBACK(__id,__val,__cb)\ + __tunable_set_val (__id, (__val), (__cb)) + +# define TUNABLE_UPDATE_VAL(__top, __ns, __id, __val, __type) \ ({ \ - __tunable_set_val \ - (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \ - DL_TUNABLE_CALLBACK (__cb)); \ + __tunable_update_val (TUNABLE_ENUM_NAME (__top, __ns, __id), \ + & (__type) {__val}); \ }) /* Namespace sanity for callback functions. Use this macro to keep the