Skip to content

Taint support #203

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions README.taint
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
Taint Suport for Jim Tcl
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Taint Suport for Jim Tcl
Taint Support for Jim Tcl

========================

Author: Steve Bennett <[email protected]>
Date: 24 May 2011
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this really planned 10 years ago?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, really. Been out of tree for that long. I thought it was time to share.
Thanks for your edits below. I'll integrate them.


OVERVIEW
--------
Perl and Ruby support the concept of tainted data, taint sources
and taint sinks. The idea is to improve security in situations
where data may be coming from outside the program (e.g. input
to a web application) should not inadvertently be output
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
to a web application) should not inadvertently be output
to a web application). This data should not inadvertently be output

on a web page unescaped (to avoid XSS attacks), to a database
(to avoid SQL injections attacks) or to execute system commands
(to avoid system attacks).

Standard Tcl does not support tainting. Instead it uses "safe"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Standard Tcl does not support tainting. Instead it uses "safe"
Standard Tcl does not support tainting, but uses "safe"

interpreters for a similar purpose. For Jim Tcl, taint support is
smaller and simpler.

HOW IT WORKS
------------

Any data read from a 'taint source' is considered tainted.
As that data moves through the system, it retains its taint property.
Tainted data should not be allowed to be consumed by a 'taint sink'.
An error should be raised instead.

Taint Sources
~~~~~~~~~~~~~
Untrusted data may come from various sources in the system.
In Jim Tcl, the sources of external data are:

* Data read file a file or socket (aio read, gets, recvfrom)
* Command line arguments ($argv)
* Loaded code or scripts (source, package require, load)
* Environment variables (env)
* Custom Tcl commands implemented as C code

Any data from these sources may be considered "tainted".

By default, sockets are considered taint sources while the other
external data sources are not. Data read from a 'taint source'
filehandle with read, recvfrom or gets is tainted.

No filehandles are considered taint sinks by default.

Client sockets produced by accept inherit the accept socket settings.

Taint Sinks
~~~~~~~~~~~
In order for tainted data to cause security problems, the data
need to be used in certain contexts. These *may* include:

* Establishing network connections (socket)
* Sending the data to certain file descriptors (aio puts, sendto)
* Modifying the filesystem (open, file delete, rename, mkdir)
* Running commands (exec)
* Evaluating scripts (eval, uplevel, source)
* Use in custom Tcl commands implemented as C code

Taint Propagation
~~~~~~~~~~~~~~~~~
As tainted data is assigned, or manipulated, it should retain
its taint property. This includes the creation of new values
based on tainted data. Jim Tcl takes a conservative approach
to taint propagation as follows:

