I am using the following in openssh/telnet code, which sets the user environment.
setenv("TEST_ENV", "testing", 1);
But this can be modified by the user, is there anyway to make it readonly env variable?
I am using the following in openssh/telnet code, which sets the user environment.
setenv("TEST_ENV", "testing", 1);
But this can be modified by the user, is there anyway to make it readonly env variable?
There's nothing in the conventional process environment to make a variable read only, only shells have that concept for their own environment/variables (the two overlap in ways, but they must be understood as distinct). The same applies for type properties like integer, array, function etc.
Have you considered using a restricted shell, like rbash
?
You could set rbash
up to run readonly TEST_ENV
) in its startup script. rbash
may be too restrictive though, but it addresses to a good extent the issues raise in the comments.
The environment is a read/write part of each process (see here and here for details), not only can a process write directly to the data part (via environ[]
), it can change the pointers to it. You might be able to do something with this (i.e. relocate to a read-only page) if you are proficient in assembly and can find your way around the crt
startup code, but I don't recommend it ;-)
If there are specific commands that users run that must have a certain environment you may be able to set only group-execute and use sudo
to set the correct variables (e.g. via /etc/environment
or env_file
directive) and run the command as the specific group (preserving uid). Recent versions support noexec
on most platforms which can be used to prevent running a new shell (though can can break programs which legitimately fork()
and exec()
).
As a last option you may be able to use LD_PRELOAD
and your own library to set a controlled environment for some/all user processes by wrapping the relevant libc functions (getenv() putenv()
etc.). libfaketime does exactly this for time related libc functions. There's a less well known tool called timetravel that does similar, but also hooks setenv()
and getenv()
so as to keep control of LD_PRELOAD
in the face of adversity.
The most robust approach is to filter the setenv() unsetenv() putenv()
(and possibly clearnv()
) calls to prevent modification, and filter getenv()
so that it always returns the required value (possibly from a file). This approach won't prevent direct manipulation of the environment memory via environ[]
, but as long as you are in control of getenv()
any process which relies on the libc API should see your value. bash
uses environ[]
directly when it initialises, but also calls getenv()
.
Readonly variables can be set in POSIX compliant shells using the readonly
command.
readonly VAR=foo # POSIX
declare -r VAR=foo # bash
export VAR
This is in no way a security feature to prevent the user from changing it. The user can always spawn a new shell and change the variable.
zsh
allows typeset +r VAR
to turn the readonly attribute off.
– Stéphane Chazelas
Mar 02 '13 at 07:48
ksh
export the readonly attribute of exported variables to the environment via the A__z
special variable, so in a newly started ksh
, the variable will still be read-only (though if you have access to env
, or perl
or any other shell or tool that can modify an environment variable, that won't stop you from doing things like env VAR=new-value ksh
– Stéphane Chazelas
Mar 02 '13 at 08:20
[t]csh
? – jordanm Mar 02 '13 at 06:19C
code patched into openssh? – jordanm Mar 02 '13 at 06:25