Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8f4df86

Browse files
Robert MarshRobert Marsh
authored andcommitted
C++: more tests for command injection
1 parent f76ce8b commit 8f4df86

5 files changed

Lines changed: 311 additions & 42 deletions

File tree

cpp/ql/test/include/iterator.h

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#if !defined(CODEQL_ITERATOR_H)
2+
#define CODEQL_ITERATOR_H
3+
4+
typedef unsigned long size_t;
5+
6+
#include "type_traits.h"
7+
8+
namespace std {
9+
struct ptrdiff_t;
10+
11+
template<class I> struct iterator_traits;
12+
13+
template <class Category,
14+
class value_type,
15+
class difference_type = ptrdiff_t,
16+
class pointer_type = value_type*,
17+
class reference_type = value_type&>
18+
struct iterator {
19+
typedef Category iterator_category;
20+
21+
iterator();
22+
iterator(iterator<Category, remove_const_t<value_type> > const &other); // non-const -> const conversion constructor
23+
24+
iterator &operator++();
25+
iterator operator++(int);
26+
iterator &operator--();
27+
iterator operator--(int);
28+
bool operator==(iterator other) const;
29+
bool operator!=(iterator other) const;
30+
reference_type operator*() const;
31+
pointer_type operator->() const;
32+
iterator operator+(int);
33+
iterator operator-(int);
34+
iterator &operator+=(int);
35+
iterator &operator-=(int);
36+
int operator-(iterator);
37+
reference_type operator[](int);
38+
};
39+
40+
struct input_iterator_tag {};
41+
struct forward_iterator_tag : public input_iterator_tag {};
42+
struct bidirectional_iterator_tag : public forward_iterator_tag {};
43+
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
44+
45+
struct output_iterator_tag {};
46+
47+
template<class Container>
48+
class back_insert_iterator {
49+
protected:
50+
Container* container = nullptr;
51+
public:
52+
using iterator_category = output_iterator_tag;
53+
using value_type = void;
54+
using difference_type = ptrdiff_t;
55+
using pointer = void;
56+
using reference = void;
57+
using container_type = Container;
58+
constexpr back_insert_iterator() noexcept = default;
59+
constexpr explicit back_insert_iterator(Container& x);
60+
back_insert_iterator& operator=(const typename Container::value_type& value);
61+
back_insert_iterator& operator=(typename Container::value_type&& value);
62+
back_insert_iterator& operator*();
63+
back_insert_iterator& operator++();
64+
back_insert_iterator operator++(int);
65+
};
66+
67+
template<class Container>
68+
constexpr back_insert_iterator<Container> back_inserter(Container& x) {
69+
return back_insert_iterator<Container>(x);
70+
}
71+
72+
template<class Container>
73+
class front_insert_iterator {
74+
protected:
75+
Container* container = nullptr;
76+
public:
77+
using iterator_category = output_iterator_tag;
78+
using value_type = void;
79+
using difference_type = ptrdiff_t;
80+
using pointer = void;
81+
using reference = void;
82+
using container_type = Container;
83+
constexpr front_insert_iterator() noexcept = default;
84+
constexpr explicit front_insert_iterator(Container& x);
85+
constexpr front_insert_iterator& operator=(const typename Container::value_type& value);
86+
constexpr front_insert_iterator& operator=(typename Container::value_type&& value);
87+
constexpr front_insert_iterator& operator*();
88+
constexpr front_insert_iterator& operator++();
89+
constexpr front_insert_iterator operator++(int);
90+
};
91+
template<class Container>
92+
constexpr front_insert_iterator<Container> front_inserter(Container& x) {
93+
return front_insert_iterator<Container>(x);
94+
}
95+
}
96+
97+
#endif

