My solution:

n, m, found = ARGV.shift.to_i, ARGV.shift.to_i, []
(n+n*n/m).times do found.push(rand(m)) end 
found.uniq!
found.slice!(n..-1)
found.sort!
found.map! { |i| i.to_s }
puts found.join("\n")

I also compared the various solutions, skipping those that took more than 
a minute:

adam.rb         elap 19.652 user 19.101 syst 0.227 CPU 98.35%
bill.rb         elap 43.157 user 41.780 syst 0.688 CPU 98.40%
ezra.rb         elap 33.861 user 32.193 syst 1.025 CPU 98.10%
joost1.rb       elap 32.797 user 31.447 syst 0.741 CPU 98.14%
joost2.rb       elap 21.465 user 20.336 syst 0.783 CPU 98.38%
wybo1.rb        elap 27.174 user 26.162 syst 0.543 CPU 98.27%
wybo2.rb        elap 23.279 user 22.241 syst 0.678 CPU 98.45%

The first (adam.rb) is not truly random.
wybo1.rb is my final solution shown above. 
wybo2.rb is what I could make inspired by joost1.rb and joost2.rb:

STDOUT.sync = false
GC.disable

num,ceil = ARGV.map { |s| s.to_i }
keep = {}

# only slightly slower but a lot shorter than rolling out:
num.times do 
  keep[rand(ceil)] = true
end

while keep.length < num
    keep[rand(ceil)] = true
end

found = keep.keys
# keeping things in place is faster:
found.sort!
found.map! { |i| i.to_s }
puts found.join("\n")
 
-- 
Wybo