removed obsolete/unused patches
This commit is contained in:
parent
03c3a473bf
commit
6f0d3e4c3f
@ -1,60 +0,0 @@
|
|||||||
commit e75e70e736ea53078eaa9fd36a5f7186e3e2235c
|
|
||||||
Author: Josh Stone <jistone@redhat.com>
|
|
||||||
Date: Fri Jun 24 14:21:26 2011 -0700
|
|
||||||
|
|
||||||
rhbz716476: Don't allow path-based auth for uprobes
|
|
||||||
|
|
||||||
For users that are only members of stapusr, and not stapdev, we only
|
|
||||||
allow loading modules that are either signed with a trusted certificate
|
|
||||||
or located in controlled paths. For the script itself, that path is
|
|
||||||
/lib/modules/.../systemtap/, and for uprobes it is the runtime. When
|
|
||||||
this policy was first written, uprobes only ever came from the runtime
|
|
||||||
path, so the path check just returned 1 always.
|
|
||||||
|
|
||||||
Later, commit 474d17ad added an optional argument to staprun -u, to
|
|
||||||
allow the user to specify their own signed copy of uprobes to load.
|
|
||||||
Unfortunately, if presented with an unsigned module, that would still
|
|
||||||
fall back to the path check, which blissfully approved it anyway.
|
|
||||||
|
|
||||||
Our policy is now that stapusr can only load a signed uprobes.ko, so the
|
|
||||||
path check for uprobes now unconditionally returns 0.
|
|
||||||
|
|
||||||
diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c
|
|
||||||
index 74eef9c..82754d4 100644
|
|
||||||
--- a/runtime/staprun/staprun_funcs.c
|
|
||||||
+++ b/runtime/staprun/staprun_funcs.c
|
|
||||||
@@ -387,8 +387,10 @@ check_stap_module_path(const char *module_path, int module_fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
- * Members of the 'stapusr' group can load the uprobes module freely,
|
|
||||||
- * since it is loaded from a fixed path in the installed runtime.
|
|
||||||
+ * Don't allow path-based authorization for the uprobes module at all.
|
|
||||||
+ * Members of the 'stapusr' group can load a signed uprobes module, but
|
|
||||||
+ * nothing else. Later we could consider allowing specific paths, like
|
|
||||||
+ * the installed runtime or /lib/modules/...
|
|
||||||
*
|
|
||||||
* Returns: -1 on errors, 0 on failure, 1 on success.
|
|
||||||
*/
|
|
||||||
@@ -398,7 +400,7 @@ check_uprobes_module_path (
|
|
||||||
int module_fd __attribute__ ((unused))
|
|
||||||
)
|
|
||||||
{
|
|
||||||
- return 1;
|
|
||||||
+ return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -596,10 +598,8 @@ void assert_uprobes_module_permissions(
|
|
||||||
if (check_signature_rc == MODULE_ALTERED)
|
|
||||||
exit(-1);
|
|
||||||
#else
|
|
||||||
- /* If we don't have NSS, then the uprobes module is considered trusted.
|
|
||||||
- Otherwise a member of the group 'stapusr' will not be able to load it.
|
|
||||||
- */
|
|
||||||
- check_signature_rc = MODULE_OK;
|
|
||||||
+ /* If we don't have NSS, the uprobes module is considered untrusted. */
|
|
||||||
+ check_signature_rc = MODULE_UNTRUSTED;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* root can still load this module. */
|
|
@ -1,88 +0,0 @@
|
|||||||
commit fa6b56faaa56c98203dcc3fbdda5eab3d91ec62d
|
|
||||||
Author: Josh Stone <jistone@redhat.com>
|
|
||||||
Date: Fri Jun 24 15:00:41 2011 -0700
|
|
||||||
|
|
||||||
rhbz716489: read instead of mmap to load modules
|
|
||||||
|
|
||||||
As staprun is preparing to load a kernel module, we first mmap the whole
|
|
||||||
module as MAP_PRIVATE. Then we proceed with our security checks,
|
|
||||||
including a trusted-signature validation on the mapped region, and if
|
|
||||||
all checks out, we'll call init_module() with that same mapped region.
|
|
||||||
|
|
||||||
However, MMAP(2) says of MAP_PRIVATE, "It is unspecified whether changes
|
|
||||||
made to the file after the mmap() call are visible in the mapped
|
|
||||||
region." From my testing, it appears that file changes do indeed show
|
|
||||||
up in our mapped memory. This means we have a TOCTOU race between
|
|
||||||
verifying the signature of that memory and then calling init_module().
|
|
||||||
|
|
||||||
By using read() instead of mmap(), we ensure that we have a fully
|
|
||||||
private copy of the module to verify and load, without fear of change.
|
|
||||||
|
|
||||||
diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c
|
|
||||||
index 74eef9c..e0a5a46 100644
|
|
||||||
--- a/runtime/staprun/staprun_funcs.c
|
|
||||||
+++ b/runtime/staprun/staprun_funcs.c
|
|
||||||
@@ -49,7 +49,7 @@ int insert_module(
|
|
||||||
assert_permissions_func assert_permissions
|
|
||||||
) {
|
|
||||||
int i;
|
|
||||||
- long ret;
|
|
||||||
+ long ret, module_read;
|
|
||||||
void *module_file;
|
|
||||||
char *opts;
|
|
||||||
int saved_errno;
|
|
||||||
@@ -109,17 +109,39 @@ int insert_module(
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* mmap in the entire module. Work with the memory mapped data from this
|
|
||||||
- point on to avoid a TOCTOU race between path and signature checking
|
|
||||||
- below and module loading. */
|
|
||||||
- module_file = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, module_fd, 0);
|
|
||||||
- if (module_file == MAP_FAILED) {
|
|
||||||
- _perr("Error mapping '%s'", module_realpath);
|
|
||||||
+ /* Allocate memory for the entire module. */
|
|
||||||
+ module_file = calloc(1, sbuf.st_size);
|
|
||||||
+ if (module_file == NULL) {
|
|
||||||
+ _perr("Error allocating memory to read '%s'", module_realpath);
|
|
||||||
close(module_fd);
|
|
||||||
free(opts);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* read in the entire module. Work with this copy of the data from this
|
|
||||||
+ point on to avoid a TOCTOU race between path and signature checking
|
|
||||||
+ below and module loading. */
|
|
||||||
+ module_read = 0;
|
|
||||||
+ while (module_read < sbuf.st_size) {
|
|
||||||
+ ret = read(module_fd, module_file + module_read,
|
|
||||||
+ sbuf.st_size - module_read);
|
|
||||||
+ if (ret > 0)
|
|
||||||
+ module_read += ret;
|
|
||||||
+ else if (ret == 0) {
|
|
||||||
+ _err("Unexpected EOF reading '%s'", module_realpath);
|
|
||||||
+ free(module_file);
|
|
||||||
+ close(module_fd);
|
|
||||||
+ free(opts);
|
|
||||||
+ return -1;
|
|
||||||
+ } else if (errno != EINTR) {
|
|
||||||
+ _perr("Error reading '%s'", module_realpath);
|
|
||||||
+ free(module_file);
|
|
||||||
+ close(module_fd);
|
|
||||||
+ free(opts);
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* Check whether this module can be loaded by the current user.
|
|
||||||
* check_permissions will exit(-1) if permissions are insufficient*/
|
|
||||||
assert_permissions (module_realpath, module_fd, module_file, sbuf.st_size);
|
|
||||||
@@ -131,7 +153,7 @@ int insert_module(
|
|
||||||
|
|
||||||
/* Cleanup. */
|
|
||||||
free(opts);
|
|
||||||
- munmap(module_file, sbuf.st_size);
|
|
||||||
+ free(module_file);
|
|
||||||
close(module_fd);
|
|
||||||
|
|
||||||
if (ret != 0) {
|
|
178
swbz12899.patch
178
swbz12899.patch
@ -1,178 +0,0 @@
|
|||||||
commit b571f9347c4a54facadb5e948e1430bd2b89158a
|
|
||||||
Author: Stan Cox <scox@redhat.com>
|
|
||||||
Date: Fri Jun 10 09:42:43 2011 -0400
|
|
||||||
|
|
||||||
Don't process the dtrace -o FILENAME.
|
|
||||||
|
|
||||||
dtrace.in (main): Use suffix for both -h and -G. Check gcc return code.
|
|
||||||
dtrace.exp: Massage results accordingly.
|
|
||||||
|
|
||||||
commit f6b267eb5f999ce380f1169ba4aa81945b8b8fd2
|
|
||||||
Author: Stan Cox <scox@redhat.com>
|
|
||||||
Date: Tue Jun 14 16:16:59 2011 -0400
|
|
||||||
|
|
||||||
Improve dtrace handling of CC environment variable.
|
|
||||||
|
|
||||||
* dtrace.in (main): Split CC to allow for application Makefile abuse.
|
|
||||||
|
|
||||||
commit 4c353c3a6d5a7b75c3e897f1605ae6a98b0b1951
|
|
||||||
Author: Stan Cox <scox@redhat.com>
|
|
||||||
Date: Tue Jun 14 17:36:23 2011 -0400
|
|
||||||
|
|
||||||
Split command line pieces with shlex
|
|
||||||
|
|
||||||
dtrace.in (main): Use shlex.split for CPP, CC, and CFLAGS
|
|
||||||
|
|
||||||
commit 12aad6f0ee85529fa29d6b0790f7afc6f075a808
|
|
||||||
Author: Stan Cox <scox@redhat.com>
|
|
||||||
Date: Wed Jun 15 15:52:38 2011 -0400
|
|
||||||
|
|
||||||
Do status setting and exit at the top level.
|
|
||||||
|
|
||||||
* dtrace.in (main): Use return instead of sys.exit; move sys.exit to top.
|
|
||||||
|
|
||||||
diff --git a/dtrace.in b/dtrace.in
|
|
||||||
index a64d110..c1ea1fe 100755
|
|
||||||
--- a/dtrace.in
|
|
||||||
+++ b/dtrace.in
|
|
||||||
@@ -17,6 +17,7 @@ import os
|
|
||||||
import posix
|
|
||||||
import string
|
|
||||||
import sys
|
|
||||||
+import shlex
|
|
||||||
from subprocess import call
|
|
||||||
from tempfile import mkstemp
|
|
||||||
|
|
||||||
@@ -179,7 +180,7 @@ def help ():
|
|
||||||
def main():
|
|
||||||
if (len(sys.argv) < 2):
|
|
||||||
usage()
|
|
||||||
- sys.exit(1)
|
|
||||||
+ return 1
|
|
||||||
|
|
||||||
i = 1
|
|
||||||
build_header = False
|
|
||||||
@@ -187,7 +188,7 @@ def main():
|
|
||||||
add_typedefs = False
|
|
||||||
keep_temps = False
|
|
||||||
use_cpp = False
|
|
||||||
- h_ext = '.h'
|
|
||||||
+ suffix = ""
|
|
||||||
filename = ""
|
|
||||||
s_filename = ""
|
|
||||||
includes = []
|
|
||||||
@@ -205,10 +206,12 @@ def main():
|
|
||||||
defines.append(sys.argv[i])
|
|
||||||
elif (sys.argv[i] == "-h"):
|
|
||||||
build_header = True
|
|
||||||
+ suffix = ".h"
|
|
||||||
elif (sys.argv[i].startswith("-I")):
|
|
||||||
includes.append(sys.argv[i])
|
|
||||||
elif (sys.argv[i] == "-G"):
|
|
||||||
build_source = True
|
|
||||||
+ suffix = ".o"
|
|
||||||
elif (sys.argv[i] == "-k"):
|
|
||||||
keep_temps = True
|
|
||||||
elif (sys.argv[i] == "--types"):
|
|
||||||
@@ -218,17 +221,16 @@ def main():
|
|
||||||
i += 1
|
|
||||||
if (build_header == False and build_source == False):
|
|
||||||
usage()
|
|
||||||
- sys.exit(1)
|
|
||||||
+ return 1
|
|
||||||
|
|
||||||
if (s_filename != "" and use_cpp):
|
|
||||||
(d,fn) = mkstemp(suffix=".d")
|
|
||||||
CPP = os.environ.get("CPP", "cpp")
|
|
||||||
- args = [CPP] + includes + defines + [s_filename, fn]
|
|
||||||
- retcode = call(args)
|
|
||||||
+ retcode = call(shlex.split(CPP) + includes + defines + [s_filename, fn])
|
|
||||||
if (retcode != 0):
|
|
||||||
print "\"cpp includes s_filename\" failed"
|
|
||||||
usage()
|
|
||||||
- sys.exit(1)
|
|
||||||
+ return 1
|
|
||||||
s_filename = fn
|
|
||||||
if (filename == ""):
|
|
||||||
if (s_filename != ""):
|
|
||||||
@@ -236,15 +238,12 @@ def main():
|
|
||||||
filename = os.path.basename(filename)
|
|
||||||
else:
|
|
||||||
usage()
|
|
||||||
- sys.exit(1)
|
|
||||||
+ return 1
|
|
||||||
else:
|
|
||||||
- if (build_header):
|
|
||||||
- h_ext = ""
|
|
||||||
- else:
|
|
||||||
- (filename,ext) = os.path.splitext(filename)
|
|
||||||
+ suffix = ""
|
|
||||||
if (build_header):
|
|
||||||
providers = _provider()
|
|
||||||
- providers.generate(s_filename, filename + h_ext, add_typedefs)
|
|
||||||
+ providers.generate(s_filename, filename + suffix, add_typedefs)
|
|
||||||
elif (build_source):
|
|
||||||
(basename,ext) = os.path.splitext(s_filename)
|
|
||||||
|
|
||||||
@@ -265,9 +264,13 @@ def main():
|
|
||||||
f.close()
|
|
||||||
CC = os.environ.get("CC", "gcc")
|
|
||||||
CFLAGS = "-g " + os.environ.get("CFLAGS", "")
|
|
||||||
- call([CC, "-fPIC"] + defines + includes + CFLAGS.split() +
|
|
||||||
- ["-I.", "-I@prefix@/include", "-c", fn, "-o",
|
|
||||||
- filename + ".o"], shell=False)
|
|
||||||
+ retcode = call(shlex.split(CC) + defines + includes + shlex.split(CFLAGS) +
|
|
||||||
+ ["-fPIC", "-I.", "-I@prefix@/include", "-c", fn, "-o",
|
|
||||||
+ filename + suffix], shell=False)
|
|
||||||
+ if (retcode != 0):
|
|
||||||
+ print "\"gcc " + fn + "\" failed"
|
|
||||||
+ usage()
|
|
||||||
+ return 1
|
|
||||||
if (not keep_temps):
|
|
||||||
os.remove(fn)
|
|
||||||
else:
|
|
||||||
@@ -277,6 +280,7 @@ def main():
|
|
||||||
os.remove(s_filename)
|
|
||||||
else:
|
|
||||||
print "cpp: " + s_filename
|
|
||||||
+ return 0
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
- main()
|
|
||||||
+ sys.exit(main())
|
|
||||||
diff --git a/testsuite/systemtap.base/dtrace.exp b/testsuite/systemtap.base/dtrace.exp
|
|
||||||
index b301793..cd97c79 100644
|
|
||||||
--- a/testsuite/systemtap.base/dtrace.exp
|
|
||||||
+++ b/testsuite/systemtap.base/dtrace.exp
|
|
||||||
@@ -60,12 +60,12 @@ exec rm -f XXX.o
|
|
||||||
|
|
||||||
verbose -log "$dtrace -G -s $dpath -o XXX"
|
|
||||||
catch {exec $dtrace -G -s $dpath -o XXX}
|
|
||||||
-if {[file exists XXX.o]} then {
|
|
||||||
+if {[file exists XXX]} then {
|
|
||||||
pass "dtrace -G -o XXX"
|
|
||||||
} else {
|
|
||||||
fail "dtrace -G -o XXX"
|
|
||||||
}
|
|
||||||
-exec rm -f XXX.o
|
|
||||||
+exec rm -f XXX
|
|
||||||
|
|
||||||
verbose -log "$dtrace -h -s $dpath -o XXX.h"
|
|
||||||
catch {exec $dtrace -h -s $dpath -o XXX.h}
|
|
||||||
@@ -96,12 +96,12 @@ exec rm -f /tmp/XXX.o
|
|
||||||
|
|
||||||
verbose -log "$dtrace -G -s $dpath -o /tmp/XXX"
|
|
||||||
catch {exec $dtrace -G -s $dpath -o /tmp/XXX}
|
|
||||||
-if {[file exists /tmp/XXX.o]} then {
|
|
||||||
- pass "dtrace -G -o /tmp/XXX.o"
|
|
||||||
+if {[file exists /tmp/XXX]} then {
|
|
||||||
+ pass "dtrace -G -o /tmp/XXX"
|
|
||||||
} else {
|
|
||||||
- fail "dtrace -G -o /tmp/XXX.o"
|
|
||||||
+ fail "dtrace -G -o /tmp/XXX"
|
|
||||||
}
|
|
||||||
-exec rm -f /tmp/XXX.o
|
|
||||||
+exec rm -f /tmp/XXX
|
|
||||||
|
|
||||||
verbose -log "$dtrace -h -s $dpath -o /tmp/XXX.h"
|
|
||||||
catch {exec $dtrace -h -s $dpath -o /tmp/XXX.h}
|
|
@ -1,72 +0,0 @@
|
|||||||
commit 0bbb80098decc9c4c43a1800538007d86b600bba
|
|
||||||
Author: Josh Stone <jistone@redhat.com>
|
|
||||||
Date: Tue Jun 7 11:23:13 2011 -0700
|
|
||||||
|
|
||||||
stapconf: Conditionalize stacktrace_ops.warning{,_symbol}
|
|
||||||
|
|
||||||
Kernel commit 449a66f removed these fields.
|
|
||||||
|
|
||||||
* buildrun.cxx: Include the new test.
|
|
||||||
* runtime/autoconf-stacktrace_ops-warning.c: Check the warning field.
|
|
||||||
* runtime/stack.c: Conditionalize the warning initialization.
|
|
||||||
|
|
||||||
diff --git a/buildrun.cxx b/buildrun.cxx
|
|
||||||
index 0bebc35..79f8818 100644
|
|
||||||
--- a/buildrun.cxx
|
|
||||||
+++ b/buildrun.cxx
|
|
||||||
@@ -215,6 +215,8 @@ compile_pass (systemtap_session& s)
|
|
||||||
output_autoconf(s, o, "autoconf-ring_buffer-flags.c", "STAPCONF_RING_BUFFER_FLAGS", NULL);
|
|
||||||
output_autoconf(s, o, "autoconf-kallsyms-on-each-symbol.c", "STAPCONF_KALLSYMS_ON_EACH_SYMBOL", NULL);
|
|
||||||
output_autoconf(s, o, "autoconf-walk-stack.c", "STAPCONF_WALK_STACK", NULL);
|
|
||||||
+ output_autoconf(s, o, "autoconf-stacktrace_ops-warning.c",
|
|
||||||
+ "STAPCONF_STACKTRACE_OPS_WARNING", NULL);
|
|
||||||
output_autoconf(s, o, "autoconf-mm-context-vdso.c", "STAPCONF_MM_CONTEXT_VDSO", NULL);
|
|
||||||
output_autoconf(s, o, "autoconf-blk-types.c", "STAPCONF_BLK_TYPES", NULL);
|
|
||||||
output_autoconf(s, o, "autoconf-perf-structpid.c", "STAPCONF_PERF_STRUCTPID", NULL);
|
|
||||||
diff --git a/runtime/autoconf-stacktrace_ops-warning.c b/runtime/autoconf-stacktrace_ops-warning.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..9c00f05
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/runtime/autoconf-stacktrace_ops-warning.c
|
|
||||||
@@ -0,0 +1,10 @@
|
|
||||||
+/* Some kernels have warning fields in stacktrace_ops. */
|
|
||||||
+#include <linux/sched.h>
|
|
||||||
+#include <asm/stacktrace.h>
|
|
||||||
+
|
|
||||||
+void foo (void)
|
|
||||||
+{
|
|
||||||
+ struct stacktrace_ops t;
|
|
||||||
+ t.warning = 0;
|
|
||||||
+ (void) t;
|
|
||||||
+}
|
|
||||||
diff --git a/runtime/stack.c b/runtime/stack.c
|
|
||||||
index 68a7e4f..b2d5d1d 100644
|
|
||||||
--- a/runtime/stack.c
|
|
||||||
+++ b/runtime/stack.c
|
|
||||||
@@ -73,6 +73,7 @@ struct print_stack_data
|
|
||||||
int level;
|
|
||||||
};
|
|
||||||
|
|
||||||
+#if defined(STAPCONF_STACKTRACE_OPS_WARNING)
|
|
||||||
static void print_stack_warning(void *data, char *msg)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -81,6 +82,7 @@ static void
|
|
||||||
print_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
static int print_stack_stack(void *data, char *name)
|
|
||||||
{
|
|
||||||
@@ -95,8 +97,10 @@ static void print_stack_address(void *data, unsigned long addr, int reliable)
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct stacktrace_ops print_stack_ops = {
|
|
||||||
+#if defined(STAPCONF_STACKTRACE_OPS_WARNING)
|
|
||||||
.warning = print_stack_warning,
|
|
||||||
.warning_symbol = print_stack_warning_symbol,
|
|
||||||
+#endif
|
|
||||||
.stack = print_stack_stack,
|
|
||||||
.address = print_stack_address,
|
|
||||||
#if defined(STAPCONF_WALK_STACK)
|
|
@ -1,30 +0,0 @@
|
|||||||
From c02332052959e4213a59ce0ff40354f51506103a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Mark Wielaard <mjw@redhat.com>
|
|
||||||
Date: Wed, 6 Jul 2011 23:07:51 +0200
|
|
||||||
Subject: [PATCH] Silence sys/sdt.h comparison of unsigned expression < 0 is always false.
|
|
||||||
|
|
||||||
Some arm g++ setups would complain about the wchar_t "signedness detection":
|
|
||||||
sys/sdt.h:102: error: comparison of unsigned expression < 0 is always false
|
|
||||||
|
|
||||||
jistone said: "((T)(-1) < 1)" would still get the right boolean value,
|
|
||||||
and shouldn't trigger range errors like "unsigned is never < 0".
|
|
||||||
---
|
|
||||||
includes/sys/sdt.h | 2 +-
|
|
||||||
1 files changed, 1 insertions(+), 1 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h
|
|
||||||
index f7e1360..0a9fd40 100644
|
|
||||||
--- a/includes/sys/sdt.h
|
|
||||||
+++ b/includes/sys/sdt.h
|
|
||||||
@@ -77,7 +77,7 @@ struct __sdt_type
|
|
||||||
#define __SDT_ALWAYS_SIGNED(T) \
|
|
||||||
template<> struct __sdt_type<T> { static const bool __sdt_signed = true; };
|
|
||||||
#define __SDT_COND_SIGNED(T) \
|
|
||||||
-template<> struct __sdt_type<T> { static const bool __sdt_signed = ((T)(-1) < 0); };
|
|
||||||
+template<> struct __sdt_type<T> { static const bool __sdt_signed = ((T)(-1) < 1); };
|
|
||||||
__SDT_ALWAYS_SIGNED(signed char)
|
|
||||||
__SDT_ALWAYS_SIGNED(short)
|
|
||||||
__SDT_ALWAYS_SIGNED(int)
|
|
||||||
--
|
|
||||||
1.7.3.4
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user