cpp/ql/test/include/string.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#if !defined(CODEQL_STRING_H)
2+
#define CODEQL_STRING_H
3+
4+
#include "iterator.h"
5+
6+
namespace std
7+
{
8+
template<class charT> struct char_traits;
9+
10+
typedef size_t streamsize;
11+
12+
template <class T> class allocator {
13+
public:
14+
allocator() throw();
15+
typedef size_t size_type;
16+
};
17+
18+
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
19+
class basic_string {
20+
public:
21+
using value_type = charT;
22+
using reference = value_type&;
23+
using const_reference = const value_type&;
24+
typedef typename Allocator::size_type size_type;
25+
static const size_type npos = -1;
26+
27+
explicit basic_string(const Allocator& a = Allocator());
28+
basic_string(const charT* s, const Allocator& a = Allocator());
29+
template<class InputIterator> basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator());
30+
31+
const charT* c_str() const;
32+
charT* data() noexcept;
33+
size_t length() const;
34+
35+
typedef std::iterator<random_access_iterator_tag, charT> iterator;
36+
typedef std::iterator<random_access_iterator_tag, const charT> const_iterator;
37+
38+
iterator begin();
39+
iterator end();
40+
const_iterator begin() const;
41+
const_iterator end() const;
42+
const_iterator cbegin() const;
43+
const_iterator cend() const;
44+
45+
void push_back(charT c);
46+
47+
const charT& front() const;
48+
charT& front();
49+
const charT& back() const;
50+
charT& back();
51+
52+
const_reference operator[](size_type pos) const;
53+
reference operator[](size_type pos);
54+
const_reference at(size_type n) const;
55+
reference at(size_type n);
56+
template<class T> basic_string& operator+=(const T& t);
57+
basic_string& operator+=(const charT* s);
58+
basic_string& append(const basic_string& str);
59+
basic_string& append(const charT* s);
60+
basic_string& append(size_type n, charT c);
61+
template<class InputIterator> basic_string& append(InputIterator first, InputIterator last);
62+
basic_string& assign(const basic_string& str);
63+
basic_string& assign(size_type n, charT c);
64+
template<class InputIterator> basic_string& assign(InputIterator first, InputIterator last);
65+
basic_string& insert(size_type pos, const basic_string& str);
66+
basic_string& insert(size_type pos, size_type n, charT c);
67+
basic_string& insert(size_type pos, const charT* s);
68+
iterator insert(const_iterator p, size_type n, charT c);
69+
template<class InputIterator> iterator insert(const_iterator p, InputIterator first, InputIterator last);
70+
basic_string& replace(size_type pos1, size_type n1, const basic_string& str);
71+
basic_string& replace(size_type pos1, size_type n1, size_type n2, charT c);
72+
size_type copy(charT* s, size_type n, size_type pos = 0) const;
73+
void clear() noexcept;
74+
basic_string substr(size_type pos = 0, size_type n = npos) const;
75+
void swap(basic_string& s) noexcept/*(allocator_traits<Allocator>::propagate_on_container_swap::value || allocator_traits<Allocator>::is_always_equal::value)*/;
76+
};
77+
78+
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const basic_string<charT, traits, Allocator>& lhs, const basic_string<charT, traits, Allocator>& rhs);
79+
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const basic_string<charT, traits, Allocator>& lhs, const charT* rhs);
80+
81+
typedef basic_string<char> string;
82+
}
83+
84+
#endif

cpp/ql/test/include/type_traits.h

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,41 @@
22
#define CODEQL_TYPE_TRAITS_H
33

