Skip to content

Commit 2de9ee9

Browse files
beaubelgraverostedt
authored andcommitted
tracing/user_events: Align set_bit() address for all archs
All architectures should use a long aligned address passed to set_bit(). User processes can pass either a 32-bit or 64-bit sized value to be updated when tracing is enabled when on a 64-bit kernel. Both cases are ensured to be naturally aligned, however, that is not enough. The address must be long aligned without affecting checks on the value within the user process which require different adjustments for the bit for little and big endian CPUs. Add a compat flag to user_event_enabler that indicates when a 32-bit value is being used on a 64-bit kernel. Long align addresses and correct the bit to be used by set_bit() to account for this alignment. Ensure compat flags are copied during forks and used during deletion clears. Link: https://lore.kernel.org/linux-trace-kernel/20230925230829.341-2-beaub@linux.microsoft.com Link: https://lore.kernel.org/linux-trace-kernel/20230914131102.179100-1-cleger@rivosinc.com/ Cc: stable@vger.kernel.org Fixes: 7235759 ("tracing/user_events: Use remote writes for event enablement") Reported-by: Clément Léger <cleger@rivosinc.com> Suggested-by: Clément Léger <cleger@rivosinc.com> Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 23cce5f commit 2de9ee9

File tree

1 file changed

+51
-7
lines changed

1 file changed

+51
-7
lines changed

kernel/trace/trace_events_user.c

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,13 @@ struct user_event_enabler {
127127
/* Bit 7 is for freeing status of enablement */
128128
#define ENABLE_VAL_FREEING_BIT 7
129129

130-
/* Only duplicate the bit value */
131-
#define ENABLE_VAL_DUP_MASK ENABLE_VAL_BIT_MASK
130+
/* Bit 8 is for marking 32-bit on 64-bit */
131+
#define ENABLE_VAL_32_ON_64_BIT 8
132+
133+
#define ENABLE_VAL_COMPAT_MASK (1 << ENABLE_VAL_32_ON_64_BIT)
134+
135+
/* Only duplicate the bit and compat values */
136+
#define ENABLE_VAL_DUP_MASK (ENABLE_VAL_BIT_MASK | ENABLE_VAL_COMPAT_MASK)
132137

133138
#define ENABLE_BITOPS(e) (&(e)->values)
134139

@@ -174,6 +179,30 @@ struct user_event_validator {
174179
int flags;
175180
};
176181

182+
static inline void align_addr_bit(unsigned long *addr, int *bit,
183+
unsigned long *flags)
184+
{
185+
if (IS_ALIGNED(*addr, sizeof(long))) {
186+
#ifdef __BIG_ENDIAN
187+
/* 32 bit on BE 64 bit requires a 32 bit offset when aligned. */
188+
if (test_bit(ENABLE_VAL_32_ON_64_BIT, flags))
189+
*bit += 32;
190+
#endif
191+
return;
192+
}
193+
194+
*addr = ALIGN_DOWN(*addr, sizeof(long));
195+
196+
/*
197+
* We only support 32 and 64 bit values. The only time we need
198+
* to align is a 32 bit value on a 64 bit kernel, which on LE
199+
* is always 32 bits, and on BE requires no change when unaligned.
200+
*/
201+
#ifdef __LITTLE_ENDIAN
202+
*bit += 32;
203+
#endif
204+
}
205+
177206
typedef void (*user_event_func_t) (struct user_event *user, struct iov_iter *i,
178207
void *tpdata, bool *faulted);
179208

@@ -482,6 +511,7 @@ static int user_event_enabler_write(struct user_event_mm *mm,
482511
unsigned long *ptr;
483512
struct page *page;
484513
void *kaddr;
514+
int bit = ENABLE_BIT(enabler);
485515
int ret;
486516

487517
lockdep_assert_held(&event_mutex);
@@ -497,6 +527,8 @@ static int user_event_enabler_write(struct user_event_mm *mm,
497527
test_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler))))
498528
return -EBUSY;
499529

530+
align_addr_bit(&uaddr, &bit, ENABLE_BITOPS(enabler));
531+
500532
ret = pin_user_pages_remote(mm->mm, uaddr, 1, FOLL_WRITE | FOLL_NOFAULT,
501533
&page, NULL);
502534

@@ -515,9 +547,9 @@ static int user_event_enabler_write(struct user_event_mm *mm,
515547

516548
/* Update bit atomically, user tracers must be atomic as well */
517549
if (enabler->event && enabler->event->status)
518-
set_bit(ENABLE_BIT(enabler), ptr);
550+
set_bit(bit, ptr);
519551
else
520-
clear_bit(ENABLE_BIT(enabler), ptr);
552+
clear_bit(bit, ptr);
521553

522554
kunmap_local(kaddr);
523555
unpin_user_pages_dirty_lock(&page, 1, true);
@@ -849,6 +881,12 @@ static struct user_event_enabler
849881
enabler->event = user;
850882
enabler->addr = uaddr;
851883
enabler->values = reg->enable_bit;
884+
885+
#if BITS_PER_LONG >= 64
886+
if (reg->enable_size == 4)
887+
set_bit(ENABLE_VAL_32_ON_64_BIT, ENABLE_BITOPS(enabler));
888+
#endif
889+
852890
retry:
853891
/* Prevents state changes from racing with new enablers */
854892
mutex_lock(&event_mutex);
@@ -2377,15 +2415,16 @@ static long user_unreg_get(struct user_unreg __user *ureg,
23772415
}
23782416

23792417
static int user_event_mm_clear_bit(struct user_event_mm *user_mm,
2380-
unsigned long uaddr, unsigned char bit)
2418+
unsigned long uaddr, unsigned char bit,
2419+
unsigned long flags)
23812420
{
23822421
struct user_event_enabler enabler;
23832422
int result;
23842423
int attempt = 0;
23852424

23862425
memset(&enabler, 0, sizeof(enabler));
23872426
enabler.addr = uaddr;
2388-
enabler.values = bit;
2427+
enabler.values = bit | flags;
23892428
retry:
23902429
/* Prevents state changes from racing with new enablers */
23912430
mutex_lock(&event_mutex);
@@ -2415,6 +2454,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
24152454
struct user_event_mm *mm = current->user_event_mm;
24162455
struct user_event_enabler *enabler, *next;
24172456
struct user_unreg reg;
2457+
unsigned long flags;
24182458
long ret;
24192459

24202460
ret = user_unreg_get(ureg, &reg);
@@ -2425,6 +2465,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
24252465
if (!mm)
24262466
return -ENOENT;
24272467

2468+
flags = 0;
24282469
ret = -ENOENT;
24292470

24302471
/*
@@ -2441,6 +2482,9 @@ static long user_events_ioctl_unreg(unsigned long uarg)
24412482
ENABLE_BIT(enabler) == reg.disable_bit) {
24422483
set_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler));
24432484

2485+
/* We must keep compat flags for the clear */
2486+
flags |= enabler->values & ENABLE_VAL_COMPAT_MASK;
2487+
24442488
if (!test_bit(ENABLE_VAL_FAULTING_BIT, ENABLE_BITOPS(enabler)))
24452489
user_event_enabler_destroy(enabler, true);
24462490

@@ -2454,7 +2498,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
24542498
/* Ensure bit is now cleared for user, regardless of event status */
24552499
if (!ret)
24562500
ret = user_event_mm_clear_bit(mm, reg.disable_addr,
2457-
reg.disable_bit);
2501+
reg.disable_bit, flags);
24582502

24592503
return ret;
24602504
}

0 commit comments

Comments
 (0)