* Any copy of a tainted value is tainted (e.g. set, proc calls)
* Any value constructed in part from a tainted value is tainted
(append, lappend, lset)
* A tainted value added to a container (dict, list, array) remains tainted.
While the tainted value can be distinguished from other values
in the container, the container is not tainted. However if the container
needs to change representation (the entire container becomes tainted.
Comment on lines +73 to +75
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
While the tainted value can be distinguished from other values
in the container, the container is not tainted. However if the container
needs to change representation (the entire container becomes tainted.
If the tainted value can be distinguished from other values
in the container, the container is not tainted. However, if the container
needs to change representation, the entire container becomes tainted.

* Integer and floating point values are not tainted

Taint types
-----------
It may be useful to distinguish between different types of taint.
Each taint type is associate with a bit field. The standard taint
Copy link
Contributor

@gromgit gromgit Jul 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Each taint type is associate with a bit field. The standard taint
Each taint type is assigned a bit in a taint bit field. The standard taint

type is 1, but taint types 2, 4, etc. may also be used. If a taint
source is marked as taint type 2, it will not be flagged as invalid
when consumed by a taint sink marked as taint type 4.

The commands exec, source, etc. consider any taint to be invalid, however
file descriptors may have specific taint source and sink types specified.

Taint-aware Commands
--------------------
The following commands will fail if any argument is tainted:

- source, exec, open, socket, load, file mkdir, file delete, file rename

In addition, 'package require' will ignore any tainted paths in $auto_path

HOW TO USE IT
-------------
To mark a value as tainted:

taint varname

To remove the taint from a value:

untaint varname

To determine if a value is tainted:

info tainted $var

To mark a filehandle as a taint source or sink (or not):

$aiohandle taint source|sink ?0|n?

More Information
----------------
In order to simplify taint propagation, the interpreter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In order to simplify taint propagation, the interpreter
To simplify taint propagation, the interpreter

examines the arguments to every command (plus the command itself).
If any argument is tainted, the command execution is considered tainted.
Any new objects (except int and double) created during the execution of the command
will be marked tainted.

The Rules
---------
- The taint and untaint commands operate on variables and taint/untaint the contents of the variable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- The taint and untaint commands operate on variables and taint/untaint the contents of the variable
- The taint and untaint commands operate on variables, and taint/untaint the contents of the variable

- Adding/modifying a list/dict/array element taints that element plus the "container" but not
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Adding/modifying a list/dict/array element taints that element plus the "container" but not
- Adding/modifying a list/dict/array element taints that element plus the "container", but not

the other elements in that container
- Tainting a container element taints the container too
- Untainting a container element does not untaint the container, even if it contains no more tainted elements
- Tainting or untainting a container taints or untaints all elements in the container
- Any element of $auto_path that is tainted will be ignored when loading packages with package require

Specific Notes
--------------
In general, a conservative approach is used to tainting, so if
a command creates a new object while any of it's arguments are tainted,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
a command creates a new object while any of it's arguments are tainted,
a command creates a new object while any of its arguments are tainted,

the new object is also tainted.

However the list-related commands are more intelligent.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
However the list-related commands are more intelligent.
However, the list-related commands are more intelligent.

All list-related commands such as lindex, lrange, lassign and lreplace will
maintain the taint of existing list elements, but will avoid tainting untainted elements.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
maintain the taint of existing list elements, but will avoid tainting untainted elements.
not change the taint of existing list elements.

For example, if the list {a b t d} contains one tainted element, 't', then [lreverse $a]
will produce a list with only one tainted element.
7 changes: 6 additions & 1 deletion auto.def
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ options {
full
allextmod => "Enable all non-default extensions as modules if prerequisites are found"
compat => "Enable some backward compatibility behaviour"
taint=1 => "Disable taint support"
extinfo => "Show information about available extensions"
with-jim-shared shared => "Build a shared library instead of a static library"
jim-regexp=1 => "Prefer POSIX regex if over the the built-in (Tcl-compatible) regex"
Expand Down Expand Up @@ -487,6 +488,10 @@ if {![opt-bool introspection]} {
msg-result "Disabling introspection"
define JIM_NO_INTROSPECTION
}
if {[opt-bool taint]} {
msg-result "Enabling taint support"
define JIM_TAINT
}
if {[opt-bool shared with-jim-shared]} {
msg-result "Building shared library"
} else {
Expand Down Expand Up @@ -658,7 +663,7 @@ foreach mod $extinfo(module-c) {
}
define BUILD_SHOBJS [join $lines \n]

make-config-header jim-config.h -auto {HAVE_LONG_LONG* JIM_UTF8 SIZEOF_INT} -bare JIM_VERSION -none *
make-config-header jim-config.h -auto {HAVE_LONG_LONG* JIM_UTF8 JIM_TAINT SIZEOF_INT} -bare JIM_VERSION -none *
make-config-header jimautoconf.h -auto {jim_ext_* TCL_PLATFORM_* TCL_LIBRARY USE_* JIM_* _FILE_OFFSET*} -bare {S_I*}
make-template Makefile.in
make-template tests/Makefile.in
Expand Down
5 changes: 5 additions & 0 deletions examples/udp.client
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ foreach i [range 5 10] {
# Receive the response - max length of 100
puts [$s recvfrom 100]
}

# If taint is supported, this is an unsafe command
# and the server will refuse to do it
$s puts -nonewline {[exec echo hello]}
puts [$s recvfrom 100]
6 changes: 6 additions & 0 deletions examples/udp.server
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
# Listen on port 20000. No host specified means 0.0.0.0
set s [socket dgram.server 20000]

# We won't run unsafe commands, but
# we don't mind sending anything back
catch {
$s taint sink 0
}

# For each request...
$s readable {
# Get the request (max 80 chars) - need the source address
Expand Down
Loading