44
namespace std {
5-
template<typename T>
6-
struct remove_reference {
7-
typedef T type;
8-
};
5+
template<class T>
6+
struct remove_const { typedef T type; };
7+
8+
template<class T>
9+
struct remove_const<const T> { typedef T type; };
10+
11+
// `remove_const_t<T>` removes any `const` specifier from `T`
12+
template<class T>
13+
using remove_const_t = typename remove_const<T>::type;
14+
15+
template<class T>
16+
struct remove_reference { typedef T type; };
917

10-
template<typename T>
11-
struct remove_reference<T&> {
18+
template<class T>
19+
struct remove_reference<T &> { typedef T type; };
20+
21+
template<class T>
22+
struct remove_reference<T &&> { typedef T type; };
23+
24+
// `remove_reference_t<T>` removes any `&` from `T`
25+
template<class T>
26+
using remove_reference_t = typename remove_reference<T>::type;
27+
28+
template<class T>
29+
struct decay_impl {
1230
typedef T type;
1331
};
1432

15-
template<typename T>
16-
struct remove_reference<T&&> {
17-
typedef T type;
33+
template<class T, size_t t_size>
34+
struct decay_impl<T[t_size]> {
35+
typedef T* type;
1836
};
37+
38+
template<class T>
39+
using decay_t = typename decay_impl<remove_reference_t<T>>::type;
1940
}
2041

2142
#endif

cpp/ql/test/query-tests/Security/CWE/CWE-078/semmle/ExecTainted/test.c

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Semmle test case for rule ExecTainted.ql (Uncontrolled data used in OS command)
2+
// Associated with CWE-078: OS Command Injection. http://cwe.mitre.org/data/definitions/78.html
3+
4+
///// Library routines /////
5+
6+
int sprintf(char *s, const char *format, ...);
7+
int system(const char *string);
8+
9+
char *getenv(char *var);
10+
11+
extern void encodeShellString(char *shellStr, int maxChars, const char* cStr);
12+
#include "../../../../../../include/string.h"
13+
///// Test code /////
14+
15+
int main(int argc, char** argv) {
16+
char *userName = argv[2];
17+
18+
{
19+
// BAD: a string from the user is injected directly into
20+
// a command.
21+
char command1[1000] = {0};
22+
sprintf(command1, "userinfo -v \"%s\"", userName);
23+
system(command1);
24+
}
25+
26+
{
27+
// GOOD: the user string is encoded by a library routine.
28+
char userNameQuoted[1000] = {0};
29+
encodeShellString(userNameQuoted, 1000, userName);
30+
char command2[1000] = {0};
31+
sprintf(command2, "userinfo -v %s", userNameQuoted);
32+
system(command2);
33+
}
34+
}
35+
36+
void test2(char* arg2) {
37+
// GOOD?: the user string is the *first* part of the command, like $CC in many environments
38+
char *envCC = getenv("CC");
39+
40+
char command[1000];
41+
sprintf("%s %s", envCC, arg2);
42+
system(command);
43+
}
44+
45+
void test3(char* arg1) {
46+
// GOOD?: the user string is a `$CFLAGS` environment variable
47+
char *envCflags = getenv("CFLAGS");
48+
49+
char command[1000];
50+
sprintf(command, "%s %s", arg1, envCflags);
51+
system(command);
52+
}
53+
54+
typedef unsigned long size_t;
55+
typedef void FILE;
56+
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
57+
char *strncat(char *s1, const char *s2, size_t n);
58+
59+
void test4(FILE *f) {
60+
// BAD: the user string is injected directly into a command
61+
char command[1000] = "mv ", filename[1000];
62+
fread(filename, 1, 1000, f);
63+
64+
strncat(command, filename, 1000);
65+
system(command);
66+
}
67+
68+
void test5(FILE *f) {
69+
// GOOD?: the user string is the start of a command
70+
char command[1000], filename[1000] = " test.txt";
71+
fread(command, 1, 1000, f);
72+
73+
strncat(command, filename, 1000);
74+
system(command);
75+
}
76+
77+
int execl(char *path, char *arg1, ...);
78+
79+
void test6(FILE *f) {
80+
// BAD: the user string is injected directly into a command
81+
char command[1000] = "mv ", filename[1000];
82+
fread(filename, 1, 1000, f);
83+
84+
strncat(command, filename, 1000);
85+
execl("/bin/sh", "sh", "-c", command);
86+
}
87+
88+
void test7(FILE *f) {
89+
// GOOD [FALSE POSITIVE]: the user string is a positional argument to a shell script
90+
char path[1000] = "/home/me/", filename[1000];
91+
fread(filename, 1, 1000, f);
92+
93+
strncat(path, filename, 1000);
94+
execl("/bin/sh", "sh", "-c", "script.sh", path);
95+
}
96+
97+
// TODO: concatenations via operator+, more sinks, test for call context sensitivity at
98+
// concatenation site
99+
100+
// open question: do we want to report certain sources even when they're the start of the string?

0 commit comments

Comments
 (0)