Subscribe via Email

Subscribe via RSS/JSON


Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan


[Aside] Shellshock – Stop blaming Bash!

Am sure everyone’s heard of the Bash Shellshock bug by now. Basically, Bash (like most other shells) has environment variables. When launching Bash you can set an environment variable too, and the newly launched Bash process will inherit that variable. So far so good, but what researchers discovered is that due to the bug you can also set environment variables such that you sneak in some commands into them; and the resulting Bash process will execute these commands for you. That’s wicked because you (the admin) might not want users to run such commands, or worse the Bash process might be running with additional rights in which case the sneaked in commands too will run with these additional rights.

There’s a lot of hue and cry over this and blame assigned to the GNU project and its creator Richard Stallman, but I liked this post by Andrew Auernheimer. The whole post is a must read but here’s the bit I would like to highlight (emphasis mine):

Shellshock is not a critical failure in bash. It is a critical failure in thousands of people who knew a tool so useful that they decided to deploy it far beyond its scope. A tool so resilient that it it did not fall over when everyone deployed against best practices. Everyone knew in the nineties that when you execute a UNIX command with untrusted input, you clear away the environment variables first. Anyone that has untrusted input embedded within a shell script does not know what they are doing. The fact that there is a way to get bash to execute untrusted code is unsurprising. The thing that surprises me is the sheer number of developers who thought it would be otherwise in complete contrast to UNIX parables and common sense.

Spot on!

Here’s a blog post on clearing the environmental variables. More techniques are in this StackOverflow post. (I haven’t made Bash scripts for a long time now, so I just got these via a quick DuckDuckGo search. There might be other/ better techniques around!)

ps. Since posting this I came across a post on the bad code state of Bash. It doesn’t take away the fact that Bash isn’t solely to be blamed for Shellshock but I thought to mention it because I found it an interesting read.

Scope in PowerShell

PowerShell variables and functions have scope. The “scope” is what defines the visibility of that variable or function.

For instance, consider the following script:

If you were to run this script, here’s the output:

As you can see, the variable x was set as 2 initially but when the function blah set it to 5 the change didn’t really affect it. This is because of scopes. What happens is that the script variable x belongs to a different scope from the function variable x and although both have the same name they are in fact two different beings. In a way it’s like the variables are in two different boxes – each script/ function has a box full of variables, and whatever change they make to the variables in their box doesn’t affect the variables in other boxes. This is the case even if a function is within a script or another function – the child-function has a box of variables independent of its parent.

Now, the concept of scopes only matter when you are making changes to a variable. If you were just reading the value of a variable then scope doesn’t matter much. Consider the following script:

Here even though the function blah has a box of its own variables, when we refer to variable x within it since the variable is not present in its box it looks up to the box of its parent and reads the value from there. Hence the output of the script is:

But suppose we had made a change to variable x within the function (as in the first case), then a new variable x is created within the scope of that function and whatever change we make is limited to that variable.

There are four types of scopes:

  1. Local scope: the box you have, the current scope basically of the script or function you are in.
  2. Global scope: the big box that’s out there, the scope containing all variables that are in your particular PowerShell session (be it a PowerShell window or ISE)
  3. Script scope: another big box, but not as big as the global scope and not as limited as the local scope, this is the scope containing all variables that are in your particular PowerShell script session. The script scope is like a global scope for scripts.
  4. Private scope: a secret box you have, containing variables you don’t want your children to see. Remember I said earlier that if a variable is not present in a function it looks to the parent scope and reads it from there? If you have any variables you don’t want such children functions to see, define them in a private scope.

Consider the following script:

This is just to illustrate the first three scopes mentioned above. Here’s the output from the script:

The variable x was set as 2 initially. Function blah changed it to 5, but that only took effect in the local scope of the function and so x was still 2. Next, function blah2 changed x to 5 in the global scope (by addressing the variable as $global:x), but that too didn’t change the value of x as the change was made in the global scope and not the script scope. Finally, function blah3 changed x to 5 in the script scope (by addressing it as $script:x) and that effected the change.

From this example one can also see the need for a script scope and a global scope. Function blah3 changed variable x globally within the script, but any variable x existing outside the script and in the PowerShell session was unaffected. Similarly function blah2 changed variable x within the PowerShell session of the script, but the variable x within the script itself was unaffected (of course, if the script didn’t have a variable x then any references to x will pick up the variable from the global scope). If we didn’t have separate scopes for scripts and the PowerShell session, all scripts would mess about with the global scope variables.

Note though: The global scope and script scope are separate only if the script is run and not dot-sourced. If a script is dot-sourced, the script scope becomes the global scope.

And lastly, private scopes. Consider this script:

And here’s the output:

Since y was defined with a private scope in the script, function blah can’t read its value.

Scopes can also be referred to by a number. 0 is the local scope, 1 is the parent scope, 2 is the grandparent scope, and so on. This is useful with the Get-Variable cmdlet, for instance. Consider the following script:

Its output is thus:

As you can see, there are only two scopes – 0 is the local scope (the script scope in this case), 1 is the global scope. If I had defined a function within the script, then scope 0 would be the local scope, 1 would be the script scope, and 2 would be the global scope.

Accessing scopes by number is also useful with cmdlets such as Set-Variable. For instance, the following sets a variable in the parent scope of the calling script:

That’s all for now. It’s worth reiterating that within a script you have a global scope and a script scope, and the two are separate. Setting a variable in the global scope from a script does not affect the variable in the script scope.

Using closure to capture the variable value in a script-block

You can’t use New-Item to create new functions or aliases. It only works for files and directories.

But you can use Set-Item to create new functions and aliases.

How would I go about making a bunch of functions via a loop? The following code creates functions named Hello-<num> which output <num> when run.

Does this work?

And there lies the problem. Instead of each definition containing the number as it’s supposed to be, they all contain the variable $i. And since $i is 10 when the foreach loop terminated, all functions return the number 10.

I can test this by setting $i to a different number:

What I need is for $i in the Set-Item script-block to not be left as a variable, but to be “captured” (for lack of a better word) and set to whatever the value of the variable is at the time the script-block is created.

If you examine the members of a script-block you’ll notice a method called GetNewClosure(). That’s what I need to use here. This method “closes off” (like “closing a deal” or “let’s close somebody”, similar to “capturing somebody”) all variables in the script-block when it’s created.

Good to know!

Closures work with function parameters too. No side-effects as far as I know.