Some of the callers of the audit tty function use spin_lock_irqsave/restore. We were using the forced always enable version, which seems really bad. Since I don't know every one of these code paths well enough, it makes sense to just switch everything to the safe version. Maybe it's a little overzealous, but it's a lot better than an unlucky deadlock when we return to a caller with irq enabled and they expect it to be disabled.
Unified · Split
| @@ -111,11 +111,12 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf) · 110 unmodified lines | ||
| 111 | 111 | void tty_audit_exit(void) |
| 112 | 112 | { |
| 113 | 113 | struct tty_audit_buf *buf; |
| 114 | + unsigned long flags; | |
| 114 | 115 | |
| 115 | − spin_lock_irq(¤t->sighand->siglock); | |
| 116 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
| 116 | 117 | buf = current->signal->tty_audit_buf; |
| 117 | 118 | current->signal->tty_audit_buf = NULL; |
| 118 | − spin_unlock_irq(¤t->sighand->siglock); | |
| 119 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
| 119 | 120 | if (!buf) |
| 120 | 121 | return; |
| 121 | 122 | |
| @@ -133,9 +134,11 @@ void tty_audit_exit(void) · 11 unmodified lines | ||
| 133 | 134 | */ |
| 134 | 135 | void tty_audit_fork(struct signal_struct *sig) |
| 135 | 136 | { |
| 136 | − spin_lock_irq(¤t->sighand->siglock); | |
| 137 | + unsigned long flags; | |
| 138 | + | |
| 139 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
| 137 | 140 | sig->audit_tty = current->signal->audit_tty; |
| 138 | − spin_unlock_irq(¤t->sighand->siglock); | |
| 141 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
| 139 | 142 | } |
| 140 | 143 | |
| 141 | 144 | /** |
| @@ -145,13 +148,14 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) · 3 unmodified lines | ||
| 145 | 148 | { |
| 146 | 149 | struct tty_audit_buf *buf; |
| 147 | 150 | int major, minor, should_audit; |
| 151 | + unsigned long flags; | |
| 148 | 152 | |
| 149 | − spin_lock_irq(¤t->sighand->siglock); | |
| 153 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
| 150 | 154 | should_audit = current->signal->audit_tty; |
| 151 | 155 | buf = current->signal->tty_audit_buf; |
| 152 | 156 | if (buf) |
| 153 | 157 | atomic_inc(&buf->count); |
| 154 | − spin_unlock_irq(¤t->sighand->siglock); | |
| 158 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
| 155 | 159 | |
| 156 | 160 | major = tty->driver->major; |
| 157 | 161 | minor = tty->driver->minor_start + tty->index; |
| @@ -221,10 +225,11 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, · 63 unmodified lines | ||
| 221 | 225 | unsigned icanon) |
| 222 | 226 | { |
| 223 | 227 | struct tty_audit_buf *buf, *buf2; |
| 228 | + unsigned long flags; | |
| 224 | 229 | |
| 225 | 230 | buf = NULL; |
| 226 | 231 | buf2 = NULL; |
| 227 | − spin_lock_irq(¤t->sighand->siglock); | |
| 232 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
| 228 | 233 | if (likely(!current->signal->audit_tty)) |
| 229 | 234 | goto out; |
| 230 | 235 | buf = current->signal->tty_audit_buf; |
| @@ -232,7 +237,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, · 1 unmodified line | ||
| 232 | 237 | atomic_inc(&buf->count); |
| 233 | 238 | goto out; |
| 234 | 239 | } |
| 235 | − spin_unlock_irq(¤t->sighand->siglock); | |
| 240 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
| 236 | 241 | |
| 237 | 242 | buf2 = tty_audit_buf_alloc(tty->driver->major, |
| 238 | 243 | tty->driver->minor_start + tty->index, |
| @@ -242,7 +247,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, · 3 unmodified lines | ||
| 242 | 247 | return NULL; |
| 243 | 248 | } |
| 244 | 249 | |
| 245 | − spin_lock_irq(¤t->sighand->siglock); | |
| 250 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
| 246 | 251 | if (!current->signal->audit_tty) |
| 247 | 252 | goto out; |
| 248 | 253 | buf = current->signal->tty_audit_buf; |
| @@ -254,7 +259,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, · 5 unmodified lines | ||
| 254 | 259 | atomic_inc(&buf->count); |
| 255 | 260 | /* Fall through */ |
| 256 | 261 | out: |
| 257 | − spin_unlock_irq(¤t->sighand->siglock); | |
| 262 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
| 258 | 263 | if (buf2) |
| 259 | 264 | tty_audit_buf_free(buf2); |
| 260 | 265 | return buf; |
| @@ -317,16 +322,17 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, · 56 unmodified lines | ||
| 317 | 322 | void tty_audit_push(struct tty_struct *tty) |
| 318 | 323 | { |
| 319 | 324 | struct tty_audit_buf *buf; |
| 325 | + unsigned long flags; | |
| 320 | 326 | |
| 321 | − spin_lock_irq(¤t->sighand->siglock); | |
| 327 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
| 322 | 328 | if (likely(!current->signal->audit_tty)) { |
| 323 | − spin_unlock_irq(¤t->sighand->siglock); | |
| 329 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
| 324 | 330 | return; |
| 325 | 331 | } |
| 326 | 332 | buf = current->signal->tty_audit_buf; |
| 327 | 333 | if (buf) |
| 328 | 334 | atomic_inc(&buf->count); |
| 329 | − spin_unlock_irq(¤t->sighand->siglock); | |
| 335 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
| 330 | 336 | |
| 331 | 337 | if (buf) { |
| 332 | 338 | int major, minor; |
| @@ -804,10 +804,11 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) · 803 unmodified lines | ||
| 804 | 804 | case AUDIT_TTY_GET: { |
| 805 | 805 | struct audit_tty_status s; |
| 806 | 806 | struct task_struct *tsk = current; |
| 807 | + unsigned long flags; | |
| 807 | 808 | |
| 808 | − spin_lock_irq(&tsk->sighand->siglock); | |
| 809 | + spin_lock_irqsave(&tsk->sighand->siglock, flags); | |
| 809 | 810 | s.enabled = tsk->signal->audit_tty != 0; |
| 810 | − spin_unlock_irq(&tsk->sighand->siglock); | |
| 811 | + spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | |
| 811 | 812 | |
| 812 | 813 | audit_send_reply(NETLINK_CB(skb).portid, seq, |
| 813 | 814 | AUDIT_TTY_GET, 0, 0, &s, sizeof(s)); |
| @@ -816,6 +817,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) · 2 unmodified lines | ||
| 816 | 817 | case AUDIT_TTY_SET: { |
| 817 | 818 | struct audit_tty_status *s; |
| 818 | 819 | struct task_struct *tsk = current; |
| 820 | + unsigned long flags; | |
| 819 | 821 | |
| 820 | 822 | if (nlh->nlmsg_len < sizeof(struct audit_tty_status)) |
| 821 | 823 | return -EINVAL; |
| @@ -823,9 +825,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) · 1 unmodified line | ||
| 823 | 825 | if (s->enabled != 0 && s->enabled != 1) |
| 824 | 826 | return -EINVAL; |
| 825 | 827 | |
| 826 | − spin_lock_irq(&tsk->sighand->siglock); | |
| 828 | + spin_lock_irqsave(&tsk->sighand->siglock, flags); | |
| 827 | 829 | tsk->signal->audit_tty = s->enabled != 0; |
| 828 | − spin_unlock_irq(&tsk->sighand->siglock); | |
| 830 | + spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | |
| 829 | 831 | break; |
| 830 | 832 | } |
| 831 | 833 | default: |