#! /usr/bin/env ruby # require 'getoptlong' require 'tmpdir' $my_version = '$Id$' $random_length = 32 $prefix = "stress" $max_rules = 200 $min_rules = 5 def get_random_name(len=$random_length) return sprintf("%0#{len}x", rand(2 ** (4 * len))) end def get_random_path() out = "" 0.upto(rand(20)) do out = "#{out}/#{get_random_name(4)}" end return out end def get_random_mode() case rand(10) when 0..4 return "r" when 5..7 return "rw" when 8 return "Px" when 9 return "rix" end end # Abstract class, though may become a real class for generation of # random types of rules class Rule end class FileRule < Rule def initialize(path=get_random_path(), mode=get_random_mode()) @path = path @mode = mode end def to_s return " #{@path} #{@mode}," end end class CapRule < Rule CAP_LIST = [ "chown", "dac_override", "dac_read_search", "fowner", "fsetid", "kill", "setgid", "setuid", "setpcap", "linux_immutable", "net_bind_service", "net_broadcast", "net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module", "sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin", "sys_boot", "sys_nice", "sys_resource", "sys_time", "sys_tty_config", "mknod", "lease", "audit_write", "audit_control", "setfcap", "mac_override", "mac_admin" ] def initialize() @cap = CAP_LIST[rand(CAP_LIST.length)] end def to_s return " capability #{@cap}," end end def prefix_to_s(name) out = [] out << "#" out << "# prefix for #{name}" out << "# generated by #{__FILE__} #{$my_version}" out << "#include " out << "#" end class Flags FLAG_LIST = [ "complain", "audit", "chroot_relative", "namespace_relative", "mediate_deleted", "delegate_deleted", "attach_disconnected", "no_attach_disconnected", "chroot_attach", "chroot_no_attach" ] FLAG_CONFLICTS = [ ["chroot_relative", "namespace_relative"], ["mediate_deleted", "delegate_deleted"], ["attach_disconnected", "no_attach_disconnected"], ["chroot_attach", "chroot_no_attach"] ] def initialize() @flags = [] if rand(2) == 1 return end 0.upto(4 - Math.log(rand(32) + 1).to_int) do |x| @flags << FLAG_LIST[rand(FLAG_LIST.length)] end FLAG_CONFLICTS.each do |c| if @flags.include?(c[0]) and @flags.include?(c[1]) @flags.delete(c[rand(2)]) end end end def to_s if @flags.empty? return "" end out = @flags.join(",") return "flags=(#{out})" end end class Profile attr_reader :rvalue attr_reader :name def initialize() @rvalue = get_random_name() @name = "/does/not/exist/#{@rvalue}" @rules = [] @flags = Flags.new() end def generate_rules @rules << FileRule.new(@name, "rm").to_s 0.upto(rand($max_rules - $min_rules) + $min_rules) do |x| case rand(100) when 0..19 @rules << CapRule.new.to_s when 19..100 @rules << FileRule.new.to_s end end end def to_s out = [] out << "#" out << "# profile for #{@name}" out << "# generated by #{__FILE__} #{$my_version}" out << "#" out << "#{@name} #{@flags} {" out << " #include " out << "" @rules.sort.each { |r| out << " #{r}" } out << "}" out << "" end end def showUsage warn "#{$my_version}" warn "usage: #{__FILE__} count" exit 1 end def gen_profiles_dir(profiles) # Mu, no secure tmpdir creation in base ruby begin dirname = "#{Dir.tmpdir}/#{$prefix}-#{get_random_name(32)}" Dir.mkdir(dirname, 0755) rescue Errno::EEXIST retry end profiles.each do |p| open("#{dirname}/#{p.rvalue}", File::CREAT|File::EXCL|File::WRONLY, 0644) do |file| file.puts(prefix_to_s(p.name)) file.puts(p.to_s) end end return dirname end def gen_profiles_file(profiles) # Mu, no secure tempfile creation in base ruby begin filename = "#{Dir.tmpdir}/#{$prefix}-#{get_random_name(32)}" File.open(filename, File::CREAT|File::EXCL|File::WRONLY, 0644) do |file| file.puts(prefix_to_s(filename)) profiles.each { |p| file.puts(p.to_s) } end rescue Errno::EEXIST retry end return filename end if __FILE__ == $0 keep_files = true opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--seed', '-s', GetoptLong::REQUIRED_ARGUMENT ], [ '--keep-files', '-k', GetoptLong::NO_ARGUMENT ], [ '--max-rules', '-M', GetoptLong::REQUIRED_ARGUMENT ], [ '--min-rules', '-m', GetoptLong::REQUIRED_ARGUMENT ] ) opts.each do |opt, arg| case opt when '--help' showUsage when '--seed' srand(arg.to_i) when '--keep-files' keep_files = true when '--max-rules' $max_rules = arg.to_i when '--min-rules' $min_rules = arg.to_i end end showUsage if ARGV.length != 1 count = ARGV.shift.to_i showUsage if count < 1 profiles = [] while profiles.length < count do profiles << Profile.new() end profiles.each { |p| p.generate_rules } begin profiles_dir = gen_profiles_dir(profiles) profile_single = gen_profiles_file(profiles) ensure if (keep_files == false) Dir.foreach(profiles_dir) do |filename| File.delete("#{profiles_dir}/#{filename}") if (filename != '.' and filename != '..') end Dir.rmdir(profiles_dir) File.delete(profile_single) else puts "PROFILEDIR=#{profiles_dir}; export PROFILEDIR" puts "PROFILESINGLE=#{profile_single}; export PROFILESINGLE" end end end