I think junction object is your only option off the top of my head. croprey noted that you can't make Task/Event be the parent of any object which only leaves you with heavier customization. To do this, I think you'd be creating a custom object that would duplicate the records in Task/Event so you can utilize lookups/junction objects. It's not a great option and would get messy quick.
Can you take this a step back? What's the goal in associating multiple products to events/Tasks? Why on the event/task? Is there another custom object you can create that would make more sense to have products attached to it? Can they associate these events/tasks to a different object that would then have a list of the products they'd want? I would push back on why they think they need to do this and what the point of an activity is.
The activity object is generally more rigid which makes sense if you consider what the object is and what it's supposed to be used for (Calendar, to-do, notifications, etc).